Browse Docs pages
Every Rotkeeper command is a Bash script invoked through the dispatcher.
This page defines the script requirements and the
command reference contract. Use
rc-preflight.sh as a minimal script example and the
generated assets reference as the help-page
model.
Where new behaviors belong
- Command scripts live in
bones/scripts/rc-<name>.sh. Invoke them only throughbash rotkeeper.sh <name>, not directly. - Shared helpers belong in
rc-utils.sh. Do not copy them into a command script. - Adding a script, subsystem, dependency, or dispatcher command requires explicit human approval.
Required shape (in order)
- Shebang and strict mode:
#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' - Header block identifying the script, purpose, version, and update date. Keep the
Project / Script / Purpose / Version / Updatedlayout. IncludeEnv assumptions,CWD assumptions, andInput/Output contracts. Name actual inputs, outputs, dependencies, and dry-run exceptions. - Help block between
# @HELPand# @END-HELP, containing a title, Usage, Description, Options, realistic Examples, and Exit codes. Use the literal{VERSION}token. The shared emitterrk_show_helpsubstitutes the loaded version for--help/-h;rc-autopsy.shextracts the same text. Define a customshow_helponly for runtime content, such asrc-newtemplate completion. Support--version/-v,--dry-run, and--verbosewhere applicable. Show dispatcher commands in examples. - Bootstrap (always, in this order):
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/rc-utils.sh" || { echo "FATAL: cannot source rc-utils.sh" >&2; exit 1; } rk_init_script "rc-<name>" "$@"rk_init_scriptparses common flags, installs traps, loads the canonical environment throughrk_load_env strict, and opens the log. Do not sourcerc-env.shdirectly.ROT_SKIP_ENV=trueis reserved for help extraction byrc-autopsy.sh. - Version: read via the shared
rk_load_version(sourced by rc-utils.sh). Never hard-code version strings. - Sidecar: provide a reviewed file sidecar under
bones/metausing the sidecar contract. Keep explanatory details there, rather than editing a generated reference page.
Registration
- Dispatcher: add a
casearm inrotkeeper.shmappingbash rotkeeper.sh <name>tobash "$BONES/rc-<name>.sh" "$@", and mention the command in the dispatcher help block. - Autopsy whitelist: add the script to
PERMITTED_RITUALSinrc-autopsy.shfor its standalone help report. DIP reads static script comments directly and does not depend on that allowlist or report. - DIP:
book --fsbookdiscovers core scripts.dipgenerates missing reference pages and rebuilds pages whosetarget_filematches the script, at the mirrored path under the activeDOCS_DIR. Authored pages without matching ownership are not replaced. - Tests:
bones/scripts/rc-test.shcopies command scripts intocrypt,busy, andsterilefixtures. Extend its workflow assertions and command-contract coverage for new behavior.
Command reference contract
The contract identifier is rotkeeper.command-reference.v1. DIP owns command
reference pages; authors own task guides. Change the script annotations,
help block, sidecar, or CHANGELOG when reference information is missing or
wrong. Do not repair a generated page by hand.
Frontmatter
Use this key order and shape. Values shown here are placeholders, not additional copies of command metadata:
---
reference_contract: "rotkeeper.command-reference.v1"
title: "rc-name.sh"
slug: "rc-name"
target_file: "bones/scripts/rc-name.sh"
template: "rotkeeper-doc.html"
status: "active"
version: "<loaded Rotkeeper version>"
author: "Rotkeeper DIP"
project: "Rotkeeper"
description: "<script Purpose line>"
---
target_file is repository-relative and determines ownership. version
comes from the shared version loader, not the script's historical header
stamp. Omit generation timestamps so an unchanged source produces unchanged
bytes. status: active identifies the page type; it is not evidence of
completeness.
Section order and sources
Use exactly one H1, the script filename. Every section below is an H2 and appears once, in this order:
| Section | Authoritative source | Content |
|---|---|---|
| Overview | Header Purpose |
What the command does |
| Usage | @HELP Usage |
Dispatcher syntax in a Bash code block |
| Options | @HELP Options |
Flags, arguments, defaults, and relevant modes |
| Examples | @HELP Examples |
Runnable dispatcher examples in a Bash code block |
| Exit codes | @HELP Exit codes |
Success, expected failures, and propagated statuses |
| Reads and writes | Header Env assumptions, CWD assumptions, Input/Output contracts |
Actual variables, dependencies, input/output paths, and dry-run behavior |
| Side effects | SIDE EFFECT (...) annotations |
Writes, moves, deletions, and relevant guards |
| Notes | Reviewed file sidecar body | Design, Limits, and Cautions |
| History | CHANGELOG | Whole matching bullets with continuation lines, grouped by release |
Use H3 for Notes subheadings and release headings in History. Deeper headings are unnecessary. Keep usage, options, and exit-code text literal; do not interpret flags or paths as Markdown markup.
If a source is missing, retain the section and state what is not documented. Do not invent an overview, imply that an empty section is complete, or replace per-script contracts with a generic environment list. Description text that carries facts beyond Purpose must be incorporated into Purpose, the contracts, or the sidecar. The full engine work in #327 must include command-specific help sections, such as Modes, under Options.
Plain-language style
- Use plain, factual language in all help pages, titles, headings, and sidecars.
- Do not use emoji, lore, limericks (including hidden comments), opinion, rhetorical questions, or decorative prose.
- Use sentence-case titles and headings. Preserve the spelling and case of the project name, script filenames, command names, and source identifiers.
- Use one term per concept: command for a dispatcher action, script for its Bash file, reference page for generated command documentation, task guide for authored instructions, and sidecar for explanatory metadata.
- Keep exactly one H1 per page. Use H2 sections and H3 subsections without skipping heading levels.
- Format commands, flags, paths, environment variables, and literal examples as code. Prefer short sentences with an explicit actor and action.
- State conditions and limits precisely. Distinguish an asset mirror from reference discovery, skipped paths from fatal errors, and asset dry-run guarantees from bootstrap logging.
- Check every behavioral claim against source and shared helpers. Generated reports and old sidecars are not authoritative.
The selected pillar names are Notes and History, replacing
Necromancer's Notes and Ritual History. Keep the existing
DIP-SOUL-EXTRACTED and DIP-HISTORY-EXTRACTED marker identifiers. The
engine migrates marker-owned headings alongside reference generation,
including boundary recognition, stub templates, and TODO counting. It also
recognizes old heading names while reading older sidecar tails.
Sidecar contract
File sidecars use this frontmatter:
---
target_file: "bones/scripts/rc-name.sh"
reviewed: "YYYY-MM-DD"
reviewed_against: "<Rotkeeper version>"
---
Use exactly these H3 body headings: Design, Limits, and Cautions. Describe implementation choices, restrictions, and operational risks without duplicating help text. Use an explicit statement when a category has no additional information. Do not add a page H1, a Notes wrapper, DIP markers, or a self-stitched copy of the body.
For directory sidecars, use title, description, and reviewed, with H3
body headings Purpose and Contents and conventions. Directory metadata is
merged into generated index frontmatter by rc-glue, so include only keys
intended for that page. Do not add file-only ownership/version keys.
File sidecars for DIP core targets mirror repository-relative paths under
bones/meta, with the final extension removed before .soul.md. Their
target_file is repository-relative. Directory sidecars mirror paths
relative to the active content root, keeping the directory name. Glue
uses directory frontmatter, not the sidecar body, when creating indexes.
It does not merge a sidecar with nonempty target_file into an index.
bash rotkeeper.sh new <file> --soul uses a content-relative lookup path
under bones/meta, but still records a repository-relative target_file.
It emits the three file headings and TODO text with reviewed: null and
reviewed_against: null. These null values identify an unreviewed scaffold,
not a completed review. Existing sidecars are preserved; dry-run publishes
neither the source nor the sidecar.
Before publishing, review each claim against the target, static help, and
shared helpers. Replace the TODO text, then set the file review date and
version together using bones/config/version. Directory sidecars record
only the review date; do not add a version key that would enter the index.
The assets sidecar reference is a reviewed
example.
Check that a consumer can reach the sidecar: DIP discovers non-content core
files, render looks up content-file sidecars, and glue looks up directories
under the content root. DIP skips Markdown cores and .github, and glue
does not walk the asset tree. For unreachable notes, fold verified content
into an existing reader-facing page and delete the sidecar. When a target
is removed, retire its sidecar and obsolete reference page, remove retired
whitelist entries, and repair links. Do not add whitelist entries to conceal
missing ownership or coverage.
Remove generated tails at the source. Regenerate references with
bash rotkeeper.sh book --fsbook followed by bash rotkeeper.sh dip.
Review the affected pages and keep unrelated generated changes out of the
commit.
Pilot findings and follow-up tasks
The assets pilot is generated by DIP from
rc-assets.sh, its sidecar, and CHANGELOG. Its reference_contract field
identifies the contract. The engine applies the same source-based rebuilding
to all owned script references, whether or not that field already exists.
Internal libraries and standalone tools without static help retain every
section and explicitly state what is not documented; DIP never executes them
to discover their behavior.
Comparison with the previous hand-written page found these source gaps, now corrected for the pilot:
- Purpose and Description incorrectly described selective reference scanning. The command mirrors the source tree.
- Contract headers omitted concrete read/write paths, dependencies, ownership-marker behavior, and bootstrap log writes during dry-run.
- Help omitted dependency exit code 2, propagated I/O statuses, and dispatcher equivalents of the old direct-script examples.
- Side effects named
bones/archivesinstead ofbones/archiveand omitted the shared ownership-marker write. - The sidecar contradicted the path allowlist, duplicated its own body, and lacked the workflow and manifest example. It now carries those verified facts, the empty-manifest format, and operational limits.
Follow-up tasks for #327:
- [x] Extend the opt-in pilot to all command pages and missing scripts without overwriting authored task guides.
- [x] Harvest command-specific help sections, multiline contracts, and continuation lines in side-effect annotations; define and test missing-source fallbacks.
- [x] Use complete CHANGELOG bullets only, including matches on continuation lines, with stable release grouping and byte-idempotent generation.
- [x] Migrate Notes and History together with section ordering, boundary handling, stub templates, TODO counting, and legacy page rewrites.
Follow-up tasks for #329:
- [x] Apply the agreed file/directory schemas and plain-language body headings; remove all self-stitched tails and update the scaffold.
- [x] Check other sidecars for the same drift as assets: false discovery claims, incorrect archive paths, missing dry-run exceptions, unsupported dependency/security claims, and omitted format or deletion limits.
- [x] Record source-reviewed dates/versions and resolve unreachable sidecars before publishing them.
Behavior rules
- Boundaries: keep reads and writes inside their expected roots, using the active layout. Use shared canonical path helpers, not raw string-prefix checks.
- Destructive paths: honor
--dry-runon every destructive operation and use the output-ownership marker rules for anything deleting underoutput. - Dependencies: check external tools with
require_binsandrequire_sha256where needed. Prefer shared wrappers such asrk_sha256. - Quoting: quote expansions unless deliberate shell semantics require otherwise; preserve the repository
.shellcheckrcexemptions rather than adding blanket suppressions. - Side effects: annotate writes, deletes, moves, and Git operations with
SIDE EFFECT (...)comments. Log their outcomes clearly.
Validation before merge
bash -non the new script.shellcheckwith the repository.shellcheckrc.bash rotkeeper.sh test(the full harness, including every layout).bash rotkeeper.sh status.- The relevant
--dry-runs. - Regenerate
bash rotkeeper.sh book --fsbookandbash rotkeeper.sh dip. Check the reference against its sources and run DIP again to confirm unchanged page bytes.
On macOS, report a realpath -m portability failure rather than weakening
the harness.
Back to: Documentation overview ยท Dispatcher reference