Skip to content

Repository files navigation

CodeAtlas

evidence-first Python 3.12 mypy strict Rust via SCIP PostgreSQL 17 Windows-first

Evidence-driven code review and project understanding. Point it at a repository or a pull request; get a project you can walk — a measured dependency map, a page per module, editor-grade source with the measured symbols marked, call-flow diagrams that cannot invent an arrow, adversarially-validated review findings, and a question box whose every answer is citation-checked. Anything that cannot be traced to a pinned revision, an extractor receipt, or a validated finding says so instead of pretending.

Project overview: measured counts, a cited narrative, a real call flow, where to start

Everything in that screenshot is either measured (the counts, the flow arrows, the fan-in rankings — each backed by an extractor receipt) or cited (the narrative's 36 statements each carry a citation that was validated against this revision; the statements that failed validation were deleted and the deletion is disclosed).


The tour

Browse every file

The files tab is the git tree at the analyzed revision — not just the modules the graph measured. Bright files carry measured symbol counts and open their module page; docs, workflows and scripts are dim but open as pinned source. Generated files are labeled, which is also why they carry no findings.

The file explorer

Read source like an editor — and see what was measured

Source renders with VS Code's own grammars (Shiki, Tokyo Night). Two colour channels, deliberately distinct: text colour is the grammar of the file's extension — never content-guessed — while the coloured left border and the name ← N badge mean a symbol the graph measured, spanning its whole definition. An unmarked identifier has no graph node, and the panel says so rather than implying full coverage.

Syntax-coloured source with measured definition spans and fan-in badges

One page per module

Click any module named anywhere in the app — a citation, a matrix row, a cycle member, a finding's location — and land on its page: what it defines (types first, ranked by fan-in, large groups collapsed, pub items marked), who uses each definition, what it imports, the flows passing through it, its place in the suggested reading order, and, on a pull-request run, exactly what the change did here. The header's interface m/n badge is the measured module depth — how much of the module is surface versus implementation, read from the signatures rust-analyzer rendered (pub(crate) counts as internal) — and changed N× is the file's churn, counted from git history in one receipted pass (the overview ranks the most-changed modules, and the map draws churn as border thickness). Every run also exports its understanding as an llms.txt-shaped artifact (/api/runs/{id}/artifact/llms-txt) so other agents can consume what was measured without knowing this tool.

ripgrep's walk.rs: 176 definitions ranked and collapsed, cycle membership, usage

The map: packages → levels → matrix → paths

On a pull request the map says which of it you touched: a count chip, a halo on changed nodes, markers on the matrix rows, and a focus facet that narrows to one side of the diff.

The full graph is never rendered — node-link views stop being readable around 25 nodes, so a server-side readability gate refuses hairballs and says why. What you get instead: packages first, one package's modules levelized (only cycle edges drawn — the ones worth seeing), and the dependency matrix for the whole project, where a cell above the diagonal is a cycle.

One package's modules by level, cycles visible

The 104×104 dependency matrix

Path-finding answers "how does A reach B" — the one node-link task that works at any size. Endpoints are offered only if they can participate, every hop is labelled with its measured edge kind, and "nothing connects A to B" is an answer, not an empty canvas.

search() reaches byte() in two labelled hops

Jump anywhere

Ctrl-K from any tab searches everything the graph measured — files land on their module page, symbols land with their definition expanded. Arrows and enter work; so does "nothing in this run's graph matches".

The command palette

Ask questions — with receipts

Ask anything about the module on screen. The agent answers from that module's source and graph slice, and every sentence is citation-checked against the revision: claims whose citations do not resolve are deleted and the deletions disclosed. Answers are cached content-addressed — the same question at the same revision is free forever — and every previously-asked question is listed for one-click reopening. Each definition also has an explain? button that asks for you.

A cached answer: eight claims, every one pinned to a line

Documentation the change left behind

From the same diff: which entities this change added, removed, renamed or moved, cross-referenced against every tracked document. A reference page still naming a removed function, docs that missed a rename, a path that moved, a new public function nobody documented — each named with its file and line. Advisory only: nothing here edits a document or blocks a review, because documentation is somebody's writing and the pipeline's job is to say what it noticed. Matching is word-bounded and exact, so compute_output is never a mention of put; the Diátaxis classification names the signal it decided on, so you can disagree with it; and every generated diagram now carries the source lines it was drawn from — plus a readability verdict, because rendering and being legible are different claims and only the first one used to be checked. An over-budget diagram is drawn anyway with its numbers stated: shortening labels until they fit is how bitflags 1.3.2 and bitflags 2.11.0 become the same box.

Review a change

A pull-request run analyzes both revisions and shows the change three ways, none of them a text diff: the structural delta (symbols and relationships added, removed, moved — "storage now imports api" appears in the diff of neither file), the public-API delta measured by cargo public-api with breaking-change severity from cargo-semver-checks, and the bounded impact set with its precision caveat attached to the artifact itself.

The change: structure, public API, and what else could be affected

Findings that survived a hostile check

Reviewers propose; a validator that never saw the proposal re-examines each finding in a fresh context, with the real build/test toolchain at hand. The review tab shows the whole funnel — including what did not survive, because a table of survivors looks identical whether the check rejected eleven candidates or none. Every verdict carries a written rationale and a confidence, both visible in the funnel. A coverage panel shows what each reviewer actually read — measured by the engine from the tool stream, never the model's own claim, with "unknown" honestly distinct from read and unread. A reviewer that fails with invalid output or a timeout gets exactly one retry (the validation errors quoted back), and both attempts stay visible in the agent ledger.

Rejections are also remembered across runs (ADR-0016): a finding that recurs at byte-identical code is suppressed instead of re-validated, shown with the original run and reason — so re-running on the same repository gets cheaper and quieter, and codeatlas compare still calls the two runs reproducible. Any edit to the file re-opens its questions.

The validation funnel: 12 proposed, what each verdict was, and why

A threat model that aims the review

Before the reviewers run, a threats tab lays out what an attacker could do here: trust boundaries with the data that crosses them, assets with the properties that actually matter, and — given equal space — what the attacker provably cannot do, because that is what keeps severity honest. Abuse paths are numbered TM-nnn; each names its existing controls and says whether their evidence checked out. A repository with no meaningful attack surface says so, rather than inventing a boundary to fill the page.

The model is built once per repository and reused — it describes what a system is, which changes far more slowly than its code — so a second review on the same repo pays nothing to know where to look. Its focus paths feed forward into the reviewers, which weight them and calibrate severity to what "high" means for this repository. A model reused from an earlier revision says which one; --refresh-threat-model rebuilds it.

A validated security finding then carries its own attack-path receipt: how attacker-influenced data reaches the flaw (source → sink → outcome), who can drive it from where, impact and likelihood each with a reason — and what the analysis could not establish, because a receipt that hides its gaps is a confidence trick.

The threats tab: boundaries, assets, and abuse paths with their controls

An attack path under a validated security finding

Architecture and decisions

A C4 container view derived from the measured graph (every box names the node it came from; nothing is drawn without evidence), exportable as Structurizr DSL — and an audit of the repository's own ADRs against the code: conformed, drifting (stated, not softened), or unverifiable, which is never allowed to look like conformance. ADRs can carry machine-addressable claims (IMP-001 (layering): api -> cache -> storage) — the audit then checks the decision's own declared order with its text as the verbatim assertion, and verdicts bind to stable claim ids; an ADR without claims gets the inferred audit, labeled as the guess it is. The page also shows the decision mesh both ways: which code violates a decision (graph evidence) and which code cites one (a receipted scan), with dangling references — in either direction — called out as broken history.

C4 containers derived from the graph

ADRs audited against the code they govern

An honest "no"

Most projects speak no protocol — and forcing a sequence diagram onto a batch tool would be the most convincing wrong artifact this tool could produce. When the model says null, the page says why, with the reasoning cited to source.

fd speaks no protocol, and the page explains exactly why

The skills are governed, not just pinned

Every inference in every run is produced by one of twelve registered skills, and each one carries a governance card a reviewer can act on without opening the skill source: owner, permission envelope (enforced by the engine, not by convention), credential needs with an honest "not specified" vocabulary, risks with mitigations, output contract, and eval coverage. The card is bound to the trusted registry by build-breaking checks — a skill version bump without card re-review fails — and behavior-critical skills carry activation evals including negative cases: on a deliberately sound crate, the recorded reviewers report nothing, the protocol modeler refuses, and the threat modeler returns an honest empty. Scope compliance is graded from measured engine telemetry (reads watched from the tool stream, denials from the permission hook) — the audit over the recorded cassettes caught two skills probing off-allowlist commands live, and the hook denying both. Same catalog on the CLI (codeatlas skills), in docs/skill-cards.md, and in the dashboard.

The skills page: cards with owners, envelopes, risks and eval coverage

Every run accounts for itself

The run detail page opens the manifest — toolchain versions, which model answered at what token cost, the run's own degradation notes ("verification tools unavailable: …"), every output by role, each row openable. Below it: the agent invocation ledger and a receipt for every deterministic tool invocation. This is the page you open when you want to know whether to believe the other pages.

The manifest, the agent ledger, and the receipts

Something to attach to the pull request

Everything above needs a server, a database and a browser build. The person you are asking to review a change has none of those. codeatlas walkthrough <run-id> writes one self-contained HTML file per module topic — an inlined diagram, and every module expanding to its real source read from the revision that was measured. No script tag, no CDN, no network: the file opens on a laptop with nothing installed, which is the whole point, and a browser test fails the build if the page requests anything at all.

It says what it is. The revision is on the page, the diagram carries its own readability verdict rather than implying the picture is fine, and when the renderer is missing it ships the diagram source and says so. Syntax colouring and cross-links stay in the dashboard — this file trades them for opening anywhere.

A walkthrough opened as a local file: inlined diagram, modules expanding to real source

Nothing leaves the machine without a human

The pipeline runs in shadow mode: it prepares the exact review payload and posts nothing. Publishing requires, simultaneously: an explicit request-approval, a human approve recorded with name and time, CODEATLAS_PUBLISH_ENABLED=1 in the environment (default off), an unset CODEATLAS_KILL_SWITCH, a clean secret scan, and no prior publication — every one re-checked at post time, because reaching a code path is not evidence of permission. The review tab reads the publication ledger rather than asserting an outcome.

A published finding can carry a one-click committable fix — but the commit button is earned, not assumed. Reviewers may propose a fix only when replacing exactly the cited lines resolves the issue entirely (the completeness rule), and the deterministic payload builder renders a GitHub suggestion block only when the comment's anchor provably covers that full span; anything less ships as visible, non-committable text. The approval preview shows the fence the human is approving. Two more levers are explicit opt-ins: --attack-paths-for-rejected buys receipts for dismissed security candidates (why no path exists, and exactly where it breaks), and --model skill=model routes any skill to a cheaper tier — with scripts/tier_experiment.py as the recall-fixture measurement that decision should wait on, and the invocation ledger recording who actually answered.


From scratch

Prerequisites

What Why Notes
Python 3.12 + uv the backend uv sync installs everything
Node 20+ the dashboard npm install in frontend/
PostgreSQL 17 the evidence store infra/ has init scripts; credentials live in the OS keyring
Rust toolchain + rust-analyzer extraction rustup, plus rust-analyzer on PATH
cargo-public-api, cargo-semver-checks the API delta PR runs degrade gracefully without them
Structurizr CLI, mmdc (optional) diagram validation absence is noted in the manifest, never silent
claude CLI, logged in (optional) narration, review, ask everything deterministic works without it

uv run poe verify-env prints the full tool matrix — what is installed versus required.

Set up

uv sync                          # Python deps into .venv
uv run poe verify-env            # check the tool matrix
# initialize PostgreSQL (see docs/runbooks/setup.md), then:
uv run python -c "from codeatlas.db.migrate import upgrade_head; from codeatlas.db.session import migrator_engine; e=migrator_engine(); upgrade_head(e); e.dispose()"
npm --prefix frontend install
uv run poe check                 # ruff + mypy --strict + pytest: everything green?

Analyze your first project

# Local path or any URL git can clone. Deterministic half only — no agent, no cost.
uv run codeatlas run --repo https://github.com/sharkdp/fd --repository-id sharkdp/fd --workdir var

# Add the narrated explanation (agent quota; --review adds the reviewers too):
uv run codeatlas run --repo <path-or-url> --repository-id owner/name --narrate [--review] [--replay] [--max-tokens N]

# Opt-ins that cost extra quota, on both `run` and `review-pr`:
#   --refresh-threat-model              rebuild this repository's cached threat model
#   --attack-paths-for-rejected         receipt dismissed security candidates too
#   --model skill_id=model_id           route one skill to another model (repeatable)

The skill catalog is readable without a database or a run:

uv run codeatlas skills                 # every skill: version, trust, evals, owner
uv run codeatlas skills reviewer-security   # one full governance card
uv run codeatlas skills --check         # governance gate: nonzero if anything drifted

Open the dashboard

uv run codeatlas serve --workdir var --port 8137 --ask     # --ask enables the question box
$env:CODEATLAS_API = "http://127.0.0.1:8137"
npm --prefix frontend run preview                          # then open http://localhost:4173

The server is read-only until told otherwise. --allow opts in to mutating capabilities, a closed vocabulary where a typo is a startup error (ADR-0023):

uv run codeatlas serve --workdir var --port 8137 --allow ask,analyze,resume
# + agent-runs: launched runs may review/narrate (spends real quota)
# + review-pr:  PR reviews of allowlisted slugs — requires --github-repo <owner/name>
#               per slug, and refuses to start on a non-loopback --host

With analyze on, the dashboard's + analyze button re-runs any repository this workdir already knows — never a free-text clone URL: analysis executes the target's build scripts, so adding a new repository stays a CLI act on the machine that will run the code. Runs execute in a subprocess (restarting serve does not kill a twenty-minute analysis), progress streams into the run detail page, and the cancel button works even for runs started from a terminal. One run at a time, globally: the LangGraph checkpointer is a single SQLite file, and the limit is physics until that moves to Postgres.

Approvals never grew buttons. Deciding records a human name, the API has no authentication, and a button would record decidedBy as whatever an anonymous client claimed — so the review tab prints copyable commands for approve, reject and publish instead, each with its preconditions.

Export a walkthrough to hand to somebody

uv run codeatlas walkthrough <run-id>                 # into the run's artifacts directory
uv run codeatlas walkthrough <run-id> --out .\share   # or wherever you want them

One self-contained HTML per module topic. On demand rather than on every run: most runs are never walked through, and writing files nobody asked for is not a side effect an analysis should have.

Review a pull request (shadow mode — posts nothing)

uv run codeatlas review-pr owner/repo 42        # analyzes base AND head, prepares the payload
uv run codeatlas status <run-id>
uv run codeatlas compare <run-id> <run-id>      # exits nonzero if two runs are not reproducible
# the same verdict lives at #/compare in the dashboard, differences apart from notes

Publish, if you choose to

uv run codeatlas request-approval <run-id>
uv run codeatlas show-approval <approval-id>    # read the exact payload; prints the --payload value
$env:CODEATLAS_PUBLISH_ENABLED = "1"            # default off — publication is an explicit act
uv run codeatlas approve <approval-id> --by "<you>" --payload <12-char-sha> [--note "..."] --publish
# or the two-step flow:
uv run codeatlas approve <approval-id> --by "<you>" --payload <12-char-sha>
uv run codeatlas publish <approval-id>

--payload is proof of reading: the value only exists in show-approval output or the dashboard, so you cannot approve bytes you have not looked at. What posts is a real PR review — inline comments anchored on lines the diff added (findings outside the diff fold into the body with permalinks), every byte carrying the AI-provenance marker the gate enforces, findings already posted by an earlier run deduplicated by that same marker. The posting path itself is live-tested (-m github_live, see docs/runbooks/github-access.md).

CODEATLAS_KILL_SWITCH=1 stops every agent invocation and every mutation — publication, API-launched runs, resumes — everywhere, immediately. The one exception is cancel: a stop button the stop switch disables would be absurd (ADR-0023). Database overrides: CODEATLAS_DB_URL / CODEATLAS_DB_HOST / CODEATLAS_DB_PORT (and CODEATLAS_TEST_DB_URL for the test database).


The guide — every feature, where it lives, how to use it

flowchart LR
    A["🔬 <b>analyze</b><br/>codeatlas run · + analyze"] --> W["📡 <b>watch</b><br/>live stage bar"]
    W --> X["🗺️ <b>explore</b><br/>eleven tabs · Ctrl-K"]
    X --> ASK["💬 <b>ask</b><br/>cited answers"]
    X --> WT["📦 <b>walkthrough</b><br/>one file to hand over"]
    X --> PR{"pull-request<br/>run?"}
    PR -- yes --> PAY["🧾 <b>payload</b><br/>shadow mode · nothing posted"]
    PAY --> APR["🔏 <b>approve</b><br/>CLI · a named human"]
    APR --> PUB["🚀 <b>publish</b><br/>the gate re-checks everything"]
Loading

Everything below exists in two places: a CLI command and (except approvals) a dashboard surface.

Note

Exit codes are consistent everywhere: 0 success · 1 the operation ran and refused or failed · 2 your arguments named something that does not exist.

🗺️ The map

Feature CLI Dashboard Needs
🔬 Analyze a repository codeatlas run + analyze (sidebar) → repository mode --allow analyze (+ agent-runs for review/narrate)
🔀 Review a pull request codeatlas review-pr + analyze → pull request mode --allow review-pr + --github-repo, PAT in keyring
📡 Watch progress / status codeatlas status run header badge + run detail tab (live, 1.5 s poll)
⏹️ Cancel a run (no CLI verb — see below) cancel in the run header --allow analyze
▶️ Resume a failed run codeatlas resume resume (no agents) in the run header --allow resume
⚖️ Compare two runs codeatlas compare compare (sidebar header) → #/compare
📦 Export walkthroughs codeatlas walkthrough walkthrough export panel on the run detail tab
💬 Ask about code ask panel on any module page --ask (alias --allow ask), claude CLI
🛡️ Skill governance codeatlas skills skills (sidebar header) → #/skills
🧾 Request approval codeatlas request-approval (CLI only — the UI prints the command) a PR run with a payload
🔏 Approve / reject codeatlas approve / reject (CLI only — copy buttons on the review tab) --payload proof of reading
🚀 Publish codeatlas publish (CLI only — copy button on the review tab) CODEATLAS_PUBLISH_ENABLED=1, PAT

🔬 Analyzing

CLI. codeatlas run --repo <path-or-url> --repository-id <owner/name> mirrors the source, pins a revision, and runs the deterministic half: extraction, graph, overview, architecture, diagrams, exports.

Flag Does Costs
--ref <ref> analyze a branch, tag or sha instead of HEAD
--review reviewers, validator, threat model, attack paths agent quota
--narrate / --no-narrate the cited project explanation — tri-state: unset follows --review, so --narrate alone describes without reviewing agent quota
--replay answer every agent call from recorded cassettes; refuses --model (cassettes are model-blind) free
--max-tokens N the run-wide agent budget (default 2,000,000)
--refresh-threat-model rebuild the repository's cached threat model agent quota
--attack-paths-for-rejected receipt dismissed security candidates too (why no path exists) one call per dismissal
--model skill=model route one skill to another model (repeatable); the ledger records who answered varies

Dashboard. + analyze at the top of the run list opens #/new. Pick a repository this workdir already knows, set the ref, toggle review, pick narrate from the tri-state. Submitting navigates straight to the new run; the overview shows the live stage bar until there is an overview to show. The run executes in a subprocess — restarting serve does not kill it.

Warning

The form has no URL field, deliberately. Analyzing a repository executes its build scripts (rust-analyzer and cargo run in the checkout, build.rs and all), so introducing a new repository is a CLI act on the machine that will run the code. The dashboard only re-analyzes what you already chose to trust (ADR-0023).

⏹️ Cancelling

The red cancel in the run header, while a run is created or running. It records a durable cancel_requested event first and terminates the executor's whole tool tree second — so it also stops runs started from a terminal (they check the event at every stage boundary), and it still works if the server restarted and lost the process handle. There is deliberately no CLI cancel verb: in a terminal, Ctrl+C is the cancel, and the reaper records what happened.

▶️ Resuming

codeatlas resume <run-id>, or the header button on a failed or cancelled run. Resumes from the last LangGraph checkpoint — the interrupted stage re-runs from scratch, finished stages do not. Both paths rebuild without an agent engine, which is why the button says no agents: a resumed run re-runs its deterministic stages only.

📡 Watching a run

codeatlas status <run-id> prints the status word. The dashboard does better: the run detail tab shows a 15-row pipeline bar — every stage pending, running, succeeded or failed with its duration and, on failure, the actual error — derived from the same event rows the pipeline commits as it goes, polled at 1.5 s while the run is active. A run whose server stopped responding says so instead of spinning.

stateDiagram-v2
    [*] --> created: codeatlas run · POST /api/runs
    created --> running: source_lock pins a revision
    running --> succeeded
    running --> succeeded_with_gaps: a reviewer failed — the status says so
    running --> failed
    running --> cancelled: a human asked, the event is honored
    running --> paused_for_approval: a payload awaits a human
    failed --> running: resume (checkpoint, no agents)
    cancelled --> running: resume (checkpoint, no agents)
    paused_for_approval --> succeeded: published
Loading

🔀 Reviewing a pull request

CLI. codeatlas review-pr owner/repo 42 fetches the PR (read-only, PAT from the OS keyring), refuses drafts and closed PRs unless --force, analyzes both revisions, runs the full review, and stops at a payload: shadow mode, nothing posted. All the run cost flags apply; --narrate defaults on.

Dashboard. + analyzepull request mode: slug + PR number, cost stated before you click. The server only accepts slugs named in its --github-repo allowlist — the refusal names what is allowed — and there is no force option: forcing a draft review stays a deliberate CLI act. The base and head shas are resolved when you submit, so the shas you saw are the shas analyzed.

🧭 Reading the results — the run tabs

Open any run from the sidebar; tabs left to right:

Tab What it answers
🧭 overview What is this project? Counts, packages, levels, cycles, most-changed modules, the cited narrative, call flows, where to start reading
🗂️ files The full git tree at the revision; measured files open module pages, everything else opens as pinned source
🗺️ map Packages → one package's levelized modules → the dependency matrix → path-finding ("how does A reach B"). On a PR run: changed-node halos, matrix markers, a diff-side focus
🏛️ architecture C4 context/containers derived from the graph, plus the Structurizr DSL
📜 decisions The repo's ADRs audited against the code: conformed / drifting / unverifiable, claims checked verbatim, the citation mesh both ways
🛡️ threats Trust boundaries, assets, attacker capabilities and non-capabilities, numbered abuse paths with their controls re-measured
📻 protocol What the project speaks, usually an evidenced "nothing"
🔀 change PR runs: the structural delta, the public-API delta with semver severity, the bounded impact set, docs drift
🐛 findings Validated findings with rationale, confidence, attack paths, source drill-down
⚖️ review The candidate → validated funnel including what died, reviewer coverage (what was actually read), the payload preview, and the approval/publication panel
🧾 run detail The manifest (openable per output), the live pipeline bar, walkthrough downloads, the agent ledger with per-call cost, every extractor receipt

Not a tab but everywhere: click any module name to land on its page (definitions ranked by fan-in, usage, imports, flows, its slice of the change) — and Ctrl+K searches everything the graph measured from any tab.

💬 Asking questions

On any module page, the ask panel takes one question about the module on screen; every sentence of the answer is citation-checked against the revision and the dropped claims are disclosed. Answers are cached by (revision, module, question) — repeats are free, and prior questions reopen with one click. Each definition also carries an explain? button that asks for you. Needs the server started with --ask and a logged-in claude CLI; the 403 you get otherwise tells you exactly that.

⚖️ Comparing runs

codeatlas compare <left> <right> or the compare link in the sidebar header (#/compare — linkable, and the run detail page prefills it via compare with…). Two runs at the same revision must produce the same graph hash and finding ledger; the page preselects the two most recent runs sharing a revision. Differences decide the REPRODUCIBLE / NOT REPRODUCIBLE verdict; token and cost drift render in a separate notes panel because they deliberately do not.

📦 Walkthroughs

codeatlas walkthrough <run-id> [--out DIR] writes one self-contained HTML file per package — or download the same bytes (a test pins the equality) from the walkthrough export panel on the run detail tab. Attach it to a PR; it opens with no server, no network, no build step. If the server has no diagram renderer, the panel says so up front rather than letting you discover it after saving.

🔏 The approval flow — deliberately CLI-only

uv run codeatlas request-approval <run-id>      # opens the approval, pauses the run
uv run codeatlas show-approval <approval-id>    # the exact bytes + the --payload value
uv run codeatlas approve <approval-id> --by "<you>" --payload <12-char-sha> [--note ""]
uv run codeatlas reject  <approval-id> --by "<you>" [--note ""]
$env:CODEATLAS_PUBLISH_ENABLED = "1"
uv run codeatlas publish <approval-id>          # or: approve … --publish in one step

The review tab shows the whole state — undecided / approved / rejected / published, with the payload preview — and offers copy buttons for all three commands, each carrying its preconditions.

Important

The dashboard will never offer buttons that decide. The API has no authentication, so a button would record decidedBy as whatever an anonymous client claimed — and the audit trail's entire value is the name in it. --payload is proof of reading: the 12-character value exists only where the payload is displayed, so you cannot approve bytes you have not looked at. A decided approval cannot be flipped.

Publishing re-checks everything at post time, because reaching a code path is not evidence of permission:

flowchart TD
    P["codeatlas publish &lt;id&gt;"] --> K{"kill switch unset?"}
    K -- no --> R["⛔ refused — the attempt itself is recorded"]
    K -- yes --> O{"not already published?"}
    O -- no --> I["↩️ idempotent: the existing record returns, nothing reposts"]
    O -- yes --> D{"decision is approved?"}
    D -- no --> R
    D -- yes --> E{"CODEATLAS_PUBLISH_ENABLED=1?"}
    E -- no --> R
    E -- yes --> S{"secret scan clean?"}
    S -- no --> R
    S -- yes --> V{"AI-provenance marker on every byte?"}
    V -- no --> R
    V -- yes --> GH["🚀 exactly one PR review posts to GitHub"]
Loading

🛡️ Skills

codeatlas skills lists the twelve governed skills (no database needed); codeatlas skills <id> prints one full card; codeatlas skills --check is the build-breaking governance gate. The same catalog renders at #/skills — owner, permission envelope, credentials, risks, eval coverage — with any governance problems listed first, because a partial catalog must say it is partial.

⚙️ The server, its capabilities, and the switch

codeatlas serve is read-only by default. Everything mutating is a launch-time opt-in with a closed vocabulary — a typo is a startup error, never a silently absent capability:

serve --allow … Unlocks Spends
(nothing) every read: all tabs, compare, walkthrough downloads nothing
ask (alias --ask) 💬 the question box agent quota per question
analyze 🔬 + analyze + ⏹️ cancel CPU only
resume ▶️ the resume button CPU only
agent-runs review / narrate toggles on launched runs agent quota
review-pr 🔀 pull-request mode — also needs --github-repo <owner/name> per slug, and refuses to start on a non-loopback host PAT (read-only) + agent quota

The API self-documents at /api/docs, and every run's understanding is exportable as llms.txt (/api/runs/{id}/artifact/llms-txt) for other tools. One hidden CLI verb exists — execute-run, what the dashboard's launcher spawns; humans use run.

Important

CODEATLAS_KILL_SWITCH=1 stops every agent invocation and every mutation — publication, API-launched runs, resumes — immediately, everywhere. The one exception is cancel: a stop button the stop switch disables would be absurd (ADR-0023).


Pipeline

flowchart LR
    subgraph acquire["📥 acquire"]
        source_lock --> extract --> build_graph --> base_revision
    end
    subgraph change["🔀 change (PR runs; no-ops otherwise)"]
        api_change --> graph_diff --> change_impact --> docs_drift
    end
    subgraph comprehend["🧭 comprehend"]
        project_overview --> architecture --> narrate
    end
    subgraph deliver["📤 deliver"]
        export_llms --> export_cytoscape --> review --> finalize
    end
    base_revision --> api_change
    docs_drift --> project_overview
    narrate --> export_llms
Loading

(Fifteen nodes — over this project's own ten-node diagram budget, and drawn anyway with its numbers stated, which is exactly what the budget rule says to do.)

(api_change runs before graph_diff on purpose: the diff's interface labels need to know which symbols the public-API delta named, and "changed but not exported" is only expressible once that delta exists. docs_drift is last of the change stages: it consumes the diff and the API delta and nothing consumes it, which is what advisory means structurally. project_overview, architecture and narrate are the deterministic half of the comprehension features — the overview, files, map, architecture, decisions, protocol and flows views all come from them. The threats tab comes from the review half, where the threat model is built before the reviewers so its focus paths can aim them. The four change stages return immediately on a whole-repository run: there is no diff, so they publish nothing rather than publishing something empty.)

source_lock pins the revisions under analysis and, in pull-request mode, resolves the base and derives the changed-path and added-line sets from the mirror. base_revision analyzes the revision the change is measured against; it is a no-op for a whole-repository run, and reuses an already-analyzed base when the extractor toolchain that produced it still matches (ADR-0013). Each graph is stored as a snapshot with an explicit role of base or head — "the run's graph" is not a well-formed question once a run holds two.

graph_diff compares the two graphs: which symbols and which relationships the change added, removed or moved. That is the signal a text diff cannot give — storage now imports api appears in the diff of neither file. Comparison runs on identities with the package version stripped out, because a symbol id embeds it and a release bump would otherwise read as the whole crate being rewritten; the version change is reported as its own fact.

api_change answers "what did this crate expose before, and what does it expose now" without a model: cargo public-api renders the public surface of each revision and the difference is arithmetic, then cargo-semver-checks classifies the severity. A package that could not be measured on both sides is listed in skipped with the reason, never reported as unchanged — "no API change" and "nothing was measured" must not look alike.

change_impact walks the dependency edges backwards from the symbols the change modified or removed. One hop by default and two at the most: static change-impact precision is around 38–50%, so an unbounded closure reaches nearly everything while being right about nearly none of it. Results are ranked (public API, crate-crossing, internal, test-only), the surplus past the report limit is counted rather than dropped, and the precision caveat is a field of the artifact so nothing can render the list without it.

The review stage then explains the change before reviewing it, because a reviewer needs to know what a change does before being told what might be wrong with it. The explanation is the one artifact a model writes, and what makes it usable is not the model's care but the validator behind it: each claim must cite something this run measured, and a claim whose citations do not resolve is removed and listed in droppedClaims. A softened false claim is still a false claim, and it keeps the authority of appearing in the report.

The stage also builds (or reuses) the repository threat model first, so its focus paths can aim the reviewers, and traces an attack path for each validated security finding after validation — both cached and fail-open, so a review is never blocked on them (ADR-0017).

docs_drift needs no model at all: it takes the entities the structural diff already named, reads every tracked document at head, and reports where the two disagree — advisory findings a human decides on, never an edit and never a gate (ADR-0021).

Design principle

Normalized, schema-validated evidence artifacts are the interfaces between pipeline stages: facts (extractor receipts) → agent inferences (candidate findings) → validated findings → presentation artifacts. No stage may launder inference into fact — the JSON Schemas in schemas/ are the source of truth for every contract.

Repository layout

Path Purpose
schemas/ Versioned JSON Schemas (Draft 2020-12) — canonical contracts
src/codeatlas/ Python backend (extractors, pipeline, validation, API, CLI)
frontend/ React read-only dashboard (Vite + TypeScript)
src/codeatlas/walkthrough/ The single-file HTML export — no server, no network, no build
.agents/skills/ Trusted, pinned skill registry + skill definitions
.agents/cards/ Per-skill governance cards (skill-card.v1), rendered to docs/skill-cards.md
docs/adr/ Architecture decision records (MADR)
docs/runbooks/ Setup, operations, rollback
docs/screenshots/ The images in this README
fixtures/ Deliberately-flawed and clean Rust fixture crates for evaluation
tests/ unit / integration / e2e / security / regression + cassettes + golden files
scripts/ verify_env.py tool-matrix probe, live-integration validators, dev helpers
infra/ Install/validate scripts, receipts, DB init

Test tiers

uv run poe check is the fast gate (ruff + mypy --strict + pytest); uv run poe check-all is the release gate — both halves including the Playwright e2e suites. Markers gate what needs external capability: subproc (git/cargo/rust-analyzer), pg (local PostgreSQL), agent_live (logged-in claude CLI). The live Playwright suite additionally needs a served run: CODEATLAS_RUN=<id> npm run e2e. One spec deliberately never touches the server: walkthrough.spec.ts opens the exported HTML over file:// and fails if the page requests anything at all, because "works with nothing running" is a claim only a browser can check.

External integrations are also validated directly against the live service before anything depends on them, since a fixture cannot prove that authentication, ref fetching or caching work against the real thing:

uv run python scripts/validate_github.py             # GitHub read paths and refusals
uv run python scripts/validate_two_revisions.py owner/repo N   # both revisions, live PR
uv run python scripts/check_real_project.py --repo <url>       # every analysis, real crate

The last one is the important one for anything graph-shaped: a levelization that collapses, an impact set that reaches everything, or a view that is a hairball only show up at real size. scripts/show_overview.py and scripts/show_views.py print the results for a human to look at — and the standing rule here is that a green suite is not evidence the presentation is right; serving a real project and looking is.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages