Kronika documentation

Site pipeline

Beyond single-document writing, the repository ships a documentation-site pipeline (pipeline/, the kronika-site binary): turn a product repository into documentation content, then validate every page before publication. Brama authors a typed content plan, never markup, and identifies product concepts in the terms validator. Evidence, structure and command coverage are checked mechanically. The pipeline is separate from the kronika CLI's sync loop.

Stages

kronika-site (pipeline/src/run.mjs) orchestrates detect → author (or load a plan) → validate → emit, stops at the first failing stage, and prints one final report, as JSON or, with --text, one path: value line per field:

kronika-site <productRepo> --sources <file> (--standard <writing-standard.md> | --plan <file>) [--out <dir>] [--model <selector>] [--text]

Exit codes: 0 all green, 1 a stage failed, 2 usage error, 69 model infrastructure down. Each stage module also runs standalone from the pipeline/ directory, with --help printing its usage:

node src/stages/detect.mjs <productRepo> --sources <docs-sources.json> [--out brief.json] [--text]
node src/stages/validate.mjs --plan plan.json --brief brief.json [--repo path] [--text]
node src/stages/emit.mjs --plan plan.json --out <dir> [--text]

Detect

pipeline/src/stages/detect.mjs reads the product repository's docs-sources.json — which must declare product and may declare binary, routes, config, changelog, limits, and a docs map of plain evidence documents — probes each declared surface, and computes brief.json. Detection never invents a surface; only declared, probed surfaces count. The completion-gate formula:

Evidence Required page kinds
always overview
CLI binary answers --help quick-start, cli-reference
HTTP route file readable api-reference
configuration document exists config-reference
CHANGELOG exists changelog; plus migration iff breaking entries
declared limits/quotas exist limits

Author

The model authors plan.json through Brama, conforming to the closed schema in pipeline/schemas/plan.schema.json. The authoring prompt is built from brief.json, the declared sources, and the writing standard the caller names with --standard <file>, read whole and injected into the prompt; the pipeline ships none. Authoring without --standard or --plan is refused before detection with exit 2, and a standard that cannot be read stops the stage as author_failed, naming the flag. The endpoint is BRAMA_URL when set, otherwise the address published in ~/.stado/forwards/brama.local. Neither means an explicit not_configured refusal naming both declarations; no address is built in. The selected declaration must be an absolute HTTP(S) base URL without credentials, query or fragment. An empty or invalid BRAMA_URL is refused by name without reading the marker; only an unset variable selects the marker, which undergoes the same validation. Refusals do not echo declaration contents. Inference redirects are refused at the selected route instead of forwarding prompts. Body-read failures retain HTTP status and transport cause; malformed JSON or missing assistant content retains endpoint, status and the complete body. An unreachable endpoint fails authoring with exit 69. Brama owns sampling settings, and HTTP failures retain the full response body. --plan <file> skips authoring, but validation can still call Brama to judge recurring undeclared words.

Validate

pipeline/src/stages/validate.mjs runs five validators; the report contains each validator's failures, and all must pass:

An exception inside a validator is a failure of that named validator, with its observed cause in the report. Invalid evidence expressions, unreadable sources and malformed plan fields do not abort reporting for the remaining validators or count as approval. Emission still requires every validator to pass.

Source commands retain complete stdout, stderr and multiline failure details, without a pipeline-selected output byte ceiling. URL evidence failures identify the URL, HTTP status and complete response body, or the transport cause. A failed source read cannot support a publishing claim.

A failed CLI help probe stops authoring before its Brama request, naming the binary, exit result, process error and both complete captured streams. Partial stdout from a failed command is not accepted as authoring evidence.

  • claims — every claim.evidence occurs in its named source.
  • drift — every documented command usage line and flag exists in the live binary's --help. Commands are allowlisted: only the product binary, only subcommand words plus --help/--version, nothing shell-interpreted. Long-option tokens must match completely: --output-format does not establish --output.
  • terms — for undeclared words used on multiple pages, Brama judges whether they name product concepts using the complete page prose as untrusted reference data. A product concept needs a declaration with an existing defining page. An unavailable, malformed or out-of-vocabulary answer fails the terms validator; it does not count as approval.
  • structure — the plan validates against the closed schema; there is no page kind outside it to choose.
  • coverage — every required page kind is present, and each command advertised by the binary's --help has a cli-reference page at cli/<command> or below it.

Detection requires a readable Commands: section with command names. CRLF output and a section ending with the response are accepted. An unreadable section is a CLI failure retaining the complete help text, not an empty command inventory. Coverage refuses a declared CLI without a successful, nonempty observed inventory, including older briefs that omitted commands.

Coverage probes the current binary's --help again with the same parser as detection. Commands added since the brief was recorded still need their pages. An unavailable binary, failed help command or unreadable command inventory fails coverage instead of accepting stale brief evidence.

Coverage recursively reads each advertised command's own --help. Nested commands require paths such as cli/fleet/create, not merely the parent page. A leaf must expose a Usage: section. Failed or unreadable child help and repeated ancestor inventories fail with the complete command path and cause. Missing plan.pages or brief.requiredKinds is a named coverage failure, not an empty collection.

Drift resolves leading command words through each parent's observed command inventory. Once a leaf is reached, following positional values are operands, not additional help subcommands. An unadvertised command word at a parent reports that parent's command path and the unresolved word.

Each product invocation on its own line is checked against its own command help, even when comments or another command come first. Backslash-newline continuations remain part of the same invocation; flags on a later command are not compared against the first command's help.

The reusable real-interface journey is node tests/coverage/cli.mjs. Declare KRONIKA_TEST_SOURCE_REVISION, KRONIKA_TEST_PRODUCT_REPO, KRONIKA_TEST_PLAN, KRONIKA_TEST_BRIEF, KRONIKA_TEST_REQUIRED_COMMAND_PAGE, KRONIKA_TEST_SUCCESS_EXIT and KRONIKA_TEST_FAILURE_EXIT. It uses an authored plan, a real detected binary and the configured Brama service when terms require judgement. The baseline must pass all validators; removing a required command page or naming an unavailable binary must fail coverage. Revisions, digests, commands, exit statuses and validator output remain in .build/coverage; only run-owned fixture copies are removed.

There is no prose quality score. The writing standard guides the author; the named validators enforce evidence, vocabulary, structure and coverage.

Emit

pipeline/src/stages/emit.mjs turns a validated plan into a DocPage data module — docs.ts in the --out directory — for the consuming site's DocumentationLayout, along with the navigation grouping. Publication is the consuming site's CI concern: deploy only on all-green.