# Runbook pack specification v0.1 A **runbook pack** is a directory `runbooks//` in the repository that owns the procedure. It contains `pack.yaml`, validated by `schema/runbook-pack.schema.json`, plus optional supporting files. The engine discovers packs by scanning `runbooks/*/pack.yaml` under a repository root, or under any root given on the command line. ## Manifest | Field | Required | Meaning | | --- | --- | --- | | `spec` | yes | Literal `runbook-pack/v0.1` | | `id` | yes | Stable dotted id, lower-case, e.g. `nk.ssh-certificates` | | `title`, `outcome` | title yes | What the operator is doing; what is true afterwards | | `owner` | yes | The repository that owns the procedure | | `exercise_status` | no | **Deprecated and ignored.** Maturity is derived from run history; old packs that carry it still load | | `engine` | yes | `native` or `legacy-command` | | `parameters` | no | Operator-supplied, non-secret values | | `prerequisites` | no | `{text, owner}` list | | `steps` | native | Ordered steps (below) | | `threat_checks` | native | What must never be logged, committed or pasted | | `ownership` | no | Concern-to-owner table | | `legacy` | legacy | How to launch the existing console | ## Parameters Each parameter has `id` (`[a-z][a-z0-9_]*`), `label`, `type` (`string|text|enum|path|bool|int`), optional `values`, `default`, `pattern`, `help`. `text` is single-line free text for use inside double quotes: spaces are allowed and shell metacharacters (`; & | ` $ < > \ ' "`) are not. Every other type also rejects spaces. **`secret` may only be `false`**: a parameter is never a secret. Steps refer to parameters as `{{id}}`. An undefined placeholder, an unused parameter, an `enum` without `values`, or a default that violates its `pattern`/`values` is a validation error. ## Steps Every step has `id`, `title`, `owner` (the repo or tool that does the work), and `verify`. Optional: `description`, `command` (a template shown to the operator, copyable, never run by the engine unless a future execution mode is enabled for that step), `risk` (`read-only|changes-state|attended|destructive`), `rollback`, `evidence`. `verify` is mandatory, so a runbook cannot be prose only: - `done_when`: the observable outcome, in words; - `command` and `expect` (`manual|exit-0|output-contains`, with `contains`). A step with `risk` of `changes-state`, `attended` or `destructive` must state a `rollback` (which may say "not reversible" and why). Commands are relative to the root of the repository that owns the pack. Verify commands run there, so a pack can call `make` targets and repo-relative scripts. ## Maturity, not a status field How far a pack can be trusted is earned, not declared: `draft`, `reviewed`, `rehearsed`, `proven`, or `stale`, derived from the runs of the pack at its current revision (`docs/maturity-and-projects.md`). The earlier `exercise_status` field is retired. ## Secrets The engine must not collect, store, log or transmit secret values. The validator rejects manifests containing secret-looking markers (`hvs.…`, private-key blocks, `otpauth://`). ## Legacy packs `engine: legacy-command` wraps an existing guided console unchanged. `legacy.command` is the argv to launch, `legacy.cwd` is relative to the pack root's repository, `legacy.url` is where the console serves. The engine lists, describes and launches it; it does not interpret its internals. Migration to `native` is optional and per pack. ## Versioning `spec` names the version. A change that invalidates existing packs raises the version; the engine keeps loading older versions it declares support for.