Skip to content

feat(mcp): steer agents to structural tools (#626)#627

Open
justrach wants to merge 2 commits into
release/0.2.5825from
issue-626-structural-steering
Open

feat(mcp): steer agents to structural tools (#626)#627
justrach wants to merge 2 commits into
release/0.2.5825from
issue-626-structural-steering

Conversation

@justrach

Copy link
Copy Markdown
Owner

Problem

Agents on the codedb MCP surface default to search → read → edit and skip the structural tools (symbol/callers/deps/outline), so the code graph goes unexercised — codedb ends up used like a leaner grep. (See #626.)

Change

Make the structural path the path of least resistance, two ways:

  • Descriptions / server instructions — reframed to prescribe structural tools first and cast codedb_search as a substring/phrase fallback, not the default.
  • Runtime nudges (the part that fights the prior in-context):
    • codedb_search on a bare identifier that resolves to an indexed symbol prepends a one-line pointer to codedb_symbol/codedb_callers (text output only; skipped for format=json).
    • codedb_read of a whole file (≥400 lines, no range) prepends a pointer to codedb_outline; wired into both the cached (renderReadBytes) and uncached read paths.

Tests

src/test_mcp.zigissue-626 cases cover the gating logic: isBareIdentifier (fires on make_bytes, not on def content / make_bytes( / 2fast) and fullFileReadHint (null under 400 lines, fires above). Full suite green: zig build test → exit 0.

Verification

Driven live through a fresh codedb mcp server: the search nudge fires for a bare indexed identifier and is correctly absent from the CLI path and from format=json. A Sonnet 4.6 agent reads the new server instruction and cites it when choosing structural tools first.

Caveat worth stating: Sonnet 4.6 in Claude Code already navigates structurally (outline-before-read, ranged reads, symbol/callers by reflex), so on these tasks neither runtime nudge actually triggered — the steering is confirmation/insurance for this model. The payoff is on grep-happier agent loops; a SWE-bench-Lite A/B is the test that can show the nudges deflecting a bad call, and is tracked separately.

Issues

Closes #626. #623 was closed as a duplicate; its distinct concern (tail-runaway / loop-redundancy convergence guardrail) is not addressed here and was preserved in that issue's close comment.

🤖 Generated with Claude Code

Agents on the codedb MCP surface default to search -> read -> edit and skip
the structural tools (symbol/callers/deps/outline), so the code graph goes
unexercised. Make the structural path the path of least resistance.

- Reframe tool descriptions + server instructions to prescribe the structural
  tools first and cast codedb_search as a substring/phrase fallback.
- Runtime nudge on search: a bare identifier that resolves to an indexed
  symbol prepends a one-line pointer to codedb_symbol/codedb_callers
  (text output only, skipped for format=json).
- Runtime nudge on read: a whole-file read (>=400 lines, no range) prepends a
  pointer to codedb_outline; wired into both the cached and uncached paths.
- Tests (issue-626) cover the gating logic: isBareIdentifier and
  fullFileReadHint.

Closes #626. (#623 closed separately as a duplicate; its distinct
loop/redundancy-detection guardrail is not addressed here.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 107174 119280 +11.30% +12106 NOISE
codedb_changes 10320 10696 +3.64% +376 OK
codedb_context 845083 824740 -2.41% -20343 OK
codedb_deps 349 350 +0.29% +1 OK
codedb_edit 33678 38073 +13.05% +4395 NOISE
codedb_find 2787 2493 -10.55% -294 OK
codedb_hot 26371 24453 -7.27% -1918 OK
codedb_outline 43091 41130 -4.55% -1961 OK
codedb_read 17389 21923 +26.07% +4534 NOISE
codedb_search 13501 54593 +304.36% +41092 NOISE
codedb_snapshot 82625 82789 +0.20% +164 OK
codedb_status 9425 8603 -8.72% -822 OK
codedb_symbol 55069 59636 +8.29% +4567 OK
codedb_tree 20293 22906 +12.88% +2613 NOISE
codedb_word 12877 11807 -8.31% -1070 OK

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14ef8b3328

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/mcp.zig
.fuzzy = false,
.max_results = 1,
};
const results = explorer.searchSymbols(spec, alloc) catch return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid full symbol scans before every search

When codedb_search receives any bare identifier in text mode, this calls searchSymbols just to decide whether to print a hint. searchSymbols is not an exact-name O(1) lookup; it iterates the symbol index and then scans outlines when there is no match (src/explore.zig around the symbol-index/outlines loops), so common searches for local variables or config words that are not definitions now pay a full symbol/outline scan before the normal content search. This is on the benchmark-critical search path for large repos; use a direct symbol-index probe or another cheap existence check for the nudge.

Useful? React with 👍 / 👎.

Comment thread src/mcp.zig
}
// Issue #626: nudge toward the structural tools when the query is a bare
// symbol name. Text output only — would corrupt the format=json payload.
if (!json_fmt) appendSearchSymbolNudge(alloc, explorer, query, out);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the search result header first

This writes the nudge before the normal N results for ... header. MCP summaries for codedb_search parse the first output line to display the result count, so an exact-symbol search now produces a bogus summary like ↪ results instead of the actual count for clients that show the summary block. Emit the nudge after the search header/results or update the summary parser to skip advisory lines.

Useful? React with 👍 / 👎.

#626)

Follow-up to the #626 structural steering. Auditing the tool surface showed
mcpGenerateGuidance already steers most graph tools as "-> next" hints
(callers->callpath, edit->changes, hot->outline, the symbol/search/outline/word
chain). The single genuine gap is codedb_deps: nothing points to it and it has
no next-hint.

- Add depsHint: after a single-definition codedb_symbol hit (the moment before
  an edit, when blast radius matters), prepend a one-line pointer to codedb_deps.
  Pure + count-gated (results.len == 1), text-only, mirrors fullFileReadHint.
- Upgrade three passive differentiator descriptions to prescriptive: codedb_deps
  (impact/blast-radius), codedb_hot (orientation), codedb_changes (what-changed).

No callpath nudge: codedb_callers already emits "-> next: codedb_callpath", so an
inline one would duplicate it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 101610 113725 +11.92% +12115 NOISE
codedb_changes 11129 10666 -4.16% -463 OK
codedb_context 798113 796423 -0.21% -1690 OK
codedb_deps 336 320 -4.76% -16 OK
codedb_edit 35457 40048 +12.95% +4591 NOISE
codedb_find 2701 2898 +7.29% +197 OK
codedb_hot 24503 27397 +11.81% +2894 NOISE
codedb_outline 36214 40889 +12.91% +4675 NOISE
codedb_read 16030 20010 +24.83% +3980 NOISE
codedb_search 13436 55341 +311.89% +41905 NOISE
codedb_snapshot 69893 71321 +2.04% +1428 OK
codedb_status 9710 9383 -3.37% -327 OK
codedb_symbol 53317 58209 +9.18% +4892 OK
codedb_tree 18895 23530 +24.53% +4635 NOISE
codedb_word 13877 13290 -4.23% -587 OK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant