Skip to content
Conduit

mcp server

code-atlas

Local-first MCP server that indexes a codebase into SQLite and exposes token-efficient search/read/navigation/impact tools.

cuongdinhngo/code-atlascommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "cuongdinhngo-code-atlas": {
      "command": "uvx",
      "args": [
        "code-atlas"
      ]
    }
  }
}

same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12

Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs

README

synced Oct 26, 2026

code-atlas

An evidence layer for AI coding agents. A local-first MCP server that indexes your codebase into a symbol graph, then answers resolved relationship questions — who calls this, what implements that, what breaks if I change this file — as rows, not as files to read.

PHP · TypeScript/JavaScript · Python · T-SQL. 24 tools. Deterministic, offline, no LLM in the core. Every edge says how it was resolved, and the adapters differ in how deep they resolve — measured per language.

~69× fewer tokens than grep-and-read to reach a resolved answer

Measured on two pinned public PHP repos (symfony/demo · brick/math): 8/8 answers correct, recall 1.0, precision 1.0, zero confidently-wrong answers. Relation questions range from 18× on a small tree to 117× on a wide one; the one scored onboarding lookup is 4.5×. The baseline is a fixed recipe — grep the name, then Read every matching file whole — not a live model, so the comparison is deterministic. Reproduce it · needs PHP and a one-time clone of the pinned repos.

The 30-second version

Ask "who calls member()?" in this repo's own TypeScript adapter.

grep — 28 hits, and it cannot tell you which are calls:

$ grep -rn 'member' adapters/typescript/src/ | wc -l
28

$ grep -rn 'member' adapters/typescript/src/ | head -3
adapters/typescript/src/qname.js:4:// §4.4 Q1). The root container is the repo-relative posix
adapters/typescript/src/qname.js:12:function member(container, name) {
adapters/typescript/src/qname.js:16:module.exports = { SEP, toPosix, member };

A comment, the definition itself, and an export line — not one of the three is a call. The agent has to open and read every one of the 28 to sort them out. That reading is the cost, and it is paid in context.

code-atlas — the 9 functions that call it, each resolved, with the tier it was resolved at:

// MCP tool call, not a shell command
find_callers(qname: "src/qname.js::member")

reason: "ok"   total_count: 9   truncated: false   depth: 1

RESOLVED  parseFile::collect               src/parse.js:278
RESOLVED  parseFile::emitBodyEdges         src/parse.js:508
RESOLVED  parseFile::emitDefaultAlias      src/parse.js:428
RESOLVED  parseFile::emitJsDocDeclarations src/parse.js:439
RESOLVED  parseFile::emitReExport          src/parse.js:419
RESOLVED  parseFile::resolve               src/parse.js:301
…

No comment, no definition, no export line — and total_count: 9 is the true size of the answer (distinct callers; the graph holds all 13 call sites behind them), not the length of the page you were handed. Building that index took 0.54 s.

Real output, reproduced on 2026-09-27 by pointing code-atlas at its own adapters/typescript/ (code-atlas-build there, 6 files).

Why code-atlas

grep returns every line containing the string. An LSP answers precisely but one editor buffer at a time. Neither gives an agent a countable answer it can act on, and both make it read files to find out. code-atlas parses each language with its best parser into a SQLite symbol graph, resolves cross-file edges once at index time, and serves callers, implementations, blast radius, reachability and the path between two symbols as rows.

Use it if: you have a large codebase (>10k files) you did not write · an AI agent is doing the reading, not a human in an IDE · you need the answer to be checkable, not plausible.

It is not a faster grep, an editor, or a language server — an LSP stays for precise in-buffer nav, and code-atlas never mutates code.

Agents do not reach for it on their own when grep can serve the question — on a 23k-file tree, five control-flow questions drew no index calls with every tool available (074). It pays off on relationship questions, and an agent is far likelier to use it once told when to: install the agent brief.

Architecture

The core is language-agnostic — no per-language branches, CI-gated. Adapters parse files and emit a common {nodes, edges} vocabulary; the core stores them, resolves cross-file edges, and exposes the MCP tools. Everything runs offline against local SQLite, with incremental updates via git diff.

Languages

LanguageParserStatus
PHP (8.5 grammar, 8.1+ runtime)nikic/php-parserAvailable — see adapters/php/
TypeScript / JavaScript (Node ≥ 18)TypeScript compiler APIAvailable — see adapters/typescript/
T-SQL (Node ≥ 18)purpose-built scanner, no production dependenciesAvailable — see adapters/sql/
Python (≥ 3.12 grammar)stdlib astAvailable — see adapters/python/
C# / .NETRoslynDeferred — see Roadmap

Resolution depth differs by adapter. A CALLS edge the adapter could not pin to one definition is stamped HEURISTIC rather than guessed, and the share of those is the depth measure (scripts/edge_health_report.py); PHP is the depth standard:

AdapterHEURISTIC share of CALLSPinned sampleReport
PHP1–4 %symfony/demo · brick/math · laravel137
TypeScript/JavaScript54.1%ky153
Python82.2%flask227
T-SQLnot measured this way — floors and layer shape insteadSQL samples233

Adding a language touches no core code — an adapter announces its own name, the file suffixes it owns and its capabilities on one handshake line, and the core routes files from that alone.

Quick start

Platform: runs on Linux, macOS, and native Windows. For heavy indexing on Windows, WSL2 on the Linux-native filesystem is recommended: a repo under /mnt/* crosses the 9p boundary (~100× slower — measured), and Defender's real-time scan adds a large cold-read cost — exclude the repo path or use a Dev Drive. The startup preflight warns about the /mnt/* case; the Defender cost it cannot see. The test and dev loop is POSIX-only — run it under WSL2 or Docker.

You need Python ≥ 3.12 with SQLite ≥ 3.25 and FTS5 (a standard CPython build has both), plus the runtime of whichever language you want to index: a PHP CLI ≥ 8.1 with Composer for PHP, Node.js ≥ 18 for TypeScript/JavaScript and T-SQL. The Python adapter is stdlib-only and runs on the same interpreter as the core.

git clone https://github.com/cuongdinhngo/code-atlas.git
cd code-atlas
python3 scripts/setup.py /abs/path/to/your-project

That installs the core, sets up every adapter whose runtime is on PATH (PHP via Composer, TS/JS and T-SQL via npm, Python needs nothing), and writes <your-project>/.mcp.json with the correct interpreter, each CA_<LANG>_CMD and the working directory filled in — the three things that are easy to get wrong by hand. Run it with no path to print the snippet instead of writing it.

To run the server without a checkout: uvx --from git+https://github.com/cuongdinhngo/code-atlas.git code-atlas, or pipx run --spec git+https://github.com/cuongdinhngo/code-atlas.git code-atlas — the adapters still need their own runtimes on PATH, and a checkout to launch them from.

In Claude Code, install it as a plugin — the server, the hooks and the skill in one step, for every project. The plugin launches the console scripts by name, so put them on PATH with a tool install:

uv tool install git+https://github.com/cuongdinhngo/code-atlas.git   # or: pipx install git+…
claude plugin marketplace add cuongdinhngo/code-atlas
claude plugin install code-atlas@code-atlas

Its hooks stay silent in a repo with no .code-atlas/; without the console scripts on PATH, the SessionStart hook prints the install line once and every hook exits 0 (376). Adapter CA_<LANG>_CMD variables stay per machine, as below. Already wired .mcp.json or the hook snippet by hand? Remove those, or each event fires twice (contrib/claude-code/).

Installed with uvx/pipx, the plugin or by hand? Add each adapter yourself — the core resolves any CA_<LANG>_CMD generically from the variable name, so each is one env var, not a code change:

npm ci --prefix adapters/typescript
export CA_TYPESCRIPT_CMD="node /abs/path/to/code-atlas/adapters/typescript/index.js --server"

npm ci --prefix adapters/sql          # dev-only deps; the scanner itself has none
export CA_SQL_CMD="node /abs/path/to/code-atlas/adapters/sql/index.js --server"

# Python adapter — stdlib only; use the same interpreter that runs the core
export CA_PYTHON_CMD="python3 /abs/path/to/code-atlas/adapters/python/index.py --server"

Then reload your MCP client (in Claude Code: restart, or re-approve the project's .mcp.json) and call get_index_status first — it is the cheap (~100-token) entry point that says whether there is an index, how stale it is, and what to call next. Then build_or_update_index, then query.

By hand: pip install -e ., then composer install --working-dir=adapters/php, then point an .mcp.json at your repo — command = code-atlas (or python3 -m code_atlas.main), cwd = the repo to index, env.CA_PHP_CMD = php /abs/path/to/code-atlas/adapters/php/index.php --server. The adapter lives in this checkout, so CA_PHP_CMD must be an absolute path. Details in adapters/php/README.md.

In a container — no host Python or PHP needed; the image bundles the pinned adapters:

docker build -f docker/Dockerfile.runtime -t code-atlas-server .
// .mcp.json — the server indexes the mounted repo and writes .code-atlas/graph.db into it
{"mcpServers": {"code-atlas": {"command": "docker",
  "args": ["run", "-i", "--rm", "-v", "/abs/path/to/your-project:/workspace", "code-atlas-server"]}}}

MCP speaks over stdio, so -i is required; the server indexes /workspace, so mount the repo there. Add "--user", "1000:1000" to keep .code-atlas/ writes owned by you. See docker/.

The runtime is fully supported; setup differs only in path/quoting and the checks the startup preflight surfaces at build time — long paths, core.autocrlf, and an adapter missing from PATH.

  • Adapter command — prefer the list form in .code-atlas.toml, so a Windows path's backslashes are never eaten by POSIX quoting (the table needs $env:CA_TRUST_PROJECT_FILE = '1' — see the config table):

    [adapter_cmd]
    typescript = ["node", "C:\\code-atlas\\adapters\\typescript\\index.js", "--server"]
    python     = ["python", "C:\\code-atlas\\adapters\\python\\index.py", "--server"]
    

    Or set the env var in PowerShell: $env:CA_TYPESCRIPT_CMD = 'node C:\code-atlas\adapters\typescript\index.js --server'.

  • Enable long paths so deep vendor/ / node_modules/ trees don't hit the 260-char limit (admin, then reboot): Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' LongPathsEnabled 1.

  • Set core.autocrlf=false for the indexed repo — otherwise a graph.db built elsewhere sees every file as changed and reparses the world.

  • Speed: exclude the repo from Defender real-time scan (admin: Add-MpPreference -ExclusionPath 'C:\path\to\repo') or put it on a Dev Drive — the AV scan dominates cold reads. For very large repos, WSL2 on the Linux-native filesystem is fastest.

  • PHP repos need php + composer on PATH, or the PHP files are skipped (the preflight says so) — use WSL2 or the container if you can't install them natively.

code-atlas-build warns for each of these it can detect — long paths, core.autocrlf, a missing adapter runtime, a /mnt/* repo on WSL. Defender and Dev Drive it cannot detect; those two are on you. A clean host prints nothing.

Onboarding a large legacy repo — where the first build takes minutes and what you exclude decides whether the database is 1 GB or 2 GB — is covered step by step in docs/runbooks/onboarding-a-repo.md.

Upgrading

Every release is an entry in CHANGELOG.md and a vX.Y.Z tag; commits after a tag are not a newer release until the next one is cut, and they gather under Unreleased (381). An entry can flag two extra steps: full rebuild required and adapter checkout must be updated. Upgrade by the route you installed with:

Installed withUpgrade
uv tool install git+… / pipx install git+…uv tool upgrade code-atlas / pipx upgrade code-atlas
uv tool install git+…@<rev> (the receipt says ?rev=)uv tool install --force git+… — upgrade never moves a pin, and the SessionStart hook names one (381)
a checkout and scripts/setup.pygit pull, then re-run python3 scripts/setup.py /abs/path/to/your-project
the Claude Code pluginclaude plugin marketplace update code-atlas, then claude plugin update code-atlas@code-atlas, then restart. Also upgrade the tool install that puts the scripts on PATH

The plugin updates only when its version moves. Measured on Claude Code 2.1.284:

  • A content change under an unchanged version answers already at the latest version.
  • marketplace update alone leaves the installed version where it was.
  • plugin update moves it.

Turn on auto-update for this marketplace. Claude Code's docs (plugins/loading.md, install.md, read 2026-10-09) say auto-update is off by default for a third-party marketplace. Once on, it runs after the first message of an interactive session, after a random delay of up to ten minutes, and applies on /reload-plugins or the next launch. Turn it on per user with /plugin → Marketplaces → Enable auto-update. Do not put it in a project's committed settings: Claude Code registers and clones every extraKnownMarketplaces entry in the background for anyone who trusts the folder (settings-reference.md, plugins/loading.md, read 2026-10-10) — a network call on every teammate's machine, code-atlas or not (381; documented, not yet measured live).

With auto-update off, the plugin still tells you a newer release is out (405). Once a day, a background SessionStart hook lists the repository's vX.Y.Z tags into ~/.cache/code-atlas/release.json. The next session start shows release X.Y.Z is out when that tag is newer than the plugin. It is silent offline. CA_RELEASE_CHECK=0 turns it off.

The SessionStart hook names every half that lags — the tool install, the plugin, and the adapter checkout, whose contract it reads by launching each configured adapter — on screen as well as to the agent (381). It gives each fix, in this order:

  1. On Windows, disconnect the server first (/mcp). A running server holds code-atlas.exe, so uv tool upgrade fails halfway with os error 32. Re-run it after disconnecting.
  2. The tool install, then the plugin, then the adapter checkout.
  3. Reconnect — a /mcp reconnect loads the new server; a plugin update applies on /reload-plugins.

After an upgrade, check two things:

  • The index. If the changelog flags a full rebuild, run code-atlas-build --full. Until then get_index_status and the state line lead with rebuild required.
  • The adapters. If CA_<LANG>_CMD points into a checkout, pull that checkout and reinstall its dependencies when the entry says so. An adapter on an older contract fails the handshake.

Agent brief (optional)

After the first index, offer the agent brief into the repo's AGENTS.md — six occasions that name a tool, plus how to spend the calls, how to read an answer's honesty fields, what the index cannot answer, and two traps. Not the full tool roster (generated from which_tool; do not hand-edit):

python3 scripts/setup.py /abs/path/to/your-project --write-agent-brief
# or: python3 scripts/gen_skill.py --write-agent-brief /abs/path/to/your-project

Load requirement per host: Cursor reads AGENTS.md directly. Claude Code reads only CLAUDE.md / CLAUDE.local.md — if CLAUDE.md lacks @AGENTS.md, the writer prints that one line to add and never edits CLAUDE.md.

What you can ask it

QuestionTool
Who calls this? What implements it? Where is it referenced?find_callers · find_implementations · find_references
What breaks if I change these files?impact, and impact_modules for the same radius rolled up to business modules
What is dead code here?find_orphans · reachable_from
How does A reach B?explain_path
Show me this symbol, without the rest of the fileread_symbol · file_outline
I did not write this repo — where do I start reading?architecture_overview · guided_tour · generate_onboarding
Are any of these ten names already taken?search_symbol with a list of queries — one call, not ten
Did this change break an architectural rule?check_architecture_rules · diff_architecture
What happens when a user does X — entry to data?trace_capability, one entry, file or module per call
Draw me this type and its ancestryclass_diagram
Which writers of this table omit a defaulted column?check_column_defaults (T-SQL)
Is something missing here — an unchecked call site, an untested symbol?none of them — use grep, and see what it cannot answer

All 24 tools, what each returns, and which take a list of subjects: docs/TOOLS.md.

From a script, with no agent: code-atlas query <tool> --args '<json>' prints the payload the MCP tool returns, as one JSON line; code-atlas query --batch <file.jsonl> (- for stdin) takes one {"tool": …, "args": {…}} per line (blank lines skipped) and answers in order from one process. Exit 0 for any answer, an empty one included; 2 for a usage error; 1 with no readable index. Every line is checked before any is asked, but a call a tool rejects stops the batch there, after the answers before it. The two index writers are refused, and shell calls are not counted in fit_counts or est_tokens_vs_grep_read. --snapshot-symbols <out> plus a later --changed-since <out> --qname … asks whether a method's body changed since that revision — comments and layout ignored (design).

Three properties worth knowing before you install

Every answer says what it is not telling you. total_count (the true size, not the page), truncated, limit_capped_to, and reason on every empty result — no_such_symbol, name_not_qualified, not_indexed, relationship_not_modelled, capability_not_configured. An empty result is never an unexplained zero, and where a better route exists the payload names a real, callable tool in try_instead. Where a language loads code by a name the file never spells — PHP autoload, a computed import()/require() or Python importlib load, T-SQL dynamic EXEC — the adapter stamps the file, and find_orphans answers resolution_unmodelled instead of calling unmeasured silence dead code. This is what makes an agent's answer auditable instead of merely confident.

Every edge carries a confidence tier — RESOLVED, HEURISTIC or DYNAMIC. A guess is never linked as a fact, and an answer whose candidates are all dynamic says so with authoritative: false. Inbound answers are ordered by that tier before the page is cut, so page 1 leads with what was resolved rather than with whatever sorts first alphabetically.

An answer can be signed. Pass sign: true to five tools and the payload gains a one-line claim you can paste into a PR body or a doc — a claim a text search cannot make, which code-atlas query --verify-claims <file> re-runs as holds / changed / unverifiable. Off by default, +75 tokens when on.

Full detail: docs/design/payload.md · docs/design/impact-and-claims.md.

Measured, not asserted

Every number here is reproducible from a runbook in this repo.

WhatResultWhere
Tokens to reach a resolved answer, vs grep-and-read~69× cheaper on pinned public PHP repos (symfony/demo · brick/math) — 8/8 correct, recall 1.0, precision 1.0; 18×–117× per relation question, 4.5× on an onboarding lookup. Re-measured 2026-09-27: 70.2×tokens-to-answer.md
Answer correctness, blind field round8 of 8 checked claims exact, zero false statementsPLAN §19
Cost of the n-th parallel agent~70 MB PSS; the 925 MB index costs 0 MB (page-cached, never mmapped)parallel-agents.md
Five agents vs one4.3× throughput, 1.3 % of RAM, zero SQLITE_BUSY reaching a callersame
Incremental no-op rebuild, large index56.1 s → 2.113 s (26×)PLAN §19
Onboarding lookups vs hand-mappingcheaper, 12/12 correct, recall 1.0121_onboarding-question-class.md

On your own repo, get_index_status(detail_level="verbose") carries est_tokens_vs_grep_read: per tool, the tokens its answers cost and an est. grep+Read baseline — the files each found answer cites, read whole. It is a live estimate against a modelled baseline, not the row-one benchmark and not a measured saving (379).

Row two is the one the design optimises for. Every failure in that round was silence or ambiguity — never a wrong answer. A tool an agent cannot trust to be wrong-free is a tool whose every answer must be re-verified by hand, which costs more than not having it.

Configuration

Every knob resolves environment → project file → default. The project file is .code-atlas.toml at the repo root (optional, meant to be committed); its keys are the environment names lower-cased without the CA_ prefix. A malformed value or an unknown key is a loud error, never a silent fallback.

Environment.code-atlas.tomlDefaultMeaning
CA_DB_PATHdb_path.code-atlas/graph.dbindex location (relative to the repo root). The file value must stay inside the repo; only the env var may point outside
CA_WORKERSworkersmax(1, min(cpu-2, 8))adapter processes during a build
CA_PAGE_LIMITpage_limit50query-time row ceiling for search/nav tools (no rebuild). Pre-259 CA_MAX_RESULTS does not set this
CA_MAX_CANDIDATESmax_candidates50build-time resolver fan-out (rebuild to apply). CA_MAX_RESULTS / project-file max_results still alias here
CA_IMPACT_DEPTH / CA_IMPACT_MAX_NODESimpact_depth / impact_max_nodes2 / 500hops and node budget for one impact query
CA_ENTRY_POINTSentry_pointsunsetfile globs that seed reachability. reachable_from and find_orphans need this — unset, they report no roots configured rather than guessing, and get_index_status nominates candidate globs with a file count for you to choose from
CA_STUB_ROOTSstub_rootsunsetdependency roots (e.g. vendor) to index declarations-only, so third-party signatures resolve
CA_INDIRECTION_RULESindirection_rulesunsetJSON rule files mapping framework indirection to edges. find_view_data needs this
CA_ARCHITECTURE_RULESarchitecture_rulesunsetJSON rule files of path-set dependency constraints. check_architecture_rules needs this
CA_TOOLStoolsall 24comma-separated tool allow-list — see the six-tool preset below
CA_<LANG>_CMD[adapter_cmd].<lang>—the complete argv that launches one adapter in server mode. The file table is honoured only with CA_TRUST_PROJECT_FILE=1
CA_TRUST_PROJECT_FILE— (env only)unset1 lets the repo's own [adapter_cmd] choose the argv. Unset, a table there is a loud error: a repo you index must not pick the command code-atlas runs
# .code-atlas.toml — [adapter_cmd] is honoured only with CA_TRUST_PROJECT_FILE=1
workers = 4
page_limit = 50
max_candidates = 50

[adapter_cmd]
php = "docker compose exec -T php php /app/adapters/php/index.php --server"
typescript = "node /abs/path/to/code-atlas/adapters/typescript/index.js --server"
sql = "node /abs/path/to/code-atlas/adapters/sql/index.js --server"
python = "python3 /abs/path/to/code-atlas/adapters/python/index.py --server"

The adapter command is the whole command: the core appends nothing to it, not even --server, so it never has to know where a language's adapter lives.

Trimming the tool surface. Twenty-four tool descriptions are read before the first question is asked. CA_TOOLS=get_index_status,search_symbol,read_symbol,find_callers,find_references,impact is the opt-in six-tool preset that covers the relationship questions; the default stays all 24.

Routing ships with the server. Its MCP instructions reach the model's system prompt and carry this repo's live index state, the load step a client needs when it delivers MCP tools as deferred names, where the graph stops, and the eight core rows of the question -> tool map. Claude Code keeps only the first 2,048 characters, so they render in that order and fit under it; the full map is the which_tool prompt and contrib/skill/. Nothing has to be installed in your repo for an agent to learn that the index exists.

Files are skipped using built-in patterns (vendor/ var/ uploads/ log/ node_modules/ .git/ *.blade.*), then .gitignore, then an optional .codeatlasignore — later rules win. The full knob table, including the LLM-enrichment switches, is in docs/TOOLS.md.

Optional LLM enrichment (off by default). The onboarding tools are fully deterministic — no LLM, no network. An opt-in package, onboarding_llm/, plugs into three seams to reword module summaries, weak layer names and the map's prose. Structure is never the seam's to change: every count, ranking and grouping is derived before a model is consulted, and the core never imports it.

Testing

scripts/gate.sh runs the whole gate in one step — bytecode invalidation, entry points, ruff, mypy, pytest, the tokens-to-answer benchmark, composer validate, php -l, phpstan at level max, tsc --checkJs --strict on both Node adapters, ruff and mypy --strict on the Python adapter, and the rulebook guardrails (R1.1, R2.2, R4.1, R7.3, R2.4) — in the same order ci.yml runs them. It exits non-zero if a check failed or was skipped, because a gate that quietly shrinks to whatever the host can run has not verified anything. Add --fast to skip the two slow checks, or --docker to run the same gate inside the test image when the host lacks a runtime.

The suite needs a POSIX host with every adapter installed. To run everything off any host (Windows/macOS included), use the Linux test image:

scripts/docker-test.sh                       # ruff + mypy + pytest -q (the full suite)
scripts/docker-test.sh pytest -q -k php      # just the PHP-adapter integration tests

Contributors: the expected pass/skip count for each route — the one place those numbers are kept — and what a legitimate skip looks like are in AGENTS.md.

Documentation

DocAnswers
docs/TOOLS.mdall 24 tools, the operator prompts, the opt-in hooks, and which tools take a list of subjects
docs/design/why an answer is shaped the way it is — payload · indexing & search · impact & claims
docs/PLAN.mdthe authoritative design, and §19 — the decision log: what was measured, what was refuted
docs/CONVENTION.mdnaming, repo layout, and §6 — the payload contract every tool answer obeys
docs/ENGINEERING_RULES.mdthe binding how we build rules, several CI-gated

Runbooks — operator protocols, each reproducible: onboarding a large legacy repo · tokens-to-answer · parallel agents · cross-repo validation · field retro · tool-recognition probe.

Contributors start at CONTRIBUTING.md, agents at AGENTS.md; vulnerabilities go through SECURITY.md.

Roadmap

  • Shipped. Phase 1 (closed 2026-09-27): the core, the onboarding system map and four adapters — PHP, TypeScript/JavaScript, T-SQL and Python — with 24 tools. Phase 2 so far: releases 0.2.0–0.9.0 and the Claude Code plugin; what each release changed is in CHANGELOG.md.
  • Open. Graph coverage and freshness work; each ticket and its gate is in docs/BACKLOG.md. Nothing is open on the onboarding map.
  • Deferred. The C#/.NET adapter — the only language left, held since 2026-08-04 (plan §19).

Design principles. SOLID at the boundaries (the axis of change is languages, expressed through one versioned contract) + YAGNI (one seam only) + standard over sample (adapters encode the language spec/standards, never a specific repo's conventions). Details in the build plan.

License

MIT — see LICENSE. © 2026 Cuong Ngo.

↑↓ navigate openesc close