Browse Docs pages
This page documents the exact fields of Rotkeeper's machine-readable files. It is derived from the scripts that read and write them (rc-assets.sh, rc-release.sh, rc-status.sh, rc-env.sh, rc-new.sh, rc-glue.sh); when a script and this page disagree, the script is authoritative.
bones/asset-manifest.yaml
Generated by bash rotkeeper.sh assets (rc-assets.sh). The previous manifest is archived to bones/archive/asset-manifest-<YYYY-MM-DD_HHMM>.yaml before regeneration. Empty asset trees produce a single # assets: [] comment.
- path: "css/theme-dark.css" # asset path relative to the layout's assets dir (home/assets in crypt)
sha256: "1dbb3b1b...c0b504d661" # hex digest via sha256sum or shasum -a 256 (shared rk_sha256)
| Field | Type | Rules |
|---|---|---|
path |
string | Relative to the assets dir; only [a-zA-Z0-9/._-] allowed, no .. or ../ segments, .DS_Store never listed |
sha256 |
string | Lowercase hex SHA-256 of the source asset file |
Lifecycle: written by assets, archived before each rewrite, and consumed by render as a precondition (render refuses to start without it or a bones/meta/asset-manifest.yaml) and by assets itself to prune stale generated copies under output/assets (pruning happens only when the output tree is marked generated).
bones/config/rotkeeper.yaml
The only always-present configuration file; written by init, optional paths may be serialized there. Every other key has a fallback in the reader, so a minimal file (title + description + default_template) is valid.
title: "Rotkeeper Config"
description: "Minimal valid config for rendering tests"
default_template: "theme-spooky-dark.html"
layout_style: "crypt" # optional: crypt | busy | sterile
paths: # optional serialized path cache (init writes it)
CONTENT_DIR: "home/content"
TEMPLATE_DIR: "bones/templates"
| Field | Type | Read by | Default / fallback |
|---|---|---|---|
title |
string | status | β |
description |
string | status | β |
project |
string | status | [not set] |
author |
string | status, new, glue | [not set] / empty |
version |
string | status | [not set] (the authoritative version is bones/config/version) |
license |
string | status | [not set] |
default_template |
string | render, glue, new, bootstrap | theme-spooky-dark.html (legacy key; theme_registry.default wins over it) |
theme_registry |
map | render, glue, new, status | mode names β template files; default selects the site-wide theme (#252) |
input_format |
string | env, render, preflight, adapter | markdown; valid values markdown | textile (anything else warns and falls back to markdown) |
layout_style |
string | env | crypt; valid profiles crypt | busy | sterile |
paths |
map | env | derived per layout style when absent |
theme_registry semantics (#252): maps mode names to template files (e.g. daisy: "theme-daisy.html", daisy-vanilla: "theme-daisy-vanilla.html"). The default entry is the per-site theme and wins over the legacy default_template key; per-page template: frontmatter wins over both. rk_resolve_default_template (rc-utils.sh) validates every registered value exists under bones/templates on resolution and falls back to the first available template when the default is missing.
paths cache semantics: a serialized paths block is validated against the active layout and repository root on load (validate_layout_alignment in rc-utils.sh). init deliberately forces an environment reload after writing it; do not hand-edit a paths block without re-running init or the alignment check will report the mismatch.
bones/config/release-manifest.txt (in the release archive)
Generated inside the distribution by bash rotkeeper.sh release <version> (rc-release.sh). This is the bill of materials for a release; the legacy rotkeeper-bom.yaml no longer exists and never ships.
Rotkeeper framework distribution manifest
version: 0.5.2
model: framework distribution (dispatcher, bones system, templates, configuration, project docs)
ruleset: release allowlist v1 (explicit root entries, required spine, forbidden prefixes and artifacts)
listed_entries: <count>
entries:
rotkeeper/AGENTS.md
rotkeeper/bones/config/release-manifest.txt
...
| Field | Meaning |
|---|---|
version |
Release version from bones/config/version |
model |
Distribution model (framework distribution is the only supported model) |
ruleset |
Allowlist contract enforced against the archive |
listed_entries |
Number of files listed under entries: |
entries: |
One sorted, root-relative path per file inside the archive β the allowlist the packager verifies against |
Verification failures (unexpected root files, missing required spine, forbidden credentials/artifacts) abort the release before the archive is finalized.
bones/archive/ β tomb archives
pack writes versioned .tar.gz tombs (tomb-<YYYY-MM-DD_HHMMSS>-NNNN.tar.gz), tombkit bundles (tombkit-*), content archives (tomb-content-*), JSON exports (tomb-export-*), and releases (releases/rotkeeper-<version>.zip).
Tomb versioning policy: archives are append-only and immutable. The random -NNNN tag (GNU and BSD safe β %N is GNU-only) guarantees unique names even for packs within the same second; old tombs are never invalidated, overwritten, or pruned. Each archive embeds a metadata.json (name, sha256 of the uncompressed tar, timestamp, mode, file count) and is recorded in bones/manifest.txt as <relative-path> <sha256>. gzip -t integrity is verified at pack time (validate_gz) and re-asserted by the test harness; any failed or interrupted pack is cleaned up by the partial-archive trap (no half-written .tar or truncated .gz survives).
CLI --json output
Several dispatcher commands emit a single machine-readable JSON object on stdout when passed --json; human-facing output, report files, and exit codes are unchanged when the flag is absent. New outputs are tagged with a stable schema field (rotkeeper.<subject>.v1) so CI consumers can version-check before parsing. As everywhere else on this page, when a script and this page disagree, the script is authoritative.
scan --json
Emitted by bash rotkeeper.sh scan --json. Scan audits the render ledger (bones/manifest.txt): missing are ledger entries absent from disk, orphans are files under the rendered output tree the ledger does not list, and digests verify ledger-listed files. The report files under bones/reports/ keep their existing shape; this object carries the same findings inside an additive envelope.
{
"schema": "rotkeeper.scan.v2",
"generated_at": "2026-08-27T00:00:00Z",
"manifest": "bones/manifest.txt",
"counts": { "missing": 0, "orphans": 0, "digest_mismatches": 0 },
"missing": [],
"orphans": [],
"digest_count": 2,
"digests": {
"home/content/index.md": "1dbb3b1bβ¦c0b504d661"
},
"digest_mismatches": [
{ "path": "bones/archive/tomb-2026-08-27_120000-1234.tar.gz", "expected": "1dbb3b1bβ¦c0b504d661", "actual": "deadbeefβ¦00000000" }
]
}
| Field | Type | Rules |
|---|---|---|
schema |
string | Always rotkeeper.scan.v2 |
generated_at |
string | ISO-8601 UTC timestamp emitted at audit time |
manifest |
string | Manifest path audited, root-relative |
counts.missing, counts.orphans, counts.digest_mismatches |
number | Lengths of the arrays below, mirrored for convenience |
missing |
string[] | Ledger entries absent from disk; empty array when clean |
orphans |
string[] | Files under OUTPUT_DIR absent from the ledger; output/assets/ is exempt (owned by the assets ritual) |
digest_count |
number | Number of entries in digests |
digests |
map | Ledger-listed file path β lowercase hex SHA-256 (files present on disk only) |
digest_mismatches |
object[] | Ledger entries with a recorded SHA-256 (pack's <path> <sha256> two-space format) whose on-disk digest differs; each entry {path, expected, actual} where actual is hex or null when the file is absent (also in missing[]) |
v1 β v2: v1's full-tree walk never produced orphans/digests β the extension filter could not match under the script's IFS (#292). v2 scopes orphans to the output tree, retargets digests at ledger entries, and adds digest_mismatches[] verifying pack's recorded SHA-256 lines (P2).
dip --json
Emitted by bash rotkeeper.sh dip --json. Rows appear in matrix order (sorted owned docs, then sorted unowned docs) with values equal to the published dip-matrix.md table cells minus markdown link decoration. Works under --dry-run without writing anything.
{
"schema": "rotkeeper.dip-matrix.v1",
"generated_at": "2026-08-27T00:00:00Z",
"matrix_file": "home/content/docs/dip-matrix.md",
"totals": { "ok": 10, "stub": 0, "missing": 0, "stale": 0, "unowned": 0, "rows": 10 },
"rows": [
{ "target_file": "bones/scripts/rc-dip.sh", "doc": "bones/scripts/rc-dip.md", "last_code_edit": "2026-08-27", "last_doc_edit": "2026-08-27", "status": "OK" }
],
"ownership_collisions": [],
"obsolete_moved": [],
"degraded": { "autopsy_report": false, "fsbook_catalog": false }
}
| Field | Type | Rules |
|---|---|---|
schema |
string | Always rotkeeper.dip-matrix.v1 |
generated_at |
string | ISO-8601 UTC timestamp |
matrix_file |
string | Published matrix path relative to root |
totals |
map | Counts by status (ok, stub, missing, stale, unowned) plus total rows |
rows[] |
object | target_file, doc, last_code_edit, last_doc_edit, status (all strings); targets without an owning script use "Unknown" |
ownership_collisions[] |
object | {doc, claims} where claims lists the two generated sources claiming the same doc page |
obsolete_moved[] |
string[] | Docs moved to the obsolete tree this run (always empty under --dry-run) |
degraded.autopsy_report, degraded.fsbook_catalog |
boolean | True when that input artifact was missing and discovery degraded |
Other producers
status, links, and a11y each support --json today with command-specific shapes (see their reference pages). They predate the envelope convention above and do not carry a schema tag; treat their exact fields as defined by the scripts themselves.
Related
- Rendering contract β the template/input contract for rendering.
- Dispatcher reference β command and layout overview.
- Documentation overview