archbird

Map codebases. Verify architecture. Plan and apply structural changes.

Archbird scans a repository and builds a deterministic map of its files, symbols, dependencies, public interfaces, tests, build routes, and components. Use it to understand unfamiliar code, give coding agents focused context, enforce reviewed architecture constraints in CI, compare ports or frontends, and check that coordinated changes produced the required structural result.

PyPI npm License

JavaScript documentation · Python documentation · Open the browser app

# Python 3.9+
python -m pip install archbird

# Or Node 18+
npm install --save-dev archbird

archbird map .  # map the current repository; npm: npx archbird map .
archbird serve  # explore it locally; npm: npx archbird serve

Language support

All interfaces produce the same Map model. The C core provides portable lexical and Tree-sitter syntax analysis; the Python, Node, and browser hosts add the precision available in their own runtimes.

  libarchbird archbird.js archbird.py archbird app
C and C++ ✓ Tree-sitter + lexical ✓ Tree-sitter + lexical ✓ Tree-sitter + lexical ✓ Tree-sitter + lexical
Python ✓ Tree-sitter + lexical ✓ Tree-sitter + lexical ✓ CPython AST + Tree-sitter + lexical ✓ Tree-sitter + lexical
JavaScript, TypeScript, and TSX ✓ Tree-sitter + lexical ✓ TypeScript compiler + Tree-sitter + lexical ✓ Tree-sitter + lexical ✓ TypeScript compiler + Tree-sitter + lexical
R ✓ Tree-sitter + lexical ✓ Tree-sitter + lexical ✓ Tree-sitter + lexical ✓ Tree-sitter + lexical

Lexical providers conservatively recover declarations, calls, and explicit protocols from source text. Tree-sitter adds syntax, scopes, imports, and exact spans. CPython AST and the TypeScript compiler add host-specific precision. SCIP is optional input for resolved definitions, references, and relationships; Archbird reads a supplied index but does not invoke an indexer.

Stages

Stage Question Output
Map What exists, and how is it connected? Searchable files, symbols, dependencies, tests, and build routes
Query Which exact evidence matters for this task? Focused, ranked context with source witnesses
Path How are two explicit architecture entities connected? Bounded shortest witnesses with typed relations, direction, evidence, and completeness
Verify Does the code follow the architecture constraints? Constraint status, violations, code locations, and unknowns
Plan What structural change follows from current evidence, and what remains unknown? An editable language-neutral Plan with objectives, operators, applicability, and acceptance constraints
Act How does that Plan ground into exact repository changes, and does its after-state pass? An accepted, sealed Act bound to exact transitions plus fresh Map and Verification evidence

Map builds the canonical repository IR. Architecture is normally scattered across source languages, packages, public interfaces, native/frontend bridges, tests, build systems, and generated artifacts. Map joins those facts once so every later stage works from the same files, symbols, relationships, and source locations. Provider-specific lexical, syntax, host-AST, and SCIP facts are normalized into this language-neutral intermediate representation without discarding their provenance or uncertainty.

Query and Path evaluate projections over the Map IR. Query selects, traverses, and ranks the small neighborhood relevant to one task. Path answers a narrower question: whether two explicit entities are connected and which relationships form the connection. They share typed projection and graph indexes, but neither operation rewrites the Map or promotes an uncertain relationship into a confirmed one.

Verify checks architectural intent against the complete relevant model. Each constraint compiles into exhaustive projections over the Map IR plus a predicate such as required symbols, allowed dependencies, acyclicity, parity, or a numeric bound. Verify never uses a ranked or truncated Query result. Its Verification artifact records pass, failure, or unknown together with the exact operands and source locations responsible.

Plan describes a structural transition. Archbird can derive a Plan from the Map IR, current Verification findings, and a requested goal, but a developer or agent may also author or edit one directly. The language-neutral Plan records ordered objectives, applicable transformation operators, acceptance constraints, source identities, and explicitly manual work; it does not contain unreviewed guessed code.

Act grounds and checks the Plan. Act combines the reviewed Plan with exact source bytes and executor input, produces candidate file transitions, and evaluates their isolated after-state through a fresh Map and Verify run. A passing result can be sealed as an accepted Act without touching the worktree. Apply is the only mutating operation: it revalidates every source lock and replays that accepted Act.

The stages therefore form one traceable pipeline:

providers ───────────────→ Map IR ──→ projections ──→ Query / Path
                              │
                              └─────→ constraints ──→ Verification
                                         │
Map IR + Verification + intent ──────────┴──→ Plan (derived or authored)
                                                   │
source + executor input ───────────────────────────┴──→ Act candidate
                                                            │
                                                fresh Map + Verify
                                                            │
                                                    accepted Act → Apply

Every output retains its source and configuration links. Missing, conflicting, incomplete, and stale information remains visible instead of being guessed away.

Command-line workflow

The CLI follows the product stages directly. Run it from the repository root; archbird.json is discovered automatically when present.

Map a repository

archbird map .
archbird map . --view architecture \
  --group-by component --level file --relations imports,calls
archbird map . --view tests --group-by directory
archbird map . --view evidence --detail full

map scans the configured/discovered scope and builds Archbird’s canonical derived evidence model of files, symbols, dependencies, public interfaces, tests, build routes, artifacts, and components. Unsupported inputs, unresolved relationships, provider recovery, and other unknown frontiers remain explicit. The default Markdown output is a readable architecture overview; use JSON when you want to save the canonical Map for later commands.

Query focused context

archbird query . --symbol 'src/runtime.c:runtime_start' \
  --depth 1 --test-depth 1 --max-chars 12000 --check
archbird query . --search 'provider registry' \
  --search-limit 8 --max-chars 12000 --check
archbird impact . --path src/runtime.c --depth 2 --check

query loads or builds that Map, selects a starting point, follows its recorded relationships, and returns a focused neighborhood. Use typed selectors such as --symbol, --path, --component, --package, or --artifact when you know what you are looking for. File ordering prefers routes with stronger evidence state (current, then unknown, then stale) and semantic resolution before distance. Each selected file exposes the best route’s state, resolution counts, provenance count, and last hop; the canonical Query still retains the underlying candidate edges and their full evidence. Repository discovery/completeness remains a separate property rather than an edge-confidence score.

query --search helps find that starting point when you do not know its exact path or symbol. It ranks lexical matches from repository names, paths, signatures, descriptions, and package metadata, then runs the same focused Query from those candidates. It tolerates prefixes, substrings, and small typos, but it does not interpret a natural-language question or turn a text match into a proven code relationship.

Query selectors accept exact or partial symbols, paths, mapped directories, globs, layers, components, tests, packages, artifacts, builds, provider surfaces, parity surfaces, and named entries. query is bidirectional by default; impact starts upstream. Occurrence-backed symbol relations are used before conservative file expansion.

--search KEYWORDS is deterministic lexical retrieval for cases where you do not yet know a path or symbol. Use concise repository vocabulary such as provider registry; it does not interpret questions, intent, or synonyms. It ranks candidate symbols, files, components, packages, and artifacts from names, paths, signatures, component descriptions, and package metadata, shows the exact field and match behind every score, then expands the selected candidates through the same typed graph. Prefix, substring, and bounded typo matches are advisory seeds; they never become semantic edges or make a constraint pass. Prefer --symbol, --path, or another typed selector once you know the target. Symbol neighbors reached only from advisory seeds do not strengthen a static test route.

Focused test routes keep file distance and symbol-hop distance separate. A case that calls a wrapper reached from the requested symbol is labeled with that wrapper and its hop distance; another case in the same file is not promoted merely because the file is nearby. Static routes remain candidates until reviewed configuration or imported per-test observations provide stronger evidence.

query --view changes uses the same complete Query artifact and ranking policy, but presents it as a coding packet: change seeds, affected code, strongest routes, ranked tests, packages/builds/artifacts, explicit uncertainty, and a ledger of collapsed evidence. It does not infer an edit or change the canonical Query.

--git-diff REVISION asks the host CLI for Git’s tracked name/status changes and passes a typed change set to the same core Query operation. Current paths seed the architecture neighborhood; deletions and paths outside the Map remain visible instead of being invented as current code. External diff drivers and text-conversion commands are disabled. Untracked files require an explicit --path until they enter Git’s diff.

--verification-result PATH adds the architecture constraints and findings whose subject-side source paths overlap the selected change. The brief shows their constraint IDs, requirement IDs, owners, severity, source paths, and whether the verification input and producer still match the current Map. It does not rerun verification, match reference-only evidence, or treat a path-free constraint as relevant.

The default is an architecture-first overview for a person or coding agent; canonical JSON still contains every selected file and mapped fact. Choose the human projection and its amount of detail independently:

archbird map --view overview --detail compact
archbird map --view architecture \
  --group-by component --level file --relations imports,calls
archbird map --view tests --group-by directory
archbird map --view evidence --detail full
archbird query --symbol runtime_start --view source
archbird query --symbol runtime_start --dump

--view selects a question-oriented preset. overview includes project landmarks and broad package/build/test connections; architecture emphasizes code dependencies; tests isolates test routes; and evidence exposes coverage, diagnostics, and completeness. --group-by reorganizes the same selected entities by directory, configured component, layer, or language. --level chooses component, file, or symbol nodes. --relations overrides the preset’s relation families and accepts comma-separated values or repeated flags. These semantic axes compile to one exhaustive graph ProjectionPlan and the resulting typed ProjectionResult drives both Markdown and the application.

--detail changes rendering density only. --compact and --full are aliases for its corresponding values. --max-chars is a final presentation guard; it never changes the canonical Map or turns incomplete evidence into success. Compact and standard Markdown rank structural groups, aggregated dependency flows, and file landmarks while reporting what the presentation omitted. File landmarks use separate bounded production/API, test/fixture, and build/artifact shortlists, followed by an unresolved-import frontier. Classification consults the Map’s file-role evidence first and then conservative repository-path conventions. Build outputs/tooling and third-party/generated candidates take precedence over test candidates, while participation metadata such as artifact-input does not by itself demote production source. Visible relation, degree, and symbol counts are orientation signals rather than correctness claims. Standard dependency rows show at most eight relation kinds and disclose the omitted and total counts. Diagnostics retain their exact canonical cause count; recognized Tree-sitter recovery and missing node messages are additionally summarized by language and parser action, with node-count ranges and representative paths. Other diagnostics remain grouped by exact severity, code, and message. --detail full enumerates the exhaustive selected graph records instead. Dependency flow is shown provider to consumer; the underlying canonical relation remains consumer to provider (A uses B).

Graph completeness and repository coverage are reported separately. A graph can exhaustively represent every selected supported fact while discovery still reports unsupported, ignored, oversized, or otherwise unknown repository inputs. Presentation omissions never change either classification. Query context profiles (exact, change, architecture, audit), per-kind quotas, route provenance/confidence, and candidate/conservative policies remain separate Query behavior.

--view source materializes source bytes selected by the Map or Query instead of storing source text in the canonical artifact. Compact detail is an indexed declaration outline. Standard detail expands exact declarations matched by a symbol Query, returns a complete directly selected file for a path Query, and leaves related files as outlines. Full detail returns every selected file; --dump is an alias for --view source --detail full. Full source cannot be combined with --max-chars, because silently dropping part of a requested dump would make it misleading.

Every emitted file is matched by repository-relative path and SHA-256 against the Map before its bytes are rendered. A saved Map therefore needs the source checkout explicitly:

archbird query --map .archbird/map.json --root . \
  --symbol 'src/runtime.c:runtime_start' --view source
archbird query --map .archbird/map.json --root . \
  --symbol 'src/runtime.c:runtime_start' --dump \
  --output .archbird/runtime-start-source.md

When a provider cannot establish an exact declaration extent, standard source shows the indexed outline and states that exact source is unavailable; it does not guess where the declaration ends. Non-UTF-8 bytes and terminal control sequences are hash-validated but are not embedded in Markdown. When valid semantic-AST and concrete-syntax extents differ, the concrete source boundary is canonical for rendering while every alternate boundary and provider remains recorded in the merge-variation ledger.

Find a connection with Path

archbird path 'src/cli.c' 'src/runtime.c' --root . \
  --relation calls --direction downstream

path SOURCE TARGET resolves exact or glob-shaped endpoint sets and finds globally shortest witnesses over the Map’s exhaustive typed graph projection. It preserves parallel relation kinds, traversal direction, evidence state, semantic resolution, and provenance. found requires an all-current, source-evidenced route and prefers it even when a shorter candidate shortcut exists. When only candidate/unknown relations connect the endpoints, Path renders those witnesses as unknown with reason candidate-witnesses, and --check fails. A missing route is reported as absent only when the selected graph and bounded search are complete; unresolved endpoints, unsupported evidence, or a depth frontier remain unknown.

Add --check when a script specifically requires a proven found result. Repository-dependent examples omit it because an honest unknown is a valid answer.

Rendering a saved Path validates its exact artifact shape, content digest, and cross-field proof invariants before producing Markdown. A current witness requires current endpoints and relations, nonempty relation evidence, and unique, builtin, or not-applicable resolution; the renderer never trusts an outcome label by itself.

Verify architecture

Reviewed architecture policy belongs in the constraints collection of the same archbird.json that defines project structure. Typed constraints infer their exhaustive Map projections; primitive assertions can use inline literals, observations, or named/inline projections. The complete quickstart.archbird.json combines these stages and needs no second suite file.

For a first check in an unfamiliar repository, configuration may contain only the reviewed constraint; discovery supplies the project model and layers:

archbird verify --config - --check <<'JSON'
{
  "constraints": {
    "NO-LARGE-SOURCE": {
      "kind": "max_file_bytes",
      "include": ["src/**"],
      "max": 1048576,
      "owner": "architecture",
      "rationale": "Keep source files reviewable."
    }
  }
}
JSON

The same fragment can be saved unchanged as archbird.json. Explicit project-model sections replace discovery; omitted sections inherit it.

# Run one saved Query plan or an ad-hoc query.
archbird query public-api-impact
archbird query --symbol demo_open --direction upstream

# Evaluate the whole reviewed policy or one named constraint.
archbird verify --check
archbird verify CORE-PUBLIC-API --check

# Preserve exhaustive repository-inventory operands when verifying a saved Map.
archbird verify --map .archbird/map.json \
  --resolution .archbird/resolution.json --check

# Emit CI-native reports from the same constraints.
archbird verify --format sarif --output .archbird/architecture.sarif --check
archbird verify --format junit --output .archbird/architecture.junit.xml --check

# Freeze reviewed existing debt and coverage as a ratchet.
archbird verify --freeze .archbird/architecture.baseline.json \
  --freeze-owner architecture \
  --freeze-rationale "Reviewed starting point"

verify without IDs evaluates every configured constraint. Positional IDs select an explicit subset and the Verification artifact records configured, requested, evaluated, and omitted counts; a successful subset is never reported as whole-policy compliance. Unknown IDs are errors. The CLI defaults to a human-readable Markdown verdict; use --format json when saving the canonical Verification artifact. Repository selection is execution context: run in the project root or use --root PATH; an external configuration uses --config CONFIG --root PROJECT. Query and Impact also accept an unambiguous path-shaped positional root, such as archbird query . --symbol demo_open. archbird impact ../project --path src/api.c works similarly. A bare positional token remains a saved query ID; use ./project rather than project when selecting a relative repository path.

A saved Map contains mapped facts, not the complete discovery inventory. Pass its matching config show artifact with --resolution when constraints depend on ignored, unsupported, oversized, or forbidden repository paths. Archbird validates the Map/resolution identities and rejects a mismatched pair. Live verify derives both from one repository state automatically.

Common typed constraints cover required/forbidden paths and symbols, file-size bounds, symbol cardinality, component membership and cycles, allowed/forbidden/ required component or file edges, package entrypoints, bridges, test routes, and provider surfaces. They require no projection boilerplate. General predicates cover set/value equality, mapped equality, directional subsets, cardinality, numeric bounds, graph edges, acyclicity, minimum test routes, and observation equality.

provider_surface normally treats configured providers as one combined declaration surface. Set require_all_providers: true when every capability must appear in every configured provider, such as a public header and a Wasm export list. Verify then reports the exact missing provider witnesses instead of accepting a declaration found only on another surface.

A projection result is exhaustive for its declared Map domain. If discovery, provider, resource, freshness, or source-lock evidence prevents a complete answer, the operand is partial or unknown and cannot make a constraint pass. Query may rank and bound context; Verify may not. Derived Map facts, asserted literals/mappings/waivers, and observed runner evidence retain distinct provenance.

Named projections are reusable configuration for constraints and queries, not a separate required CLI stage. One-off primitive operands stay inline:

{
  "constraints": {
    "API-SIZE": {
      "assert": "cardinality",
      "actual": {
        "projection": {
          "select": "symbols",
          "paths": ["include/**"],
          "public_only": true
        }
      },
      "max": 30,
      "owner": "core",
      "rationale": "Keep the supported native surface reviewable."
    }
  }
}

Constraint-owned waivers require an ID, owner, rationale, an exact finding fingerprint or comparison/key pair, and an expiry date or input-digest boundary. Baselines classify new, known, reintroduced, and resolved findings while ratcheting covered facts. Cross-repository constraints receive explicitly named saved Maps with --map-input ID=PATH; behavioral parity receives reviewed artifacts with --observation ID=PATH. Similar names alone never establish semantic equivalence.

Every constraint has a stable ID, owner, rationale, optional requirement IDs, tags and severity. Findings cite exact evidence and separately record comparison, evidence state, applicability, disposition, baseline state, and a stable fingerprint. JSON, Markdown, SARIF, and JUnit are views of the same canonical Verification result.

Add observed test evidence

Static test routes are candidates. observe converts project-owned per-test coverage reports into exact runtime test-to-symbol evidence:

archbird observe . --map .archbird/map.json \
  --request .archbird/coverage-request.json \
  --output .archbird/test-symbols.json

archbird query --symbol runtime_start \
  --test-symbol-observations .archbird/test-symbols.json

Python supports coverage.py JSON with dynamic test contexts; Node supports V8 JSON. Both hosts support isolated Istanbul, llvm-cov export, and gcov JSON. Formats without per-test contexts require one isolated report per case. Archbird checks source hashes and rejects aggregate coverage that cannot prove which test produced a hit; it never runs the tests or coverage tools.

Plan, Act, and Apply

Plan evaluates the complete current Verify policy and derives one editable artifact. Omit the constraint name to include every current issue, or scope generation by existing constraint ID:

Build and behavioral acceptance commands are stable project policy. Define them once as direct argument arrays in archbird.json; Archbird never invokes a shell:

{
  "gates": {
    "build": {
      "argv": ["cmake", "--build", "build"],
      "timeout_seconds": 600
    },
    "focused-tests": {
      "argv": ["ctest", "--test-dir", "build", "--output-on-failure"],
      "depends_on": ["build"],
      "timeout_seconds": 600,
      "max_output_bytes": 1048576
    }
  }
}

Every configured gate runs over the same copied after-state used to build the acceptance Map. Dependencies provide a deterministic order and allow build outputs to feed later tests. Any failure, timeout, output-limit breach, or blocked dependency rejects the Act before the working tree is changed. The accepted Act seals each normalized definition, status, duration, environment identity, complete output digests, bounded output tails, and the initial after-state workspace identity. These are trusted reviewed commands with source isolation and provenance, not an operating-system security sandbox.

# Inspect the current task DAG without saving a second artifact.
archbird plan --format markdown
archbird plan --output .archbird/plan.json
archbird plan CORE-PUBLIC-API --output .archbird/plan.json
# Review a derived rename candidate, then assert the intended transformation.
archbird plan CORE-PUBLIC-API --rename old_api=new_api \
  --output .archbird/plan.json

# Derive residual work from a committed base without changing the worktree.
# ...developer or agent partially changes the implementation and consumers...
archbird plan FFI-SURFACE --git-diff HEAD \
  --output .archbird/plan.json

# Or save an explicit Map before work begins.
archbird map --format json --output .archbird/before-map.json
# ...developer or agent changes the implementation and consumers...
archbird plan FFI-SURFACE --before-map .archbird/before-map.json \
  --output .archbird/plan.json

# Ground, verify, and inspect the exact Act without writing.
archbird act .archbird/plan.json
# Supply reviewed implementation semantics for exact unresolved items.
archbird act .archbird/plan.json \
  --submit IMPLEMENT_ITEM=reviewed-module.py \
  --submit TEST_ITEM=reviewed-test.py
archbird act .archbird/plan.json --format patch
archbird act .archbird/plan.json --format json \
  --output .archbird/act.json

# Replay only the accepted Act after review.
archbird apply .archbird/act.json

Plan’s target contract is language-neutral: it names architectural objectives, operators, exhaustive applicability, dependencies, executor capability, and acceptance without embedding source syntax or replacement bytes. When a reviewed constraint identifies one exact missing symbol or test route but does not determine implementation code, Plan retains that target as a structured non-executable add_symbol or add_test_route operation instead of reducing it to an opaque manual note. This lets Plan order a semantic implementation before its declaration and its tests while continuing to state that Act has no authorized source transformation. A developer or agent may submit reviewed full-file content for one exact add_symbol destination, or for an add_test_route item when Map identifies exactly one file in its reviewed test group, with repeatable act --submit ITEM=FILE. The symbol destination may be an existing mapped file or a missing exact path. The Plan remains byte-identical and language-neutral; the native Act core observes the destination, chooses an exact create or replace transition, records read/write/match evidence, builds one real isolated after-Map, and rejects the entire Act unless the original and preserved constraints pass. A missing definition, declaration, and test route can therefore form one useful agent/developer task DAG without Archbird inventing a signature, body, or test. plan --format markdown renders that same canonical Plan as a review packet; it does not create another artifact. Absent or ambiguous test locations remain manual. An exact missing path from required_paths similarly becomes a path-only create_file objective. Plan does not embed the future file bytes. Supply reviewed content with act --submit ITEM=FILE; native Act requires the destination to remain absent, previews one exact creation, and accepts it only when the isolated after-Map closes the constraint. An exact missing required_file_edge similarly becomes an input-required add_dependency objective containing only the source path, target path, relation kind, and optional relation name. A reviewed source-file submission must produce that edge in the fresh Map; an unchanged or unrelated edit is rejected with zero worktree writes. Plan also records an exhaustive source-scoped file_edges projection and the one permitted item-key addition. Act compares the real before/after ProjectionResults and rejects any extra dependency addition or removal even when the selected constraint passes. An exact current forbidden_file_edges violation between two mapped files becomes the symmetric input-required remove_dependency objective. Plan records the exact source, target, and relation without choosing replacement semantics. Reviewed source content must remove the forbidden relation from the fresh Map; preserving the edge rejects the complete Act with zero worktree writes. The same source-scoped delta contract permits only that one edge removal, so deleting an unrelated import is rejected independently of constraint closure. Aggregated component edges, incomplete evidence, and external or unmapped targets remain on the reviewed redirect/manual path. redirect_dependency and declare_symbol currently follow this boundary end to end. Given reviewed --redirect OLD=NEW intent, Plan stores the exhaustive edge ProjectionPlan, exact relation, affected source paths, and symbol identities. Act reevaluates that projection once and dispatches its typed evidence by mapped source language. The native C executor resolves exact declarations, definitions, include spelling, and call sites. The native Python executor resolves one exact imported binding and its CPython-AST calls, uses an already observed import-module spelling for the replacement, and preserves an explicit local alias. The native ECMAScript executor supports JavaScript, TypeScript, and TSX named imports when Tree-sitter proves the binding and the TypeScript compiler proves every redirected call. It uses a replacement module spelling already observed from the same source directory and preserves explicit aliases, including aliases whose local name equals the old imported name. The Node frontend supplies the required TypeScript evidence by default; a syntax-only Map is rejected. Incomplete projections, ambiguous definitions, missing observed include/import routes, multi-name imports, non-call references, and non-unique call sites block Act instead of producing partial edits.

Low-level asserted operations currently include replace_range, delete_file, move_file, and edit_json_pointer. They are useful for bounded edits supplied by a developer or agent, but are not the model for derived Plan operations. create_file, add_dependency, and remove_dependency are language-neutral, input-required Plan objectives; exact content belongs to Act submission.

A one-extra/one-missing symbol constraint may suggest a rename, but that does not establish intent: the derived candidate stays non-executable until a developer or agent supplies --rename OLD=NEW. The reviewed command evaluates one exhaustive symbol_occurrences projection seeded by the constraint’s selected declaration paths. Plan stores only the language-independent symbol objective, normalized ProjectionPlan identity, and repository-relative source scope. Act reevaluates the projection, requires identical complete evidence, and lets the native Python or ECMAScript executor validate and materialize exact declaration, import, export, binding, and reference edits. Unrelated same-name declarations outside the selected scope are not renamed. Qualified identities may rename only their terminal identifier while preserving the same enclosing identity. Python coverage includes exact same-module references, qualified imported-attribute references, and literal __all__ export tokens; ECMAScript reference sites require TypeScript-compiler evidence. Public alias or CommonJS assignment targets are separate reviewed surface identities and are not rewritten as though they were internal declaration occurrences.

For an exact provider_surface issue, Plan can add a missing configured Make registration, C header file_pattern declaration, or bounded C/N-API exports registration. It can also use reviewed --rename OLD=NEW intent to replace a stale Make entry when the target resolves uniquely. Each provider definition has a canonical digest in Map and Plan, so distinct definitions over one path do not collapse into one identity. Plan records the neutral provider objective and bounded source scope; it stores no Make token, C signature, export-table syntax, anchor, source hash, byte range, or replacement text. Act validates the provider digest against the current configuration and Map. Act/Make derives the token spelling and requires one registration anchor. Act/C rederives a single-line declaration from the exact implementation and an existing declaration peer. For an exports addition it requires one effective mapped C file, one mapped napi_<capability> wrapper, syntax-clean source, and an existing mapped DECLARE_NAPI_METHOD or N-API descriptor peer; it clones that peer while preserving multiline layout and line endings. Selectors that map the provider to multiple files, active uses of stale entries, unresolved targets, ambiguous implementations, missing anchors, multiple token matches, and distinct provider definitions that would require one coincident source edit remain manual or are rejected by Act. If the replacement is already registered by that provider, Plan normalizes the target state to removal of the stale old registration instead of proposing a duplicate.

For an exact required_package_entrypoint failure with one npm package and a literal package-relative target, Plan emits the language-neutral set_package_entrypoint objective. Act’s native JSON executor grounds main, direct exports, and existing-object bin routes through the lossless JSON Pointer editor, then requires the fresh after-Map to close the original constraint. The target must be an existing regular file but need not be a mapped source file; extensionless npm executables are therefore supported. Act resolves it relative to the package manifest and seals its exact read-only source state. Conditional or nested exports, ambiguous package selectors, missing targets, and route shapes that would require replacing an existing object remain manual. Plan contains the package route and target, not JSON syntax, byte offsets, or replacement text.

--before-map OLD.json can derive the same provider registration replacement without asserted rename intent when an observed partial migration proves it. The old surface member must have been uniquely resolved in the before Map; the current old registration must be unused and unresolved; and exactly one new current member must retain the same implementation paths and use ledger with declaration and implementation signatures differing only by the symbol name. Both Maps must share project, configuration, and producer identities and have no error diagnostics. Plan and Act retain both Map identities. Missing signatures, incompatible histories, or multiple matching targets do not authorize an edit.

--git-diff REVISION constructs that before Map from one verified Git commit in an isolated raw-object snapshot under Archbird’s cache directory, using the current project configuration and ordinary discovery/provider pipeline. It does not run checkout filters and never checks out or writes the source worktree. The option accepts a commit, not a revision range, and cannot be combined with --map or --before-map. The temporary snapshot is removed after its canonical Map is built; unchanged provider facts remain eligible for the normal content-addressed cache.

When a constraint itself requires a missing surface member, that reviewed policy supplies the intent. If the member has one implementation candidate and is already declared by another provider or has current uses, Plan derives one add_provider_capability item per missing supported provider without another flag. An exact C/N-API export may instead use the current bridge use plus the uniquely mapped wrapper in its configured provider file. A C declaration item precedes its Make or export registration for the same surface member. Both the missing and unregistered findings remain origins, and every generated item is explicitly derived. Incomplete evidence, ambiguous implementations, unsupported provider kinds, or colliding edit targets remain manual.

When several reviewed surface members are missing from the same Make provider, Plan emits one item per obligation and Act composes their distinct insertions into one source-locked file transition. Composition is limited to the same variable, anchor, and side; tokens are ordered canonically. Byte-identical edits produced by separate Plan obligations also compose once while the transition retains every originating item ID. Coincident edits with different effects remain conflicts.

For a required_symbols constraint scoped to one exact C header, Plan can derive the neutral declare_symbol objective when one same-language mapped definition establishes a bounded two-file evidence scope. Plan records only the destination, symbol, and source paths that the executor may read. Act/C then requires an existing declaration/definition peer and rederives the exact single-line implementation signature and placement from those hash-checked sources; no C syntax, byte range, source hash, or anchor is stored in Plan. It preserves indentation and line endings. Globs, multiple implementations, missing peers, multiline or internal definitions, header-only decoration differences, and source comments at the insertion anchor remain manual or are rejected. This can be combined with a missing Make registration in one Plan and accepted as one two-file architecture change.

An unresolved, unused registration can likewise become a derived removal when the Map proves zero implementation candidates, zero uses, one exact Make declaration, and at least one other uniquely resolved declaration from the same provider. The last guard prevents Plan from emptying a configured provider or treating two stale entries as proof for each other. Mixed replacement cases, active or ambiguous entries, duplicate token spellings, and removals that do not close the complete constraint remain manual.

An asserted edit_json_pointer operation handles reviewed manifest and export table changes without replacing or reformatting the whole file. It names one source-locked file, one RFC 6901 pointer, the exact expected old JSON value (or explicit absence), and the replacement value. The native core rejects stale hashes, duplicate keys, missing parents, ambiguous expectations, and invalid JSON, then returns one exact byte edit. Archbird does not derive this representation-level intent from a generic architecture finding.

The native provider executors ground add_provider_capability, remove_provider_capability, and rename_provider_capability. Act/Make preserves assignment operators, comments, continuations, whitespace, and unrelated variables. It handles direct tokens only; variable expansion is not inferred. Act/C supports the bounded header and N-API forms above. Zero, duplicate, ambiguous, stale, multi-file, or syntax-recovered matches block the Act. Unified-diff text is selected with archbird act PLAN --format patch; it is only an Act rendering, not another artifact or lifecycle stage.

The CPython provider establishes Python declaration, binding, and reference sites. Tree-sitter establishes ECMAScript declarations and import/export bindings; the TypeScript compiler must establish ECMAScript reference targets, including aliased import origins without rewriting their local aliases. Candidate or unresolved calls, duplicate targets, unsupported inputs, and lexical-only C/C++ call binding prevent Act from producing a partial edit.

Existing sources are locked by SHA-256; ranges use UTF-8 byte offsets and include the expected text. Multiple range edits to one file become one atomic file transition and one unified diff. Paths must be canonical repository-relative paths. Symlinks, non-regular files, overlapping edits, stale hashes, conflicting destinations, and dependency cycles block before the first write.

Verify evidence often establishes a required state without establishing the code that should implement it. Plan records those cases as non-executable manual items with candidate paths and explicit unknowns. Act refuses to apply until every item has a reviewed executable operation; it never invents a function body, replacement dependency, package target, or test.

For file and component dependency issues, the exhaustive edge projection also retains each exact inducing import, include, call, or semantic-reference site. An exact mapped forbidden file edge can therefore retain a neutral removal objective. Broader issues produce a manual item exposing sites with fact identity, line, UTF-8 byte range, expected text, and source SHA-256 when the provider supplies a nonempty editable span. A zero-width semantic anchor remains explicit evidence and a non-executable reason, not a fabricated text edit. This bounds the locations a developer, agent, or structured executor must inspect without pretending that an aggregated forbidden edge determines its intended replacement route.

Act first rebuilds the current Map and Verify result. Their project, input, configuration, producer, policy, and result identities must match the Plan’s source snapshot. Act then applies the prepared create/modify/delete/move set to an immutable source overlay, reruns discovery and providers from those bytes, and evaluates the union of item acceptance constraints and preserved constraints against that isolated after-Map. A not_satisfied, unknown, or evaluation failure emits no accepted Act and performs no worktree write. Satisfied acceptance seals the exact Act bytes and after-state identities. Apply observes every affected path and native preflight classifies the whole Act as ready, already satisfied, partially applied, or drifted. A complete after-state replay succeeds with zero writes; partial application and drift fail. Ready bytes are replayed transactionally under an exclusive repository-local lock. Commit failures restore only Act-owned paths; concurrent changes to those paths are detected and never overwritten. Archbird does not run project compilers or tests; configure test observations and build evidence when those results must participate in Verify.

Destructive generated items require a current, complete, exhaustive relation projection. Unresolved imports or other relation frontiers make the item non-executable rather than allowing an apparently unused file or symbol to be removed. Every constraint in the source Verification is checked against the isolated after-state before commit, including constraints that passed when the Plan was generated.

Plan ingestion is bounded before expensive work: 64 MiB for canonical Plan JSON and each source, 4,096 items or touched files, 16 MiB per operation text field, 256 MiB aggregate touched source and patch, 64 MiB per file patch, and 64 KiB per metadata string. Source coordinates stop at JavaScript’s exact integer limit (2^53 - 1) so Python and Node consume the same Plan.

Explore the live repository

archbird serve
archbird serve --no-config
archbird serve --root ../project

serve starts a browser-based architecture explorer and immediately prints its loopback URL. Use it to expand selected components into files and selected files into symbols while the rest of the architecture stays collapsed; inspect typed connections and source witnesses; overlay configured constraint coverage and findings; run focused queries; and compare Map snapshots as the repository changes. Analysis progress is visible from the first page render. If an update fails, the explorer reports the failure and keeps showing the last valid Map and generation-matched Verification.

archbird serve
archbird serve --no-config
archbird serve --root ../project

serve prints a loopback URL immediately, analyzes in a worker, publishes only valid generations, and retains the last good Map when a later candidate fails. Live Map, Query, projection, Verify, and graph-view work runs in the server’s native Archbird core; the page does not fetch browser Wasm for live repository exploration. Wasm is reserved for the static app’s local folder/ZIP and saved artifact workflows. The application provides:

  • useful zero-config exploration from the same exhaustive graph ProjectionResult used by Markdown: switch overview, architecture, tests, and evidence views, then independently group by directory, configured component, layer, or language; configured components and constraints refine the graph when archbird.json exists but never gate the zero-config path;
  • one mixed-resolution architecture graph: double-click, press Enter, or use the inspector to expand a component or inferred layer through directories into files, then expand one file into symbols while unrelated groups remain collapsed; collapse, hide, and restore controls are presentation state and never rewrite Map or Projection evidence;
  • entity-type colors, generation-matched constraint/finding overlays, keyboard navigation, pointer-centered normalized wheel zoom, slider zoom, layout direction, evidence-class, and edge-kind controls; selecting never changes the viewport, while expanding animates children from the activated node and keeps that node at the same screen position; dependency arrows default to provider → consumer flow and can switch explicitly to consumer → provider uses;
  • compact node and edge hover details for identity, relation counts, evidence, and verification state; external symbol relations stay at the file frontier until explicitly revealed for one symbol;
  • graph-local filtering plus focused typed or lexical Query from the current canonical Map;
  • exact source witnesses for live repositories, retained last-good evidence, repository snapshots, and structural comparison between saved generations;
  • canonical artifact and graph-view JSON downloads plus GraphML and Mermaid graph exports;
  • task-oriented Diff and change-artifact summaries, Verification finding review with explicit waiver candidates, and project-configuration review;
  • system, light, and dark themes with responsive graph and inspector layouts.

The same application can run statically on GitHub Pages. A browser can open a saved artifact, local directory, or ZIP and analyze supplied files through the Wasm Worker without uploading source or requiring a server. Directory input passes path/size metadata and discovery documents through native discovery before reading selected source bytes, so default-excluded dependency/build trees do not fail merely because they contain large binaries. Saved artifacts do not contain repository source bytes, so source viewing is available only while a live server or browser repository session owns those bytes. Browser directory and ZIP inputs are explicit snapshots rather than watched filesystem handles; reload changed input to create another generation. Server mode evaluates Map and ProjectionPlans in the native Node/Python host and sends typed ProjectionResults to the page. Normal live exploration does not download the canonical Map; Save canonical artifact fetches those bytes explicitly. Static folder/ZIP and saved-Map workflows evaluate the same plans in the browser Wasm host. A successfully mapped repository with no supported source files shows an explicit empty-scope state rather than a blank graph.

Reuse saved evidence safely

Save complete evidence when subsequent operations must use the exact same repository state:

mkdir -p .archbird
archbird map . --format json --pretty \
  --output .archbird/map.json --check
archbird config show . --pretty \
  --output .archbird/resolution.json --check

archbird query --map .archbird/map.json \
  --symbol 'src/runtime.c:runtime_start' --depth 1 --max-chars 12000 --check

archbird query --map .archbird/map.json \
  --search 'provider registry' --search-limit 8

archbird impact --map .archbird/map.json \
  --path src/runtime.c --depth 2

archbird path 'src/cli.c' 'src/runtime.c' \
  --map .archbird/map.json --relation calls --direction downstream

archbird query --map .archbird/map.json \
  --symbol 'src/runtime.c:runtime_start' \
  --view changes --detail compact --check

archbird query --git-diff HEAD \
  --view changes --detail compact --check

archbird query --git-diff HEAD --view changes \
  --verification-result .archbird/verify.json --check

Archbird excludes .archbird/** by default, so saving generated artifacts there does not change repository discovery or freshness. Use --no-default-excludes only when that tool-output tree is intentionally part of the analyzed scope.

Plain saved-Map queries accept every supported Map schema even when another Archbird core produced the artifact. Add --check when the result will drive a decision: it also requires the saved producer digest to match the active core. That producer check does not establish live-source freshness; use freshness for a new Map-to-repository comparison. C/API query requests use producer_policy: "compatible"|"current"; every Query records the effective policy and its current, different, or unknown producer classification.

Progress is adaptive: --progress auto updates one terminal line only when an analysis takes long enough to notice and stays silent for pipes and agents. Use --progress always for captured agent/CI logs or --progress never for silence.

direct, candidate, and conservative are static evidence strengths, not claims that a test ran. Zero error diagnostics means selected analysis completed; unresolved calls, parser recovery, partial surfaces, and unsupported coverage remain visible.

Audit a saved Map against live source before treating it as current:

archbird freshness . --snapshot .archbird/map.json \
  --output .archbird/freshness.json --check

Programmatic APIs

Python

from archbird import Project, compile_plan_json, render_plan_markdown

project = Project.from_repository(".")
map_json = project.map_json(pretty=True)
print(project.map_markdown(max_chars=12_000).decode())
print(project.query_markdown(symbols=["runtime_start"], depth=1).decode())
selection = project.query_json(symbols=["runtime_start"], depth=0)
print(project.source_markdown(
    artifact_json=selection
).decode())
if project.verification_configured:
    verification_json = project.verify_json()
    plan_json = compile_plan_json(
        project, project.map_json(), verification_json
    )
    print(render_plan_markdown(plan_json).decode())
print(project.query_markdown(
    symbols=["runtime_start"], depth=1, view="changes", detail="compact"
).decode())

JavaScript / Node

const { Project, compilePlan, renderPlanMarkdown } = require("archbird");

const project = Project.fromRepository(".");
try {
  console.log(project.mapMarkdown({ maxChars: 12000 }).toString("utf8"));
  const selectionJson = project.queryJson({
    symbols: ["runtime_start"], depth: 0,
  });
  console.log(project.sourceMarkdown({
    artifactJson: selectionJson,
  }).toString("utf8"));
  if (project.verificationConfigured) {
    const mapJson = project.mapJson();
    const verificationJson = project.verifyJson();
    const planJson = compilePlan(project, mapJson, verificationJson);
    console.log(renderPlanMarkdown(planJson).toString("utf8"));
  }
  console.log(project.queryMarkdown({
    symbols: ["runtime_start"], depth: 1, view: "changes", detail: "compact",
  }).toString("utf8"));
} finally {
  project.dispose();
}

Browser

const { createBrowserArchbird } = require("archbird/browser");

const archbird = await createBrowserArchbird();
const project = archbird.Project.fromFiles([
  new archbird.Source(
    "src/index.ts",
    new TextEncoder().encode("export const answer = 42;\n"),
  ),
]);
try {
  console.log(project.map());
  const selectionJson = project.queryJson({ symbols: ["answer"], depth: 0 });
  console.log(project.sourceMarkdown({
    artifactJson: selectionJson,
  }).toString("utf8"));
} finally {
  project.dispose();
}

C

#include <archbird/archbird.h>

ArchbirdEngine *engine = NULL;
ArchbirdStatus status = archbird_engine_create(NULL, &engine);
if (status == ARCHBIRD_OK) {
  /* Supply repository-relative sources or normalized provider facts, then
     call Map, Verify, Query, Diff, or workspace APIs. */
  archbird_engine_destroy(engine);
}

The public C ABI uses opaque handles, allocator-aware byte buffers, explicit statuses, and canonical JSON boundaries. It is experimental ABI v0.

Complete API inventory

Python and Node expose parallel Map, Query, Verify, Plan, and Act capabilities where their runtimes permit them. The inventories below are checked against archbird.__all__ and Object.keys(require("archbird")); host-specific schema, cache, OKF, observation, and runtime inspection helpers intentionally differ.

| Python area | Public names | | — | — | | Repository model | Project, Source, Workspace | | Map, Query, and Path | analyze_workspace_json, audit_map_freshness, diff_maps_json, export_graph, path_map_json, path_map_markdown, query_map_json, query_map_markdown, render_map_markdown, render_path_markdown, render_source_markdown, resolve_discovery | | Projection and policy | compile_project_configuration, compile_query_plan_json, evaluate_constraints_json, evaluate_projection_json, freeze_constraints_json | | Plan and Act | accept_act_json, act_overlay, act_source_requirements, apply_accepted_act, compile_plan_json, inspect_ast_grep_executable, materialize_act_json, materialize_ast_grep_operations, observe_act_sources, observe_plan_sources, plan_source_requirements, preflight_act_apply, render_act, render_plan_markdown, run_act_gates, validate_act, validate_plan | | Observations and OKF | analyze_okf_source, compile_test_observations, export_okf_bundle, publish_okf_bundle, validate_test_symbol_observations, write_okf_bundle | | Runtime and schemas | __version__, implementation_digest, PATTERN_CONTRACT, PATTERN_CONTRACT_VERSION, PATTERN_ENGINE, PATTERN_OPTIONS, PATTERN_UNICODE, read_schema, schema_names |

| Node area | Public names | | — | — | | Repository model | Project, Source, Workspace | | Map, Query, and Path | analyzeWorkspace, auditMapFreshness, diffMaps, exportGraph, pathMap, pathMapMarkdown, queryMap, queryMapMarkdown, renderMapMarkdown, renderPathMarkdown, renderSourceMarkdown, resolveDiscovery | | Projection and policy | compileProjectConfiguration, compileQueryPlan, evaluateConstraints, evaluateProjection, freezeConstraints, reportConstraints | | Plan and Act | acceptAct, actOverlay, actSourceRequirements, applyAcceptedAct, compilePlan, materializeAct, observeActSources, observePlanSources, planSourceRequirements, preflightActApply, renderAct, renderPlanMarkdown, runActGates, validateAct, validatePlan | | Observations and OKF | analyzeOkfSource, compileTestObservations, publishOkfBundle | | Runtime and planning | defaultProviderCacheDir, defaultProviderCacheMaxBytes, discoveryPlan, jsonCanonicalize | | Runtime metadata | ENGINE, IMPLEMENTATION_SHA256, NATIVE_ABI_VERSION, PATTERN_CONTRACT, PATTERN_CONTRACT_VERSION, PATTERN_ENGINE, PATTERN_OPTIONS, PATTERN_UNICODE, PROVIDER_SUPPORT, VERSION |

archbird/browser exports createBrowserArchbird(). Browser repository input is an explicit inventory/byte snapshot, not ambient filesystem access. Project.fromFiles() resolves discovery from supplied bytes. Hosts that receive large directory inventories can call Project.discoveryContentPaths(), read only those small discovery inputs, call Project.resolveInventory(), then read resolution.files and construct the project with Project.fromResolvedFiles(). This is the metadata-first path used by the app. The resolved facade is:

Project, Source, auditMapFreshness, ENGINE, NATIVE_ABI_VERSION, PATTERN_CONTRACT, PATTERN_CONTRACT_VERSION, VERSION, and core.

The core property is the advanced raw Wasm facade.

npm package entrypoints are archbird, archbird/browser, archbird/schema/*, archbird/serve, archbird/wasm, archbird/wasm-sync, and archbird/worker.

The complete C ABI is declared in include/archbird/archbird.h:

| C area | Public functions | | — | — | | Engine and structured edits | archbird_engine_create, archbird_engine_destroy, archbird_engine_error, archbird_engine_error_offset, archbird_engine_options_init, archbird_engine_options_init_for_input, archbird_graph_options_init, archbird_implementation_sha256, archbird_json_canonicalize, archbird_json_pointer_edit, archbird_json_pointer_edit_options_init, archbird_json_pointer_edit_result_init, archbird_json_validate, archbird_make_variable_token_edit, archbird_make_variable_token_edit_options_init, archbird_make_variable_token_edit_result_init, archbird_make_variable_token_insert, archbird_make_variable_token_insert_options_init, archbird_make_variable_token_insert_result_init, archbird_unified_diff_options_init | | Discovery | archbird_discovery_add_ignore, archbird_discovery_add_path, archbird_discovery_create, archbird_discovery_destroy, archbird_discovery_render, archbird_discovery_resolve, archbird_discovery_should_descend | | Configuration, projections, constraints | archbird_constraints_evaluate, archbird_constraints_freeze, archbird_constraints_report, archbird_constraints_report_with_blocking, archbird_project_configuration_compile, archbird_projection_evaluate, archbird_projection_render_markdown, archbird_query_plan_compile | | Project evidence | archbird_project_add_provider_facts, archbird_project_add_source, archbird_project_add_test_symbol_observations, archbird_project_config_sha256, archbird_project_create, archbird_project_destroy, archbird_project_finalize_providers, archbird_project_finalize_sources, archbird_project_manifest_sha256, archbird_project_map_input_sha256, archbird_project_merge_summary, archbird_project_provider_count, archbird_project_provider_fact_count, archbird_project_render_file_facts, archbird_project_render_map, archbird_project_render_merge_conflicts, archbird_project_render_merge_ledger, archbird_project_render_provider_facts, archbird_project_render_source_markdown, archbird_project_scan_builtin, archbird_project_scan_builtin_provider, archbird_project_scan_builtin_provider_file, archbird_project_set_config, archbird_project_source, archbird_project_source_count, archbird_provider_facts_validate, archbird_source_manifest_validate, archbird_test_symbol_observations_validate | | Map, Query, Path, interchange | archbird_map_diff, archbird_map_export_graph, archbird_map_freshness, archbird_map_path, archbird_map_path_markdown, archbird_map_query, archbird_map_query_markdown, archbird_map_query_markdown_view, archbird_map_query_markdown_view_with_verification, archbird_map_render_markdown, archbird_map_render_markdown_view, archbird_okf_analyze, archbird_okf_publish, archbird_path_render_markdown, archbird_unified_diff | | Workspace | archbird_workspace_analyze, archbird_workspace_plan | | Plan and Act | archbird_act_accept, archbird_act_materialize, archbird_act_preflight_apply, archbird_act_source_requirements, archbird_act_validate, archbird_plan_compile, archbird_plan_render_markdown, archbird_plan_source_requirements, archbird_plan_validate |

Agent protocol

The Python CLI and source launcher expose the same live repository service over MCP stdio:

archbird mcp
archbird mcp --root ../project
archbird mcp --no-config

An MCP host launches that command and communicates through stdin/stdout. The server maps the repository once, watches it for changes, retains recent valid generations, and exposes read-only tools for status, Map presentation, exhaustive projections, focused Query, hash-checked source, Verify, and Diff. It does not advertise Act because the current live service does not yet provide Map-aware change planning.

Map, Projection, Query, source, Verification, and Diff results include generation- and digest-bound resource links. Tool results are structured JSON plus text where useful, and are bounded to 2 MiB; Map and Query have smaller configurable presentation budgets. archbird_source validates the requested repository-relative path and current bytes against the selected Map generation. Project configuration can come from the repository or a file, but not stdin, because MCP owns stdin.

The transport follows the MCP stdio transport and the tool/resource shapes follow the MCP server specification.

CI and agent workflow

archbird map . --progress always \
  --format json --output .archbird/map.json --check
archbird verify \
  --format sarif --output .archbird/architecture.sarif --check

For agents:

Copy this compact policy into a project’s AGENTS.md, CLAUDE.md, or equivalent agent instructions:

Use Archbird before broad source exploration.

- Start with `archbird map . --view overview --detail standard --max-chars
  12000 --check`.
- When an exact identity is known, use `archbird query . --symbol
  'PATH:SYMBOL' --depth 1 --test-depth 1 --max-chars 12000 --check`.
- When the identity is unknown, use `archbird query . --search 'CONCISE
  REPOSITORY TERMS' --max-chars 12000 --check`. Search is lexical; its ranked
  matches are advisory starting points, not proven semantic edges.
- Read an exact declaration with `archbird query . --symbol 'PATH:SYMBOL'
  --view source --detail standard --max-chars 12000 --check`. Read one complete
  selected file with `archbird query . --path PATH --dump --check`; do not add
  `--max-chars` to `--dump`.
- Use `archbird path SOURCE TARGET --check` for an explicit connection
  question. Only a current, source-evidenced witness is `found`; candidate-only
  or incomplete connectivity remains `unknown`.
- Run `archbird verify --root . --check` before and after architecture-sensitive
  work. Verify is exhaustive; Query may rank, collapse, and bound context.
- Treat static test routes as navigation candidates, not proof that a test ran.
  Use project-owned runner observations for execution evidence.
- Before reusing `.archbird/map.json`, run `archbird freshness --root .
  --snapshot .archbird/map.json --check`.
- Review generated Plans and accepted Acts. Never run `archbird apply` unless
  repository mutation is explicitly authorized and the exact Act was reviewed.
- If Archbird disagrees with source, inspect source directly and report a
  general reproducer; never hide uncertainty or manufacture observed evidence.

For repeated read-only exploration, an MCP-capable agent can launch archbird mcp --root . and use its generation-bound Map, Projection, Query, source, Verify, and Diff tools. Plan, Act, and Apply remain explicit CLI review steps.

Project configuration

Archbird works without config. Add archbird.json when names and boundaries are reviewed project intent. CLI arguments override project config, which overrides versioned discovery defaults.

archbird config show . --pretty
archbird config init . --output archbird.json

config init is a review candidate, not architecture truth.

For monorepos, discovery follows explicit npm/Yarn workspaces and uv [tool.uv.workspace] member patterns (including uv exclusions). It also probes a direct-child Python pyproject.toml only when inventoried Python source exists below that directory. The native resolver requests exact regular manifest files; each request is limited to 256 KiB, with at most 128 npm and 32 Python candidates. config show exposes the request ledger, limits, provenance, and overlap/truncation/conflict diagnostics. Authored project, layers, and packages fields still take precedence over every inferred candidate.

At the repository root, the same bounded request protocol reads at most one setup.cfg and one CMakeLists.txt. Literal setuptools metadata can contribute a source-backed Python package/import root; one literal lexical-root CMake project() call can contribute project identity. Archbird does not evaluate setuptools directives, interpolation, CMake variables, includes, macros, or conditional/function bodies. It distinguishes modules, regular packages, and namespace-package discovery, rejects unsupported include/exclude ambiguity, and rejects a CMake identity if project is redefined or unreachable after a root return(). Rejected identity is omitted from the project model and recorded as a warning: discovery-manifest-invalid for malformed or ambiguous input, and discovery-manifest-identity-unsupported for valid CMake or setup.cfg that this reader cannot resolve statically. npm/PEP 621/setup.cfg/R/ Autoconf identity keeps priority over the CMake fallback; CLI and authored project identity remain authoritative over all of them.

{
  "project": "demo",
  "layers": [
    {
      "name": "core",
      "role": "core",
      "language": "c",
      "globs": ["include/**/*.h", "src/**/*.c"],
      "public_headers": ["include/demo.h"]
    },
    {
      "name": "javascript",
      "role": "frontend",
      "language": "typescript",
      "globs": ["js/src/**/*.ts"]
    }
  ],
  "components": [
    {"name": "native-core", "paths": ["include/**", "src/**"]},
    {"name": "javascript-api", "paths": ["js/src/**"]}
  ]
}

That first file changes only Map construction. Add a reusable exhaustive projection, a named Query, and a constraint when the project is ready to make reviewed architecture policy persistent:

{
  "projections": {
    "public-core-api": {
      "select": "symbols",
      "paths": ["include/demo.h"],
      "public_only": true
    }
  },
  "queries": {
    "public-api-impact": {
      "projection": "public-core-api",
      "direction": "upstream",
      "depth": 1
    }
  },
  "constraints": {
    "CORE-PUBLIC-API": {
      "assert": "required_subset",
      "expected": {"literal": ["demo_close", "demo_open"]},
      "actual": {"projection": "public-core-api"},
      "severity": "error",
      "owner": "core",
      "rationale": "Supported native entrypoints must remain public."
    }
  }
}

These are top-level members of the same archbird.json; the fragment is shown separately to make the progression visible. The complete configuration vocabulary is:

| Section | Purpose | | — | — | | project, description | optional stable project identity and human context | | exclude, discovery | project-level selection and explicit discovery policy | | layers, components | selected source/provider groups and reviewed architecture groupings | | packages, builds, artifacts | manifests, public entrypoints, compilation-database/Autoconf/Make/npm routes, logical outputs and loaders | | bridges | declared/used/implemented ABI, binding, or message surfaces | | tests | static cases, reviewed case routes, and generated-source relations | | named_entries, parity | configured entrypoint protocols and reviewed surface relationships | | indexes | one or more SCIP indexes with prefixes, position encoding, and build variants | | projections, queries, constraints | reusable derivations, saved Query plans, and reviewed architecture policy | | gates | reviewed build or test commands that must pass in Act’s isolated after-state | | limits | bounded Map analysis policy |

Selectors are segment-aware: src/*.c matches immediate children and src/**/*.c is recursive. Components group selected files; they do not discover new source. route_to records broad asserted intent; case_routes is case-specific. Patterns use the pinned archbird-pcre2-v1 contract rather than Python re or JavaScript RegExp.

Zero-config discovery consumes conventional root compile_commands.json and index.scip files when present. Declare multiple compiler outputs explicitly and give each one a stable variant when a repository has CPU, CUDA, Wasm, or other builds:

{
  "builds": [
    {"name": "wasm-db", "kind": "compile_commands", "path": "build/wasm/compile_commands.json", "variant": "wasm"}
  ],
  "indexes": [
    {"name": "wasm-scip", "format": "scip", "path": "build/wasm/index.scip", "variant": "wasm"}
  ]
}

Archbird reads these artifacts; it never invokes the compiler or indexer. Compilation routes retain repository source paths, the compiler basename, and a command digest without publishing absolute build-machine paths. SCIP facts retain their variant, producer, source anchoring, coverage, and freshness.

Map also uses repository-local C/C++ include search paths from compilation databases. It follows compiler search order for each translation unit and propagates that context through the headers reached by its literal includes. Variants must resolve an include to the same selected file; disagreement stays unresolved. Resolved edges cite the repository-relative compilation-database path, while external roots and absolute machine paths remain private. In zero-config mode, a conventional repository include/ match remains useful candidate evidence but does not establish the import. An authored import_roots entry or agreeing compilation-database evidence promotes the same connection to current.

The block above is mirrored by examples/minimal.archbird.json. A complete native/Python/TypeScript/package/build/test example is examples/quickstart.archbird.json. The Draft 2020-12 project-configuration schema is schema/archbird.schema.json. The native configuration compiler is authoritative and additionally enforces relational invariants that standard JSON Schema cannot express, such as min <= max. A shared accepted/rejected corpus keeps the schema and native C, Python, Node, and Wasm compilers aligned for their common contract. Project configuration is unversioned: absent project-model fields inherit discovery, while explicitly present fields replace the corresponding discovered value. Generated Map, ProjectionResult, Query, Verification, and change artifacts each carry an independent schema version and migration schedule; Archbird has no global schema version.

Evidence providers

Archbird stores normalized facts, not parser-specific trees. Several providers can contribute without erasing provenance or blindly unioning contradictions.

Level Evidence Providers
L0 paths, bytes, hashes, manifests, coverage shared C/Wasm core
L1 declarations, calls, test/build/FFI strings portable lexical/protocol providers
L2 syntax, scopes, imports, call shapes, spans, recovery pinned Tree-sitter C, C++, Python, JS, TS/TSX, R
L3 resolved definitions, references, relationships supplied SCIP; CPython AST; TypeScript compiler
L4 behavior and exact runtime hits project-owned observed artifacts

Tree-sitter recovery is fact-local. Semantic indexes retain producer, document coverage, source anchoring, and freshness. Provider conflicts, ambiguity, and unresolved targets remain explicit.

Interchange and command surface

Canonical Archbird JSON is authoritative. Optional inputs/projections are:

Format Direction Role
SCIP input semantic definitions, references, relationships
OKF v0.1 Python input/output; Node library projection browsable knowledge bundle; prose never becomes constraints
graph-view JSON output typed interactive graph
GraphML, Mermaid output graph interchange and bounded diagrams
SARIF, JUnit output Verify/change CI integration
archbird export json --map .archbird/map.json --view components \
  --output .archbird/components.json
archbird export graphml --map .archbird/map.json \
  --output .archbird/architecture.graphml
archbird export mermaid --map .archbird/map.json \
  --output .archbird/architecture.mmd

The command names are:

Python: map, config, query, impact, path, diff, observe, freshness, workspace, verify, plan, act, apply, export, okf, serve, mcp, support.

Node: map, config, query, impact, path, diff, observe, freshness, workspace, verify, plan, act, apply, export, serve, support.

config provides show|init; export provides json|graphml|mermaid and Python additionally provides okf; Python okf provides validate|index|query. Use archbird COMMAND --help for flags. Exit status is 0 for success, 1 when requested --check blocks, and 2 for invalid input/configuration.

Persistent caches are content-addressed and core-validated. Archbird reuses per-file provider facts after a file changes and reuses a materialized complete Map when the configuration, selected source bytes, providers, and core are all unchanged. Both tiers share a 1 GiB default budget; use --cache-max-bytes, ARCHBIRD_CACHE_MAX_BYTES, --cache-dir, or --no-cache to control storage. Cache eviction or write failure never changes canonical analysis output. Concurrent writers use owned atomic temporaries: live or unverifiable writers are preserved, while abandoned same-execution-domain writes are reclaimed when the host has a safe process-liveness probe. The Python host supervises bounded multiprocess CPython-AST worker batches and terminates its workers when a batch does not return within --python-provider-timeout seconds; this execution policy does not enter canonical Map identity.

Guarantees, limits, and distribution

  • Identical selected source, config, provider implementations, and supplied evidence produce byte-identical canonical output under the same Archbird implementation.
  • Archbird performs no analyzed-project import/execution, network call, model call, or agent invocation. Repository mutation occurs only through explicit archbird apply ACT.json; Plan compilation and Act are non-mutating.
  • Lexical/syntax evidence is not whole-program semantic resolution; static test routes are not runtime execution or behavioral coverage.
  • Dynamic dispatch/reflection, C preprocessing, complete Make evaluation, ABI layout, and arbitrary generated code need stronger supplied evidence or remain unknown.
  • PyPI supplies CPython-AST precision and a CPython 3.10 manylinux x86-64 wheel; other supported Python/platform combinations build the included C snapshot.
  • npm requires Node 18, has a Linux x64 glibc prebuild, and otherwise uses bundled Wasm unless native compilation is explicitly requested.
  • Schemas and ABI are pre-1 and can evolve under semantic versioning.

Archbird is licensed under Apache-2.0. The shared core uses pinned yyjson, PCRE2 10.47, Tree-sitter runtime, and grammar submodules under their upstream licenses; source distributions retain the corresponding license files.

Development

Clone the pinned third-party sources together with Archbird:

git clone --recurse-submodules --shallow-submodules \
  https://github.com/zemlyansky/archbird.git
cd archbird

# For an existing clone made without submodules:
git submodule update --init --recursive --depth 1

# Build and test the C core and shared library.
make native-test

# Build the live source frontends against build/libarchbird.so.
make build-py
./archbird map

make build-js
node js/src/cli.js .

# Complete local gates.
make test
make verify
make native-wasm-smoke
make app-test

Native CMake builds and cppcheck use BUILD_JOBS=2 by default so complete gates remain bounded on development hosts without swap. Increase the explicit bound on larger machines, for example make verify BUILD_JOBS=8; outer make -jN controls target scheduling but does not replace this nested-build limit.

Use make editable-install PYTHON=/path/to/python for Python source development and make build-c after C edits. The root submodules are development inputs; PyPI and npm releases contain generated, content-hashed C snapshots and never require Git or submodules at installation time. tools/sync_csrc.py creates those publishable snapshots from the pinned gitlinks; generated snapshots are not a second source of truth.