neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證用於 AI 程式編寫代理的工程圖譜。程式碼智慧、永久記憶、計畫與跨多專案的 MCP 上下文。
AI 翻譯
Engineering Graph for AI coding agents. Code intelligence, persistent memory, plans and multi-project context over MCP.
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Engineering Graph for AI agents. Code intelligence, persistent memory, plans and
multi-project context over MCP, for Claude CLI (claude-code) and Gemini CLI.
It runs an isolated PostgreSQL database with pgvector, indexes codebases into
graphs of files, entities and their relations, and serves those graphs to both
agents over MCP. One stack holds as many codebases as you index, and an agent
working in one of them can read the graph of another. Every indexed codebase is
mounted read-only, so nothing in this stack can modify your sources.檢視完整 README ↗Engineering Graph for AI agents. Code intelligence, persistent memory, plans and
multi-project context over MCP, for Claude CLI (claude-code) and Gemini CLI.
It runs an isolated PostgreSQL database with pgvector, indexes codebases into
graphs of files, entities and their relations, and serves those graphs to both
agents over MCP. One stack holds as many codebases as you index, and an agent
working in one of them can read the graph of another. Every indexed codebase is
mounted read-only, so nothing in this stack can modify your sources.
Full docs: https://oberon-systems.github.io/enggraph/
host codebase docker compose stack
------------- --------------------
/path/to/project --(ro)--> +-----------+
| indexer | one-shot indexing job
+-----------+
| writes nodes and edges
v
+-----------+
| postgres | pgvector/pgvector:pg16
+-----------+
^ ^ ^ read
| | |
+-----------+ +--------+ +-----+
| mcp-server| | viewer | | web |
+-----------+ +--------+ +-----+
^ ^ ^
| +----------+
| | the graph page, proxied
+---------------------------------+
Claude, Gemini <->| nginx :3000 |<-> browser
+---------------------------------+
nodes, edges) and the vector
embeddings (chunks) that search_code searches by meaning with.
Plans, memories, suggestions and issues are nodes of built-in projects rather than
tables of their own. Everything derived from a tree is scoped to a row of
projects, and nodes is keyed on (project, id), since README.md
is a node id in every codebase there is. Plans are the exception: they are written by an agent and rebuilt
by nobody, so they live in one table for the whole database and carry the
project as a tag rather than an owner./v1/embeddings with a small model, so a file chunk
and a search query become vectors of the same space. It is part of the
stack and starts with make up. EMBED_SERVER_URL points the same client
at a llama-server on a machine with a GPU instead.enggraph.
Every node records which producer found it in metadata.source./mcp./mcp and /sse to the
MCP server, /worker to the summarization API, everything else to the
dashboard. See the route table.Every address the stack serves is reached through one host port. nginx publishes it and picks the backend from the path; no other service is published at all.
| Path | Served by | What it is |
|---|---|---|
/mcp, /mcp/<project> | mcp-server | Streamable HTTP, the transport to use |
/sse, /sse/<project>, /message | mcp-server | the older SSE pair |
/health | mcp-server | what make status probes |
/worker/... | worker-api | the remote summarization queue, prefix stripped |
| everything else | web | the dashboard, its API and the graph page |
GATEWAY_PORT (default 3000) and GATEWAY_BIND (default 0.0.0.0) in
.env decide where it listens. Binding every interface is what a
summarization worker on another machine needs, and it also puts the
dashboard - which writes to the database on behalf of a browser and has no
authentication of its own - within reach of the local network. Set
GATEWAY_BIND=127.0.0.1 if you run no remote worker.
Reaching the stack under any other name or port means saying so:
GATEWAY_HOSTS is the Host header allowlist both the MCP server and the
dashboard API enforce, and a value that does not name the address you use
answers 403 while /health still looks healthy.
Migration 0031 (release 0.24.0) replaces the database schema. Up to 0030 dropping a project breaks the database: a drop deleted one row and trusted foreign-key cascades for the rest, the rows of the dropped project stayed behind, and the database could neither be migrated nor restored from its own backup. 0031 removes every foreign key, renames the tables and stops storing file text. Take a whole-database backup before upgrading, and read BREAKING CHANGES first: it lists what changed and how to recover a database the old schema damaged.
The index job is the indexer service, and the upstream extractor is
gone. The compose service graphify is now indexer, its limits are
INDEXER_CPUS, INDEXER_MEM and INDEXER_MEM_RESERVATION, and make up
rewrites a generated override that still names the old service. The graph
stdio MCP server, graph.json and the graph-out volume are removed: the
enggraph server answers the same questions for every project. See
BREAKING CHANGES.
Upgrading from 0.x to 1.0.0 goes through 0.24.0. On 0.24.0 run
make db migrate and make backup, then check out 1.0.0 and run make up.
An install below 0.24.0 upgrades to 0.24.0 first. The steps are in
BREAKING CHANGES.
Alembic replaces goose (release 1.0.0). The schema is unchanged and a database 0.24.0 migrated is taken over as it is. An older one is refused: bring it to 0.24.0, the last release that carries goose, first. See BREAKING CHANGES.
The dashboard is a Python package (release 1.0.0). Its addresses
and its /api are unchanged, the web image is built from packages/web,
and nothing in the repository needs Node.js any more: make web <target> is
removed. See
BREAKING CHANGES.
The Python services moved into packages/ (release 0.24.0). The
graphify image is gone: pull api, embed, summarize and viewer
instead. The embedding and summary queues run as services of their own,
make summarize and make embed are removed, and the stack no longer loads
a summarizing model itself. See
BREAKING CHANGES.
This project was called claude-context-mcp. The name tied it to one agent and
described a transport rather than a product, and what it holds has since grown
past a context server: a code graph, persistent memory, plans and a suggestion
backlog across every project you index.
Everything the old name reached moved with it. An existing install upgrades in five steps, in this order:
make down # under the old checkout
mv ~/.local/share/context-mcp ~/.local/share/enggraph # database, models, backups
git pull && make build && make up
make reregister # every codebase now addresses the server as `enggraph`
make install # this codebase: the old shell block dropped
make install takes the # >>> enggraph >>> block out of ~/.bashrc, and
the # >>> claude-context-mcp >>> one with it: the shell aliases those
defined are gone, and a project is onboarded with make install AGENT_ROOT=<path> instead. The images publish to
ghcr.io/oberon-systems/enggraph, the tools an agent sees are
mcp__enggraph__*, and selection files in a tree (.enggraph-keep,
.ctxignore and the like) are no longer read - see
Choosing what gets indexed.
make init)make llm-model-install and mounted read-only at /modelsmake init # virtualenv, pre-commit hooks, .env from the template
$EDITOR .env # set PROJECT_PATH and POSTGRES_PASSWORD
make build # build both service images
make up # start the database, the services and the entry point
make install # onboard this codebase and index it
curl -fsS localhost:3000/health
make install is the whole of it, for this repository or for any other tree:
make install AGENT_ROOT=/home/you/work/api
Four things, none of which replaces a file that already exists:
| Step | What it leaves behind |
|---|---|
| the formats | reported from the file types the tree holds; the first index run records them on the project row |
.mcp.json | the enggraph server for Claude Code, at /mcp/<project> |
.gemini/settings.json | the same address for the Gemini CLI |
CLAUDE.local.md, GEMINI.md | how an agent should use the graph, from templates/CLAUDE.local.md - GEMINI.md only when the tree has none of its own |
Then it indexes the tree, so the address it just wrote answers immediately.
Every step reports written, merged, kept or skipped, and the run ends
with that list, so a second run is how a codebase picks up a piece added later
rather than a way to reset one. The project name comes from the same code the
indexer uses, which is what stops the /mcp/<project> address from naming a
project that will never exist.
| Variable | Default | Purpose |
|---|---|---|
AGENT_ROOT | this repository | the tree being onboarded |
PROJECT_NAME | its last path segment | the name it is stored and addressed under |
SOURCE | AGENT_ROOT | the tree it reads; none registers no tree |
TYPE | codebase | docs or config; unset keeps the stored |
SHELL_RC | ~/.bashrc | the rc file an old alias block is taken out |
Earlier versions wrote shell aliases behind a # >>> enggraph >>> marker.
They are gone: make install deletes that block and the
# >>> claude-context-mcp >>> one it replaced. A block opened without its
closing marker is left alone and reported, since editing around it is a
decision about someone else's shell.
make build is optional: the images are published to
ghcr.io/oberon-systems/enggraph, and make up pulls them when they
are missing. A local build produces exactly that reference at :latest, which
is the one docker-compose.yaml pins, so it takes the published image's place
until make pull fetches it again. make build prints the image id it left
behind, and says so when the running stack still holds the previous one.
One stack serves every codebase you index, and any tree can be indexed without being touched:
make -C /path/to/enggraph install AGENT_ROOT=/home/you/work/api
make -C /path/to/enggraph install AGENT_ROOT=/home/you/work/infra
AGENT_ROOT defaults to the directory make is called from, so a bare
make -C /path/to/enggraph install run inside a codebase onboards that
codebase.
A re-index is authoritative: it reports how many files it selected and how many
of them a node was written for, and names the ones it had to leave out. Both
producers skip a file whose content has not changed since the last run, so a
re-index is cheap. What a file is compared against is its content and the
revision of the parsers reading it, so upgrading this project re-parses the
trees its parsers now read differently, without being asked to.
The dashboard's Fresh button distrusts both caches and re-parses everything,
for when a graph looks incomplete rather than merely old.
It is POST /index with fresh, which is also what the API takes from any
other client.
Each lands under a name taken from the last segment of its path (api,
infra; override with PROJECT_NAME=). Names beginning with _ are reserved
for the built-in projects described under Agent memory. The indexed repository needs nothing
of its own for this - no checkout of this project inside it, no .env, no
Makefile - because the path is an argument of the indexing job rather than a
setting. What it leaves out is stored here too - described below.
TYPE= says what kind of project it is, which is what a search across the
database narrows on:
make install AGENT_ROOT=/home/you/work/handbook TYPE=docs
make install AGENT_ROOT=/home/you/work/infra TYPE=config
codebase is the default, and docs and config are the other two an index
run may write. They are all indexed trees and differ only as a filter - the
fourth, memory, is not a tree at all. The type is stored once: a later
An index run without a type keeps it rather than resetting it to the default.
An agent connects to one project and can read the others:
claude mcp add --transport http --scope project enggraph http://localhost:3000/mcp/api
Every tool then works on api without being told, and takes an optional
project argument to reach another graph in the same database - which is what
answers a question spanning two repositories, an Ansible role and the service
it deploys, an API and its client. list_projects returns what is indexed,
with each project's type.
search_code_nodes is the one read that need not stop at a project.
project: "*" searches every graph in the database, and project_type: "docs"
searches every project of that kind - which is how a convention is found
without knowing which repository wrote it down. The limit is shared out between
the projects rather than spent on whichever sorts first, so a search over six
codebases answers with all six.
search_code is the same reach for a question asked in words rather than in
identifiers: it fuses that lexical match with a vector search over the text of
the indexed files and answers with the file and the line range to read. The
vector half is written by a queue that does nothing until embedding is
switched on in the dashboard, and until then the tool answers with its lexical
half and says so. What it costs, what runs the model - a container on CPU here
or a llama-server on a machine with a GPU - and how the switch resolves
across levels:
embedding.
An organization is read the same way by every tool, not only that one: it is
a set of projects rather than a tree, so naming it covers each project it holds
and every row says which one answered. describe_project is where a session
starts - it says whether the project is an organization, lists what it holds
with the sentence written about each member, and, given a path, names the
project that reads that directory.
Removing one is the same shape:
Dropping a project is the dashboard's job: it shows what the drop costs and
asks for the name back before it does anything.
It prints what the drop costs and asks before deleting anything (FORCE=1
skips the prompt). The counts are printed in three parts on purpose: nodes,
edges, file hashes and embeddings come back with one index run, manually
written summaries do not come back at all, and plans are not deleted in the
first place - they keep the name as a tag and stay readable through
get_plans. Unlike an index run,
this target has no default - naming nothing is an error rather than a delete of
whatever PROJECT_PATH happens to point at. The drop_project MCP tool does
the same from an agent, reporting first and deleting only when called again
with confirm: true.
Node ids are unique within a project, not across the database: README.md is a
node in every one of them. Edges stay inside one project, because the indexer
is handed a single tree and resolves every target within it.
A project is one tree. Grouping several of them is what an organization is
for: a project of that type reads no tree of its own and holds others by
reference, so one search reaches every member while each keeps its name, its
/mcp/<name> address and its own graph.
make install AGENT_ROOT=/home/you/work/mono SOURCE=none TYPE=organization
make install AGENT_ROOT=/home/you/work/mono/deploy/configs
make install AGENT_ROOT=/home/you/work/mono/tools/agents
SOURCE=none registers the row, the address and the agent files without a
tree, which is what an organization is; the two projects after it are ordinary
trees. Which of them the organization holds is settled in the dashboard, on
its overview tab under Members: Add member lists a project there while it
stays a project of its own, and Move into it, on the member's own page,
makes the organization where it is listed instead.
A member is indexed once however many organizations hold it, inherits the indexing schedule of the organization for anything it has not settled itself, and adds the organization's ignore lines to its own. While an organization lists a project, that project refuses to be dropped: taking it out is a decision of its own.
An organization has no root path, so it carries the synthetic
registered://<name> it was registered with, and pressing Index on it
starts one run per member that is not turned off.
make install writes both files described here, which is the reason to read
this section rather than follow it: what follows is the manual form, for a
codebase onboarded by hand or a registration make install deliberately left
alone.
The server speaks Streamable HTTP at /mcp, and at /mcp/<project> to bind a
session to one of the indexed codebases. The older SSE pair (/sse plus
/message, /sse/<project>) is still served for clients that cannot do
better, but nothing should be pointed at it by choice.
Three commands, three places the registration can live. Pick one; they are alternatives, not steps.
Per project, committed with the codebase - this is what make install writes,
to .mcp.json at the project root:
claude mcp add --transport http --scope project enggraph http://localhost:3000/mcp/myproject
Per project, kept on your machine instead - --scope local is the default, and
it writes to ~/.claude.json under projects["/path/to/myproject"], leaving
the tree with no file of ours in it:
Registering only names the address. Claude still asks before every call to a
server it holds no permission rule for, so make install writes one into
~/.claude/settings.json:
{
"permissions": {
"allow": ["mcp__enggraph"],
"ask": ["mcp__enggraph__drop_project", "mcp__enggraph__drop_memory"]
}
}
A bare server name allows every tool it exposes; the four drop_* tools go
back into ask, which outranks allow, so nothing deletes graph state without
a prompt. That file is yours rather than any codebase's, which is why the rule
is written once and holds for every project you onboard afterwards.
PERMISSIONS=0 skips the step, and a server you have already denied or set to
ask keeps the answer you gave it.
Gemini reads .gemini/settings.json at the project root. There is no add
subcommand; write the file:
{
"mcpServers": {
"enggraph": {
"type": "http",
"httpUrl": "http://localhost:3000/mcp/myproject",
"trust": true
}
}
}
trust skips the per-call confirmation prompt. It is reasonable here because
the server only reads a graph of your own code, and unreasonable for anything
that reaches the network.
This repository's own .mcp.json and .gemini/settings.json are working
examples.
Whether the client actually attached is what the sessions count in make status answers; see the Make targets section.
Copy .env.example to .env; make up and make install refuse to run
without it. Sets the project path/name, database credentials, the entry
point's port and bind address, and the optional
ALLOWED_HOSTS/ALLOWED_ORIGINS DNS-rebinding allowlist. The stack is a singleton by design - one compose project name,
one fixed data directory - so onboarding a tree elsewhere reuses
the running stack rather than starting a second one. Full variable
reference: deployment.
By hand, until something says otherwise: the Index button on the dashboard,
and nothing else, is what starts a run. A schedule turns that into periodic
(every N minutes) or auto (a run when a watched file changes, throttled,
and never otherwise), set globally, per organization or per project. Details:
usage.
Every file a parser reads is indexed, and so is a script without an extension whose shebang names one. Each run records the formats it found on the project, and the Update formats button on its settings tab does the same without indexing. What is left out is a gitignore-style document at three levels - every project, an organization, one project - and the three are summed, on top of the built-in skip list and key material. Per-format nuances - what Ansible, Docker Compose, Puppet, JSON, HTML and PHP parsing extracts - are in formats.
Run make for the full list, including the per-service subdivisions.
make init create the virtualenv and install the pre-commit hooks
make install onboard AGENT_ROOT=<path> onto the stack and register it
TYPE=docs|config categorises it; unset keeps what is stored
SOURCE=<dir> is the tree it reads, SOURCE=none reads none
make reregister rewrite every onboarded codebase's agent configuration
make lint run every pre-commit hook over every file
make build build every service image
make pull pull the published images, discarding a local build
make up start the database, the services and the entry point
make down stop the stack, keeping the database volume
make mounts rewrite the compose override from the projects table
make llm-model-install
download the summarizer weights (FORCE=1 re-downloads)
make backup write the database, or PROJECT=/PROJECT_NAME= alone, to a file
KEEP=<n> keeps the n newest backups of that kind, 7 by default
make restore put FILE=<path> back, over the database or over one project
make logs follow the service logs
make status show whether the stack runs and whether anything uses it
make psql open a psql session against the context database
make db migrate apply every pending schema revision
make db version show the revision the database is at, and the history
make db new write the next revision file, NAME=<slug>
make clean remove containers, the database directory and the built images
Every directory under skills/ holding a SKILL.md is one skill:
enggraph (plans, graph exploration, memory and the suggestion backlog),
commit (driving commitizen), database (plain tables with no keys between
them, new features in new tables, ALTER only for a type change the user
allowed), delegate (handing work to the Gemini CLI and reviewing it) and
write-docs (the documentation house style, and finding the linter that gates
it). Nothing installs them into a codebase: they are baked
into the api image, imported into the database, and the MCP server hands
them to each agent, which writes them to .claude/skills/<name>/SKILL.md
itself. See Keeping skills current.
make status prints the running services, the /health payload and the number of
indexed nodes. The sessions field in that payload is the count of connected MCP
clients: a healthy stack reporting 0 means the client never attached, which is a
different problem from the stack being down.
The schema Makefile is reachable as a subcommand, and works standalone too:
make db version
make db help
| Tool | Arguments | Returns |
|---|---|---|
describe_project | optional project, path | What a project is: type, description, the tree it reads, and for an organization the members it holds |
get_code_graph_neighbors | node_id | Incoming and outgoing edges of a node, with the relation type |
search_code_nodes | query, optional project, project_type, limit | Nodes whose name or id matches, in one project, a whole kind, or every member of an organization |
search_code | query, optional project, project_type, limit, rerank, mode | Files whose text or name answers the question, ranked, with the line range to read |
search_text | pattern, optional loose, regex, path, project, project_type, limit | Every line of the mounted trees containing a string, with file and line, like grep |
shortest_path | source_id, target_id, optional max_hops | Shortest chain of relations between two nodes |
find_definition | symbol, optional project, file_path | Where a symbol is defined: file, line, the class holding it, summary |
find_callers | symbol, optional project, file_path, max_hops | Graph calls edges and call sites matched by name, each with its evidence |
find_callees | symbol, optional project, file_path, max_hops | What a symbol calls, from graph edges alone |
find_references | symbol, optional project, file_path, |
Both return JSON text. Errors come back as a tool result with isError set,
rather than tearing down the client session.
Indexing writes a fast summary for every file from its leading docstring or
first heading. A model writes better ones, as a pass of its own: the
summarize service pushes the queue to a model server named by
SUMMARIZE_SERVER_URL or the dashboard settings, and a worker on a machine
with a GPU can claim the same queue over HTTP, with no checkout of the code
and no database access - including from Windows. Full walkthrough, model
catalogue and the remote worker setup:
summarization.
Plans are managed by an AI client through save_plan, get_plans and
drop_plan, and live as nodes of the built-in _plans project rather
than being owned by the project they are about - that is a free-text tag in
metadata, not a key, so a plan survives a project drop and
drop_project. Full
lifecycle (status vs type, the "*" project):
usage.
What an agent works out about a repository - a convention, a decision, why
something is the way it is - has nowhere to live in a tree it may only read.
save_memory, get_memory and drop_memory write it into _memory, a
built-in project of type memory that is created by the migration and holds
records rather than files. Nothing indexes into it: names beginning with _
are refused by indexing, so a memory is never pruned by a re-index the way
a derived node is.
A memory is tagged with what it is about, the way a plan is - a project name,
or "*" for one that belongs to no repository in particular - and a read of
one scope always sees the global ones alongside it. Because _memory is a
project like any other, search_code_nodes with project_type: "memory"
finds memories, and project: "*" finds them next to what the code says.
An agent that had to answer something by hand knows exactly what the graph was
missing, and until now said so in a sentence that died with the session. So the
same gap was rediscovered every session and never accumulated evidence: one
reported eight times looked exactly like one reported once. save_suggestion,
get_suggestions and drop_suggestion write it into _suggestions, a
built-in project alongside _memory, holding what the graph could not answer
and the concrete change that would fix it.
The identifier is the mechanism. It is a stable slug derived from the gap, so
reporting the same gap again is the same call: the record keeps its first
sighting, moves its last, counts a hit, and reopens if it had been marked
resolved - a gap hit again is not a resolved one. Each carries a kind, a
status, and the lever closing it would move: tokens when the answer was
re-derived by hand, coverage when the graph does not describe it at all,
runtime when it was answerable but slow. Reading defaults to the open ones,
most often hit first, which is the ranking the whole thing exists for.
A project also owes work that is no gap of the tooling: bugs, security
problems, features, improvements and debt. save_issue, get_issues and
drop_issue keep them in _issues, a built-in project beside
_suggestions, each issue open, closed or declined. Closing one can
name the git commit that fixed it, the plan that carried it out with that
plan's prompts, or both, and the dashboard shows them on the issues tab of
every project.
make up serves a dashboard at http://localhost:3000: an Ask page that
runs an agent's read tools and shows what they answer, indexed projects and
their staleness, a per-project node/graph/file browser, when and what each
project indexes, every plan in the database, editable in place, the issues
of each project, and the recorded gaps, ranked by how often they were hit. It has no authentication of
its own, so anything that can reach the entry point can edit what it shows.
Details:
usage. Its mockups are
drawn in a disposable Penpot stack: dev/web.
make backup # the whole database
make backup PROJECT_NAME=api # one codebase
make restore FILE=context-20260819-115420.dump
Whole-database backups are a pg_dump archive; single-project backups are a
plain-SQL replay, since pg_dump can't select by row. Both rotate (KEEP,
7 by default) and both print what they're about to replace before doing it.
Take a whole-database backup before every upgrade: make up applies new
migrations, and a migration is undone only by restoring that backup.
Full walkthrough: deployment.
The schema is owned by Alembic: the revisions live in packages/core and
are baked into the api image, and make up applies whatever is pending
before anything else touches the database. Core tables:
projects - one row per project, carrying the tree it reads and the type a
search narrows on - org_members, which says which organization holds
which project, plus nodes, edges and chunks. No table holds a
foreign key: the code deletes and re-keys the rows a project owns itself.
Plans, memories, suggestions and issues are nodes rows under the built-in
projects _plans, _memory, _suggestions and _issues, which no tree is indexed
into, so they survive a project drop and make clean. Full internals,
including how
make db <target> drives Alembic and what a restore needs:
nuances.
All code, comments and commit messages are pure ASCII English. A pygrep
pre-commit hook enforces this, so a stray non-ASCII character blocks the commit.
make lint # pre-commit over the whole tree
cz c # commit through commitizen with the wyld-cz adapter
make init installs both the pre-commit and commit-msg hook types, so
commit messages are validated automatically. Adding a new file extension to the
repo means adding its hook to .pre-commit-config.yaml.
cz bump --changelog # bump the version, write CHANGELOG.md, create the tag
.cz.yaml records the last released version, so cz bump derives the next
one from the commits since that tag. Two settings exist because of the ASCII
rule: bump_message overrides commitizen's default release message, which
contains a Unicode arrow, and allowed_prefixes lets the bump: message
through cz check.
cz bump rewrites .cz.yaml through PyYAML, which sorts the keys and strips
comments, so that file cannot carry explanatory comments of its own. It and the
generated CHANGELOG.md are excluded from the prettier and markdownlint hooks,
which would otherwise reformat them and make every release commit fail.
The dashboard's pages are Jinja2 templates. djlint checks them, and the
prettier hook leaves them alone: it would read them as plain HTML and rewrite
the tags. The dashboard's one script, static/app.js, is under prettier.
packages/ the Python services, one package and one image each:
core, indexer, api, embed, summarize, viewer, mcp, web
dev/web/ the dashboard mockups and their Penpot stack
skills/ the agent skills, handed out by the MCP server
templates/ the CLAUDE.local.md an onboarded codebase gets
scripts/ helper scripts: onboarding, backup, restore, pre-commit
docker-compose.yaml
Makefile root entry point, delegates to the service Makefiles
max_hops| Every incoming edge but containment, and every mention of the name |
find_implementations | symbol, optional project, file_path, max_hops | What extends or implements a class or interface |
find_tests | symbol, optional project, file_path, max_hops | Test files that reach a symbol within two hops |
impact_analysis | symbol or a file path, optional project, file_path, depth | What a change could reach: direct, indirect, tests, public API, configuration |
get_project_links | optional project, direction, depth, relation, node_id | Which projects use which and by what, what one provides, and the names left unlinked |
trace | node_id, optional project, max_steps | Follows a node across projects: what provides it, who takes it, what applies them there, what they deploy to |
find_linked_name | name, optional kind, project, project_type | Who defines and who uses a host, image or package, by any spelling of its name |
save_project_link | target_project, relation, optional project, source_id, target_id, note | Declares a relation between two projects that no manifest states |
drop_project_link | target_project, relation, optional project, source_id, target_id | Removes a relation declared with save_project_link |
save_project_export | kind, name, optional project, node_id | Says a project provides a name no file of it states, such as an image CI builds |
drop_project_export | kind, name, optional project | Removes an export declared by hand; one a manifest declares stays |
save_node_summary | node_id, summary | Saves or updates a summary for a specific node |
get_node_summary | node_id | Retrieves summary, file path, and type for a node |
save_plan | plan_id, title, content, optional project, status, type, nodes | Creates or updates a persistent plan; project: "*" makes it global |
get_plans | optional project, status, type, node_id, node_project | Plans of one project plus the global ones; project: "*" lists all |
drop_plan | plan_id | Deletes one plan outright, for one written by mistake, and its prompts with it |
save_prompt | prompt_id, plan_id, title, content, optional status | Creates or updates the execution prompt of a plan, under that plan's scope |
get_prompts | optional project, status, plan_id | Prompts of one project plus the global ones, or of one plan; status: "*" for every status |
drop_prompt | prompt_id | Deletes one prompt outright; its plan stays |
save_roadmap | roadmap_id, title, optional project, content, status | Creates or updates a roadmap; its items are written one by one |
get_roadmaps | optional project, status, roadmap_id | Roadmaps with their items in order, each with its plan's status and that plan's prompts |
drop_roadmap | roadmap_id | Deletes a roadmap and its items; the plans they named stay |
save_roadmap_item | roadmap_id, item_id, optional title, content, section, status, plan_id, position | Creates an item, or changes only what is given on an existing one; position moves it |
drop_roadmap_item | roadmap_id, item_id | Deletes one item of a roadmap |
drop_project | name, optional confirm | Reports what dropping a project costs, and drops it on confirm: true |
save_memory | memory_id, title, text, optional about, summary, tags, nodes | Writes a memory into _memory; about: "*" makes it global |
get_memory | optional memory_id, about, tags, query, node_id, node_project, limit | Memories of one scope plus the global ones, in full |
drop_memory | memory_id, optional about | Deletes one memory that turned out to be wrong |
save_suggestion | suggestion_id, title, detail, optional about, summary, kind, lever, status, bump, query, nodes | Records a gap in _suggestions; saving under an existing slug counts a hit rather than duplicating |
get_suggestions | optional suggestion_id, about, status, kind, query, node_id, node_project, group_by, limit | Open gaps of one scope plus the global ones, most often hit first, or rolled up by group_by |
drop_suggestion | suggestion_id, optional about | Deletes one suggestion written by mistake; a closed gap is retired instead |
save_issue | issue_id, optional about, title, detail, kind, summary, status, commit, plan_id, resolution, nodes | Opens an issue in _issues, or changes only what is given; closing names the commit or the plan |
get_issues | optional issue_id, about, status, kind, plan_id, query, node_id, node_project, limit | Open issues of one scope plus the global ones, newest first, each with its plan and prompts |
drop_issue | issue_id, optional about | Deletes one issue written by mistake; one that will not be done is declined instead |
list_indexed_files | optional project | The files tracked in indexed_files, which is the parser half of the tree |
get_file_hash | file_path, optional project | The stored content hash of one file, or nothing when never indexed |
set_file_hash | file_path, hash, optional project | Writes a file's hash, marking it indexed |
clear_file_hash | file_path, optional project | Forgets a file's hash, so the next run re-parses it |
list_skills | optional project | The skills a session should have installed, each with its sha256 version |
get_skill | name, optional project | One skill's text, version stamped, and the path to write it to |