Machine formats and JSON reports
01Every command can answer in JSON for scripts and agents. This page lists the documents, their schemas and the envelope fields that every document carries.
vibe list --json --path hello-vibe
{
"ok": true,
"command": "list",
"project": "<TMP>/work/hello-vibe",
"count": 1,
"packages": [
{
"kind": "flow",
"name": "wal",
"version": "1.0.0",
"bridge": false,
"authors": [
"Oleg Chirukhin"
],
"source_url": "file:///<TMP>/registry/org.vibevm.world/wal/v1.0.0",
"content_hash": "sha256:58eccc204df7e63e78e8d15f9416b6fd528e786b74d9e0e5e2fcb859716ea0d0",
"boot_snippet": null,
"files_written": []
}
]
}
One rule for every format
03Anything a foreign parser reads, a report a script parses, a file another language writes, a manifest a browser fetches, is described by a schema and registered in one inventory. The Rust types and the TypeScript types are generated from the schema, never written by hand, so the two sides cannot drift. An unregistered format is not merely discouraged: it cannot be expressed in the type system that writes it.
04 16. JTD + codegen for wire contracts
05 4.1 The format registry.formats/REGISTRY.tomlinventories every surface a foreign parser reads: id, epoch, schema path, recoverable-or-not, independent-parser count, sunset date, golden-corpus path. From it theFormatIdenum is generated, and all wire I/O goes throughwire::publish(FormatId, …)/wire::load(FormatId, …)— an unregistered format is inexpressible in the type system, not merely discouraged. An unnumbered format is a format that will be broken without anyone noticing.
06The schemas are JSON Typedef documents under schemas/ in the source tree. The registry is formats/REGISTRY.toml. For each format it records the epoch, the schema, whether the format can be rebuilt from other state, and how many parsers read it. It also names a corpus of golden documents that a build compares against.
07
A format's policy is computed, not chosen, from
two axes: is it recoverable without a human, and how many independent parsers
exist. Recoverable + one parser → hard gate + silent rebuild (lockfile,
caches). Recoverable + many parsers → epochs, parallel publication, generated
clients, narrow projection (catalog, CLI JSON). Unrecoverable + one parser →
epoch-in-file + codemod (configs). Unrecoverable + many parsers is the worst
quadrant — minimise it, epoch it, migrate it by bot (vibe.toml is the only
resident, and creating a new format in this quadrant requires an explicit
owner decision recorded in the format registry).
The envelope
08A --json document is one JSON object per command, or a stream of objects for commands that report in stages, such as an install. Every object carries ok, the command that produced it, and the report fields the schema names; when the caller identified itself with --invoked-by, the object carries invoked_by, and under --unattended it carries unattended: true.
The documents
| Command | Document | Schema |
|---|---|---|
vibe init --json |
the scaffold report | init_report.jtd.json |
vibe install --json |
the plan, then the report | install_plan.jtd.json, install_report.jtd.json |
vibe update --json |
the update report | update_report.jtd.json |
vibe uninstall --json |
the removal report | uninstall_report.jtd.json |
vibe reinstall --json |
the regeneration report | reinstall_report.jtd.json |
vibe list --json |
the installed packages | list_report.jtd.json |
vibe registry publish --json, vibe registry sync --json |
the publish and sync reports | registry_publish_report.jtd.json, registry_sync_report.jtd.json |
vibe extensions --json, vibe extensions analyze --json |
the extension registry and the lane analysis | extensions_report.jtd.json, extensions_analyze.jtd.json |
the lifecycle verbs with --json |
the plan, the report, the state and the parked tasks | lifecycle_plan.jtd.json, lifecycle_report.jtd.json, lifecycle_state.jtd.json, lifecycle_tasks.jtd.json |
vibe deploy, vibe deployments --json |
the deploy intent, the receipts, the inverse plan and the checkpoints | deploy_intent.jtd.json, deploy_receipt.jtd.json |
vibe requirements --json |
the requirements report | requirements_report.jtd.json |
vibe tree --json |
the package tree | a JSON Schema document, package-tree.schema.v1.json |
vibe doc manifest --json, vibe doc todo --format json, vibe doc surface --record |
the page manifest of a documentation package, the maintenance queue, the surface snapshot of a version and the diff of two | doc_manifest.jtd.json, doc_todo.jtd.json, doc_surface.jtd.json, doc_surface_diff.jtd.json |
10The fields of every schema in the table, generated from the schema files in the order above:
11The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"init"` for this report. |
| `project` | yes | string | |
| `path` | yes | string | Forward-slash-normalised display path of the initialised directory. |
| `created` | yes | uint32 | Number of files freshly created. |
| `kept` | yes | uint32 | Number of files left untouched because they already existed (idempotency). |
| `outcomes` | yes | list of `outcome` | Required member: an idempotent init that touched nothing writes `[]`, never an absent key — omitting a required collection would produce a document invalid by this same schema (rule R21). |
`outcome`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `path` | yes | string | Forward-slash-normalised path relative to the project root. |
| `action` | yes | `outcome_action` | |
| `reason` | yes | string | Human-readable label like "agent redirect" or "boot: project foundation". |
12The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `command` | yes | string | Always `"install:plan"` for this report. |
| `plans` | yes | list of `plan_entry` | Required member: a plan with no entries writes `[]`, never an absent key — omitting a required collection would produce a document invalid by this same schema (rule R21). |
`plan_entry`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `package` | yes | string | `<kind>:<name>` (no version). |
| `version` | yes | string | Resolved exact version, e.g. `"0.1.0"`. |
| `source_url` | yes | string | URL the content was fetched from. Per PROP-002 §2.1 this is informational — identity is the content_hash. |
| `content_hash` | yes | string | `sha256:<hex>` over the package tree. The identity of the install. |
| `writes` | yes | list of string | Forward-slash-normalised relative paths the install would create. Required member: an entry that would write nothing still writes `writes` as `[]` — omitting a required collection would produce a document invalid by this same schema (rule R21). |
| `boot_snippet` | no | string | Filename of the boot snippet this package contributes, when one is present. |
13The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"install"` for this report. |
| `project` | yes | string | |
| `materialised` | yes | list of string | Dependency-slot paths materialised this run — a directory each, never counted as files. Excludes any slot a rollback removed. |
| `skipped` | yes | list of string | Slot paths already present for the resolved version and source identity, trusted without materialising. |
| `pruned` | yes | list of string | Slot paths removed — present before, absent from this resolution. |
| `nodes_regenerated` | yes | list of string | Workspace-relative path of every node whose boot artifacts were regenerated. |
| `complete` | yes | boolean | True when this invocation ran to completion. False when it stopped part-way — the slot sets above are then a partial, boundary-measured record, never a final one. |
| `unchanged` | yes | boolean | True on the PROP-011 §2.2 fast path: `vibe.lock` was already fresh, so no resolution ran and no slot moved. |
| `delegation` | no | `install_delegation` | Present exactly when a hosted `agent` contribution parked this install. The install stopped there and `ok` stays true — a park is a durable handoff, not a failure — while `complete` records whether the apply had finished first. |
| `hooks` | no | list of `install_hook_report` | Install-hook reports (PROP-020 §2.1), pre-install first then post-install, so a skipped or flagged hook is never silent. |
| `contributions` | no | list of `install_contribution_report` | Lifecycle contributions this command itself ran — slot-scoped rows from the install barrier and the `phase:install` ritual. `vibe install` is the outermost command on these paths and therefore the only one that reports them; a phase verb whose prerequisite install runs them reports them in its own lifecycle report instead. |
| `notices` | no | list of string | Lifecycle notices raised while planning the ritual this command ran — an ignored auto-compile row, a selector that matched nothing. Surfaced on the outermost command's own report so a notice is never lost with the per-row echo that used to carry it. |
| `trace` | no | `compile_trace_report` | The shared compile-trace member (PROP-054 `##OBS-TRACE`, R3.4): present exactly when this command ran with compile tracing enabled; disabled old JSON omits it and remains readable. |
`install_delegation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `run_id` | yes | string | The durable run identity the hosting agent resumes under. |
| `tasks` | yes | list of string | Ordered project-relative outbox task files awaiting the hosting agent. |
| `resume` | yes | string | The exact command that resumes this run. |
`install_slot_target`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `group` | yes | string | |
| `name` | yes | string | |
| `version` | yes | string | |
| `kind` | yes | string | |
| `root` | yes | string | |
`install_hook_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `phase` | yes | string | |
| `status` | yes | string | |
| `note` | no | string | |
`install_contribution_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `key` | yes | string | |
| `phase` | yes | string | |
| `point` | yes | string | |
| `handler` | yes | string | |
| `provider` | yes | string | |
| `tier` | yes | string | |
| `status` | yes | string | |
| `message` | no | string | |
| `version` | no | string | |
| `reference` | no | string | |
| `flagged` | no | boolean | A soft post-install failure: reported and surfaced, but not fatal to a durable install. |
| `stdout` | no | string | |
| `stderr` | no | string | |
| `stdout_truncated` | no | boolean | |
| `stderr_truncated` | no | boolean | |
| `slot_target` | no | `install_slot_target` | The materialised slot this row executed against. |
14The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"update"` for this report. |
| `project` | yes | string | |
| `scope` | yes | one of `all`, `scoped` | `all` is the whole-workspace update; `scoped` names one or more packages. |
| `packages` | yes | list of string | The package coordinates this invocation targeted. Empty for `all`. |
| `packages_resolved` | yes | uint32 | How many packages this update re-resolved. |
| `version_bumps` | yes | list of string | One line per package whose locked version moved. |
| `materialised` | yes | list of string | Dependency-slot paths materialised this run — a directory each, never counted as files. Excludes any slot a rollback removed. |
| `skipped` | yes | list of string | Slot paths already present for the resolved version and source identity, trusted without materialising. |
| `pruned` | yes | list of string | Slot paths removed — present before, absent from this resolution. |
| `nodes_regenerated` | yes | list of string | Workspace-relative path of every node whose boot artifacts were regenerated. |
| `complete` | yes | boolean | True when this invocation ran to completion. False when it stopped part-way — the slot sets above are then a partial, boundary-measured record, never a final one. |
| `unchanged` | yes | boolean | True on the PROP-011 §2.2 fast path: `vibe.lock` was already fresh, so no resolution ran and no slot moved. |
| `delegation` | no | `update_delegation` | Present exactly when a hosted `agent` contribution parked this update. `ok` stays true; `resume` is the update command, never `vibe install`. |
| `hooks` | no | list of `update_hook_report` | Install-hook reports for this run. Emitted even when empty: the pre-R7.3 document carried this member unconditionally and consumers key on it. |
| `contributions` | no | list of `update_contribution_report` | Slot-scoped lifecycle rows this command itself ran. This command is the outermost one on its path and therefore the only one that reports them. |
| `trace` | no | `compile_trace_report` | The shared compile-trace member (PROP-054 `##OBS-TRACE`, R3.4): present exactly when this command ran with compile tracing enabled; disabled old JSON omits it and remains readable. |
`update_delegation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `run_id` | yes | string | |
| `tasks` | yes | list of string | |
| `resume` | yes | string | |
`update_hook_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `phase` | yes | string | |
| `status` | yes | string | |
| `note` | no | string | |
`update_contribution_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `key` | yes | string | |
| `phase` | yes | string | |
| `point` | yes | string | |
| `handler` | yes | string | |
| `provider` | yes | string | |
| `tier` | yes | string | |
| `status` | yes | string | |
| `message` | no | string | |
| `version` | no | string | |
| `reference` | no | string | |
| `flagged` | no | boolean | |
| `stdout` | no | string | |
| `stderr` | no | string | |
15The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"uninstall"` for this report. |
| `package` | yes | string | `<kind>:<name>` of the package that was removed. |
| `version` | yes | string | |
| `removed_count` | yes | uint32 | |
| `paths` | yes | list of string | Forward-slash-normalised paths of every file removed. User-owned paths (e.g. `spec/boot/00-core.md`, `spec/boot/90-user.md`, `spec/WAL.md`) are filtered out at plan-time and never appear here. Required member: a removal that took nothing still writes `paths` as `[]` — omitting a required collection would produce a document invalid by this same schema (rule R21). |
16The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"reinstall"` for this report. |
| `project` | yes | string | |
| `forced` | yes | boolean | Whether `--force` re-fetched from source. MATERIALISATION force only: it is not the generic lifecycle `force` that mints a fresh run id and reparks a hosted row. |
| `materialised` | yes | list of string | Dependency-slot paths materialised this run — a directory each, never counted as files. Excludes any slot a rollback removed. |
| `skipped` | yes | list of string | Slot paths already present for the resolved version and source identity, trusted without materialising. |
| `pruned` | yes | list of string | Slot paths removed — present before, absent from this resolution. |
| `nodes_regenerated` | yes | list of string | Workspace-relative path of every node whose boot artifacts were regenerated. |
| `complete` | yes | boolean | True when this invocation ran to completion. False when it stopped part-way — the slot sets above are then a partial, boundary-measured record, never a final one. |
| `unchanged` | yes | boolean | True on the PROP-011 §2.2 fast path: `vibe.lock` was already fresh, so no resolution ran and no slot moved. |
| `delegation` | no | `reinstall_delegation` | Present exactly when a hosted `agent` contribution parked this reinstall. `ok` stays true; `resume` is a reinstall command that can actually service the continuation. |
| `hooks` | no | list of `reinstall_hook_report` | Install-hook reports for this run. Emitted even when empty: the pre-R7.3 document carried this member unconditionally and consumers key on it. |
| `contributions` | no | list of `reinstall_contribution_report` | Slot-scoped lifecycle rows this command itself ran. This command is the outermost one on its path and therefore the only one that reports them. |
| `trace` | no | `compile_trace_report` | The shared compile-trace member (PROP-054 `##OBS-TRACE`, R3.4): present exactly when this command ran with compile tracing enabled; disabled old JSON omits it and remains readable. |
`reinstall_delegation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `run_id` | yes | string | |
| `tasks` | yes | list of string | |
| `resume` | yes | string | |
`reinstall_hook_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `phase` | yes | string | |
| `status` | yes | string | |
| `note` | no | string | |
`reinstall_contribution_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `key` | yes | string | |
| `phase` | yes | string | |
| `point` | yes | string | |
| `handler` | yes | string | |
| `provider` | yes | string | |
| `tier` | yes | string | |
| `status` | yes | string | |
| `message` | no | string | |
| `version` | no | string | |
| `reference` | no | string | |
| `flagged` | no | boolean | |
| `stdout` | no | string | |
| `stderr` | no | string | |
17The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"list"` for this report. |
| `project` | yes | string | |
| `count` | yes | uint32 | |
| `packages` | yes | list of `list_entry` | Required member: an empty project lists `[]` packages, never an absent key — omitting a required collection would produce a document invalid by this same schema (rule R21). |
`list_entry`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `kind` | yes | `package_kind` | |
| `name` | yes | string | |
| `version` | yes | string | |
| `source_url` | yes | string | |
| `content_hash` | yes | string | |
| `boot_snippet` | yes | string or null | Filename of the package's boot snippet under `spec/boot/`, or null if absent. |
| `files_written` | yes | list of string | Required member: an entry always writes `files_written`, `[]` when the install wrote no files — omitting a required collection would produce a document invalid by this same schema (rule R21). |
| `registry` | no | string | `[[registry]].name` from `vibe.toml` that served this package. Absent for `--registry <path>` and legacy installs. |
| `source_ref` | no | string | Git ref the content was fetched at — typically `v<version>`. Absent for non-git sources. |
| `resolved_commit` | no | string | Commit hash the ref resolved to. Reserved for resolver-aware installs. |
| `overridden` | no | boolean | True iff this package was resolved through a `[[override]]` entry in `vibe.toml`. PROP-044 §2b rules the boolean axis two-part with no third state, so an absent key means `false` — exactly how the hand-written twin already serialises it. |
18The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"registry:publish"` for this report. |
| `host` | yes | string | Human-readable host name from the `RepoCreator` adapter — e.g. `"gitverse.ru"`. |
| `org_url` | yes | string | Organization-root URL the package was published under, as recorded in `vibe.toml`'s `[[registry]].url`. |
| `repo_name` | yes | string | Repository name under the org, derived from the registry's `naming` convention. For default `kind-name` naming this is `<kind>-<name>`. |
| `repo_url` | yes | string | Clone URL of the per-package repository — what consumers' lockfile `source_url` would record. |
| `tag` | yes | string | The tag pushed for this release — typically `v<semver>`. |
| `created_repo` | yes | boolean | True iff this run created the repository (it didn't exist before). False iff the repo was reused — typical when re-publishing additional versions. |
| `dry_run` | yes | boolean | True iff `--dry-run` was passed. When true, no API calls or pushes were made; the report describes the planned action. |
19The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"registry:sync"` for this report. |
| `refreshed` | yes | list of `refreshed_entry` | Required member: a sync that refreshed nothing writes `[]`, never an absent key — omitting a required collection would produce a document invalid by this same schema (rule R21). |
| `skipped` | yes | list of `skipped_entry` | Required member: a sync that skipped nothing writes `[]`, never an absent key — omitting a required collection would produce a document invalid by this same schema (rule R21). |
`refreshed_entry`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `kind` | yes | `package_kind` | |
| `name` | yes | string | |
| `via` | yes | string | Either `registry:<name>` or `override`. |
| `ref` | yes | string | Git ref the clone was refreshed against — typically `v<version>` or a branch name for overrides. |
`skipped_entry`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `kind` | yes | `package_kind` | |
| `name` | yes | string | |
| `reason` | yes | string | |
20The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | |
| `project` | yes | `project` | |
| `selector_subject` | yes | `selector_subject` | |
| `count` | yes | uint32 | |
| `effective_count` | yes | uint32 | |
| `declarations` | yes | list of `extension_entry` | |
| `notices` | yes | list of string | |
`project`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `root` | yes | string | |
| `identity` | yes | string | |
| `version` | yes | string | |
| `manifest_kind` | yes | `manifest_kind` | |
| `effective_stack` | yes | string or null | |
`selector_subject`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `kind` | yes | one of `unscoped` | |
| `package` | yes | string or null | |
| `path` | yes | string or null | |
`extension_entry`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `sequence` | yes | uint32 | |
| `key` | yes | string | |
| `id` | yes | string | |
| `point` | yes | string | |
| `provider` | yes | `provider` | |
| `handler` | yes | `handler` | |
| `authored_config` | yes | `json_map` or null | |
| `effective_config` | yes | `json_map` or null | |
| `authored_auto` | yes | boolean or null | |
| `auto` | yes | boolean | |
| `activated` | yes | boolean | |
| `disabled` | yes | boolean | |
| `compiler_internals` | yes | boolean | |
| `inputs` | yes | `string_list` or null | |
| `applies_to` | yes | `applies_to` or null | |
| `selector_matches` | yes | boolean | |
| `pass` | yes | `pass` or null | |
| `when` | yes | `json_map` or null | |
| `natural_tier` | yes | `tier` | |
| `tier` | yes | `tier` | |
| `state` | yes | `state` | |
| `effective` | yes | boolean | |
| `native` | yes | `native_observation` or null | |
| `order` | yes | `order` | |
`provider`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `source` | yes | one of `dependency`, `host` | |
| `identity` | yes | string | |
| `version` | yes | string | |
| `kind` | yes | `package_kind` or null | |
| `root` | yes | string or null | |
| `content_hash` | yes | string or null | |
`applies_to`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `packages` | yes | `string_list` or null | |
| `paths` | yes | `string_list` or null | |
`pass`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `kind` | yes | `pass_kind` | |
| `level` | yes | `ir_level` or null | |
| `from` | yes | `ir_level` or null | |
| `to` | yes | `ir_level` or null | |
| `after` | yes | string or null | |
| `before` | yes | string or null | |
| `replace` | yes | string or null | |
| `formats` | yes | `string_list` or null | |
| `artifact` | yes | string or null | |
`native_observation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `artifact_path` | yes | string or null | |
| `build_state` | yes | string | |
| `content_hash` | yes | string or null | |
`order`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `provider` | yes | uint32 or null | |
| `declaration` | yes | uint32 | |
| `activation` | yes | uint32 or null | |
21The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema` | yes | uint32 | Report schema epoch; 1 in epoch 1. The behaviour cell refuses every other value, so a newer report fails loudly instead of parsing into a wrong meaning. |
| `command` | yes | string | The command identity that produced this report — `extensions-analyze`. Validated non-blank and control-free by the behaviour cell. |
| `artifacts` | yes | list of `artifact_row` | One row per compiled artifact, in compile order. A node with no static-lane contributions compiles nothing and emits the empty list — the honest answer, not an error. |
`byte_pair`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `before` | yes | `byte_count` | The byte count the pass received. |
| `after` | yes | `byte_count` | The byte count the pass returned. |
`contribution_row`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `provider` | yes | `provider_identity` | The typed provider the bytes are attributed to. |
| `kind` | yes | `contribution_kind` | Which of the four lane-contribution kinds this row is. |
| `origin` | yes | string | The contribution's display provenance (`ContributionMeta.origin`) — a node rel path or a `<group>/<name>` package coordinate, possibly with a `[shared by …]` suffix. DISPLAY only; identity lives in `provider`. Non-blank, control-free; validated by the behaviour cell. |
| `path` | yes | string | The contribution's declared path (`ContributionMeta.path`), workspace-relative and forward-slashed. The path the declaring row named, which may legitimately differ from any address' own path. |
| `bytes` | yes | `byte_count` | The emitted bytes this contribution's own material occupies — its chunk-stream (or prepared-document) rendering, trailing separator whitespace excluded. `0` for an `elided` contribution (its marker is frame) and the `#use` reference text's length for a `hoisted` one. |
| `occurrences` | yes | uint32 | How many occurrences of this contribution the lane brackets (`0` for `elided` and `hoisted`, `1` for `simple`, the occurrence count of the compiled closure for `normal`). |
`delta_row`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `pass` | yes | string | The schedule pass name (`transform:lane:<key>`, `transform:emitted:<key>`). Non-blank, control-free; validated by the behaviour cell. |
| `stage` | yes | `stage` | Which stage the pass ran at. |
| `lane_byte_delta` | yes | `byte_pair` or null | The lane's chunk-stream byte count before and after a `lane`-stage pass. Null on every other stage. |
| `artifact_byte_delta` | yes | `byte_pair` or null | The emitted artifact's byte count before and after an `emitted`-stage pass. Null on every other stage. The chain of these pairs reconciles: each `before` is the previous `after`, and the last `after` is the artifact's `total_emitted_bytes`. |
`artifact_row`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `lane` | yes | `lane_identity` | Which lane owner's artifact this row describes. |
| `artifact_id` | yes | string | The artifact id (`static-md`, `static-xml`) — for a builtin static lane, the same identity the target names. Validated against the artifact/target vocabulary by the behaviour cell: an id its target disclaims names nothing. |
| `target` | yes | `artifact_target` | The artifact's compile target. |
| `total_emitted_bytes` | yes | `byte_count` | The artifact's emitted byte count — the exact length of the tape the compile produced. |
| `occurrence_count` | yes | uint32 | How many contribution occurrences the lane brackets — the sum of the row's contribution occurrences. |
| `frame_overhead_bytes` | yes | `byte_count` | The bytes no contribution owns: the prologue (header, resolution preamble, renames tombstone), the per-contribution markers and every separator. The complement of the contributions inside the total — reconciliation is the law, not an aspiration. |
| `contributions` | yes | list of `contribution_row` | The attribution rows, in lane order (the effective-boot order the plan declared). |
| `deltas` | yes | list of `delta_row` | The transform passes that ran for this artifact, in application order. Empty when the owner plan is empty — every owner in a tree that activates nothing compiles the exact historical schedule, and an empty list is that statement. |
| `token_estimate` | yes | uint32 or null | The artifact's estimated token count. Present ONLY beside a non-null `estimator_id`; this epoch ships no estimator, so every row the CLI produces spells this member null. A report that carries an estimate without naming its estimator is refused by the behaviour cell — a number with no named method is not an estimate, it is a rumor. |
| `estimator_id` | yes | string or null | The estimator that produced `token_estimate` — an explicit identity, never an implicit heuristic. Null exactly when `token_estimate` is null. |
22The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `command` | yes | string | |
| `requested` | yes | string | |
| `chain` | yes | list of string | |
| `contributions` | yes | list of `planned_contribution` | |
| `notices` | yes | list of string | |
`planned_contribution`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `key` | yes | string | |
| `phase` | yes | string | |
| `point` | yes | string | |
| `handler` | yes | string | |
| `provider` | yes | string | |
| `tier` | yes | string | |
| `reference` | no | string | Authored source reference for a synthetic or translated lifecycle contribution. |
| `slot_target` | no | `slot_target` | Package slot whose pre/post-install timing event this contribution targets. |
| `version` | no | string | |
`slot_target`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `group` | yes | string | |
| `name` | yes | string | |
| `version` | yes | string | |
| `kind` | yes | string | |
| `root` | yes | string | |
23The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `ok` | yes | boolean | |
| `command` | yes | string | Always `"lifecycle"` for this report. |
| `requested` | yes | string | The exact default-lifecycle phase requested by the user. |
| `chain` | yes | list of string | The REQUESTED full chain: every phase spelling this invocation set out to run, in order, including a leading `clean` when the clean lifecycle was composed. It does not shrink when the run stops early. |
| `steps` | yes | list of `lifecycle_step_report` | The ACTUALLY EXECUTED prefix of `chain`, in the same order — one outcome per phase that ran. A completed run reports every phase in `chain`; a run that parked for a hosting agent ends at the phase whose status is `delegated`, and the phases after it are absent because they did not run. |
| `contributions` | yes | list of `lifecycle_contribution_report` | Effective lifecycle contributions in canonical execution order with their execution outcomes. |
| `notices` | yes | list of string | Non-fatal collection notices that must remain observable in structured output. |
| `delegation` | no | `lifecycle_delegation` | Present exactly when the invocation parked an agent execution for the hosting agent. Human/quiet rendering consumes the same value as the typed member. |
| `trace` | no | `compile_trace_report` | The shared compile-trace member (PROP-054 `##OBS-TRACE`, R3.4): present exactly when this command ran with compile tracing enabled; disabled old JSON omits it and remains readable. |
| `verification` | no | `verification_evidence` | The shared verification-evidence member (PROP-054 §14.7, `##EVIDENCE-WIRE-AND-SURFACES`, R7.5): present exactly when the verify phase reached engine-owned evidence reconciliation — INCLUDING the `stale`, `missing` and `unstable` outcomes, which are the reason the member exists. Reports from earlier phases and every pre-R7.5 document omit it and remain byte-shape compatible. It is a separate axis from this report's own `ok`: a matched identity can sit beside a failed verify contribution, and neither rewrites the other. |
`lifecycle_contribution_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `key` | yes | string | |
| `phase` | yes | string | |
| `point` | yes | string | |
| `handler` | yes | string | |
| `provider` | yes | string | |
| `tier` | yes | string | |
| `status` | yes | string | Honest handler outcome such as `ok`, `fail`, or `skip`. |
| `flagged` | no | boolean | True when a durable operation completed but this contribution left it requiring attention. |
| `message` | no | string | Structured handler message. Human mode may render it; JSON mode never leaks it outside this document. |
| `reference` | no | string | Authored source reference for a synthetic or translated lifecycle contribution. |
| `slot_target` | no | `slot_target` | Package slot whose pre/post-install timing event this contribution targeted. |
| `stdout` | no | string | Bounded UTF-8 lossy capture of script stdout for structured lifecycle reports, at most 1 MiB. Binary stdout is the reply protocol and is never stored here. |
| `stderr` | no | string | Bounded UTF-8 lossy capture of handler stderr for structured lifecycle reports, at most 1 MiB. |
| `stdout_truncated` | no | boolean | True when stdout exceeded the 1 MiB structured-report bound and was truncated. |
| `stderr_truncated` | no | boolean | True when stderr exceeded the 1 MiB structured-report bound and was truncated. |
| `version` | no | string | |
`slot_target`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `group` | yes | string | |
| `name` | yes | string | |
| `version` | yes | string | |
| `kind` | yes | string | |
| `root` | yes | string | |
`lifecycle_step_report`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `phase` | yes | string | |
| `status` | yes | string | Phase outcome vocabulary. R2.4 writes `ok`, `fresh`, or `no-op`; the first handler failure aborts the chain. R7.3 adds `delegated`: the chain parked at this phase and later phases did not run. |
`lifecycle_delegation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `run_id` | yes | string | The durable run identity the hosting agent resumes under. |
| `tasks` | yes | list of string | Ordered project-relative outbox task files awaiting the hosting agent. |
| `resume` | yes | string | The exact command that resumes this run (`vibe <requested-phase>`). |
24The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema` | yes | uint32 | |
| `run` | yes | `state_run` | |
| `execution` | yes | map of `execution_record` | |
`state_run`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `requested` | yes | string | |
| `chain` | yes | list of string | |
| `started` | yes | string | |
| `run_id` | no | string | Durable identity of the run that wrote this state — 32 lowercase hex. Every post-R7.3 begin carries it, for EVERY invocation and not only a delegated one; the old wording ("present whenever any row is delegated") described a narrower writer than the one that shipped and would have licensed a fresh run with no id at all. Absent only in pre-R7.3 files, and such a file is readable exactly where no ownership claim depends on the id — a delegated row, or an evidence measurement attributing itself to a run, needs it and refuses without it. |
| `selected` | no | string | Portable workspace-relative RelPath ("." or member rel) of the selected node that authored the run. Written by every post-A6 begin; required with any delegated row by the later semantic validator; absent only in legacy/pre-A6 state with no delegated row. |
| `slot_continuation` | no | `slot_continuation` | The unfinished slot-lifecycle continuation this run owes, recorded BEFORE the first pre-install callback and cleared when the slot run completes. Present only while a slot-scoped row is delegated; absent in every pre-R7.3 file and after completion. |
| `compile_trace` | no | boolean | Whether this run compiles with the trace observer enabled — the STICKY activation bit (PROP-054 `##OBS-TRACE`, R3.4). Written with the effective value (current request OR, on adoption, this persisted bit), so a resume keeps tracing even when the original one-shot flag is absent and the manifest changed meanwhile. Absent in pre-R3.4 files and reads false. |
`slot_continuation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `targets` | yes | list of `slot_target_record` | The exact ordered payload-event target set — the same set the one-shot post-install plan consumes. |
`slot_target_record`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `group` | yes | string | |
| `name` | yes | string | |
| `version` | yes | string | |
`execution_record`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `phase` | yes | string | |
| `fingerprint` | yes | string | |
| `status` | yes | one of `ok`, `fail`, `skip`, `fresh`, `delegated` | |
| `duration_ms` | yes | uint32 | |
| `artifacts` | yes | list of `state_artifact` | |
| `tasks` | no | list of string | Project-relative outbox task files this delegated row published. Absent/empty for every non-delegated status. |
| `scope` | no | one of `phase`, `slot` | Which plan a delegated row belongs to, recorded by the engine rather than inferred by parsing the execution key or a task filename. `phase` rows are reconciled against the current phase plan, `slot` rows against the current slot plan. Absent for non-delegated rows and in pre-R7.3 files. |
| `input_measurement` | no | `state_input_measurement` | The declared-input measurement this execution produced (PROP-054 `##EVIDENCE-SCOPE-IS-DECLARED`, R7.5): the durable half of a later verification claim, checkpointed in the SAME state transaction as the record it sits in — no second `.vibe/evidence.*` file, no second crash window. Absent for every pre-R7.5 file, for an execution that declares no `inputs` (which is typed `unavailable` at verify, never a digest of the empty set), and for every row written before the measuring writer lands. |
`state_artifact`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `id` | yes | string | |
| `path` | yes | string | |
| `kind` | yes | string | |
| `witness` | no | `state_digest_witness` | The content witness recorded when this artifact was produced or fresh-probed (PROP-054 `##EVIDENCE-ARTIFACT-WITNESS`). Absent for every pre-R7.5 row and for any output whose witness was refused — a non-regular, linked, aliased, escaping or moving path — and such an artifact is `unavailable` at verify rather than a silent pass. |
| `measured_run_id` | no | string | The run that produced `witness` — 32 lowercase hex, the run header's own id at the moment of measurement. Recorded beside the witness so a resume under a new run id can still say WHICH run measured this artifact instead of inheriting the claim silently. |
`state_input_measurement`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `execution` | yes | string | |
| `phase` | yes | string | |
| `declaration_fingerprint` | yes | string | `sha256:` followed by 64 lowercase hex over the execution's declaration — the sibling of the manifest digest below, never its alias (R7.5 architecture §1.2). |
| `patterns` | yes | list of string | The declared project-relative glob patterns, verbatim and in declaration order. Explicit even when empty: an authored empty list is a complete empty declared scope, and it stays distinguishable from an ABSENT declaration, which never produces a measurement at all. |
| `measured_run_id` | yes | string | The run that took this measurement — 32 lowercase hex. Required: a measurement that cannot name its run is not evidence, and every post-R7.3 begin carries a run id for every invocation. |
| `witness` | yes | `state_digest_witness` | The canonical manifest witness over exactly the files those patterns selected. |
`state_digest_witness`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `algorithm` | yes | string | The domain-separated algorithm name (`sha256:vibe-input-manifest-v1`, `sha256:file-v1`, `sha256:tree-v1`). |
| `digest` | yes | string | `sha256:` followed by 64 lowercase hex over the algorithm's declared scope. |
| `files` | no | uint32 | How many regular files entered the manifest — present for the manifest form, absent for the artifact forms that count nothing. |
| `bytes` | no | string | How many content bytes entered the manifest — a CANONICAL unsigned decimal string, exactly as the shared `digest_witness` fragment spells it. JTD has no `uint64` and a declared input set may exceed 4 GiB, so the count is never narrowed on either side of this wire. Present exactly where `files` is. |
25The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema` | yes | uint32 | Epoch-1 schema number; `1` today. |
| `status` | yes | one of `absent`, `idle`, `parked` | The durable handoff verdict over `.vibe/lifecycle.toml`. `absent` means no state file exists and is the ONLY status that omits `run`; `idle` means valid state with no delegated row — it carries `run` and an empty `tasks`; `parked` means valid state with delegated rows — it carries `run`, a valid run id and a nonempty `tasks`. This status ↔ run/tasks/run-id relation is enforced in Rust over the generated types (the corpus behavior cell): JTD cannot express it. |
| `tasks` | yes | list of `pending_task` | One row per typed `delegated` execution, ordered by the durable chain's phase order with the execution key as tie-break — never by directory enumeration or filename parsing. Emitted even when empty (`absent`, `idle`). |
| `run` | no | `tasks_run` | The state file's run header, carried for both `idle` and `parked`; only `absent` omits it. |
`tasks_run`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `requested` | yes | string | The exact default-lifecycle phase the run requested. |
| `chain` | yes | list of string | The run's full requested phase chain, in order. |
| `started` | yes | string | The run's start timestamp. |
| `run_id` | no | string | The durable 32-lowercase-hex run identity the outbox tasks live under. `parked` requires it (relationally checked in Rust, not expressible in JTD); a state no run delegated may omit it. |
| `selected` | no | string | The canonical forward-slashed workspace-relative selected-node identity (`.` for the workspace root) — it names the node root that interprets `tasks[].path`. Optional only so readable legacy idle state (pre-R7.4 files without it) still parses; every new write carries it, and `parked` requires it (relationally checked in Rust). |
`pending_task`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `execution` | yes | string | The delegated row's execution key, verbatim from state. |
| `phase` | yes | string | The phase whose plan delegated this row. |
| `scope` | yes | one of `phase`, `slot` | Which plan owns the park — recorded by the engine, never inferred by parsing the execution key or a task filename. |
| `path` | yes | string | The validated state-owned outbox task path — the one file `(run id, execution key)` deterministically owns. It is carried relative to the SELECTED NODE root and interpreted against it (`selected` names that root): the spelling is the unchanged `.vibe/agentic/outbox/<run>/<task>` rel for every member, root or not — never re-spelled with `..` segments, never made absolute, and never relative to the workspace state root. |
| `document` | yes | string | The exact bounded UTF-8 task document — frontmatter with the ordered output contract plus the verbatim system/request prose. Never reparsed outputs or a second DTO. |
26The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema` | yes | uint32 | Record schema epoch; 1 in epoch 1. The behaviour cell refuses every other value, so a newer journal fails loudly instead of parsing into a wrong meaning. |
| `plan_hash` | yes | string | The hash of the plan this intent executes — exactly 64 lowercase hex, no `sha256:` prefix; validated by the behaviour cell. Recovery joins an intent to its receipt through this hash. |
| `target` | yes | `deploy_target_identity` | The full identity of the deploy target the plan selected: project, optional package, profile, target id and generation. |
| `resources` | yes | list of `planned_resource` | Every resource the plan intends to touch, with its desired digest — the exact set recovery compares against, so an empty list is an explicit statement (a plan that touches nothing), never an omission. |
| `started_at` | yes | `rfc3339_timestamp` | When the intent was written. |
| `prior_generation` | no | uint32 | The generation of the prior receipt this deploy supersedes; absent for a first deployment with no prior receipt. |
`deploy_target_identity`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `project` | yes | string | The project identity; non-blank and control-free; validated by the behaviour cell. |
| `profile` | yes | string | The profile name that selected the target — backend-id grammar `[a-z0-9][a-z0-9._-]{0,63}`; validated by the behaviour cell. |
| `target` | yes | string | The deploy target id — backend-id grammar; validated by the behaviour cell. |
| `generation` | yes | uint32 | The generation this intent deploys; 0 is a legal first generation. |
| `package` | no | string | The package identity when the deploy comes from one package rather than the host project; non-blank; validated by the behaviour cell. |
`planned_resource`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `resource` | yes | string | The resource identity — an owned path or a named resource; non-blank and control-free; validated by the behaviour cell. |
| `desired_digest` | yes | string | The digest the plan wants this resource at — exactly 64 lowercase hex; validated by the behaviour cell. |
| `prior_digest` | no | string | The digest the prior receipt recorded for this resource — exactly 64 lowercase hex; validated by the behaviour cell. Recovery accepts a resource at either digest; a third digest means concurrent mutation and a refusal. |
27The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema` | yes | uint32 | Record schema epoch; 1 in epoch 1. The behaviour cell refuses every other value, so a newer receipt fails loudly instead of parsing into a wrong meaning. |
| `identity` | yes | `deploy_identity` | The project (and optional package) identity the deployment belongs to. |
| `profile` | yes | string | The profile name that selected the target — backend-id grammar `[a-z0-9][a-z0-9._-]{0,63}`; validated by the behaviour cell. |
| `target` | yes | string | The deploy target id — backend-id grammar; validated by the behaviour cell. |
| `generation` | yes | uint32 | The generation of this target the receipt finalises; the prior generation lives in the intent journal. |
| `artifact_digest` | yes | string | The digest of the deployed artifact — exactly 64 lowercase hex, no `sha256:` prefix (one digest spelling across the three R8A2 records); validated by the behaviour cell. |
| `provider` | yes | `provider_identity` | The exact mechanism provider identity that applied the deployment. |
| `desired_config_digest` | yes | string | The digest of the desired config the deployment reconciled to — exactly 64 lowercase hex; validated by the behaviour cell. |
| `scope` | yes | `destination_scope` | The destination scope — explicit, never inferred: privilege and blast radius read from here. |
| `resources` | yes | list of `owned_resource` | Every path/resource this deployment owns and its post-apply digest — the exact set `undeploy` may remove. An empty list is an explicit statement (a deployment owning no files), never an omission. |
| `reversible` | yes | boolean | Whether the provider could undo this deployment. An installer that cannot roll back says so before apply; a receipt never implies a transaction its provider cannot provide. |
| `applied_at` | yes | `rfc3339_timestamp` | When apply ran. |
| `status` | yes | `receipt_status` | The final status. `applied` is mid-flight (written before independent verify); every terminal status finalises the receipt. |
| `evidence` | no | string | The provider evidence summary; non-blank and control-free; validated by the behaviour cell. Typed evidence kinds are the mechanism atom's to define — this member carries the summary a reader prints. |
| `prior_state_handle` | no | string | The handle under which the prior state survives for rollback; absent when there was none or the deployment is irreversible. Non-blank; validated by the behaviour cell. |
| `finalized_at` | no | `rfc3339_timestamp` | When the receipt was finalised. The behaviour cell pins the matrix: present exactly for the terminal statuses (`verified`, `failed`, `rolled-back`) and absent for `applied`, because receipt finalisation is last. |
`deploy_identity`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `project` | yes | string | The project identity; non-blank and control-free; validated by the behaviour cell. |
| `package` | no | string | The package identity when the deploy comes from one package rather than the host project; non-blank; validated by the behaviour cell. |
`provider_identity`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `key` | yes | string | The provider key in the ExtensionKey spelling `group/name#id`. Exactly one `/` before exactly one `#`, every component non-blank; validated by the behaviour cell. |
| `version` | no | string | The provider's own version string; non-blank. Deliberately not parsed here — the provider registry owns its grammar. |
| `content_hash` | no | string | The provider's content hash in the one identity spelling `sha256:` + 64 lowercase hex — the same form every lockfile row carries; validated by the behaviour cell. |
`owned_resource`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `resource` | yes | string | The resource identity — an owned path or a named resource; non-blank and control-free; validated by the behaviour cell. |
| `post_digest` | yes | string | The digest observed after apply — exactly 64 lowercase hex; validated by the behaviour cell. `undeploy` refuses to erase a path whose digest moved away from this value. |
28The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `requirements` | yes | uint32 | The requirements wire epoch — 2 today. Epoch 2 adds only the optional authored `requires` set and its identity frames. A reader that does not know the number stops rather than guessing at the members. |
| `observation` | yes | `requirements_observation` | What this answer is, and of what: its own identity, when it was taken, the selected node it was taken over, and the digest of exactly the bytes it read. |
| `query` | yes | `requirements_query` | The query as it was EFFECTIVELY answered — defaults resolved, not the raw arguments. A reader must be able to reconstruct the question from the answer alone. |
| `sources` | yes | list of `source_result` | The BASE source layer: one typed result per authored source this answer enumerated, sorted by package and carrying each package at most once whatever its kind. It is what makes a malformed or missing authored source representable — a state `relation_sources` cannot stand in for, because relation enrichment is a different question about different bytes. Only an `available` result may own fact rows; the other three states say, in the report itself, why a package contributed none. |
| `relation_sources` | yes | list of `relation_source` | The optional ENRICHMENT layer: one typed state per package the relation provider was asked about, sorted by package. Explicit even when empty — with `relations = false` the empty list and the `not-requested` states are the same honest statement: no map was loaded. It never speaks for the base source layer above. |
| `rows` | yes | list of `requirement_row` | One row per addressed fact, sorted by full address. Explicit even when empty: a project with no addressed facts answers with an empty list, not with a missing member. |
| `truncated` | yes | boolean | True when the query's own `limit` cut the row set. Never a soft warning: an orchestrator that reads a truncated answer as complete would conclude the opposite of what it holds. |
`requirements_observation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `observation_id` | yes | string | `sha256:` followed by 64 lowercase hex over every canonical member of this answer except `observed_at`. Two identical observations carry one id; a changed adoption registry moves it. |
| `observed_at` | yes | `timestamp` | When the observation was taken. Excluded from `observation_id` on purpose — the clock is an input, not part of what was read. |
| `selected` | yes | string | The selected workspace node the answer is about: `.` for the root, or a forward-slashed workspace-relative member path. |
| `source_digest` | yes | string | `sha256:` followed by 64 lowercase hex over exactly the spec and registry bytes this answer read — the scope claim, kept separate from `observation_id` so a reader can tell «the sources moved» from «the question changed». |
| `lifecycle_run_id` | no | string | The current lifecycle run id (32 lowercase hex) when one exists in durable state — the join key to a verification-evidence document. Absent on a project that has never run a lifecycle phase; the query itself creates no state and never mints one (`##EXTERNAL-WORK-LOOP`). |
`requirements_query`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `limit` | yes | uint32 | The effective row bound — default 100, inclusive range 1..=256. Present even at its default: an answer must state the bound it was cut by. |
| `relations` | yes | boolean | Whether relation enrichment was requested. False means `not-requested`: no specmap engine and no carried map is loaded, and no provider is called even once. |
| `address_prefix` | no | string | The `spec://` prefix the query was scoped to. Absent when the query asked about every addressed fact; never a bare fact id, which would name nothing a second reader could resolve. |
`source_result`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `source` | yes | `requirement_source` | The (kind, package) coordinate this result is about — the same pair a fact row names, so the two join exactly. |
| `state` | yes | one of `available`, `unavailable`, `invalid`, `orphaned` | `available` — the source was read and parsed, and it may own fact rows. `unavailable` — no such source exists here (an absent package layout, an unmaterialised slot). `invalid` — the bytes were read and did not parse. `orphaned` — no authored source, but the adoption registry carries entries addressed to it. Closed: each word carries a different instruction, and a reader that met a fifth one would have no safe behaviour. |
| `digest` | no | string | `sha256:` followed by 64 lowercase hex over exactly the bytes this source contributed. Present for `available` and `invalid` — both READ the bytes — and absent for `unavailable` and `orphaned`, where there were none to read. |
| `reason_code` | no | string | A bounded, nonblank machine reason. Required for `unavailable`, `invalid` and `orphaned`; forbidden for `available`, which lost nothing and has nothing to explain. |
| `adoption_entries` | no | uint32 | How many adoption-registry entries are addressed to a source that does not exist. Present, and greater than zero, exactly for `orphaned`: the count IS what makes the orphan worth reporting. |
`relation_source`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `package` | yes | string | The `group/name` coordinate this state is about. |
| `state` | yes | one of `not-requested`, `current`, `carried`, `stale`, `unavailable`, `invalid` | What the provider could say. Closed: an unknown spelling is a reader error, and every one of these six words carries a different instruction for an orchestrator deciding whether to trust an edge. |
| `provenance` | yes | one of `fresh-project-map`, `carried-package-map`, `none` | WHERE the edges came from — a project map built fresh in memory, the carried `package.specmap.json` of an installed package, or nowhere at all. Closed, and decided by `state` rather than chosen freely. |
| `reason_code` | no | string | A bounded, nonblank machine reason for a state that lost enrichment (`stale`, `unavailable`, `invalid`). Absent for `not-requested`, `current` and `carried` — nothing was lost, so there is nothing to explain. |
`requirement_row`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `address` | yes | string | The full `spec://<group>/<package>/<path>#<fact>` address — always the whole thing, never a bare id (`##OPTIONAL-IR-FACT-EVIDENCE`). |
| `source` | yes | `requirement_source` | Where the authored document was read from. It must name an `available` entry of the root's `sources[]`, and the coordinate parsed out of this row's own `address` must equal its `package` — the row and the source result are one claim, checked from both ends. |
| `authoring` | yes | `authoring_observation` | What the source document itself claims — the `vibe-specdoc` marker axis. |
| `adoption` | yes | `adoption_observation` | What THIS project recorded about the fact — the consumer-owned `vibe-facts` overlay axis, kept separately present so «no record exists» stays distinguishable from «a record exists with no status». |
| `relations` | yes | list of `requirement_relation` | The relation edges touching this address, sorted and unique. Explicit even when empty — and always empty when the query did not request relations, which the `relation_sources` states say out loud. |
`requirement_source`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `kind` | yes | one of `host`, `package` | Whether the document was read from this project's own spec roots or from a lock-selected materialised package slot. Closed: the two have different provenance and different adoption semantics. |
| `package` | yes | string | The `group/name` coordinate the document belongs to — the host project's own coordinate for a `host` row, the installed package's for a `package` row. Present for both kinds: it is the coordinate half of the row's own address, restated so a reader need not parse the address to group by package. |
`authoring_observation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `presence` | yes | one of `marked`, `unmarked` | Whether the authored document carries a status marker for this fact. An addressed fact with no marker still appears in the answer, as `unmarked` — silence is an observation, not an absence of one. |
| `status` | no | `fact_status` | The authored status. Present exactly for `marked`. |
| `requires` | no | list of `required_artifact_kind` | The optional authored terminal-artifact contract. Absent means unclassified; present is a non-empty set emitted in canonical vocabulary order with no duplicate. It is not a terminal or fulfilment verdict. |
`adoption_observation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `presence` | yes | one of `not-applicable`, `absent`, `indeterminate`, `recorded` | How the consumer adoption overlay answers about this address: `not-applicable` for a host-authored fact (there is no consumer overlay to consult), `absent` when no registry row exists, `indeterminate` when a row exists carrying no status, `recorded` with the exact status when one is present. Closed, and four words on purpose — a boolean here would erase three different facts. |
| `status` | no | `fact_status` | The recorded adoption status. Present exactly for `recorded`. |
`fact_status`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `stage` | yes | one of `unknown`, `idea`, `spec`, `impl`, `test`, `doc`, `freeze` | Where the unit stands in its development cycle (PROP-043 §3.3). Closed: a value outside the set is a validation error, never a silent pass-through. |
| `state` | yes | one of `hold`, `plan`, `work`, `done`, `void` | Work state at the current stage (PROP-043 §3.4). Closed for the same reason `stage` is. |
`requirement_relation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `verb` | yes | one of `implements`, `verifies`, `documents`, `deviates`, `informs` | The traceability verb, in the specmap engine's own closed spelling. `verifies` is an EDGE, not a verdict: it says a symbol claims to verify this fact, never that verification passed — that answer lives on the lifecycle evidence root and the join is the orchestrator's. |
| `provenance` | yes | one of `authored`, `generated`, `proposed` | How the edge came to exist, in the specmap engine's own closed spelling. |
| `symbol` | yes | string | The module-qualified code symbol the edge starts at. |
| `file` | yes | string | Forward-slashed repo-relative source path of that symbol. |
| `line` | yes | uint32 | 1-based source line of the symbol. At least 1 — line 0 names nothing. |
29The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema_version` | yes | uint32 | |
| `package` | yes | `doc_package` | The card and the officiality of the documentation itself — what a shelf, a language selector and a catalogue row show before any page is opened. |
| `pages` | yes | list of `doc_page` | Every page of the package, in the reading order the layer law gives them — stable text before text that moves with the product (PROP-048 `##THE-LAYER-LAW`). A package with no pages yet writes `[]`, never an absent key. |
| `navigation` | no | `navigation` | What the package asked its navigation to look like (PROP-057 `##NAV-PINNED`), present only when it asked. Absent means the navigation is the pages in the order below and nothing else, which is what every documentation written before the field said. |
`bridge_authorship`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `maintainers` | yes | list of string | Who wrote the bridge — the package's own `[package].authors`, which name the authors of the wrapper, its metadata and its adapters, and of nothing upstream. Written even when empty, because an empty list of maintainers is a fact about a published bridge and not a hole to fill with the upstream names. |
| `upstream_authors` | yes | list of string | Who wrote the bytes the bridge points at — the `upstream_authors` of every `[[embedded_source]]`, in declaration order and without repetition. One name appears once however many sources carry it, because a reader is being told who wrote the work and not how many times the manifest says so. |
| `upstream_license` | no | string | The licence of the upstream bytes, present only when every source carries the same one. Absent when the sources disagree: one line cannot state two licences, and a page that picked the first would be stating a legal fact that is not true. |
`navigation`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `pinned` | yes | list of string | The document paths the site and the local reader list first, in the order given — `start/what-vibevm-is`, the page's address under the spec root without its extension. Written even when empty: a package that declared `[navigation]` for its section titles alone pins nothing, and the emptiness is the statement. |
| `sections` | yes | list of `navigation_section` | One row per top-level folder of the page tree, with the title the navigation shows for it. A folder the package does not name is shown under its own directory name, which is a fallback and not a translation. |
`navigation_section`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `id` | yes | string | The folder, as the page paths spell it: the first segment of `start/index.xml` is `start`. An id, not a title, so a translation of the manual names the same sections as its source while showing other words. |
| `title` | yes | string | What the navigation shows for that folder, in the package's own language — one documentation is one language, so this needs no second field. |
`documented_subject`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `package` | yes | string | The subject's `<group>/<name>` coordinate, exactly as `[[documents]]` spells it. |
| `version` | yes | string | The semver constraint `[[documents]]` puts on the subject's version. A constraint, not a version: the site picks the newest documentation whose constraint admits the subject version a reader is looking at (`##REL-VERSION-SELECTION`). |
| `status` | yes | `documentation_status` | |
`adapted_source`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `package` | yes | string | The source documentation's `<group>/<name>` coordinate, exactly as `[translates]` spells it. |
| `version` | yes | string | The semver constraint `[translates]` puts on the source documentation's version. |
| `status` | yes | `translation_status` | |
`card_media`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `icon` | yes | string | The square mark that heads the package page and sits on shelf cards. |
| `banner` | yes | string | The wide image across the head of the package page. |
| `preview` | yes | string | The link card — `og:image`, `twitter:image`, JSON-LD's `image`. Its proportions are incompatible with the banner's on purpose, which is why it is its own role and never a crop. |
`doc_package`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `group` | yes | `group` | |
| `name` | yes | string | |
| `version` | yes | `version` | |
| `publisher` | yes | string | Who published this documentation — the package's group, printed beside the title wherever the title appears (`##DISC-PUBLISHER-VISIBLE`). Named as its own member rather than left to be re-derived from `group`, because the shell parses nothing and computes nothing (`##PIPE-SHELL-PARSES-NOTHING`): every value it shows arrives named. |
| `title` | yes | string | The display name on shelves, in the selector, in the page heading and in the catalogue (`##CARD-TITLE`). Required for kind `doc`; identity stays the coordinate, so two documentations may share a title. |
| `abstract` | yes | string | What it covers, for whom, what it assumes known, what it leaves out — three to six sentences in the package's own language, bounded at about a thousand characters (`##CARD-DESCRIPTION-AND-ABSTRACT`). |
| `lang` | yes | string | The language every page in this manifest is written in — the package's `[i18n].canonical`, a BCP-47 tag, `en` when the manifest declares none (`##LOC-LANGUAGE-FIELD`). There is no second `lang` field on a package and no list of languages here: another language is another package, found through its `translates` edge. |
| `status` | yes | `documentation_status` | The strongest standing this documentation holds over any of its subjects — the one value a shelf, a star and a catalogue row need when a package documents more than one thing. The per-subject truth is in `subjects`. |
| `subjects` | yes | list of `documented_subject` | Every subject of `[[documents]]`, which a `doc` package is required to declare at least one of (`##REL-DOCUMENTS-REQUIRED`). Emitted even when empty: a manifest built over a manifest that broke that rule must show the emptiness, not hide it. |
| `audiences` | yes | list of `audience` | Every audience any page of this documentation is written for, sorted and without repetition — the audiences a catalogue row shows. Derived from the page markup, never declared. |
| `rendered_at` | yes | `timestamp` | When this build rendered the pages. One of the exactly two dates a reader may see (`##READER-META-AND-PRINT`), and it belongs to the build rather than to any one page, so it is written once. The writer never calls the clock: the instant arrives as an input, which is what keeps the bytes of a build reproducible. |
| `description` | no | string | The one-line subtitle for lists and the page's meta description; absent when the package declares none. |
| `authorship` | no | `authorship` | Who wrote the prose this package carries, from `[package].authorship` (`##CARD-AUTHORSHIP`). Absent means unknown, which is what a package that declares nothing says: the site then shows no badge, and a filter by authorship leaves the package out of both named groups rather than guessing it into one. |
| `kind` | no | `package_kind` | Which of the eight kinds the package this rendering came from declares itself to be. Absent when the manifest predates the field, and absent when the package named no kind at all or named a word outside the register — both of which are «nobody told this card what it is», and a card draws no mark it was not given (`##CARD-PLACEHOLDERS-GENERATED`). It is a statement about the RENDERED package and not about the rendering: a level-0 view of a `tool` carries `tool` and also carries `projection`, which is how a shelf marks the wrench and still says the page was generated. |
| `projection` | no | boolean | True when this rendering is the site's own projection of a package's bytes — the level-zero view every package gets for free (`##LEVEL-ZERO-MARKED`), whose manifest page, README and boot snippet nobody wrote as pages. False, and therefore absent, for a documentation package, whose pages an author wrote. A shelf reads it to mark the first as generated and to leave the second alone. |
| `bridge` | no | `bridge_authorship` | The two authorships a bridge keeps apart (PROP-023 `##AUTHORSHIP-SEPARATION`), present only for a package that declares `[package].bridge = true`. Carried rather than recomputed by the shell: both lists are already in the package's own manifest, and the one thing a reader must never see is the maintainer of a wrapper printed as the author of the work it wraps. |
| `translation` | no | `adapted_source` | Present exactly when this package is a translation — that is, when it declares `[translates]`. Its absence is what says «this is a source documentation», so no second flag exists to disagree with it. |
| `published_at` | no | `timestamp` | When this version of the package was published, for the sitemap's `lastmod` (`##SEO-SITEMAP`). Absent for a documentation that has never been published — an in-tree package being read from a developer's own checkout has no publication date, and inventing one would be a lie a crawler believes. |
| `media` | no | `card_media` | Where the card's three images are published. Every build of this pipeline writes it, and writes all three: a role that declares nothing is not a role without a picture — the placeholder is generated (`##CARD-PLACEHOLDERS-GENERATED`) — so a card that carries `media` carries three addresses and never two. It is optional because the registry rules this format `foreign_parsers = "many"` and its readers are permissive by design (PROP-044 §4.4): a manifest written before the addresses were carried is still a manifest, and a reader that refused one would refuse every document already published. Absent means «this document predates the field», never «this package has no picture». |
`doc_page`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `path` | yes | string | The page's address inside the package — a `/`-separated path under the package's spec root, `model/lock-and-store.xml`. Forward slashes on every platform, so one manifest reads the same everywhere, and the site's address map turns it into a URL without an index (`##SITE-MOUNT`). |
| `title` | yes | string | The page's H1. |
| `genre` | yes | `page_genre` | |
| `audiences` | yes | list of `audience` | Who the page is written for, sorted and without repetition, from the `audience` of its `<status>` markers. Empty means the page marked none, which the coverage gate can see and a guess would hide. |
| `anchors` | yes | list of string | Every named anchor the page carries, in document order: the title's id, each section's id, each fact's id. These are the immutable addresses a citation may point at (`##INV-ANCHORS-IMMUTABLE`); the positional `pNN` numbers are NOT here, because they live by the current text and would turn a manifest into a promise the next edit breaks. |
| `summary` | yes | string | The page's leading fact — its first paragraph, which the style law requires to stand alone and names as the page's line in `llms.txt` (`AUTHORING.md` §7). Taken, never composed: a summary written by the pipeline would be a second description of the page that nobody proofreads. |
| `reading_time_min` | yes | uint32 | Minutes to read the page, rounded up, never below one: the words the page carries at 250 a minute for `en` and 200 for every other language, `ru` included (PROP-057 `##READER-META-AND-PRINT`, the rates of the vision's D-22 item 9). A `derived` block contributes nothing — the manifest is built from the page's own bytes and a generated reference has none until the product is run. |
| `reviewed_at` | no | `timestamp` | When a human last read this page aloud against the product, from the package's `reviews.toml` (`##OBS-MAINTENANCE-TOOLS`). The second of the exactly two dates a reader may see. Absent when the page has never been read aloud — which is a state worth showing, not a zero to fill in. |
30The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema_version` | yes | uint32 | |
| `package` | yes | string | The documentation package's `<group>/<name>@<version>` coordinate. |
| `examples_measured` | yes | boolean | Whether this run executed the documented examples. Running them builds a sandbox per fixture and costs minutes, so the queue leaves them to `--examples`; when it is false the example rows are ABSENT rather than zero, and the flag is here so nobody reads an unmeasured queue as a clean one. |
| `metrics` | yes | `todo_metrics` | |
| `sections` | yes | list of `todo_section` | The queue itself, grouped by where the work came from. A section with nothing in it is still emitted: «no unresolvable citations» is an answer, and a missing section reads as a check nobody ran. |
`todo_metrics`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `gaps` | yes | uint32 | Queue rows from coverage, examples and citations together — the first metric, and the one that should go to zero. |
| `page_age_median_days` | yes | uint32 or null | Median days since a page was last read aloud, from `reviews.toml`. `null` when the package records no readings at all — a manual nobody has read aloud yet has no median, it has a backlog. |
| `adaptation_divergences` | yes | uint32 or null | How far the adaptations are from their source, counted as STRUCTURAL divergences — pages, anchors and blocks that do not mirror. The seventh edition removed the revision count this row used to hold, because «how far behind» needs a history the project does not keep (`##LOC-NO-REVISION`). `null` when the package adapts nothing. |
| `coverage_percent` | yes | uint32 or null | The share of obligation-and-audience pairs a page tells. `null` when the run stood outside a checkout and had no corpus to state the obligations. |
| `tics_per_100k_words` | yes | uint32 or null | Style findings per hundred thousand words of prose. The metric table states the rate per THOUSAND words; the unit here is a hundred times finer so the number is an exact integer, and a reader divides by a hundred to get the table's own unit. The reason is not taste: every schema in this project is free of floats, and the first float takes the `Eq` floor off every generated type — a cost this row is not worth paying. `null` when the package ships no banned list for its own language, which is the state where a zero would mean «nothing to find one with». |
| `debt_p1` | yes | uint32 | `docs:` lines of severity P1 in the host's `BACKLOG.md`. The target is zero and the other severities live in the queue's own section. |
| `findings_without_decision` | yes | uint32 or null | Journal entries whose «→ regulation» field is still empty. The metric table counts entries and decisions; one number says the same thing, because the target is that every entry has one. `null` when the package carries no journal. |
| `days_since_reconcile` | yes | uint32 or null | Days since the last full reconciliation, from the date `reviews.toml` records. `null` when none has happened. |
`todo_section`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `name` | yes | `section_name` | |
| `measured` | yes | boolean | Whether this run asked the question. A section that was skipped carries no items and says so here. |
| `items` | yes | list of `todo_item` | |
`todo_item`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `subject` | yes | string | The page, the address or the debt line the row is about. |
| `reason` | yes | string | Why it is in the queue, in one line an author can act on without opening anything else. |
| `severity` | yes | `item_severity` | |
31The document
| Field | Required | Type | Meaning |
|---|---|---|---|
| `schema_version` | yes | uint32 | |
| `version` | yes | string | The version number the caller declared, verbatim. It is an INPUT and never a reading: the product cannot tell one amend of a version from another, and a snapshot that guessed its own number would be pretending to a history the project does not keep (`##OBS-VERSION-CONTRACT`). |
| `commands` | yes | list of `surface_command` | Every command of the binary, in the order a walk of `--help` reaches them, each with the flags it accepts. This is the surface a reader types, so it is taken from the help the reader would read and never from the parser's source. |
| `manifest_fields` | yes | list of string | Every dotted key path `vibe.toml` accepts, sorted — `package`, `package.title`, `package.binary[].name`. The list is what the real parser answers when asked, so it states what the product accepts rather than what a struct is called. |
| `lock_fields` | yes | list of string | The same for `vibe.lock`. |
| `schemas` | yes | list of `surface_schema` | Every JTD schema the format registry names, with its members. A document a foreign parser reads is a contract, and its members are the part of the contract a page quotes. |
| `facts` | yes | list of `surface_fact` | The text of every specification fact marked `actionstage="doc"` with an audience — the promises the documentation answers to. The TEXT is here and not a hash of it: a diff that could only say «this changed» would send a writer to read the whole corpus again. |
| `formats` | yes | list of `surface_format` | The format registry as it stood, record by record. |
`surface_command`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `path` | yes | string | The command line a reader types as far as this node — `vibe doc build`. |
| `summary` | yes | string | The one-line description the parent's help gives it, empty at the root. |
| `flags` | yes | list of `surface_flag` | |
`surface_flag`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `name` | yes | string | The long form when there is one, else the short — `--format`, `-h`. |
| `value` | yes | string | The placeholder the flag takes, empty when it is a switch — `FORMAT`, `PATH`. |
| `summary` | yes | string | |
`surface_schema`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `id` | yes | string | The format id in the registry — the address that survives the file moving. |
| `path` | yes | string | |
| `fields` | yes | list of `surface_schema_field` | |
`surface_schema_field`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `form` | yes | string | The definition the member belongs to, empty for the document's own root. |
| `name` | yes | string | |
| `required` | yes | boolean | Whether the member sits in `properties` rather than `optionalProperties`. Moving a member between the two is a contract change and this is what makes it visible. |
| `shape` | yes | string | The member's form in one phrase — `string`, `uint32`, `elements of doc_page`, `enum user\|author`. |
`surface_fact`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `address` | yes | string | `<observed path>#<anchor>` — the address a page cites it by. |
| `audiences` | yes | list of string | |
| `text` | yes | string | |
`surface_format`
| Field | Required | Type | Meaning |
|---|---|---|---|
| `id` | yes | string | |
| `epoch` | yes | uint32 | |
| `schema` | yes | string | |
| `recoverable` | yes | boolean | |
| `foreign_parsers` | yes | string | |
| `corpus` | yes | string | |
| `sunset` | yes | string | |
32The documents of the index server, the scrape contract and plan, the compiler trace and the native ABI have schemas of their own in the same folder; the registry lists all of them.
Edge cases and rules
33A document that no schema describes is a defect, not a feature; the campaign that wrote this manual filed the ones it found in the product's backlog, and the examples on these pages mark such documents as unchecked rather than passed.
34Formats carry an epoch; while the product is not yet public, an incompatible change of a format is free and unmigrated, and the registry says so. A published format changes only with a break note and, where needed, a migration.
35
6.2 vibe.toml is the most expensive format in the
system — authored, unrecoverable, resident in foreign repositories, and an
external surface de facto because agents read files, not APIs. It is the one
place we honestly pay the stability tax: an epoch marker in the file,
introduced before first publication (absence ≠ "assume 1"; absence is the
distinct pre-epoch state, interpreted by a heuristic exactly once in history);
strictness with did-you-mean hints in our namespace (in a hand-written file an
unknown key is a typo and the author is present — the asymmetry with the
machine-written catalog is principled, not inconsistent); a named reserve
section we never touch; a generated projection as the published copy, so
foreign tools read a recoverable artifact while the hand-written original
remains our internal concern; migration by codemod + bot PR; and a minimal
surface — every new manifest key is a years-long obligation and requires a
break note, a codemod, and generated documentation.
36Raw parsing with shell tools counts as a parser: the registry assumes someone pipes a report into a JSON tool, and treats the format accordingly.
37
Foreign curl | jq will happen regardless of
generated clients, and there will never be a signal of it (raw files in git
give no telemetry, by design). The honest posture: assume raw parsing exists,
keep the narrow gate genuinely boring, and treat any change to it at the
highest severity class.