Get started with ad2v
This guide takes you from a fresh machine to a map of your own repository, a PR diff in CI, and an MCP host that can answer questions about your system. Every command here was run on a clean clone.
Requirements
- Python ≥ 3.11 (the CLI, extractors and MCP server are pure Python).
- git, to clone the repository and for
ad2v history. - Node ≥ 20, only to build the map viewer and the MCP App.
- Linux, macOS or Windows.
Install
Option A: full install (CLI + map viewer + MCP App)
git clone https://github.com/shanglai/ad2v.git cd ad2v python3 -m venv .venv source .venv/bin/activate pip install -e . # build the viewer and the MCP App (needs the venv active: fixtures uses Python) cd viewer npm ci npm run fixtures npm run build npm run build:app cd .. ad2v --version # ad2v 0.7.0.dev0
git clone https://github.com/shanglai/ad2v.git cd ad2v python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -e . cd viewer npm ci npm run fixtures npm run build npm run build:app cd .. ad2v --version
No git? Download the ZIP, unpack it, and run the same steps from that folder (ad2v history still needs git and a repository to read).
Prefer uv? uv sync --extra dev works too.
Option B: CLI only
pip install "git+https://github.com/shanglai/ad2v.git"
Good for CI and for the MCP tools. It does not include the built viewer, so ad2v view stops with “the viewer is not built”. Use option A on machines where you want the map.
Your first map (5 minutes)
The repository ships a small two-container system, payments-recon, with specs, tests and deliberate problems. From the ad2v folder:
ad2v extract --repo fixtures/payments-recon \ --spec fixtures/payments-recon/specs \ --test-results fixtures/payments-recon/test-results/junit.xml \ --out recon.ad2v ad2v status recon.ad2v --side spec ad2v view recon.ad2v
view opens your browser on 127.0.0.1. Things to try:
- Zoom: wheel to zoom, double-click to enter a box, Esc to go up, / to search.
- Status: enter
api; find the red dashed orphan and the risky loop inmatching.py. - Replay: pick
POST /v1/reconciliationsin Replay a workflow…, step through it and move the detail slider. - Legend: the Legend button explains every status and glyph.
For an 8-epoch history with AI badges, try the demo map: ad2v view viewer/tests/fixtures/demo.ad2v (created by npm run fixtures), or open the live demo in your browser.
Your own project
Keep your specs inside the repository (so history sees them change) and the .ad2v file outside it, or in a gitignored .ad2v/: it stores code snippets.
my-project/ ├── src/… ← Python code ├── tests/… ← optional: test_req_001_… names link tests to requirements ├── specs/ ← OpenAPI, Gherkin, Markdown ├── ad2v.yaml ← optional manifest └── .gitignore ← add: .ad2v/
1. Let ad2v look first
ad2v init reads files only. It runs nothing, calls no model, and writes only with --write. It reports spec folders, containers and their languages, id prefixes, SQL, infrastructure and test configuration, then proposes an ad2v.yaml.
ad2v init --repo ../my-project ad2v init --repo ../my-project --write ~/ad2v-maps/my-project.yaml
Fill in any empty value it leaves (for example a route prefix that lives in a setting).
2. Extract and view
ad2v extract --repo ../my-project --manifest ~/ad2v-maps/my-project.yaml \ --test-results ../my-project/junit.xml --out ~/ad2v-maps/my-project.ad2v ad2v view ~/ad2v-maps/my-project.ad2v
extract prints the spec roots it used and the languages it did not read. Later, ad2v init --repo … --check my-project.yaml lists what changed since (new folders, stale excludes, missing prefixes) and exits 1 if anything did.
Spec formats
Use what you have and mix freely. Without --spec, ad2v uses spec_root from ad2v.yaml, else the first of specs/, spec/, docs/specs/, .kiro/specs/, sdd/, docs/sdd/ that holds a spec, plus a root openapi.yaml.
| Format | Example |
|---|---|
| OpenAPI 3 | specs/openapi.yaml; pairs with FastAPI / Flask / Starlette routes. x-ad2v-refs: [REQ-001] ties an endpoint to a requirement. |
| Gherkin | specs/features/*.feature, scenarios tagged @REQ-001; # language: es works. |
| ad2v convention | ## Component: Reconciliation API {#CMP-001} then - [REQ-001] When …, the system shall … |
| spec-kit | specs/001-payments/spec.md; ids become 001-payments:FR-001. |
| Kiro | .kiro/specs/*/requirements.md |
| Team formats | Requirement tables, user stories (HU-001), EARS in English or Spanish (Cuando …, el sistema deberá …), or your own regexes. |
Full rules: spec Markdown convention.
Explicit links (recommended)
ad2v pairs by route and by name on its own. These make it precise:
- Code annotations:
# ad2v: REQ-001on the line above a function, or a docstring linead2v: REQ-001. In other languages:// ad2v: REQ-001. - Test names:
test_req_001_starts_runcounts as a linked test. - Test results:
pytest --junitxml=junit.xml, passed with--test-results, is what turns linksverified. - Manifest:
pairing.components,pairing.path_prefix_map,pairing.path_constantsand human-confirmedpairing.links(see ad2v.yaml).
History and diff
Extract git history into one file, one epoch per commit whose inputs changed. ad2v uses git archive: it never checks out or runs anything.
ad2v history --repo . --spec specs --commits HEAD~20..HEAD --into project.ad2v ad2v diff project.ad2v --from parent --to head --format md ad2v materialize project.ad2v --epochs last:5 # make epochs browsable in the viewer ad2v pin project.ad2v head --label v1.2 # keep this one through prune
The diff reports added, removed and renamed nodes (renames follow lineage), status transitions including stale, risk changes, spec changes and workflow changes. --into on extract appends a new head epoch and reuses the parse cache.
CI: a diff comment on every pull request
Copy examples/github-action/ad2v-diff.yml to .github/workflows/. It builds two epochs (merge base and PR head), renders the diff in at most ~60 lines, and creates or updates one PR comment. It needs only the job's own GITHUB_TOKEN. While ad2v is not on PyPI, change its install step to:
- name: Install ad2v run: pip install "git+https://github.com/shanglai/ad2v.git"
Pin a commit or tag (…/ad2v.git@<sha>) for reproducible CI.
MCP hosts: Claude, VS Code, others
ad2v mcp is a read-only MCP server over your .ad2v files. Tools include ad2v_locate, ad2v_search, ad2v_get_node, ad2v_links, ad2v_workflow, ad2v_diff, ad2v_architecture and ad2v_show. Hosts with MCP Apps render the map inline. Materialize at least one epoch first.
Claude Code
claude mcp add ad2v -- /path/to/ad2v/.venv/bin/python -m ad2v mcp --root /path/to/maps
Add --scope project to share it through .mcp.json.
Claude Desktop
In claude_desktop_config.json, with absolute paths to the venv's Python:
{
"mcpServers": {
"ad2v": {
"command": "/Users/you/projects/ad2v/.venv/bin/python",
"args": ["-m", "ad2v", "mcp", "--root", "/Users/you/projects/maps"]
}
}
}
VS Code
// .vscode/mcp.json
{
"servers": {
"ad2v": {
"type": "stdio",
"command": "${workspaceFolder}/.venv/bin/python",
"args": ["-m", "ad2v", "mcp", "--root", "${workspaceFolder}"]
}
}
}
ad2v mcp --http binds 127.0.0.1 only and has no authentication. Hosts that need a remote HTTPS server (such as ChatGPT connectors) would need an authenticating proxy you set up yourself; read the MCP guide checklist first.No MCP host? ad2v view project.ad2v --chat --manifest ad2v.yaml answers questions in the viewer with your own model.
Infrastructure (Terraform / OpenTofu)
ad2v never runs Terraform. Produce a plan yourself and keep it out of the repository:
terraform init && terraform plan -refresh=false -out tfplan && terraform show -json tfplan > plan.json ad2v extract --repo . --out app.ad2v --infra-plan prod=plan-prod.json --infra-plan dev=plan-dev.json ad2v c4 app.ad2v --env prod --format structurizr --out workspace.dsl
Or set infra_root: [infra] in ad2v.yaml to read .tf files statically (also used by history). You get the env-var bridge (which variables each deployment provides, which the code reads but nobody provides) and the Architecture tab, per environment. GCP and AWS core resource types; only allowlisted attributes and env var names are stored. Details: infra guide.
Optional LLM layer
Bring your own model for a semantic judge, link suggestions, summaries, narrations and prose-spec extraction. Providers: vertex, openai_compatible, or the offline fake. Results are informative: they never change an epoch id, and a model can only suggest.
ad2v llm plan project.ad2v --manifest ad2v.yaml # no calls; token and USD estimate ad2v llm run project.ad2v --manifest ad2v.yaml --tasks judge,suggest --max-cost-usd 0.50 --yes ad2v suggestions list project.ad2v ad2v suggestions accept project.ad2v <id> --manifest ad2v.yaml # writes pairing.links
run refuses to start without a budget and --yes, and stops before exceeding it. Results are cached by exact input, so reruns are free. Start with judge,suggest; summarize,narrate scale with repository size.
Plug-ins
Language extractors and framework packs are plug-ins behind a stable API (ad2v.api 1.0, entry points ad2v.extractors and ad2v.frameworks). Plug-ins run with your privileges, so only built-ins are active by default; enable others per repository:
ad2v extractors list ad2v extract --repo . --out x.ad2v --extractor routes-dsl ad2v extractor check my-lang --fixture tests/fixture # conformance kit
Guide and two out-of-tree examples: docs/plugins.md.
CLI reference
| Command | What it does |
|---|---|
init | Read a repository and propose an ad2v.yaml; --check compares with an existing one. |
extract | Write a fresh file (--out) or append a head epoch (--into). |
history | One epoch per commit in a revision range. |
status | Effective statuses with reasons; filter by --side, --status. |
diff | Compare epochs; table, json or md. |
view | Serve the map on 127.0.0.1 (read-only); --chat for BYOM chat. |
mcp | Read-only MCP server over --file or --root; --http for local HTTP. |
c4 | Export the C4 view (structurizr or json) per environment. |
inspect | Look at a node, a kind, or the top risks. |
log · pin · unpin · prune | Manage epochs; prune keeps the last N and pinned ones. |
materialize · layout | Prepare epochs and their deterministic layout for the viewer. |
dump | Canonical sorted JSONL; --normative-only is the determinism contract. |
validate | Check a file against the format: schema, ids, hashes, roll-ups. |
llm · suggestions · specs | Optional model layer: plan, run, eval; review suggestions; bootstrap specs from prose. |
extractors · extractor check | List plug-ins; run the conformance kit. |
Every command accepts --help. An <epoch> is an epoch id, head, parent, a pin label, or a commit SHA prefix (≥ 7 chars).
ad2v.yaml
Optional. Without it, each top-level directory with pyproject.toml, setup.py or a Dockerfile is a container.
system: {name: payments-recon}
containers:
- {name: api, paths: [api], kind: service, replicas: 2}
- {name: worker, paths: [worker], kind: worker}
exclude: [migrations]
spec_ids: {test_name_prefixes: [REQ, CMP]}
pairing:
components: {CMP-002: worker} # spec component -> container
path_prefix_map: {/api: ""} # route normalization
orphan_policy: auto # auto | strict | off
path_constants: {"settings.API_V1_STR": "/api/v1"}
links: [] # human-confirmed pairs
infra_root: [infra] # optional: read .tf statically
extractors:
enabled: [] # third-party plug-ins (opt-in)
llm: # optional, informative only
provider: vertex
project: my-gcp-project
model: gemini-3.8-flash
budget_usd: 1.00
Limits
- Code extraction is Python only today; other languages show as
not_evaluable. - Not yet parsed: Kiro
design.md/tasks.md, spec-kitplan.md/tasks.md. - Infra: Terraform only (plan JSON or
.tf), GCP and AWS core types. Azure, Pulumi, CloudFormation and Kubernetes manifests are detected but not read. verifiedneeds a JUnit file; without one the best status isimplemented.- Treat AI drift badges as leads, not verdicts.
Troubleshooting
Cannot find module './generated/demo-data'when building the viewer: runnpm run fixtures(with the venv active) beforenpm run build.- “the viewer is not built”: you installed the CLI only. Build the viewer from a clone (option A).
- MCP host says
ModuleNotFoundError: ad2v: pointcommandat the venv's Python, with an absolute path. - “not materialized”: run
ad2v materialize project.ad2v --epochs last:5. - Routes link as
needs_review: they are mounted under a setting; map it inpairing.path_constants. - Windows paths in JSON: double the backslashes or use forward slashes.