semantic-code-mcp
AGENTS.md4 starsChanged 16 days agoMITView on GitHub
A local MCP server that gives coding agents code search: tree-sitter splits a project into chunks, SQLite keeps them and their words, and search_code finds code by its words; a setting adds meaning, a model's ONNX export on onnxruntime. Python 3.14 · uv · mcp 2.x (MCPServer) · onnxruntime and tokenizers, the extra meaning (all-MiniLM-L6-v2's ONNX) · SQLite and FTS5 (LanceDB an extra) · tree-sitter (Python, Rust, Markdown) · structlog · pydantic and pydantic-settings. All under src/semantic_code_mcp/, each layer building…
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repositoryOne other file it gives its agents.
- semantic-searchSkill
The file
We split this AGENTS.md into the rules it gives an agent
12 rules. About 1 is common, 9 are distinctive, and 2 are very specific to this project.
≈1
Common · estimate
Many files like this have a rule of this kind.
≈9
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 31
Review before presenting: Read every changed line: the right layer?
- Distinctive: line 34
Ask first: before adding a dependency, changing the storage schema, a domain model or an MCP tool's signature.
- Common: line 35
Never commit secrets or credentials.
- Very specific: line 41
All under src/semantic_code_mcp/, each layer building only on those after it:
- Distinctive: line 52
No function inside another: a helper is a function or method of the module, with a name and parameters.
- Distinctive: line 53
No literal with a meaning in an expression: a number, a string key, a timeout, a limit is a named constant or data, with a comment saying …
- Very specific: line 54
No tuple where a type belongs: a named pydantic model, never list[tuple[X, Y]].
- Distinctive: line 55
No alias or compatibility shim: rename a thing and fix every user.
- Distinctive: line 56
No new module-level mutable state.
- Distinctive: line 63
Every change leaves the repository better than it found it, in every part it touches.
- Distinctive: line 67
Root cause first: Before a fix, say why the fault can happen and change that.
- Distinctive: line 74
Before you change or review code in an area, read its file whole.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Semantic Code MCP
A local MCP server that gives coding agents code search: tree-sitter splits a project into chunks, SQLite keeps them and their words, and search_code finds code by its words; a setting adds meaning, a model's ONNX export on onnxruntime.
Commands
uv sync # install dependencies
uv run python -m semantic_code_mcp # run the server over stdio
uv run pytest # the tests
uv run pre-commit run --all-files # every gate a commit runs, over every file
uv run python -m evals quality # search quality on the pinned corpora; `speed` for speed
uv run python -m evals agents --corpus-file <file> # agents' sessions by arm; spends the subscription
uv run python -m evals rescore <run> # a kept agents run scored again by its corpora's keys- The gates are one list,
.pre-commit-config.yaml, each with its command; CI runs the same list. Leave a hook out only on purpose, by naming it inSKIP. - Everything runs through
uv. Add a dependency withuv add(dev:uv add --dev): never pip, an activated virtualenv, or a hand edit of a dependency list.
Stack
Python 3.14 · uv · mcp 2.x (MCPServer) · onnxruntime and tokenizers, the extra meaning (all-MiniLM-L6-v2's ONNX) · SQLite and FTS5 (LanceDB an extra) · tree-sitter (Python, Rust, Markdown) · structlog · pydantic and pydantic-settings.
How we work
- The plan is ADR 006.
docs/decisions/006-rebuild-on-mcp-2.mdholds the stages; work follows them and the ADR changes when the plan does. - Chunks of work. A chunk is a large block of the plan, a group of an ADR's steps, in many commits; an independent reviewer (
.claude/agents/search-reviewer.md) reads its whole range once, before the next starts. - Product first. Effort goes to what users get, and to what measures or gates it:
evals/and the gates pre-commit or CI runs. - A helper for the author's own work (a probe, a runner, a check run by hand) is throwaway code in the session's scratch directory: no tests, no review, never committed; where git, pytest or shell does the job, none is written.
- Tests hold behaviour. A behaviour someone can name gets a test first, seen failing, at the cheapest level:
.claude/rules/testing.md. - Review before presenting. Read every changed line: the right layer? redundant work? every line needed?
- Speed and search quality are measured, never judged by feel; a change to either says its numbers.
- Speed has targets:
evals/targets.pyholds them andevals speednames each one a run crosses; a change that crosses one says why, with its figures. - Ask first before adding a dependency, changing the storage schema, a domain model or an MCP tool's signature.
- Never commit secrets or credentials.
- A commit follows Conventional Commits with a required scope,
type(scope): description. - Planned work is in
TODO.md, where an item done is removed; how it is built, indocs/decisions/; what changed, inCHANGELOG.md.
Architecture
All under src/semantic_code_mcp/, each layer building only on those after it:
- cli → app → server → services → the parts → domain.
uv run lint-importsrefuses an import against them;pyproject.tomlholds the contracts and their reasons. - The parts: discovery lists the files, watching follows their changes by each system's own watcher, the chunkers split them, embedding makes the vectors, storage keeps them with a record of each file and a manifest of what built the index.
mcpstays in the server layer, the app and the cli; each library stays in the part that wraps it.- The app builds the server; its lifespan holds the one
ProjectRegistryevery request shares. Nothing is module-level state. - Interfaces are abstract classes in
src/semantic_code_mcp/domain/interfaces.py; tests use the fakes intests/fakes.py.
Rules for all code
- A name says what it holds, in full words:
first_row,project_root, neverr,t0,idx. - No function inside another: a helper is a function or method of the module, with a name and parameters.
- No literal with a meaning in an expression: a number, a string key, a timeout, a limit is a named constant or data, with a comment saying what it is.
- No tuple where a type belongs: a named pydantic model, never
list[tuple[X, Y]]. - No alias or compatibility shim: rename a thing and fix every user.
- No new module-level mutable state; what is shared is built in one place and passed in.
- A parameter every caller must give has no default.
- Exceptions are specific types, never a bare
Exception; log with structlog, neverprint(). - What is not obvious gets a one-line comment; a module's docstring says why it exists.
Only better
Every change leaves the repository better than it found it, in every part it touches. A change that only works is not done.
- Construction first. Settle who owns each state, which layer it lives in and the contract before writing code.
- Simplest first. A new state, table, gate or module says why nothing simpler does.
- Root cause first. Before a fix, say why the fault can happen and change that; a guard hiding a wrong value needs a reason.
- Show it with facts. Say what a reader can check; say as plainly what did not get better.
- The verdict is somebody else's. A chunk is done when an independent reviewer has read its whole diff.
- A regression found becomes a gate where a tool can hold it.
Rules by area
Before you change or review code in an area, read its file whole; a brief to another agent names the files.
.claude/rules/python.md— any Python file: types, enums, logging, errors, modules..claude/rules/mcp-server.md— the MCP tools and their answers undersrc/semantic_code_mcp/server/..claude/rules/testing.md— any test undertests/..claude/rules/scripts.md— the gates of our own underscripts/..claude/rules/documentation.md—TODO.md,CHANGELOG.mdand the decisions underdocs/decisions/..claude/rules/publishing.md— a release..claude/rules/instructions.md— this file and the rules of each area.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

