Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions __tests__/server-instructions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Server Instructions Tests
*
* The MCP `initialize` instructions land in the agent's system prompt on
* EVERY session, for every client — so they carry a size budget (the header
* of server-instructions.ts already demands "keep it tight"; this pins it),
* and the literal marker strings that agents pattern-match on (staleness
* banners, the dedup pointer line) must survive any rewording.
*/

import { describe, it, expect } from 'vitest';
import {
SERVER_INSTRUCTIONS,
SERVER_INSTRUCTIONS_NO_ROOT_INDEX,
} from '../src/mcp/server-instructions';

describe('server instructions', () => {
it('keeps the literal marker strings agents pattern-match on', () => {
expect(SERVER_INSTRUCTIONS).toContain(
'⚠️ Some files referenced below were edited since the last index sync',
);
expect(SERVER_INSTRUCTIONS).toContain('⚠️ CodeGraph auto-sync is DISABLED');
expect(SERVER_INSTRUCTIONS).toContain('changed on disk after the last index sync');
expect(SERVER_INSTRUCTIONS).toContain('Already sent earlier in this conversation');
});

it('keeps the core operative guidance', () => {
expect(SERVER_INSTRUCTIONS).toContain('codegraph_explore');
expect(SERVER_INSTRUCTIONS).toContain('codegraph init');
// The default MCP surface is codegraph_explore alone — no other tool
// may be named (they are hidden unless re-enabled via CODEGRAPH_MCP_TOOLS).
expect(SERVER_INSTRUCTIONS).not.toMatch(/codegraph_(?!explore)\w+/);
expect(SERVER_INSTRUCTIONS_NO_ROOT_INDEX).toContain('projectPath');
expect(SERVER_INSTRUCTIONS_NO_ROOT_INDEX).toContain('codegraph init');
});

it('stays inside the per-session size budget (chars ≈ tokens×4)', () => {
// ~1k tokens. Injected into every session of every MCP client; growth
// here is paid by every agent conversation before any work happens.
expect(SERVER_INSTRUCTIONS.length).toBeLessThan(4000);
expect(SERVER_INSTRUCTIONS_NO_ROOT_INDEX.length).toBeLessThan(1500);
});
});
82 changes: 40 additions & 42 deletions src/mcp/server-instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,59 +19,57 @@
*/
export const SERVER_INSTRUCTIONS = `# Codegraph — code intelligence over an indexed knowledge graph

Codegraph is a SQLite knowledge graph of every symbol, edge, and file in
the workspace — pre-computed structure you would otherwise re-derive by
reading files (cached intelligence: thousands of parse/trace decisions you
don't pay to re-reason each run). It indexes 30+ languages
(TypeScript/JavaScript, Python, Go, Rust, Java, C#, C/C++, PHP, Ruby, Swift,
Kotlin, and more) — don't assume a language here isn't covered. Reads are
sub-millisecond; the index lags writes by ~1s through the file watcher. Reach for it BEFORE *and* while
writing or editing code — not just for questions: one call returns the
verbatim source PLUS who calls it and what it affects, so you edit with the
blast radius in view. More accurate context, in far fewer tokens and
round-trips than reading files yourself.
Codegraph is a SQLite knowledge graph of every symbol, edge, and file in the
workspace, covering 30+ languages (TypeScript/JavaScript, Python, Go, Rust,
Java, C#, C/C++, PHP, Ruby, Swift, Kotlin, …) — don't assume a language isn't
covered. Reads are sub-millisecond; the index lags writes by ~1s through the
file watcher.

## One tool: codegraph_explore — use it instead of reading files

There is a single tool, \`codegraph_explore\`, and it is Read-equivalent. It
takes either a natural-language question or a bag of symbol/file names and
returns the **verbatim, line-numbered source** of the relevant symbols
grouped by file — the same \`<n>\\t<line>\` shape \`Read\` gives you, safe to
\`Edit\` from — PLUS the call path among them (including dynamic-dispatch hops
like callbacks, React re-render, and JSX children that grep can't follow) and
a blast-radius summary of what depends on them.
\`codegraph_explore\` is Read-equivalent. Give it a natural-language question
("how does X work", a bug, "what/where is X", an area survey) or a bag of
symbol/file names; one call returns the **verbatim, line-numbered source** of
the relevant symbols grouped by file — the same \`<n>\\t<line>\` shape \`Read\`
gives you, safe to \`Edit\` from — PLUS the call path among them (including
dynamic-dispatch hops like callbacks, React re-render, and JSX children that
grep can't follow) and a blast-radius summary of what depends on them. For an
overloaded name it returns every matching definition's body in one call.

Whether you're answering "how does X work" or implementing a change (fixing a
bug, adding a feature), call \`codegraph_explore\` before you Read. ONE call
usually answers the whole question. Codegraph IS the pre-built search index —
so running your own grep + read loop, or delegating the lookup to a separate
file-reading sub-task/agent, repeats work codegraph already did and costs more
for the same answer. A direct codegraph answer is typically one to a few
calls; a grep/read exploration is dozens.

## How to query

- **Almost any question — "how does X work", architecture, a bug, "what/where is X", or surveying an area** → \`codegraph_explore\` with a natural-language question or the relevant names. ONE capped call returns the verbatim source grouped by file; most often the ONLY call you need.
- **"How does X reach/become Y? / the flow / the path from X to Y"** → \`codegraph_explore\`, naming the symbols that span the flow (e.g. \`mutateElement renderScene\`) — it surfaces the call path among them, riding dynamic-dispatch hops, and returns their source.
- **Reading or editing a file/symbol you can name** → put its name or file path in the \`codegraph_explore\` query — it returns that current line-numbered source (safe to \`Edit\` from) with the call path and blast radius attached, so you don't Read it separately. For an overloaded name it returns every matching definition's body in one call.
- **Need more?** Call \`codegraph_explore\` again with more specific names — treat the source it returns as already Read.
Use it BEFORE and while writing or editing indexed code, not just for
questions: one to a few calls replace the dozens of round-trips of a
grep + Read loop (or a delegated file-reading sub-task/agent — both repeat
work the index already did). For a flow ("how does X reach/become Y?"), name
the symbols spanning the flow in one query (e.g. \`mutateElement renderScene\`)
— it surfaces the call path between them. Need more? Query again with more
specific names, and treat any source it returned as already Read.

## Anti-patterns

- **Trust codegraph's results — don't re-verify them with grep.** They come from a full AST parse; re-checking with grep is slower, less accurate, and wastes context.
- **Don't grep or Read first** to find or understand indexed code — ONE \`codegraph_explore\` returns the relevant symbols' source together in a single round-trip. Reach for raw \`Read\`/\`Grep\` only to confirm a specific detail codegraph didn't cover, or for what codegraph doesn't index (configs, docs).
- **Don't reconstruct a flow by hand** — name the endpoints in one \`codegraph_explore\` and it surfaces the path between them, dynamic-dispatch hops included.
- **After editing, check the staleness banner.** When a tool response starts with "⚠️ Some files referenced below were edited since the last index sync…", the listed files are pending re-index — Read those specific files for accurate content. Every file NOT in that banner is fresh, so still trust codegraph. A different, rarer banner — "⚠️ CodeGraph auto-sync is DISABLED…" — means live watching stopped entirely (the whole index is frozen, not just a few files); until it's resolved, Read files directly to confirm anything that may have changed.
- **A file flagged "⚠ changed on disk after the last index sync" drifted from its index** (most common on projects queried via \`projectPath\`, which have no live watcher). Codegraph never serves a possibly-mis-sliced body from such a file — it either shows the file's full CURRENT source (trust it as a Read) or omits the source with this flag. When the source was omitted, Read that specific file; line numbers referencing it elsewhere in the response may be shifted until that project's next sync. All unflagged files remain trustworthy.
- **Don't re-verify codegraph's results with grep.** They come from a full
AST parse; grep re-checking is slower, less accurate, and wastes context.
- **Don't grep or Read first** to find or understand indexed code. Raw
\`Read\`/\`Grep\` is for confirming a specific detail codegraph didn't cover,
or for what it doesn't index (configs, docs).
- **Don't reconstruct a flow by hand** — name the endpoints in one call.

## Staleness signals

- **"Already sent earlier in this conversation" is a pointer, not a gap.** When a file's section carries that line instead of (or above) its source, an earlier \`codegraph_explore\` in THIS conversation already returned those exact lines and the file has not changed since — so the copy already in your context is current and exact. Scroll back to it; don't re-fetch it and don't Read the file. The bytes it freed went into source you have not seen yet, elsewhere in the same response.
- A response starting "⚠️ Some files referenced below were edited since the last index sync…": the LISTED files are pending re-index — Read those specific files; every file not listed is fresh, so still trust codegraph.
- The rarer "⚠️ CodeGraph auto-sync is DISABLED…" banner: live watching stopped and the whole index is frozen — until resolved, Read files directly to confirm anything that may have changed.
- A file flagged "⚠ changed on disk after the last index sync" drifted from its index (most common via \`projectPath\`, which has no live watcher). Codegraph never serves a possibly-mis-sliced body from such a file: it either shows the file's full CURRENT source (trust it as a Read) or omits the source with this flag — then Read that file, and expect line numbers referencing it elsewhere in the response to be shifted until that project's next sync. Unflagged files remain trustworthy.
- **"Already sent earlier in this conversation" is a pointer, not a gap**: an earlier \`codegraph_explore\` in THIS conversation already returned those exact lines and the file hasn't changed since — scroll back to that copy; don't re-fetch and don't Read. The freed bytes went into source elsewhere in the response you haven't seen yet.

## Limitations

- If a tool reports a project isn't indexed (no \`.codegraph/\`), stop calling codegraph tools for that project for the rest of the session and use your built-in tools there instead. Indexing is the user's decision — mention they can run \`codegraph init\` if it comes up, but don't run it yourself.
- Index lags file writes by ~1 second.
- Cross-file resolution is best-effort name matching; ambiguous calls may return multiple candidates.
- No live correctness validation — that's still the TypeScript compiler / test suite / linter's job. Codegraph supplements those with structural context they don't have.
- If a tool reports a project isn't indexed (no \`.codegraph/\`), stop calling
codegraph tools for that project this session and use built-in tools there.
Indexing is the user's decision — mention \`codegraph init\` if it comes up,
but don't run it yourself.
- Cross-file resolution is best-effort name matching; ambiguous calls may
return multiple candidates.
- No live correctness validation — that's still the compiler / test suite /
linter's job; codegraph supplements them with structural context.
`;

/**
Expand Down