Overview
vg build maps your source code into a deterministic graph artifact (.vibgrate/graph.json), enabling all downstream code graph queries. Incremental: only re-processes changed files.
Usage
vg build [paths...]
| Flag | Default | Description |
|---|---|---|
[paths...] | . | Folders or files to map |
--only <langs> | — | Restrict to languages (e.g. ts,py,go) |
--exclude <glob> | — | Extra ignore glob (repeatable) |
--jobs <n> | auto | Worker count (1 = single-threaded) |
--scip <file> | auto-detect | Ingest a SCIP index for precise resolution |
--no-scip | — | Ignore any SCIP index |
--no-tsc | — | Skip the TypeScript resolver (heuristic floor only) |
--no-html | — | Do not write graph.html |
--no-report | — | Do not write GRAPH_REPORT.md |
--no-warm | — | Do not warm the semantic index after building |
--grammars <dir> | — | Grammar .wasm directory for offline/air-gapped use |
-o, --export <file> | — | Also write the map to a file (format from extension) |
--attest | — | After the map is written, sign it. See Sign and check the map |
--verify | — | Check an attestation against the map on disk, and run the determinism self-check. Does not sign, and does not replace the map |
--attest-key <path> | $VG_ATTEST_KEY, else .vibgrate/attest-key.pem | Ed25519 private key PEM used by --attest |
--attestation <file> | .vibgrate/attestation.intoto.jsonl | Where --attest writes, and where --verify reads |
--pub <path> | — | Public key PEM that pins the signer for --verify |
Examples
# Map current directory
vg build
# Map specific folders only
vg build src/ lib/
# TypeScript only, single-threaded
vg build --only ts --jobs 1
# Export map to JSON as well
vg build -o map.json
Sign and check the map
There is no vg attest-actions command. Signing and checking are flags on vg build. vg attest and vg verify are retired names. Each exits 5 and prints where the flag moved:
error: `vg attest` has moved to `vg build --attest`
error: `vg verify` has moved to `vg build --verify`
--attest builds the map, writes the usual artifacts, then signs that map. --verify does not take that path. If both flags are set, --verify runs and nothing is signed.
The attestation is a signed statement that this map was produced by this vg version, over this corpus, and (when git can say so) at this commit. A later vg build --verify checks that statement against the map already on disk. It does not decide that the source was reviewed, and it does not certify a build environment.
--attest | --verify | |
|---|---|---|
| Reads | The project tree, then an Ed25519 private key | The attestation file, the map already on disk, and the project tree (the determinism rebuilds). --pub adds a public key PEM |
| Writes | The usual map artifacts, then the attestation file. The first run with no key at the default path also writes the key pair | Nothing. The in-memory rebuilds are not saved over graph.json, and no attestation is written |
--attest writes a one-line DSSE envelope at .vibgrate/attestation.intoto.jsonl. --attestation <file> chooses another path. The payload type is application/vnd.in-toto+json. Inside it is an in-toto Statement (https://in-toto.io/Statement/v1) whose predicate type is https://vibgrate.com/attestation/code-graph/v1. The subject is graph.json. Its sha256 is the canonical map with generatedAt left out, so two builds of the same content share a digest. The signature block also carries the signer's public key, so a later check can test that the bytes were not altered without a separate key file. The same graph and the same Ed25519 key produce the same envelope. No timestamp is written. The default .vibgrate/.gitignore does not list attestation.intoto.jsonl. Commit that file. Do not commit the private key.
The key is read in this order: --attest-key <path>, then VG_ATTEST_KEY, then .vibgrate/attest-key.pem. When nothing names a key and the default path is missing, the first run creates an Ed25519 key there, mode 0600, and writes the public key beside it as .vibgrate/attest-key.pem.pub. It prints:
minted a new Ed25519 signing key at .vibgrate/attest-key.pem (keyid <16 hex chars>) — keep it, add it to .gitignore, and reuse it to re-sign reproducibly
Keep that private key and add it to .gitignore. A key you name with --attest-key or VG_ATTEST_KEY is never created for you.
--verify builds the map in memory to check determinism (two cache-off builds, then one cache-warm build) and does not write those builds over graph.json. The attestation check reads the file and compares it to the map already on disk. It does not rebuild in order to check the signature, and it does not re-read git. --pub <path> pins the signer. Without it, a good signature is integrity only.
JSON status is verified (exit 0), signature-valid (exit 0), or failed (exit 2). verified needs a pinned key, a valid signature, and a statement that was not marked dirty when you signed. The reason signature valid, signer trusted, graph digest matches is the one that compared the map. signature valid, signer trusted means no map was on disk, so the digest was not compared. A missing file at the default path, with no --attestation and no --pub, is not a failure. The command prints the line below, and JSON sets attestation to null.
attestation: none (sign one with `vg build --attest`)
Signing and checking use local Ed25519 only. Nothing is uploaded. While signing, git records the commit, whether the tree was dirty, and the branch name, when those commands work. They do not fetch or push. vg build --attest is still a build: unless you pass --offline or --local, it can download the Architecture module, and an interactive terminal can start an embedding-model download unless you also pass --no-warm, --json, or --quiet. vg build --verify does not install modules.
Sign the map, then check it against the public key written next to the private key:
vg build --attest
vg build --verify --pub .vibgrate/attest-key.pem.pub
With a clean tree at sign time and a matching map, the reason is signature valid, signer trusted, graph digest matches.
Asking to verify a file that is not there fails. From the project root, before any attestation has been written:
vg build --verify --attestation .vibgrate/attestation.intoto.jsonl
error: no attestation at .vibgrate/attestation.intoto.jsonl — sign one with `vg build --attest`
Exit code 3. The path in the message is the path you named.
Exit 3. You passed --attestation, or you passed --pub, and that file is not there. Sign with vg build --attest, or point --attestation at the file you committed.
error: no attestation at <path> — sign one with `vg build --attest`
Not a failed signature. No file is at the default path, and you did not name one. The exit is 0 when the determinism checks pass, and 4 when they do not.
attestation: none (sign one with `vg build --attest`)
Exit 5. --attest-key or VG_ATTEST_KEY names a file that is not there. The default path is created only when you do not name a key.
error: signing key not found: <path>
Exit 5. The file is there but is not a PEM private key.
error: could not read an Ed25519 private key from <path>
Exit 5. The PEM is some other algorithm, or unknown. Use an Ed25519 key.
error: attest requires an Ed25519 key, but <path> is <type>
Exit 2. Read the reason on the line above. A digest mismatch means the map on disk changed after signing: run vg build --attest again with the same key. malformed attestation payload (not a valid in-toto statement) means the envelope parsed but the payload is not an in-toto statement.
A file that is not a JSON line never reaches that reason. Parsing it throws, the process exits 1, and the message is the parser text plus a ref line. --pub is read only after an attestation file is found. A public-key path that is not there is the same exit 1. When the attestation file is also missing, you get the exit 3 line above instead.
error: attestation verification failed
Exit 4. The in-memory rebuilds disagreed, or the toolchain fingerprint does not match the committed map. This exit is reported even when the attestation also failed.
error: determinism self-check failed
Global Options
All graph commands accept: --cwd <dir>, --graph <file>, --json, --quiet, --local, --deep, --no-cache.