Codebase Memory — Knowledge Graph Tools
Graph tools return precise structural results in ~500 tokens vs ~80K for grep.
Always prefer MCP graph tools over grep, glob, or file search for code discovery.
Priority Order
search_graph — find functions, classes, routes, and variables by pattern.
trace_path — trace who calls a function or what it calls.
get_code_snippet — read specific function or class source code.
check_index_coverage — validate candidate paths and missed ranges before claims.
query_graph — run Cypher queries for complex patterns.
get_architecture — get a high-level project summary.
Quick Decision Matrix
Use project="@current" for eligible graph reads in the active checkout, or use the exact project="<name>" returned by list_projects.
Never replace @current with its borrowed source project in later graph calls because the alias revalidates the worktree on every call.
| Question |
Tool call |
| Who calls X? |
trace_path(project="<name>", function_name="X", direction="inbound") |
| What does X call? |
trace_path(project="<name>", function_name="X", direction="outbound") |
| Full call context |
trace_path(project="<name>", function_name="X", direction="both") |
| Find by name pattern |
search_graph(project="<name>", name_pattern="...") |
| Dead code |
search_graph(project="<name>", max_degree=0, exclude_entry_points=true) |
| Cross-service edges |
query_graph(project="<name>", query="<cypher>") |
| Impact of local changes |
detect_changes(project="<name>") |
| Risk-classified trace |
trace_path(project="<name>", function_name="X", risk_labels=true) |
| Text search |
search_code(project="<name>", pattern="...") or Grep |
Current Worktree Resolution
index_status(project="@current") resolves an existing current-root index first.
- In an unindexed linked worktree,
@current borrows a canonical checkout graph only when both trees are clean, share one Git common directory and HEAD, and the graph-recorded Branch snapshot matches.
- Keep using
@current for search_graph, query_graph, trace_path, get_code_snippet, get_graph_schema, get_architecture, and index_status so each call revalidates the borrowed snapshot.
- Inspect
pi_cbmem_resolution; borrowed_canonical_base means the result is read-only borrowed graph evidence rather than a worktree index.
- Borrowed
get_code_snippet reads the reported lines from the current worktree.
- Do not use
@current with search_code, check_index_coverage, detect_changes, manage_adr, ingest_traces, delete_project, or index_repository.
- For required coverage on borrowed evidence, call
check_index_coverage once with the reported source project, read flagged paths from the current worktree, then rerun index_status(project="@current") before relying on the result.
Do not use the reported source project for graph reads.
- If
@current rejects a dirty, divergent, stale, missing, or ambiguous context, do not bypass the guard with the canonical project name.
Index the worktree or use current-root file reads and grep instead.
- Treat borrowed coverage as best-effort because Codebase Memory exposes no immutable generation lease or complete semantic-input comparison.
Exploration Workflow
Use @current for eligible calls below when the first step succeeds; otherwise substitute the exact project discovered by list_projects.
index_status(project="@current") — resolve and validate the active checkout when supported.
list_projects — fall back to discovering and copying an exact project name when @current is unavailable.
get_graph_schema(project="<name>") — understand node and edge types.
search_graph(project="<name>", label="Function", name_pattern=".*Pattern.*") — find code.
get_code_snippet(project="<name>", qualified_name="project.path.FuncName") — read source.
check_index_coverage(project="<name>", paths=["path/to/file"]) — validate every evidence path.
Tracing Workflow
search_graph(project="<name>", name_pattern=".*FuncName.*") — discover the exact name.
trace_path(project="<name>", function_name="FuncName", direction="both", depth=3) — trace relationships.
get_code_snippet(project="<name>", qualified_name="project.path.FuncName") — verify material source claims.
check_index_coverage(project="<name>", paths=["path/to/file"]) — validate every evidence path.
detect_changes(project="<name>") — map the Git diff to affected symbols.
When to Fall Back to Grep/Glob
- Search for string literals, error messages, or configuration values.
- Search non-code files such as Dockerfiles, shell scripts, or configuration files.
- Fall back when MCP tools return insufficient results.
Examples
- Find a handler:
search_graph(project="<name>", name_pattern=".*OrderHandler.*").
- Find who calls it:
trace_path(project="<name>", function_name="OrderHandler", direction="inbound").
- Read its source:
get_code_snippet(project="<name>", qualified_name="pkg/orders.OrderHandler").
Evidence Tiers
- Scout (Tier 1): quick positive lookup with few calls and targeted source checks.
Mark it provisional, and do not make negative or exhaustive claims.
- Verify (Tier 2, default): task-directed graph evidence, relevant trace directions, exact snippets for material claims, and relevant pagination.
- Auditor (Tier 3): bounded-scope full verification with a current generation, complete relevant pagination, both call directions and broader relationships when material, and every limitation disclosed.
- After candidate paths are known in any tier, call
check_index_coverage once with every evidence path.
Add relevant scopes for negative or exhaustive claims.
A clean result means no recorded gap, not proof of completeness.
For partial, skipped, excluded, stale, pending, or unknown coverage, read or grep the reported ranges or scope before relying on graph results.
Session Resets and Subagents
- At session start or after compaction, try
index_status(project="@current"), then use list_projects or an exact-name index_status fallback before choosing Scout, Verify, or Auditor.
- Before spawning a subagent, query the graph and coverage in the parent.
Pass the tier, project, generation or freshness, bounded scope, queries and pagination state, qualified symbols, paths, call-chain findings, coverage evidence with ranges and reasons, source fallback already performed, and unresolved questions in the delegated task context.
- Do not assume subagents inherit MCP access or the parent conversation.
If a child lacks MCP tools, it must not call or claim MCP access.
It should use the supplied evidence and read or grep exact source, especially every reported missed-coverage range.
Quality Analysis
- Dead code:
search_graph(project="<name>", max_degree=0, exclude_entry_points=true)
- High fan-out:
query_graph(project="<name>", query="MATCH (f)-[:CALLS]->() WITH f, count(*) AS n WHERE n >= 10 RETURN f.name, n ORDER BY n DESC LIMIT 20")
- High fan-in:
query_graph(project="<name>", query="MATCH ()-[:CALLS]->(f) WITH f, count(*) AS n WHERE n >= 10 RETURN f.name, n ORDER BY n DESC LIMIT 20")
15 MCP Tools
index_repository, index_status, list_projects, delete_project,
search_graph, search_code, trace_path, detect_changes,
query_graph, get_graph_schema, get_code_snippet, get_architecture,
check_index_coverage, manage_adr, ingest_traces
Edge Types
CALLS, HTTP_CALLS, ASYNC_CALLS, DATA_FLOWS, IMPORTS, DEFINES, DEFINES_METHOD,
HANDLES, IMPLEMENTS, OVERRIDE, USAGE, CALL_REFERENCE, CONFIGURES, FILE_CHANGES_WITH,
SIMILAR_TO, SEMANTICALLY_RELATED, CONTAINS_FILE, CONTAINS_FOLDER,
CONTAINS_PACKAGE
Cypher Examples (for query_graph)
MATCH (a)-[r:HTTP_CALLS]->(b) RETURN a.name, b.name, r.url_path, r.confidence LIMIT 20
MATCH (f:Function) WHERE f.name =~ '.*Handler.*' RETURN f.name, f.file_path
MATCH (a)-[r:CALLS]->(b) WHERE a.name = 'main' RETURN b.name
Gotchas
search_graph(project="<name>", relationship="HTTP_CALLS") filters nodes by degree — use query_graph with Cypher to see actual edges.
query_graph has a 100k row ceiling — add a Cypher LIMIT for broad queries or use search_graph pagination.
trace_path needs exact names — use search_graph(project="<name>", name_pattern="...") first.
direction="outbound" misses cross-service callers — use direction="both".
search_graph results default to 50 per page — check has_more and use offset.
@current is a pi-cbmem read alias, not a Codebase Memory project or a shared-index identity.
1---2name: codebase-memory3description: Use the codebase knowledge graph for structural code queries. Triggers on: explore the codebase, understand the architecture, what functions exist, show me the structure, who calls this function, what does X call, trace the call chain, find callers of, show dependencies, impact analysis, dead code, unused functions, high fan-out, refactor candidates, code quality audit, graph query syntax, Cypher query examples, edge types, how to use search_graph.4---56# Codebase Memory — Knowledge Graph Tools78Graph tools return precise structural results in ~500 tokens vs ~80K for grep.910Always prefer MCP graph tools over grep, glob, or file search for code discovery.1112## Priority Order13141. `search_graph` — find functions, classes, routes, and variables by pattern.152. `trace_path` — trace who calls a function or what it calls.163. `get_code_snippet` — read specific function or class source code.174. `check_index_coverage` — validate candidate paths and missed ranges before claims.185. `query_graph` — run Cypher queries for complex patterns.196. `get_architecture` — get a high-level project summary.2021## Quick Decision Matrix2223Use `project="@current"` for eligible graph reads in the active checkout, or use the exact `project="<name>"` returned by `list_projects`.24Never replace `@current` with its borrowed source project in later graph calls because the alias revalidates the worktree on every call.2526| Question | Tool call |27|----------|----------|28| Who calls X? | `trace_path(project="<name>", function_name="X", direction="inbound")` |29| What does X call? | `trace_path(project="<name>", function_name="X", direction="outbound")` |30| Full call context | `trace_path(project="<name>", function_name="X", direction="both")` |31| Find by name pattern | `search_graph(project="<name>", name_pattern="...")` |32| Dead code | `search_graph(project="<name>", max_degree=0, exclude_entry_points=true)` |33| Cross-service edges | `query_graph(project="<name>", query="<cypher>")` |34| Impact of local changes | `detect_changes(project="<name>")` |35| Risk-classified trace | `trace_path(project="<name>", function_name="X", risk_labels=true)` |36| Text search | `search_code(project="<name>", pattern="...")` or Grep |3738## Current Worktree Resolution3940- `index_status(project="@current")` resolves an existing current-root index first.41- In an unindexed linked worktree, `@current` borrows a canonical checkout graph only when both trees are clean, share one Git common directory and `HEAD`, and the graph-recorded Branch snapshot matches.42- Keep using `@current` for `search_graph`, `query_graph`, `trace_path`, `get_code_snippet`, `get_graph_schema`, `get_architecture`, and `index_status` so each call revalidates the borrowed snapshot.43- Inspect `pi_cbmem_resolution`; `borrowed_canonical_base` means the result is read-only borrowed graph evidence rather than a worktree index.44- Borrowed `get_code_snippet` reads the reported lines from the current worktree.45- Do not use `@current` with `search_code`, `check_index_coverage`, `detect_changes`, `manage_adr`, `ingest_traces`, `delete_project`, or `index_repository`.46- For required coverage on borrowed evidence, call `check_index_coverage` once with the reported source project, read flagged paths from the current worktree, then rerun `index_status(project="@current")` before relying on the result.47 Do not use the reported source project for graph reads.48- If `@current` rejects a dirty, divergent, stale, missing, or ambiguous context, do not bypass the guard with the canonical project name.49 Index the worktree or use current-root file reads and grep instead.50- Treat borrowed coverage as best-effort because Codebase Memory exposes no immutable generation lease or complete semantic-input comparison.5152## Exploration Workflow5354Use `@current` for eligible calls below when the first step succeeds; otherwise substitute the exact project discovered by `list_projects`.55561. `index_status(project="@current")` — resolve and validate the active checkout when supported.572. `list_projects` — fall back to discovering and copying an exact project name when `@current` is unavailable.583. `get_graph_schema(project="<name>")` — understand node and edge types.594. `search_graph(project="<name>", label="Function", name_pattern=".*Pattern.*")` — find code.605. `get_code_snippet(project="<name>", qualified_name="project.path.FuncName")` — read source.616. `check_index_coverage(project="<name>", paths=["path/to/file"])` — validate every evidence path.6263## Tracing Workflow64651. `search_graph(project="<name>", name_pattern=".*FuncName.*")` — discover the exact name.662. `trace_path(project="<name>", function_name="FuncName", direction="both", depth=3)` — trace relationships.673. `get_code_snippet(project="<name>", qualified_name="project.path.FuncName")` — verify material source claims.684. `check_index_coverage(project="<name>", paths=["path/to/file"])` — validate every evidence path.695. `detect_changes(project="<name>")` — map the Git diff to affected symbols.7071## When to Fall Back to Grep/Glob7273- Search for string literals, error messages, or configuration values.74- Search non-code files such as Dockerfiles, shell scripts, or configuration files.75- Fall back when MCP tools return insufficient results.7677## Examples7879- Find a handler: `search_graph(project="<name>", name_pattern=".*OrderHandler.*")`.80- Find who calls it: `trace_path(project="<name>", function_name="OrderHandler", direction="inbound")`.81- Read its source: `get_code_snippet(project="<name>", qualified_name="pkg/orders.OrderHandler")`.8283## Evidence Tiers8485- **Scout (Tier 1):** quick positive lookup with few calls and targeted source checks.86 Mark it provisional, and do not make negative or exhaustive claims.87- **Verify (Tier 2, default):** task-directed graph evidence, relevant trace directions, exact snippets for material claims, and relevant pagination.88- **Auditor (Tier 3):** bounded-scope full verification with a current generation, complete relevant pagination, both call directions and broader relationships when material, and every limitation disclosed.89- After candidate paths are known in any tier, call `check_index_coverage` once with every evidence path.90 Add relevant scopes for negative or exhaustive claims.91 A clean result means no recorded gap, not proof of completeness.92 For partial, skipped, excluded, stale, pending, or unknown coverage, read or grep the reported ranges or scope before relying on graph results.9394## Session Resets and Subagents9596- At session start or after compaction, try `index_status(project="@current")`, then use `list_projects` or an exact-name `index_status` fallback before choosing Scout, Verify, or Auditor.97- Before spawning a subagent, query the graph and coverage in the parent.98 Pass the tier, project, generation or freshness, bounded scope, queries and pagination state, qualified symbols, paths, call-chain findings, coverage evidence with ranges and reasons, source fallback already performed, and unresolved questions in the delegated task context.99- Do not assume subagents inherit MCP access or the parent conversation.100 If a child lacks MCP tools, it must not call or claim MCP access.101 It should use the supplied evidence and read or grep exact source, especially every reported missed-coverage range.102103## Quality Analysis104- Dead code: `search_graph(project="<name>", max_degree=0, exclude_entry_points=true)`105- High fan-out: `query_graph(project="<name>", query="MATCH (f)-[:CALLS]->() WITH f, count(*) AS n WHERE n >= 10 RETURN f.name, n ORDER BY n DESC LIMIT 20")`106- High fan-in: `query_graph(project="<name>", query="MATCH ()-[:CALLS]->(f) WITH f, count(*) AS n WHERE n >= 10 RETURN f.name, n ORDER BY n DESC LIMIT 20")`107108## 15 MCP Tools109`index_repository`, `index_status`, `list_projects`, `delete_project`,110`search_graph`, `search_code`, `trace_path`, `detect_changes`,111`query_graph`, `get_graph_schema`, `get_code_snippet`, `get_architecture`,112`check_index_coverage`, `manage_adr`, `ingest_traces`113114## Edge Types115CALLS, HTTP_CALLS, ASYNC_CALLS, DATA_FLOWS, IMPORTS, DEFINES, DEFINES_METHOD,116HANDLES, IMPLEMENTS, OVERRIDE, USAGE, CALL_REFERENCE, CONFIGURES, FILE_CHANGES_WITH,117SIMILAR_TO, SEMANTICALLY_RELATED, CONTAINS_FILE, CONTAINS_FOLDER,118CONTAINS_PACKAGE119120## Cypher Examples (for query_graph)121```122MATCH (a)-[r:HTTP_CALLS]->(b) RETURN a.name, b.name, r.url_path, r.confidence LIMIT 20123MATCH (f:Function) WHERE f.name =~ '.*Handler.*' RETURN f.name, f.file_path124MATCH (a)-[r:CALLS]->(b) WHERE a.name = 'main' RETURN b.name125```126127## Gotchas1281. `search_graph(project="<name>", relationship="HTTP_CALLS")` filters nodes by degree — use `query_graph` with Cypher to see actual edges.1292. `query_graph` has a 100k row ceiling — add a Cypher `LIMIT` for broad queries or use `search_graph` pagination.1303. `trace_path` needs exact names — use `search_graph(project="<name>", name_pattern="...")` first.1314. `direction="outbound"` misses cross-service callers — use `direction="both"`.1325. `search_graph` results default to 50 per page — check `has_more` and use `offset`.1336. `@current` is a pi-cbmem read alias, not a Codebase Memory project or a shared-index identity.