Lightrion AOSP RAG — Documentation
This page covers how to configure your AI coding tool to query the Lightrion AOSP RAG service, what each tool does, which AOSP versions are available, and what to expect.
Overview
The service exposes an MCP server over Streamable HTTP at
https://aosp-rag.lightrion.com/mcp/.
All requests are authenticated with a bearer token issued to you during signup.
The server provides five tools: search_code, get_chunk,
get_file, list_versions, and diff_versions.
Any MCP-compatible client can call them.
Setup — Claude Code
Add the server to your Claude Code configuration with your API key:
claude mcp add --transport http aosp-rag \
https://aosp-rag.lightrion.com/mcp/ \
--header "Authorization: Bearer lr_prod_..."
Verify it’s connected:
claude mcp list
Then start a session and reference the server in your prompts:
Using the aosp-rag MCP server, search for "audio focus
in car media playback" and show the top three results.
Setup — Cursor
In Cursor settings, open the MCP servers panel and add a new server:
- Transport: HTTP
- URL:
https://aosp-rag.lightrion.com/mcp/ - Headers:
Authorization: Bearer lr_prod_...
Setup — opencode
opencode configures MCP servers in opencode.json (or
opencode.jsonc) under the mcp key.
Add Lightrion as a remote server:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"aosp-rag": {
"type": "remote",
"url": "https://aosp-rag.lightrion.com/mcp/",
"enabled": true,
"oauth": false,
"headers": {
"Authorization": "Bearer lr_prod_..."
}
}
}
}
Two things worth noting:
"oauth": falseis required — Lightrion uses bearer-token authentication, not OAuth. Without this, opencode will try to initiate an OAuth flow on first use and fail.- The trailing slash on
/mcp/matters — without it, the endpoint returns 404.
Once saved, verify the server is connected:
opencode mcp list
You should see aosp-rag with status connected.
To make opencode call the tools automatically when relevant, add a hint to
your AGENTS.md file:
When the user asks about Android source code, use the aosp-rag tools.
Setup — other MCP clients
Any MCP client that supports the Streamable HTTP transport works, including Cline, Zed,
and custom clients. Point the client at
https://aosp-rag.lightrion.com/mcp/ and add an
Authorization: Bearer <your_key> header.
The five tools
search_code
Semantic search across the AOSP source tree, ranked by relevance.
Arguments:
query(string, required) — natural-language description of what you want to findversion(string, optional) — AOSP release to query:"17","16","15","14", or"13". Defaults to"17"if omitted.release_tag(string, optional) — pin to a specific minor release (e.g."android-15.0.0_r20"), or pass"*"to query the full release history. See per-minor-release queries.limit(int, default 10) — how many results to return (max 50)filters(object, optional) — payload filters onlanguage,layer,component,symbol_kind,file_path,release_tagsinclude_content(bool, default false) — if true, inline the full chunk content with every result. Saves a follow-upget_chunkround-trip when the workflow already knows it’ll want every match’s full body.
Returns: a list of chunks, each with
chunk_id, file_path, language,
symbol_name, start_line, end_line,
a short preview, a relevance score in the range
0–1, plus release_tags (compact range form — see
below), first_seen_release,
and last_seen_release for each chunk. When
include_content=true, every chunk also carries a full
content field.
get_chunk
Retrieve a chunk’s full content and metadata by ID. Supports single or bulk fetches.
Arguments:
chunk_id(string OR array of strings, required) — a singlechunk_idfrom asearch_coderesult, OR an array of chunk_ids for a bulk fetch (parallel fan-out, partial-success tolerant).version(string, optional) — AOSP release the chunk_id(s) belong to. Must match the version passed to the correspondingsearch_codecall. Defaults to"17".
Returns: for a single ID, the chunk record with full
content. For an array, an object {chunks: [...], n_requested, n_ok, n_err}
where each entry in chunks is either a full chunk or an
error indicator if that specific ID failed.
get_file
Read any source file by repository path, optionally bounded by line range.
Arguments:
file_path(string, required) — the path relative to the AOSP root, e.g.frameworks/base/core/java/android/media/AudioManager.javaversion(string, optional) — AOSP release to read from. Defaults to"17".release_tag(string, optional) — read the file as it was at a specific historical release. Omit to read the version’s default release.start_line(int, optional)end_line(int, optional)
Returns: the file content (or the requested range) with line numbers and language metadata.
list_versions
Discover which AOSP versions are available on the server. Takes no arguments.
Returns: the default version, plus per-version metadata:
release_tag, n_chunks, n_points,
and the underlying Qdrant collection name.
Use this when you want to discover which releases are queryable without hardcoding the version list — useful in scripts and agent workflows that should keep working as new releases are added.
diff_versions
Run the same semantic query against two AOSP versions in parallel and
classify the resulting chunks into five buckets: unchanged,
modified, moved, only_in_a,
only_in_b. Use this for migration analysis
(“what changed between AAOS 14 and 17 for the audio subsystem?”),
API evolution tracking, and cross-version archaeology.
Supports two modes:
-
Major-to-major — pass two different major
versions like
version_a="14"andversion_b="17". Each side is queried at its latest indexed release tag. -
Minor-to-minor — pass full release tags on
BOTH sides within the same major, e.g.
version_a="android-14.0.0_r29"andversion_b="android-14.0.0_r75". Useful for tracking what shipped in a quarterly maintenance release or in a security patch within an Android major.
Arguments:
query(string, required) — semantic search query, same shape assearch_codeversion_a(string, required) — first AOSP version. Accepts a major like"14", or a full release tag like"android-14.0.0_r29"/"14.0.0_r75".version_b(string, required) — second AOSP version. If both arguments resolve to the same major, both must carry an explicit (different) release tag for a minor-to-minor diff.limit(int, default 10, max 25) — max chunks fetched per versionfilters(object, optional) — same shape assearch_code.filters, applied to both versionsverify(bool, default false) — kept for API stability; no-op now that theunchangedclassification is byte-perfect by construction (see below)
Returns: an object with a summary (counts
per bucket) and the five bucket arrays. The response also echoes
version_a, version_b, release_tag_a,
release_tag_b, and diff_mode
("major_to_major" or "minor_to_minor") so the
caller always knows which axes were diffed. unchanged entries
carry byte_identical: true and verified: true.
moved entries carry a type
(renamed / moved / moved_and_renamed)
and a similarity score; those discovered via chunk_id
intersection (byte-identical) also carry byte_identical: true.
A note on the chunk format
Every chunk returned by search_code, get_chunk,
and diff_versions carries metadata that makes cross-version
archaeology cheap:
-
release_tagsis returned in a compact range form like["r1-r24", "r27-r84"]rather than the full["android-13.0.0_r1", "android-13.0.0_r2", ...]array. Roughly 85% fewer tokens per result, and gaps in coverage (e.g. r25/r26 above) become visible at a glance. -
first_seen_releaseandlast_seen_releaseare returned as full release strings (e.g."android-14.0.0_r29") ready to pass directly to a follow-uprelease_tagargument.
Why diff_versions classifications are deterministic
Lightrion’s chunk_id is a content hash of the chunk
body. Identical code across versions yields the same
chunk_id; any byte-level change produces a different one.
diff_versions uses this directly:
-
Same chunk_id in both versions ⇒
unchanged(ormovedif the file_path or symbol_name differs — same body, different location). Byte-equal by construction. -
Same (file_path, symbol_name) but different chunk_id
⇒
modified. Content differs by construction. - No structural match either way ⇒ fall back to preview-similarity matching at threshold 0.7 with greedy assignment, which surfaces fuzzy moves and renames.
The verify argument is therefore informational rather than
corrective: the unchanged bucket is byte-perfect with or
without it.
AOSP versions available
The service currently indexes five releases. Each tool accepts an optional
version argument to target a specific one.
- AOSP 17 — tag
android-17.0.0_r1· 797,636 chunks · default - AOSP 16 — tag
android-16.0.0_r4· 862,224 chunks - AOSP 15 — tag
android-15.0.0_r36· 841,106 chunks - AOSP 14 — tag
android-14.0.0_r75· 849,557 chunks - AOSP 13 — tag
android-13.0.0_r84· 596,119 chunks
All major AOSP releases from 13 to 17 are indexed and queryable, with per-minor-release granularity (r1 through each major’s latest tag). Drop us a line at support@lightrion.com if you need an older release prioritised.
Choosing a version
When you call any of the tools, pass version explicitly to target a release:
Using aosp-rag with version=15, search for "vehicle HAL"
and show me the top result.
If you omit version, the server uses its default
(currently AOSP 17, the most recent release). The default may change in future
major releases; pin version in scripts where reproducibility matters.
Important: chunk_ids are scoped per version.
A chunk discovered via search_code(version="15") can only be
retrieved with get_chunk(version="15"). The agent typically
tracks this for you, but it’s worth knowing if you build custom workflows.
Per-minor-release queries
Each chunk carries a release_tags array listing every minor
release where it appears. This lets your agent answer
“in which minor release did this method change?” precisely,
rather than guessing.
You can also restrict a search to a specific minor release via the optional
release_tag argument:
Using aosp-rag with version=15 and release_tag=android-15.0.0_r20,
search for "PropertyHalService getProperty".
When omitted, release_tag defaults to each major’s latest
tag. Pass "*" to query across the full release history of a
major — useful for archaeology queries like
“when was this added?”.
What we index — and what we don’t
AOSP is roughly 100 GB of source per major release. We don’t embed all of it — some paths would hurt semantic search more than they help, and some are out of scope for an AOSP-focused engine. Here is the current exclusion list and the reasoning behind each choice. If one of these gets in your way, tell us — the list isn’t fixed.
Excluded at the repository level
These top-level directories are pruned from the walk and never indexed:
external/— third-party libraries vendored into AOSP (Boost, OpenSSL, Skia, ICU, etc.). Excellent code, but not Android-authored; upstream sources serve you better when you need to read them.prebuilts/— precompiled binaries, toolchains, and bundled SDKs. Not semantic-search material.cts/andvts/— the Compatibility and Vendor Test Suites. Validation code, not the runtime paths most queries are asking about.developers/— tutorials and sample apps maintained alongside AOSP. Not platform behaviour.pdk/— the legacy Platform Development Kit. Mostly stubs and boilerplate.tools/— clang, make, soong helpers, and other build infrastructure. Useful, but unrelated to runtime behaviour.
Each major release saves roughly 100 GB of disk and a comparable amount of embedding cost. The selectivity is what makes multi-version indexing economical.
Excluded at the file level
Within the indexed tree, these files are still skipped — either because they carry no source code or because they’d add noise to ranking:
- Binary, archive, and media files —
.png,.jpg,.svg,.jar,.aar,.apk,.dex,.so,.a,.o,.zip,.ttf,.mp3,.pdf, and the rest of the usual suspects. Nothing to embed. - Localized resource directories —
res/values-XX/,res/drawable-XX/,res/mipmap-XX/,res/layout-XX/and their locale variants (-fr,-zh-rTW, etc.). These are mechanical translations of the defaultres/values/and add nothing for code understanding. The defaults are indexed. - Generated and nested-test files —
_test.gogenerated tests and content under/test/test/nested test-data trees. Real test code outside those paths is indexed normally. - Build artifacts and VCS state —
out/,.git/,.repo/,node_modules/. The usual suspects, listed for completeness.
Small files get merged, not dropped
One source of confusion is “why doesn’t my five-line
#define show up as its own chunk?” The chunker has a
minimum of roughly fifty tokens per chunk; anything smaller gets merged
with neighbouring code or rolled into a whole-file chunk so it still
appears in the index, just under a larger semantic unit. This affects
kernel UAPI headers, single-define files, trivial test fixtures, and
similar — they’re searchable, you just won’t hit a
standalone chunk for them.
Want something added?
These exclusions are tradeoffs, not edicts. If you have a concrete use
case where one of them gets in the way — you’re writing a CTS
test and want CTS coverage, you’re investigating an
external/ dependency’s integration with AOSP, or
anything else — we’d like to hear about it.
Open an issue at github.com/Lightrion/skills or email support@lightrion.com and tell us what you were searching for and what would have helped. We can’t promise to index everything, but every one of these choices was made with someone’s workflow in mind — including, potentially, yours.
Example queries
Try these from your AI coding tool once configured:
Using aosp-rag, list_versions and tell me what's available.
Using aosp-rag with version=16, how does Android handle
audio focus in car media playback? Search for the relevant
code and walk me through the implementation.
Using aosp-rag, run diff_versions for "BroadcastQueue
deliverToReceiverLocked" between android-14.0.0_r29 and
android-14.0.0_r75 (minor-to-minor within Android 14).
Tell me what shipped in the quarterly maintenance window.
Using aosp-rag, run diff_versions for "CarPropertyService
setProperty" between AOSP 13 and AOSP 17. Summarize what
moved, what changed, and what was added.
Using aosp-rag, search_code for "subscribePropertyEvents"
in AOSP 14 with release_tag="*" and tell me, based on
first_seen_release, which minor release first introduced
this method.
Using aosp-rag with version=16, search for "audio focus
car media" then call get_chunk with chunk_id as an array
of the top 3 results to read all of them in one call.
Using aosp-rag with version=15, what files implement the
AIDL interfaces for the vehicle HAL? Search for "IVehicle"
in AIDL files.
Using aosp-rag, find the SELinux policy rules for the
audio HAL. They're probably in .te files.
Rate limits
Each API key has a per-minute and per-hour rate limit. Defaults are
60 requests per minute and 1,000 requests per hour.
Limits are returned in standard X-RateLimit-* response headers, and
exceeded limits return HTTP 429 with a Retry-After header.
If you have a legitimate use case that requires higher limits, email support@lightrion.com and we’ll consider raising your quota.
Key management
Keys are issued once and not retrievable later. If you lose your key, request a new one from the home page (the old one will eventually be revoked).
To revoke a key, email security@lightrion.com
with the first 12 characters of the key (e.g. lr_prod_aBcD).
Data and privacy
We log request metadata for analytics: HTTP method, path, status code, latency, the MCP
tool name (e.g. search_code), and a coarse summary of arguments
(string length, list size). We do not log the raw text of your queries
or the content returned to you.
See the privacy policy for the full details.
Support
Feedback, bug reports, and questions all welcome:
support@lightrion.com.
Or just reply to the welcome email — it comes from
dan@lightrion.com, which is a real address you can write to.
As an early user, you’re helping us shape the product. If something doesn’t work, doesn’t feel right, or surprises you in a good way, please tell us.