Chapter 12: AI Agent Integration, Adaptive Retrieval, and CLI RPC

When an AI coding agent—such as Claude Code, Gemini CLI / Antigravity, OpenAI Codex, or Aider—is dropped into a multi-thousand-document Knowledge Base or software repository, naive grep and full-file reads quickly exhaust its context window and inflate latency. Retired logs in archive/, raw transcripts in raw/, and superseded ADRs often share the same keywords as active architectural rules, causing unweighted keyword search to surface stale guidance first.

AutoDoc gives every CLI coding agent direct, zero-configuration access to its hybrid search engine, frontmatter validator, link graph, and .todo-list/ task store through two built-in CLI flags: autodoc --call <verb> '<json>' and autodoc --contracts. Furthermore, AutoDoc ships a versioned operating manual (KB_OPERATIONS.md) that teaches agents an adaptive retrieval ladder: probing the daemon's active pipeline stages once per session and reading exact section line spans ([line_start, line_end]) instead of entire files.


1. Self-Describing RPC Contracts (autodoc --contracts)

Under the AutoDoc Module Convention (ADR 1791719881, core/module), every RPC verb in the daemon is registered from a declarative module.Contract struct (rpc/contracts.go, core/todo/module.go). A contract specifies the verb's name, the protocol version it arrived in (Since), its Scope (Global, Workspace, LocalPeer), its Audience (Agent, User, Internal), its ordered positional Params, its Result shape, and the numeric PublicError codes it may return.

Because Module.Verbs() and Module.Errors() are pure data functions that perform no I/O, an agent or tool can inspect the complete RPC catalog offline—even when no daemon is running—using autodoc --contracts:

# Print the full catalog (protocol version, all verbs, and all error codes) as JSON
autodoc --contracts

# Filter to a single domain or verb and render Markdown reference tables
autodoc --contracts 'todos.*' --format md
autodoc --contracts 'search.query' --format md

Inside the repository, go generate ./rpc runs internal/contractsgen over this exact catalog to generate the verb and error tables in AGENTS.md and autodoc.nvim's lua/autodoc/contracts.lua. A golden contract test (TestContractsAreGolden and TestAgentsMDIsGenerated) guarantees that documentation, CLI help, and wire dispatch never drift apart.


2. Wiring CLI Coding Agents to autodoc --call

From a shell, or an AI agent. autodoc --call <verb> '<JSON array of parameters>' calls any verb of the daemon (starting it when nothing answers) and prints the result as JSON:

autodoc --call workspace.list
autodoc --call search.query '["kb", "storage decision", {"paths": ["adrs"], "limit": 10}]'

AGENTS.md tells an AI agent how to search with it: the verbs, the query syntax, the options (stages, paths, tags, facets, limit) and the errors.

A typical agent session:

# 1. Discover available workspaces and confirm "kb" is in state "ready"
autodoc --call workspace.list '[]'

# 2. Run a 3-stage hybrid search scoped to active ADRs and conventions
autodoc --call search.query '["kb", "merge a stacked PR with --delete-branch", {"paths": ["conventions", "adrs"], "limit": 3}]'

# 3. Validate a draft Markdown document against _schema/frontmatter.yaml
autodoc --call doc.validate '["kb", "adrs/1792200100-my-decision.md", "---\ntype: adr\n..."]'

Daemon Autostart, Handshake, and Structured Error Recovery

autodoc --call handles connection lifecycle automatically so agents never need custom socket-dialing code:

Configuring Claude Code, Gemini CLI / Antigravity, Codex, and Aider

When AutoDoc spawns an embedded agent tab (tui/agentinstances.go), it automatically sets $AUTODOC_WORKSPACE and writes a workspace agent guide pointing to AGENTS.md and KB_OPERATIONS.md. For external agent sessions launched in standalone terminals or Neovim (auto-agents), add two rules to your project's AGENTS.md, CLAUDE.md, or GEMINI.md:

  1. Export AUTODOC_WORKSPACE="<workspace-name>" (or resolve it via autodoc --call workspace.list '[]').
  2. Instruct the agent to read KB_OPERATIONS.md on startup and check its revision: frontmatter field.

3. The KB_OPERATIONS.md Adaptive Retrieval Ladder

Not every machine runs the same local models: a workstation may run Ollama with snowflake-arctic-embed2 and a bge-reranker-v2-m3 cross-encoder, while a lightweight laptop or CI container may run words-only (lexical) indexing or temporarily switch models.

Rather than hardcoding one search strategy, KB_OPERATIONS.md teaches agents to let the first search.query response dictate the retrieval mode for the session by inspecting stages.performed and stages.skipped:

flowchart TD
    Start["Agent Needs Workspace / KB Context"] --> KnownTarget{"Known Path, ID, or Exact Error String?"}
    KnownTarget -->|"Yes"| DirectRead["Direct Read or Scoped rg Over Target File"]
    KnownTarget -->|"No (Topic Lookup)"| Probe["Run search.query with paths Scope and limit 3"]
    Probe --> InspectStages{"Inspect stages.performed and stages.skipped"}

    InspectStages -->|"semantic + rerank performed"| Top3["Read Top 3 Hits via line_start..line_end Span"]
    InspectStages -->|"semantic performed, rerank skipped"| Top10["Re-run search.query with limit 10 and Read Matching Spans"]
    InspectStages -->|"lexical only (semantic skipped)"| LexicalLadder["Words-Only Ladder: 2-3 Distinctive Keywords + Prefix* + doc.find + graph.neighbors"]
    InspectStages -->|"Daemon Offline"| ScopedGrep["Fallback: Scoped rg Skipping archive/** and raw/**"]

    Top3 --> RelCheck{"Need Supersession or Cross-Doc Lineage?"}
    Top10 --> RelCheck
    LexicalLadder --> RelCheck
    ScopedGrep --> RelCheck
    DirectRead --> RelCheck

    RelCheck -->|"Yes"| GraphWalk["Call graph.links, graph.backlinks, or graph.neighborhood"]
    RelCheck -->|"No"| DraftEdit["Draft New or Updated Document with YAML Frontmatter"]
    GraphWalk --> DraftEdit

    DraftEdit --> Validate["Run autodoc --call doc.validate Before or After Saving"]
    Validate --> DiagCheck{"Any Diagnostics Returned?"}
    DiagCheck -->|"Yes"| FixDiag["Fix Frontmatter Rule / Field Violation"]
    FixDiag --> Validate
    DiagCheck -->|"No"| Complete["Commit Clean Document and Update Task via todos.*"]

Step 1: Known Target vs. Topic Lookup

Step 2: Adapt to stages.performed vs. stages.skipped

Every search.query response includes a stages diagnostic block:

{
  "mode_used": "hybrid",
  "semantic": "ready",
  "rank": {"state": "ready", "model": "BAAI/bge-reranker-v2-m3", "error": ""},
  "stages": {
    "requested": ["lexical", "semantic", "rerank"],
    "performed": ["lexical", "semantic", "rerank"],
    "skipped": {}
  }
}
  1. semantic and rerank both performed (Best Case): Keep limit: 3. With cross-encoder reranking active, the answer document sits in the top 3 hits 94%–100% of the time, and limit: 3 consumes ~60% fewer tokens than limit: 10.
  2. semantic performed, rerank skipped: Increase limit to 10. Without the reranker, RRF fusion places the answer in the top 3 on 72% of queries and in the top 10 on 91%.
  3. semantic skipped (lexical only): Switch to the Words-Only Ladder:
    • Never pass a full conversational sentence to FTS5 lexical search (which requires every word to appear in the same section and fails on 17 of 18 conversational queries).
    • Instead, pass 2 to 3 distinctive keywords or a starred prefix ("--delete-branch stacked*").
    • Combine lexical search with index.documents (filtering by facets, tags, paths, or sort: "updated"), doc.outline (for heading hierarchy), and graph.neighborhood / graph.links / graph.backlinks (to follow supersedes, superseded_by, amends, and adr relations).
    • If one retry with a dropped word or prefix still misses, fall back to scoped rg -il --glob '!archive/**' --glob '!raw/**'.

Step 3: Read [line_start, line_end] Spans, Not Whole Files

Each hit in search.query returns exact 1-based section boundaries: line_start, line_end, byte_start, byte_end, and the heading breadcrumb. Agents should read only [line_start, line_end] using their line-ranged Read tool (or doc.read / section slices) and stop as soon as the question is answered. Read a document end-to-end only when acting on an entire convention, ADR, or review.


4. Empirical Findings from the 96-Session Benchmark Study

The rules in KB_OPERATIONS.md are grounded in controlled measurements recorded in docs/benchmarks/kb-retrieval.md across two production Knowledge Bases:

AI Agent KB Retrieval Cost: Grep vs AutoDoc Lexical vs AutoDoc 3-Stage Hybrid05001,0001,5002,0002,5003,0003,500Measured Cost (Tokens / Seconds x100)1. Grep + Full-File Read2. AutoDoc Lexical3. AutoDoc 3-Stage HybridRetrieval MethodBenchmark MetricEnd-to-End Seconds x100Median Tokens Read

Key Takeaways from the Benchmark Data

VerbParametersResult_ShapeProtocol_SinceAgent_Usage_and_Notes
search.query[workspace, query, opts? ({limit, stages, paths, tags, facets})]{hits: [{path, breadcrumb, snippet, line_start, line_end, relevance, via, rank_score}], mode_used, semantic, rank, stages}1Primary topic and code declaration lookup; inspect stages.performed and read only [line_start, line_end] spans
doc.read[workspace, path]{content, version}1Reads full document content and its conditional version token (or derived Markdown for DOCX/HTML)
doc.write[workspace, path, content, version]{version}1Conditionally writes document at version (or '' to create); answers -32062 rpc.conflict if stale
doc.outline[workspace, path][{level, text, line}]1Returns the document's Markdown heading outline in top-to-bottom line order
index.documents[workspace, opts? ({sort, fields, tags, paths, facets, missing, diagnosed, limit, cursor})]{docs: [{path, generation, title, updated, fields, diagnostics?}], more, next}13Lists documents by frontmatter facets, recency, missing fields, or schema diagnostics
doc.validate[workspace, path, content]{diagnostics: [{field, line, rule, message}]}8Validates draft Markdown frontmatter against _schema/frontmatter.yaml without writing to disk
graph.neighborhood[workspace, path, depth, opts? ({kinds})]{nodes, edges: [{src, dst, kind}]}1Traverses wikilinks, embeds, and frontmatter relations (supersedes, superseded_by, amends, adr) up to depth hops
graph.unresolved[workspace, opts? ({kinds})][{src, raw, reason}]1Finds broken links (missing), ambiguous targets (ambiguous), and supersession cycles (cycle)
graph.resolve[workspace, from, target]{path, status, candidates}9Resolves a [[wikilink]] or relative path from an unsaved buffer just as the indexer would
todos.list[at, opts? ({buckets, tag, assignee, priority, has_errors})]{tasks: [...], malformed: [...], partitions?, cursor}20Lists active tasks in .todo-list/ or queries YYYY/MM archive partitions on demand
todos.status[at, id, rev, status]task: {id, status, rev, path, ...}20Atomically transitions a task between open, in-progress, deferred, completed, and archived conditional on rev

Summary

By combining self-describing contracts (autodoc --contracts), zero-config CLI invocation (autodoc --call), and the empirical retrieval ladder in KB_OPERATIONS.md, AI coding agents retrieve exact architectural context in seconds at a fraction of the token budget. In Chapter 13, we examine how AutoDoc guarantees that when multiple agents, Neovim buffers, and GUI editors write back to the workspace simultaneously, no edit is ever silently lost or corrupted.


← Previous: Chapter 11: Terminal Tabs & Agent Handoff | Index | Next: Chapter 13: Concurrency & Safe Multi-Agent Writes →