Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
70d77c0
feat(cli): enforce runtime variable identity contract
tobyhede May 5, 2026
fd2fd56
docs: tighten persisted state review checks
tobyhede May 6, 2026
cfcadaa
fix(cli): preserve external runbook claim refs
tobyhede May 6, 2026
b7d9138
feat: switch concrete run IDs to rd prefix
tobyhede May 6, 2026
c5abcff
feat(core): brand run ids
tobyhede May 6, 2026
bca72ef
Fix runbook ref claim resolution
tobyhede May 6, 2026
d3bea53
Address runbook ref and claim review feedback
tobyhede May 6, 2026
830c83e
Fix run id test fixtures
tobyhede May 6, 2026
f4cea8d
Resolve step totals from persisted runbook identity
tobyhede May 6, 2026
98c7f0f
Fix rdpath stale active state fallback
tobyhede May 6, 2026
20d51e5
fix: address pr 267 review issues
tobyhede May 6, 2026
f0f9044
test: update scenario snapshots for runbook paths
tobyhede May 6, 2026
ef42d14
fix: address pr 267 follow-up findings
tobyhede May 6, 2026
0f2a7c1
fix: tighten RD_INPUT_* ignore assertion to be case-insensitive
tobyhede May 7, 2026
5723415
fix(cli): return substep id from emitClaimedSuccess for delegated sub…
tobyhede May 7, 2026
8983353
fix(cli): reject symlinked runbook escaping source root via realpath …
tobyhede May 7, 2026
d455aa0
test(cli): wrap symlink test cleanup in try/finally (H1 follow-up)
tobyhede May 7, 2026
507a0f5
test(cli): enforce filename/embedded id contract in readRunbookState …
tobyhede May 7, 2026
393a44a
test(cli): assert vars redacted from stashed status when parentLinkag…
tobyhede May 7, 2026
9808918
test(cli): assert persisted delegation childRunbookRef shape after cl…
tobyhede May 7, 2026
2bb6ab7
test(core): assert childRunbookRef preserved verbatim across retryDel…
tobyhede May 7, 2026
9481210
test(core): cover terminal stopped lifecycle for claimed child (K4)
tobyhede May 7, 2026
28c8f35
docs(reference): clarify runbook.path semantics for external source (D1)
tobyhede May 7, 2026
ff81814
refactor(cli): type applyExecutionTerminalRelease runbookId as RunId …
tobyhede May 7, 2026
ef1650f
refactor(cli): narrow OrchestrateTransitionArgs.runbookId to RunId (H2)
tobyhede May 7, 2026
d3c1f34
refactor(cli): narrow resolveTerminalReleaseModeForRunbook runbookId …
tobyhede May 7, 2026
463fe22
refactor(core): narrow SessionService.stash() return to RunId | null …
tobyhede May 7, 2026
0ac7ea0
test(cli): capture and restore prior RD_INPUT_* env value in reserved…
tobyhede May 7, 2026
f5c63dc
test(cli): drop stale executeCommand mock; assertion targets executeC…
tobyhede May 7, 2026
d18b5a2
test(cli): narrow makeState id parameter to RunId (T7)
tobyhede May 7, 2026
9d60205
docs(cli): fix runExecutionLoop JSDoc param after C3 brand-once rename
tobyhede May 7, 2026
6fdb895
test(core): rephrase K5 comment to avoid cspell-flagged word
tobyhede May 7, 2026
baa0485
Preserve RD_INPUT env in variable tests
tobyhede May 7, 2026
cee131c
test(cli): use brandRunIdForTest helper in startRunbook fixtures
tobyhede May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
language: "en-US"
tone_instructions: >-
Focus on type safety, state machine correctness, security policy correctness,
persisted state compatibility, CLI output stability, and design principles
persisted state no-migration, CLI output stability, and design principles
from CLAUDE.md. Be direct and specific. Flag action-type mapping violations.

reviews:
Expand Down Expand Up @@ -56,7 +56,11 @@ reviews:
- No silent mapping: STOP, COMPLETE, BREAK, DEFER, GOTO, NEXT, CONTINUE, and RETRY must preserve their distinct semantics.
- No synthetic IDs: use XState native event system and state graph structure.
- Guard functions must express domain conditions only.
- Persisted state compatibility: changes to RunbookState, snapshots, lifecycle, variables, delegation state, or schemaVersion must follow the no-migration rule from CLAUDE.md.
- Persisted state no-migration: this project is pre-release. Do not request
migrations, compatibility shims, fallback reconstruction, or legacy identity
derivation for RunbookState, snapshots, lifecycle, variables, delegation state,
or schemaVersion changes. Flag explicit or implicit migration/adaptation; stale
state should be rejected and require complete, stop, prune, or restart.
- path: "packages/core/src/policy/**/*.ts"
instructions: |
Security-sensitive policy code. Focus on:
Expand Down Expand Up @@ -200,12 +204,18 @@ reviews:
docstrings:
mode: "off" # Handled by eslint-plugin-jsdoc in CI
custom_checks:
- name: "Persisted state compatibility"
- name: "Persisted state no-migration"
mode: "warning"
instructions: |
Warn if files that define persisted runbook state, state snapshots, lifecycle fields, variable storage, delegation state, or schemaVersion behavior change and the PR also silently migrates existing .rundown/runs/ data.
This project is pre-release. There is no supported legacy .rundown/runs state.
Do not request migrations, compatibility shims, fallback reconstruction, or legacy runbookRef derivation.

Warn if files that define persisted runbook state, state snapshots,
lifecycle fields, variable storage, delegation state, or schemaVersion behavior
change and the PR explicitly or implicitly adapts, rewrites, or migrates stale
.rundown/runs/ data.
Pass if the PR does not touch persisted state behavior.
Pass if the PR preserves compatibility or detects stale state and requires completion, stop, or prune before restart.
Pass if stale or incompatible state is rejected and the user must complete, stop, prune, or restart.
- name: "CLI schema coverage"
mode: "warning"
instructions: |
Expand Down Expand Up @@ -246,7 +256,7 @@ code_generation:
Generate Jest tests that cover valid syntax, invalid syntax, diagnostics, frontmatter edge cases, code blocks, transitions, FOR clauses, and DELEGATE annotations.
- path: "packages/core/**/*.ts"
instructions: |
Generate Jest tests that cover state transitions, result/handler/action separation, persisted-state stale detection, policy enforcement, sandbox edge cases, output schema stability, and error paths.
Generate Jest tests that cover state transitions, result/handler/action separation, stale persisted-state rejection requiring complete, stop, prune, or restart, policy enforcement, sandbox edge cases, output schema stability, and error paths.
- path: "packages/cli/**/*.ts"
instructions: |
Generate Jest tests that verify JSON output, --text output, --schema output, command option validation, and user-facing errors. Prefer existing CLI test helpers and snapshots only when the repository already uses them for that behavior.
Expand Down
2 changes: 2 additions & 0 deletions cspell-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,12 @@ rehydrated
renderable
resumability
runbook
runbookref
runbooks
rundown
rundownrc
rundowntest
runid
runme
rustc
sandboxing
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/project-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,6 @@ review/
Guidelines:
- Use `#!/usr/bin/env bash` and `set -euo pipefail`
- Accept parameters positionally with usage messages
- By default write output to `.rundown/work/<runbook-name>/` for intermediate artifacts; override via the `WorkPath` template variable (set with `--input WorkPath=...` or config) or the `WORK_PATH` environment variable read by scripts
- By default write intermediate artifacts under the project-shared `.rundown/work` base, using `rdpath --ctx <ContextId>` or `{{ path "..." }}` when artifacts need workflow isolation
- Exit 0 for success (PASS), non-zero for failure (FAIL)
- Keep scripts focused — one responsibility per script
4 changes: 2 additions & 2 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ rundown status
**Output:**
```text
File: my-runbook.runbook.md
State: .rundown/runs/wf-2024-01-07-abc123.json
State: .rundown/runs/rd_0123456789abcdef0123456789abcdef.json
Action: CONTINUE
Result: PASS

Expand Down Expand Up @@ -652,7 +652,7 @@ Output formatting is implemented in `packages/cli/src/services/output-emitter.ts

```text
File: runbook.runbook.md
State: .rundown/runs/wf-xxx.json
State: .rundown/runs/rd_0123456789abcdef0123456789abcdef.json
Action: START
At: 1

Expand Down
46 changes: 35 additions & 11 deletions docs/reference/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,15 @@ The session tracks top-level runs and delegated children separately.

```json
{
"defaultStack": ["wf-2026-04-28-parent"],
"defaultStack": ["rd_11111111111111111111111111111111"],
"stashedRunbookId": null,
"claims": {
"rdclm_F3J3n3d_f8fo0a0b1B2c3Q": {
"kind": "claim-record",
"claimId": "rdclm_F3J3n3d_f8fo0a0b1B2c3Q",
"childRunId": "wf-2026-04-28-child",
"childRunId": "rd_22222222222222222222222222222222",
"tokenHash": "sha256:...",
"parentRunId": "wf-2026-04-28-parent",
"parentRunId": "rd_11111111111111111111111111111111",
"parentStepId": "1.1",
"parentFrameKey": "1|",
"parentEntry": 1,
Expand Down Expand Up @@ -286,8 +286,11 @@ Each run state file stores enough information to resume deterministically.

```json
{
"id": "wf-2024-01-07-abc123",
"runbook": "my-runbook.runbook.md",
"id": "rd_4b7f0c2d9e1a4b7f0c2d9e1a4b7f0c2d",
"runbook": {
"source": "project",
"path": ".rundown/runbooks/my-runbook.runbook.md"
},
"runbookPath": ".rundown/runbooks/my-runbook.runbook.md",
"title": "My Runbook",
"description": "Runbook description",
Expand All @@ -312,6 +315,9 @@ Each run state file stores enough information to resume deterministically.

| Field | Runtime requirement |
| --- | --- |
| `id` | Persisted run identifier generated at execution start. |
| `runbook` | Canonical runbook identity object: `{ source, path }`, where `source` is `project`, `plugin`, `bundled`, or `external`, and `path` is a safe source-root-relative Markdown path. |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
| `runbookPath` | Display/execution file path relative to the current project when possible. |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
| `step`, `substep` | Current structural position. |
| `retryCount` | User-visible retry count across retry sites. |
| `variables` | Live variable space, including accumulated outputs. |
Expand Down Expand Up @@ -367,10 +373,10 @@ remain regular template variables.

User-provided variable names MUST match `/^[a-zA-Z_][a-zA-Z0-9_]*$/`.

The names `step`, `index`, and `context` are reserved case-insensitively.
Reserved names MUST be rejected in frontmatter `inputs`, frontmatter `required`,
explicit invocation inputs, input files, and config files. Reserved
`RD_INPUT_*` variables are skipped with a warning.
The names `step`, `index`, `context`, `runid`, and `runbookref` are reserved
case-insensitively. Reserved names MUST be rejected in frontmatter `inputs`,
frontmatter `required`, explicit invocation inputs, input files, and config
files. Reserved `RD_INPUT_*` variables are skipped with a warning.

### 8.4 Undefined Variables

Expand Down Expand Up @@ -403,8 +409,9 @@ dynamic current-frame values but remain reserved for user input.
| --- | --- |
| `Date`, `DateTime`, `Year`, `Month`, `Day` | Current date/time components. |
| `Branch` | Current git branch, or empty outside git. |
| `WorkPath` | Branch-isolated artifact directory; fallback `.rundown/work`; base for `{{ path "..." }}`. |
| `RunId` | Fresh execution identifier for this runbook execution. |
| `WorkPath` | Fixed default artifact base `.rundown/work`; base for `{{ path "..." }}`. |
| `RunbookRef` | Canonical `{ source, path }` identity for the resolved runbook. Injected during runbook preparation. |
| `RunId` | Fresh execution identifier for this runbook execution. Injected only for runnable execution, not for discovery or `rd resolve`. |
| `ContextId` | Shared identity across a delegation tree; scopes path helpers into `.rd-<ContextId>/`. |
| `Step`, `Index` | Dynamic current step and iteration. |
| `context.current.*` | Dynamic current structural context. |
Expand All @@ -417,6 +424,17 @@ Static built-ins MAY be overridden by higher-precedence sources. Dynamic
built-ins MUST NOT be overridden. Plugin runbooks MAY receive upper-snake-case
plugin variables such as `CLAUDE_PLUGIN_ROOT`.

The default `WorkPath` value is shared at the project level and does not include
a branch, run, or checkout suffix. Use `ContextId` with `{{ path "..." }}` or
`rdpath --ctx` for workflow isolation inside `.rundown/work/.rd-<ContextId>/`;
run-scoped artifact helpers add `runs/<RunId>/` below that context directory
when a per-run location is required.

`RunbookRef` is available before template substitution so runbooks can render
their own canonical identity. `RunId` is minted later, when a run is actually
started or claimed, so commands that only resolve variables MUST NOT emit or
persist a synthetic `RunId`.

<a id="shell-environment"></a>

### 8.7 Shell Environment
Expand All @@ -429,6 +447,8 @@ environment filtering.
| `RD_WORK_PATH` | `WorkPath` |
| `RD_CONTEXT_ID` | `ContextId` |
| `RD_RUN_ID` | `RunId` |
| `RD_RUNBOOK_REF` | `RunbookRef.path` |
| `RD_RUNBOOK_SOURCE` | `RunbookRef.source` (`project`, `plugin`, `bundled`, or `external`) |
| `RD_OUTPUTS_<VarName>` | Naked step/substep `OUTPUTS` entry. |

Rundown-injected `RD_*` variables use Rundown-wins semantics: user-supplied
Expand All @@ -441,6 +461,10 @@ resolved static variable map. On resume, the runtime MUST re-apply FOR bounds
and template placeholders from this frozen variable state so rendering remains
deterministic.

Delegated children inherit the parent's `ContextId` and user variables, but
MUST NOT inherit the parent's `RunId` or `RunbookRef`. Each child receives a
fresh `RunId` and the canonical `RunbookRef` for its own resolved runbook.

## 9. Security Integration

The runtime delegates full policy semantics to
Expand Down
7 changes: 7 additions & 0 deletions docs/reference/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ Default file access:
- Write allow: `{repo}/.claude/**`, `{repo}/.rundown/runs/**`, `{repo}/.rundown/locks/**`, `{repo}/.rundown/contexts/**`, `{repo}/.rundown/session.json`, `{repo}/.rundown/work/**`, `{repo}/node_modules/**`, `{repo}/dist/**`, `{repo}/build/**`, `{repo}/.next/**`, `{tmp}/**`
- Write deny: `**/.env`, `**/.env.*`, `**/credentials.json`, `**/*secret*`, `**/*password*`, `{repo}/.rundown/config.yaml`

The default `WorkPath` built-in resolves to the project-shared
`.rundown/work` directory. Rundown does not add branch- or run-derived suffixes
to that base path. Workflows that need separation should use the `ContextId`
scope (`.rundown/work/.rd-<ContextId>/`) or run-scoped artifact paths below that
context; the default policy intentionally grants the full `.rundown/work/**`
tree so those scoped paths remain writable.

Read deny includes SSH keys and certificates (`id_rsa`, `id_ed25519`, `*.pem`, `*.key`) to reduce credential exfiltration risk. Write deny does not include those patterns so key generation workflows can write new keys when otherwise allowed.

Allowed environment variables:
Expand Down
Loading
Loading