MCP Tools
rag-rat mcp starts a local rmcp STDIO server. The server is read-only for configured source
roots; it may update the configured SQLite index when automatic stale-index healing is needed. It
opens the index through the configured root, so search and graph tools resolve the active git commit
plus dirty worktree overlay in the same way as CLI queries.
Install
The MCP server is launched by the MCP client over STDIO; it does not listen on a TCP port. The
recommended setup is rag-rat init from the target repo, which indexes it and prints the one command
that registers a project-scoped MCP server (init does not register it for you). The per-repo
setup, by hand:
cd /path/to/your/repo
cargo install rag-rat # or: cargo install --path crates/rag-rat-cli --bin rag-rat
rag-rat index --discover
rag-rat models install sentence-transformers/all-MiniLM-L6-v2
rag-rat reconcile --changed-first --limit 500 --batch-size 64
rag-rat doctor
Use embedding-hash (built with --no-default-features) instead of FastEmbed when a small
dependency footprint matters more than real semantic embeddings:
rag-rat models install embedding-hash
Register a project-scoped server that runs in the repo so it resolves that repo’s rag-rat.toml:
claude mcp add --scope project rag-rat -- rag-rat mcp
or a project .mcp.json / equivalent:
{
"mcpServers": {
"rag-rat": { "command": "rag-rat", "args": ["mcp"] }
}
}
Do not register a single global/user-scoped server with a hardcoded --config /some/repo/...:
it would serve that one repo’s index and memories in every project. Keep the server project-scoped
and let it find rag-rat.toml from the repo it runs in. --config <path> remains available for a
specific profile, and rag-rat mcp --json switches tool results from TOON to JSON.
To run from a checkout without installing, use a project-scoped server whose command is
cargo run --manifest-path /path/to/rag-rat/Cargo.toml --bin rag-rat -- mcp.
Tools
The MCP surface is 47 tools in nine groups. The signatures are below; the prose sections that
follow describe response shapes and per-tool behavior. Every symbol/search/read tool additionally
accepts an optional "worktree": string — an absolute path to a linked git worktree, served as a
branch overlay over the indexed checkout — omitted from the signatures below for brevity.
Search & symbols
semantic_search:{ "query": string, "limit"?: number, "include_graph"?: "none" | "compact" | "full", "graph_limit"?: number, "include"?: ("generated" | "git" | "papertrail" | "fallback")[], "explain"?: boolean }symbol_lookup:{ "symbol"?: string, "ref"?: string, "id"?: string, "lang"?: string, "allow_ambiguous"?: boolean, "limit"?: number, "include"?: ("memories" | "generated")[] }docs_for_symbol:{ "symbol"?: string, "ref"?: string, "id"?: string, "allow_ambiguous"?: boolean, "limit"?: number }
Call graph & impact
find_callers:{ "symbol"?: string, "ref"?: string, "id"?: string, "resolution"?: "exact" | "syntactic" | "fuzzy", "allow_ambiguous"?: boolean, "limit"?: number, "include"?: ("references" | "unresolved" | "macros" | "common_methods" | "coverage" | "memories")[], "edge_kinds"?: string[] }trace_callees:{ "symbol"?: string, "ref"?: string, "id"?: string, "resolution"?: "exact" | "syntactic" | "fuzzy", "allow_ambiguous"?: boolean, "limit"?: number, "include"?: ("references" | "unresolved" | "macros" | "common_methods" | "coverage" | "memories")[], "edge_kinds"?: string[] }impact_surface:{ "query"?: string, "symbol"?: string, "ref"?: string, "id"?: string, "resolution"?: "exact" | "syntactic" | "fuzzy", "allow_ambiguous"?: boolean, "limit"?: number, "include"?: ("tests" | "docs" | "git" | "papertrail" | "text_fallback" | "memories")[], "full_memories"?: boolean }check_library_usage:{ "path"?: string, "package"?: string, "deprecated_only"?: boolean, "limit"?: number }compare_graph_to_text:{ "symbol"?: string, "ref"?: string, "id"?: string, "pattern": string, "resolution"?: "exact" | "syntactic" | "fuzzy", "allow_ambiguous"?: boolean, "limit"?: number, "include"?: ("tests" | "references" | "unresolved" | "macros" | "common_methods")[], "edge_kinds"?: string[] }compare_graph_to_scip:{}ffi_surface:{ "limit"?: number }
Orientation & ranking
repo_brief:{ "mode"?: "spine" | "churn" | "god_modules" | "refactor_candidates", "limit"?: number, "include"?: ("memories" | "generated")[] }repo_clusters:{ "limit"?: number, "include"?: ("memories" | "generated")[], "min_cluster_size"?: number }important_symbols:{ "limit"?: number, "personalize"?: string[] }
Clones
find_clones:{ "min_similarity"?: number, "min_copies"?: number, "limit"?: number }clones_for_symbol:{ "id"?: string, "ref"?: string, "path"?: string, "line"?: number }
Read
read_chunk:{ "chunk_id": number, "include_graph"?: "none" | "compact" | "full", "graph_limit"?: number, "include"?: ("memories")[] }
Git & tracker history
commit_search:{ "query": string, "limit"?: number }git_history_for_path:{ "path": string, "limit"?: number }git_history_for_symbol:{ "symbol"?: string, "ref"?: string, "id"?: string, "lang"?: string, "allow_ambiguous"?: boolean, "limit"?: number }commits_touching_query:{ "query": string, "limit"?: number }git_blame_chunk:{ "chunk_id": number }papertrail_for_chunk:{ "chunk_id": number, "limit"?: number }papertrail_for_symbol:{ "symbol"?: string, "ref"?: string, "id"?: string, "lang"?: string, "allow_ambiguous"?: boolean, "limit"?: number }papertrail_for_commit:{ "commit_hash": string, "limit"?: number, "include"?: ("fallback")[] }papertrail_issue_search:{ "query": string, "limit"?: number }papertrail_refs_for_path:{ "path": string, "limit"?: number }rationale_search:{ "query": string, "limit"?: number, "include"?: ("fallback")[] }
Index health
llm_status:{}heal_index:{ "limit"?: number }papertrail_sync_status:{}index_status:{}
Repo memories
memory_create:{ "kind": MemoryKind, "title": string, "body": string, "confidence": "high" | "medium" | "low", "created_by"?: string, "source"?: "agent" | "human" | "imported" | "generated", "tags"?: string[], "payload"?: object, "bind"?: BindTarget }memory_rebind:{ "memory_id": string, "bind": BindTarget }memory_update:{ "memory_id": string, "kind"?: MemoryKind, "title"?: string, "body"?: string, "confidence"?: "high" | "medium" | "low", "status"?: "active" | "stale" | "obsolete" | "rejected", "tags"?: string[], "payload"?: object }memory_search:{ "query": string, "limit"?: number }memory_for_symbol:{ "symbol"?: string, "ref"?: string, "id"?: string, "allow_ambiguous"?: boolean, "limit"?: number }memory_for_path:{ "path": string, "limit"?: number }memory_for_call_path:{ "edge_sequence_hash": string, "limit"?: number }memory_show:{ "memory_id": string }memory_validate:{}memory_doctor:{}memory_mark_obsolete:{ "memory_id": string }memory_edge_add:{ "source_node_id": string, "relation": "depends_on" | "relates_to" | "supersedes" | "derived_from" | "tracks", "target_node_id"?: string, "target_repo_id"?: string, "github_owner"?: string, "github_repo"?: string, "github_number"?: number }memory_edge_remove:{ "edge_key": string }memory_edges:{ "direction": "from" | "into", "node_id"?: string, "github_owner"?: string, "github_repo"?: string, "github_number"?: number }
MemoryKind is one of Invariant, Decision, RejectedAlternative, Risk, BugPattern,
TestExpectation, PerformanceNote, SecurityNote, FFIBoundary, PlatformQuirk, FollowUp,
OpenQuestion, Task, Concept, Obsolete. BindTarget names exactly one anchor — see
Repo memories below for its shape. payload is accepted only for the
polymorphic graph-node kinds Task and Concept (#465); passing it for any other kind is rejected.
Dream (memory maintenance)
dream:{ "limit"?: number, "all"?: boolean }dream_review:{ "finding": string, "verdict": "accept" | "dismiss" | "reset" }
The include array replaces the former include_* boolean params (#149 follow-up — shorter,
token-cheaper). Presence in the list turns a section on. Omit include entirely to keep each
tool’s defaults (e.g. impact_surface returns tests/docs/git/papertrail/text_fallback/memories;
graph tools return memories). A present list is the EXACT on-set — so it’s also how you disable a
default-on section: impact_surface with "include": ["git"] returns git history only, and any
tool with "include": [] returns the bare result. Each tool accepts only its own flags (see the
signatures above). The server also accepts a JSON-string-encoded array ("[\"git\"]") as well as a
real array, so the surface works even from clients that serialize array params as strings
(anthropics/claude-code#24599).
Compact vs full memories. impact_surface’s repo_memories payload is compact by default
(#37): each memory is summarized to a scannable header — memory_id, kind, title, confidence,
status, and its primary binding’s anchor_status / binding_kind / path / span / id — so an
agent skims the high-signal facts without scrolling full bodies. The lane shape is unchanged
(direct / path_crossed / call_path_crossed / stale). Pass "full_memories": true for the
full bodies + every binding + call paths, or fetch full detail per-anchor via
memory_for_symbol / memory_for_path / memory_for_call_path. (full_memories is orthogonal to
include: drop "memories" from include to omit the lane entirely.)
tools/list is served by rmcp and exposes typed JSON schemas derived from the same request structs
used by the handlers. Existing tool names and response fields are kept stable for current MCP clients.
Response encoding (TOON)
Tool results are returned as TOON (Token-Oriented Object Notation), not JSON. TOON is a
token-efficient text encoding that renders uniform result rows (caller lists, symbol candidates,
clusters) as a dense [N]{cols}: table — measured ~30% smaller than compact JSON on those payloads,
and never larger in practice (it ties compact JSON on nested shapes). Because MCP results are text
content consumed by an LLM, the denser encoding is both valid and cheaper. There is no per-call flag;
MCP output is always TOON. The JSON snippets below describe the logical shape of each response —
the same fields, just shown in JSON for readability. (The rag-rat CLI mirrors this: it defaults to
TOON and takes a global --json flag for JSON output.)
symbol_lookup is the candidate-selection step for symbol-shaped tools. It returns:
{
"candidates": [
{
"id": "sym_a3f29c1b",
"logical_variant_count": 2,
"logical_group_reason": "cfg_variant",
"ref": "crates/app/src/runtime/task_spawn.rs::spawn_blocking",
"qualified_name": "crates/app/src/runtime/task_spawn.rs::spawn_blocking",
"kind": "function",
"signature": "pub(crate) async fn spawn_blocking<F, T>(...)"
}
],
"disambiguation_required": true
}
Graph, docs, git-history, papertrail, and symbol-specific impact tools accept id,
ref, or symbol and resolve them in that priority order. id is the
opaque, stable handle a symbol_lookup (or any symbol-returning tool) emits — a sym_<hex>
token; copy it verbatim and pass it back, never parse it as a number. There is no numeric
symbol_id on the wire: it’s an internal rowid reassigned on every reindex, so it could not be
cached safely across an edit (#149). If a bare symbol maps to multiple candidates, the tool
returns the same candidate object instead of guessing. Pass allow_ambiguous: true only for
navigation/debugging when name fallback is acceptable.
Logical symbols group multiple concrete symbol rows that represent one source-level API, such as
Rust #[cfg] variants of the same function in the same file. Use id with
resolution: "exact" when callers target the logical API rather than one cfg body. Exact logical
mode only returns edges whose verified target_symbol_id is a member of the group. Graph envelopes
include the selected logical_symbol and its variants; cfg_expr may be null until cfg
attribute extraction is recorded by the parser.
Search tools return chunk IDs, paths, line spans, current-text snippets in the summary field, and
scores. Search and read_chunk validate stored chunk anchors against current source before
returning context; stale files are reindexed once per tool call and their SQLite FTS5 rows are
updated before retrying. Use read_chunk only after a search or lookup has narrowed the context.
Auto-heal is capped at four files per call. If more stale files are detected, tools return a
needs_reindex error instead of doing unbounded work. Deleted source for a requested chunk returns
Gone; a chunk that disappears after file reindex returns StaleChunk.
index_status reports content_revision, fts_source_revision, fts_dirty, and fts_fresh.
Search tools synchronize dirty or stale SQLite FTS state before querying so results are not served
from an outdated FTS table.
semantic_search graph and evidence controls:
include_graph:none,compact, orfull. Default iscompact.graph_limit: maximum caller/callee/import/type evidence entries to attach. Default is3for search and20forread_chunk.include: array ofgenerated(index generated files),git(git-history ranking boosts),papertrail(cached tracker papertrail boosts),fallback.gitandpapertrailare on by default — omitincludeto keep them; pass an explicit list to override.explain: include score components (bm25,vector,symbol,graph,git,papertrail). Default isfalse.
Every hit also carries retrieval_mode (lexical, vector, or hybrid) — always present, so a
caller knows whether embeddings contributed without setting explain. It is lexical for every
hit when no embedding model is active.
Graph tools are backed by tree-sitter-derived syntax edges. Edge kinds are imports, exports,
calls_name, constructs, dispatches, uses_macro, uses_operator, uses_precedence_group,
references_type, implements, and contains; confidence is reported as
edge_confidence (confidence is retained as the compatibility alias) with values Exact,
Syntactic, NameOnly, or Ambiguous. Graph evidence is syntactic, confidence-labeled evidence,
not compiler-grade name resolution or hard truth. Search results default to compact graph evidence
with bounded caller/callee lists; read_chunk defaults to full graph evidence. Caller and callee
entries include exact tree-sitter callsite spans: callsite.path, callsite.line, and
callsite.span ([start_line, end_line]).
Graph tools and impact_surface accept resolution:
exact: only verified target-symbol rows are returned. A row is allowed only when the edge’s verified target resolves to the selected symbol (itsid/ref), or the resolved fully-qualified symbol identity matchessymbol. Every returned row hasverified_target_symbol: true.syntactic: default. Exact matches plus qualified syntactic evidence are returned. Unresolved qualified call targets may be shown, but broad bare-name ambiguous fallback is excluded.fuzzy: compatibility/navigation mode. Suffix and bare-name fallback are allowed, including ambiguous candidates. Treat these rows as possible evidence, not proof.
Use id (the sym_<hex> handle from a previous symbol_lookup) with
resolution: "exact" to target a resolved symbol — including the cfg/duplicate-variant case, where
the handle addresses the whole logical group (all its members). Bare names in exact mode
intentionally return little or nothing unless id is provided.
find_callers and trace_callees return a graph envelope, not a bare row array:
{
"query": {
"tool": "find_callers",
"id": "sym_a3f29c1b",
"ref": "crates/app/src/runtime/task_spawn.rs::spawn_blocking",
"resolution": "exact"
},
"summary": {
"returned_count": 38,
"total_matching_edges": 38,
"truncated": false,
"exact_verified": 38,
"syntactic": 0,
"name_only": 0,
"ambiguous": 0,
"unresolved": 0,
"false_positive_risk": "low",
"completeness_risk": "low"
},
"coverage": {
"indexed_files": 1055,
"parser_failures": 0,
"stale_files": 0,
"known_index_gaps": [],
"parser_coverage_for_paths": []
},
"results": []
}
The trust signal is in summary and coverage: exact mode should have
exact_verified == total_matching_edges, truncated: false, no parser failures for covered paths,
stale_files: 0, and completeness_risk: low. If the source changed after indexing, stale_files is non-zero
for the covered paths and the result should be treated as needing reindex before audit use.
When strict graph rows are verified but same-name unresolved callsites exist, known_index_gaps
contains a plain-language note such as
31 unresolved qualified callsites match the requested final segment but are not verified to this symbol.
trace_callees is repo-relevant by default. It returns verified or syntactic calls_name edges and
verified/repo-local constructs edges. It hides unresolved calls, unresolved macros, type
references, imports/exports, common method/combinator calls, and std/common constructors unless a
caller asks for them explicitly:
Pass these in the include array (each off by default; memories is on by default):
unresolved: include unresolved qualified/name-only calls.macros: includeuses_macroedges such asformat!,json!, andvec!.common_methods: include common low-signal calls such asclone,map,map_err,and_then,unwrap_or,unwrap_or_else,to_string,to_owned,as_ref,as_mut,get,insert, and unresolved/commonnew.references: include type references, imports, exports,contains, andimplements.coverage(graph tools): attach the parser/coverage block.memories: attach crossing repo memories (on by default; pass"include": []to drop them).
find_callers uses exact target resolution first, then qualified-name and target-name fallbacks;
fallback hits are labeled with resolution, verified_target_symbol, raw evidence, and optional
receiver_hint so clients can treat name-only or ambiguous edges as possible evidence instead of
compiler truth. Rust macro invocations are stored as uses_macro and are not resolved to same-named
normal modules or functions.
compare_graph_to_text is the graph-vs-rg audit bridge. It resolves a selected symbol, runs the
same reverse caller graph traversal used by find_callers, runs a line-oriented regex search over
currently indexed source files, then compares (path, line) sets:
{
"query": {
"id": "sym_a3f29c1b",
"ref": "crates/app/src/runtime/task_spawn.rs::spawn_blocking",
"pattern": "crate::runtime::task_spawn::spawn_blocking\\(",
"resolution": "syntactic"
},
"summary": {
"text_hits": 38,
"graph_hits": 31,
"matched": 29,
"graph_only": 2,
"text_only": 9,
"likely_parser_gaps": 7,
"likely_false_positives": 1,
"complete": false,
"recommended_fallback": "both"
},
"matched_hits": [],
"text_only_hits": [],
"graph_only_edges": [],
"likely_parser_gaps": [],
"likely_false_positives": []
}
Matching is by path + callsite line. Text hits with no graph edge at that location are reported as
text_only_hits and copied into likely_parser_gaps; graph edges with no text match are reported as
graph_only_edges. Exact or logical graph-only rows may be legitimate imported, aliased, or
unqualified calls whose source line does not match the supplied regex. Fuzzy/name-only graph-only
rows are also listed in likely_false_positives. The tool includes the same coverage object as
graph traversal envelopes so audit output can be checked for stale source and parser failures before
treating the counts as authoritative.
compare_graph_to_scip is the graph-vs-compiler audit bridge — where compare_graph_to_text diffs
the tree-sitter graph against a regex, this diffs it against the SCIP oracle. It reports only
contradictions: edges where the heuristic resolved a callee to one target and the compiler says
it is actually another. Calls the heuristic merely missed or under-resolved are agreement-shaped
(the oracle classifies them Upgrade / ResolvedExternal) and are not reported — so an empty
result means “no contradictions,” not “SCIP found no missed edges.” It takes no arguments ({}) and
reports over the whole oracle-covered checkout; it requires rag-rat oracle run to have populated
compiler verdicts first, and returns nothing when no oracle data exists. Use it to debug the resolver
where tree-sitter and the compiler actively disagree. See oracle.md.
impact_surface is the graph-backed rg replacement path for a selected symbol. For
id, ref, or symbol requests it returns sections instead of a flat list:
direct_semantic_callersdirect_semantic_calleesimport_export_dependentstests_touching_symbol_pathdocs_mentioning_symbol_pathtext_fallback_hitsrecent_commits_touching_symbol_pathpapertrail_rationale_itemscompleteness_and_caveats
Use the same disambiguation controls as graph tools. resolution: "exact" means direct graph
callers/callees are verified against the selected symbol; syntactic allows qualified
tree-sitter evidence; fuzzy is for navigation only. The sections are controlled by the include
array — tests, docs, git, papertrail, text_fallback, memories, all on by default (omit
include to keep them; pass e.g. ["git"] to narrow to git history only). If exact graph callers
are empty but text fallback finds symbol/path hits, the caveats
section explicitly says that graph extraction or resolution gaps are likely. Free-text query
requests retain the older flat impact item shape for compatibility.
check_library_usage reports how the code uses its EXTERNAL libraries, from the SCIP oracle’s
external symbol info (index.external_symbols, parsed into the external_symbols table by
oracle run — data the reader used to discard). It joins every resolved-external call site to its
dependency contract by moniker and groups per dependency symbol. Each entries[] element carries the
moniker, package, kind, display_name, the dependency’s current signature_text /
signature_language / documentation (context — reason about arity / misuse yourself, nothing
is asserted), the deprecated flag (the one asserted verdict — a deterministic “deprecated”
marker in the docs/signature), and the call_sites (path + line span) with a call_count. The
report also returns total_external_call_sites, distinct_monikers, deprecated_call_sites, and
call_sites_without_signature_info (external calls whose moniker had no contract — coverage
transparency, not a finding). Filter with path (a file or directory prefix), package (a single
dependency), and deprecated_only. status is ok, no_oracle_run (run rag-rat oracle run
first), or no_external_symbols (the indexer emitted no external symbol info). It does NOT assert
arity or removed/renamed drift: call-site arg counts are not instrumented and a “removed” verdict
needs a cross-version baseline (re-index on lockfile change) — both are follow-ups. See
oracle.md.
Git history tools return historical evidence. commit_search searches commit subjects and bodies;
git_history_for_path returns commits touching a current path; git_history_for_symbol resolves
the current symbol path/range first, then returns path history; commits_touching_query combines
commit-message evidence with current file-change evidence; git_blame_chunk computes blame lazily
and caches it by source_text_hash.
index_status.git_history reports whether git history is available, current git HEAD, indexed HEAD,
commit count, and file-change count. Non-git roots report unavailable history without failing source
or docs indexing.
Papertrail tools read the local cache only. rag-rat papertrail sync mirrors every resolved
tracker binding through its native provider client; --full forces a complete historical re-walk
to heal cached rows. Source and commit references remain annotations and do not select what the
mirror fetches.
Papertrail outputs keep current_source separate from evidence. Cached snippets are labeled as
historical tracker evidence (historical_tracker / literal_tracker_ref) and classified as
decision, rejected_alternative, constraint, risk, obsolete, or context. Each evidence
row names its tracker (github), project (owner/repo), item_kind (issue |
change_request), item_key, and doc_kind (item | comment).
index_status.papertrail reports cached refs, issues, change requests, comments, last sync time,
and each binding’s authentication and native synchronization capability.
papertrail_sync_status returns that cache section directly. heal_index repairs or removes
already-indexed files whose current source no longer matches the stored SQLite index, then refreshes
SQLite FTS. It also probes every FTS mirror with a ranked query — the only read that decodes the
docsize shadow, whose corruption every ordinary integrity check misses — and rebuilds corrupt
mirrors from their durable sources, reporting them in fts_healed (or fts_deferred when a
staged rebuild in flight makes the repair unsafe — rerun once it completes). It does not discover
brand-new files; run rag-rat index for discovery.
Embedding artifacts are explicit and current-only. llm_status reports embedding model state,
artifact counts, FastEmbed build/cache/model details, and the last reconcile throughput summary when
available. The CLI-only models install embedding-hash command selects the deterministic baseline
embedder. Building with --features fastembed enables the real local
sentence-transformers/all-MiniLM-L6-v2 backend; models install sentence-transformers/all-MiniLM-L6-v2 is the intended
FastEmbed cache-population step. doctor reports FastEmbed build support, cache path, model,
dimension, current/stale/missing/failed embedding counts, last reconcile throughput, and the next
command needed to make local AI current. reconcile writes model-id, dimension, text-hash-bound, and
embedding-input-hash-bound chunk embeddings in configurable batches for eligible current chunks
only.
semantic_search combines BM25 candidates, vector similarity, symbol/name/path boosts,
graph-neighborhood boosts, and optional git/tracker papertrail boosts. Embeddings are used only when
the active model is installed, the embedding dimension matches active model metadata, the artifact
status is Current, the artifact text hash matches the current chunk text hash, and the stored
embedding input hash matches the current bounded embedding input; stale embeddings are treated as
absent. There is no summarizer or LLM runtime in this milestone.
Reconcile intentionally does not embed every chunk. It skips generated/coarse chunks, tiny chunks,
oversized low-value chunks, unsupported languages, low-signal import/export barrels, and test
fixtures with explicit policy reasons such as SkipGenerated, SkipTooSmall, SkipTooLarge,
SkipLowSignal, SkipLanguageUnsupported, and SkipTestFixture. Source symbols and docs are
prioritized ahead of tests and low-signal chunks. rag-rat reconcile --plan reports skipped counts
by policy and missing work by priority; reconcile JSON reports batch size, input character counts,
truncated input counts, chunks_per_sec, chars_per_sec, and average input size. Use
rag-rat reconcile --changed-first --max-seconds 60 --batch-size 64 for bounded daily catch-up and
rag-rat reconcile --until-clean --batch-size 64 for a full backlog pass.
Indexing uses a Rayon worker pool for CPU-heavy preparation: file reads, hashing, tree-sitter chunk/symbol preparation, and git-log parsing run across available cores. Reconcile builds bounded embedding inputs, runs model inference outside SQLite transactions, then writes vectors through one short serialized transaction per batch.
Parser failures are visible through index_status.parser_failure_paths, with path, language, and
message for each failed source parse. Markdown files are chunked by headings instead of parsed with
tree-sitter.
Orientation & ranking
repo_brief, repo_clusters, and important_symbols answer “what is this repo, and what holds it
together?” before you know a symbol to look up.
repo_brief ranks files by mode: spine (central coupling — what the rest of the code depends on),
churn (git change frequency), god_modules (oversized high-fan-in files), or refactor_candidates.
Each row carries size/coupling/churn/memory signals and a suggested next tool. repo_clusters groups
the repo into ownership clusters from path proximity, graph edges, and git co-touch, with a
representative file per cluster (min_cluster_size sets the floor). Both accept the orientation
include array (memories on by default, generated off).
important_symbols ranks the most load-bearing symbols by weighted PageRank over the call/type/import
edge graph — SCIP-aware once rag-rat oracle run has populated compiler edges. With no
personalize, it auto-seeds from your current git diff and returns importance relative to your
current changes (the random surfer teleports back to what you’re editing, lifting the spine those
symbols depend on). Pass personalize (a list of names, path::name refs, or sym_<hex> handles) to
seed it explicitly, or a single "global" to force whole-repo PageRank. The result is labeled: mode
(which scale), seed_source (seed provenance), and symbols. See oracle.md for how the
oracle sharpens the ranking.
Clones
find_clones returns candidate clone classes ranked by refactor ROI (cross-module spread × member
count × token length × load-bearing factor × cohesion), each with a completeness provenance block.
min_similarity (if set) must be in [0.5, 1.0] (θ default 0.7); min_copies defaults to 2. A
limited query (limit: N) is capped at the refine budget (currently 50): it returns at most 50
classes, all refined with anti-unification metrics; omit limit (or pass null) to retrieve every
class with only the top 50 refined. completeness.refine_budget_clamped is true when a supplied limit
hit that cap. The candidate graph is precomputed in the background, so the tool stays responsive on
large repos.
clones_for_symbol returns the one clone class containing a specific symbol — selected by exactly
one of id (a sym_<hex> handle), ref (path::name), or path + line together. It returns
the candidate class if the symbol is fingerprinted and has clone siblings, or null if it is unique
or not fingerprinted. This is the same signal the Write/Edit clone-check hook uses at write time.
Repo memories
Memory tools read and write the durable, source-anchored notes described in the
README. memory_create records one (typed kind, title, body,
confidence), memory_search finds them by keyword, and memory_for_symbol / memory_for_path /
memory_for_call_path fetch the full memories bound to an anchor (the expanded form of the compact
headers impact_surface attaches). memory_show expands one memory to its full body by
memory_id — the expand path for a [memory] surface = "summary" compact attachment.
memory_update edits text/status/confidence/kind/tags; memory_mark_obsolete retires a memory
(kept for audit, hidden from active recall). memory_validate re-anchors every memory against current
source and marks each current / relocated / stale / gone / pending (it also runs
automatically after indexing); memory_doctor lists the stale/gone/pending ones with suggested
re-anchor targets. Rebind a moved memory with memory_rebind rather than obsoleting and recreating it
— a pending anchor is alive on an in-flight worktree branch and re-anchors itself when that branch
lands, so leave those alone.
BindTarget (the bind on memory_create / memory_rebind) names exactly one anchor form:
a logical symbol (id), a concrete chunk_id, a graph edge_id, a path (optionally with
start_line + end_line), a commit_hash, a tracker-item ref (tracker + project +
item_key), a call-path (edge_path: an ordered list of edge ids, from which the server derives
the authoritative edge_sequence_hash), or a directory (dir, relative to the repo root; "" anchors
to the root). On memory_create only, omit bind entirely to create an unanchored node — a
Concept or standalone Task that lives only as a graph node. memory_rebind requires a real
target: it rejects an empty bind (to unanchor an existing memory, delete and recreate it).
Memory graph edges. Memories are not only a flat list — they form a typed graph.
memory_edge_add connects a source node to another node or a GitHub issue with a relation:
depends_on (a task DAG), relates_to (a mind-map link), supersedes, derived_from, or tracks
(issue ← task). Give exactly one target: a target_node_id (with an optional target_repo_id for
a cross-repo edge) or a full GitHub ref. memory_edges lists a node’s edges — direction: "from" for
its outgoing edges (dependencies / links / tracks), direction: "into" for the reverse traversal
(e.g. the tasks that tracks an issue, or the nodes that depend on this one). memory_edge_remove
deletes an edge by its stable edge_key.
Dream — memory maintenance
dream is the pull surface for keeping the memory layer honest as the code moves under it. It
recomputes a deterministic maintenance worklist on each call and returns it ranked, each finding
with a stable id:
- coverage gaps — load-bearing symbols (by the same PageRank as
important_symbols) that carry no memory, so the next agent editing them gets nothing. - stale references — a memory citing a path or anchor that no longer resolves.
- model-verdict findings (e.g.
memory_divergence) that a prior opt-in model pass persisted — see below.
dream is classified as a write tool (like rag-rat dream, it syncs the dream_findings table)
even though it returns a worklist. It runs the deterministic findings only; it does not run the
optional model passes — those stay on the CLI/cron rag-rat dream --verify (recompute each memory’s
verdict against current source reality) and --compact (rewrite a memory to a tighter summary), which
run a small model on an ephemeral remote GPU ([llm.dream.remote]) only when work is pending. Findings
those passes persist still surface through dream.
dream_review applies a human (or strong-agent) verdict to one finding by id — a full id or an
unambiguous git-style prefix — as accept (a real gap to act on), dismiss (noise), or reset (clear
a prior verdict, back to the open worklist). Verdicts survive future dream runs, so the worklist burns
down instead of re-proposing settled findings. Pass all: true to dream to also list the already
accepted / dismissed findings (for a reviewer to see and reset). This mirrors the CLI
rag-rat dream <id> --accept|--dismiss|--reset.