@jaybeeuu/agent-cortex 2.6.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +269 -0
- package/README.md +102 -8
- package/agents/README.md +2 -2
- package/agents/ralph/agent.md +19 -16
- package/agents/ralph/claude/wake.md +4 -4
- package/agents/ralph/pi/wake.md +15 -20
- package/bin/agent-cortex.mjs +176 -67
- package/bin/installers/claude.mjs +33 -8
- package/bin/installers/pi.mjs +11 -1
- package/docs/skills/skill-anatomy.md +212 -0
- package/extensions/post-merge-watch/README.md +133 -0
- package/extensions/post-merge-watch/index.test.ts +247 -0
- package/extensions/post-merge-watch/index.ts +123 -0
- package/extensions/post-merge-watch/package.json +16 -0
- package/extensions/post-merge-watch/watch.test.ts +469 -0
- package/extensions/post-merge-watch/watch.ts +431 -0
- package/extensions/session-clear/README.md +74 -0
- package/extensions/session-clear/index.test.ts +524 -0
- package/extensions/session-clear/index.ts +159 -0
- package/extensions/session-clear/package.json +16 -0
- package/lib/cli.mjs +88 -1
- package/lib/harness-update.mjs +254 -0
- package/lib/harness-versions.mjs +36 -2
- package/lib/self-update.mjs +553 -0
- package/package.json +2 -1
- package/scripts/lib/docs.mjs +67 -0
- package/skills/engineering/implement-task/SKILL.md +124 -0
- package/skills/engineering/tdd/SKILL.md +2 -0
- package/skills/planning/create-task/REFERENCE.md +20 -3
- package/skills/planning/create-task/SKILL.md +1 -1
- package/skills/planning/create-task/pipeline.json +16 -0
- package/skills/planning/create-task/scripts/create-chores.mjs +51 -24
- package/skills/planning/create-task/templates/code.md +8 -3
- package/skills/planning/create-task/templates/document.md +8 -3
- package/skills/planning/create-task/templates/fix.md +8 -3
- package/skills/planning/create-task/templates/housekeeping.md +69 -0
- package/skills/planning/create-task/templates/post-merge.md +67 -0
- package/skills/planning/create-task/templates/review.md +8 -3
- package/skills/planning/create-task/templates/verify.md +8 -3
- package/skills/productivity/bd-tool/SKILL.md +55 -0
- package/skills/productivity/write-a-skill/SKILL.md +2 -2
- package/skills/review/refactor-skill/SKILL.md +2 -2
- package/skills/review/review-defects/EXAMPLES.md +122 -0
- package/skills/review/review-defects/SKILL.md +91 -0
- package/skills/style/style-tests/EXAMPLES.md +30 -0
- package/skills/style/style-tests/SKILL.md +10 -6
- package/skills/workflow/plan/SKILL.md +14 -3
- package/skills/workflow/ralph/REFERENCE.md +137 -30
- package/skills/workflow/ralph/SKILL.md +26 -16
- package/skills/workflow/ralph/scripts/post-merge-check.mjs +651 -0
- package/skills/workflow/run-pipeline-stage/SKILL.md +41 -23
- package/skills/workflow/run-pipeline-stage/playbooks/code.md +14 -8
- package/skills/workflow/run-pipeline-stage/playbooks/document.md +2 -2
- package/skills/workflow/run-pipeline-stage/playbooks/fix.md +2 -2
- package/skills/workflow/run-pipeline-stage/playbooks/housekeeping.md +58 -0
- package/skills/workflow/run-pipeline-stage/playbooks/post-merge.md +54 -0
- package/skills/workflow/run-pipeline-stage/playbooks/review.md +34 -3
- package/skills/workflow/run-pipeline-stage/playbooks/verify.md +2 -2
- package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +66 -10
- package/skills/workflow/run-pipeline-stage/scripts/recover-brief.mjs +805 -0
- package/skills/workflow/run-pipeline-stage/scripts/trail-entry.mjs +702 -0
- package/skills/workflow/using-agent-skills/SKILL.md +15 -7
- package/token-map.README.md +41 -4
- package/token-map.json +16 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,274 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 683808c: State the bead-state rule in `bd-tool` and `AGENTS.md`: operational state (progress, what a stage
|
|
8
|
+
learned, the decisions taken, branch/PR/commit/worktree refs) lives in bead fields, while durable
|
|
9
|
+
committable documents stay files, and `handoff.md` plus the working-docs artefact directory are
|
|
10
|
+
unchanged. The built-in statuses carry the working state — `bd statuses` lists all seven, so no
|
|
11
|
+
state label is added. What happened goes in the trail with `bd note`, which appends. The text names
|
|
12
|
+
`stage=` as forbidden for state, with the reason: `bd set-state` removes the existing label for the
|
|
13
|
+
dimension it sets, so it would rewrite a chore's route. Ship this in the same release as the
|
|
14
|
+
removal of the `ralph-*.log` and `progress.md` writer sites (`agnt-ctx-ul91.1`): a published
|
|
15
|
+
version that states the rule while a skill still writes progress files would contradict itself.
|
|
16
|
+
- 87ebb46: Give the pipeline one shared writer for the bead trail, and stop the file-based progress logs.
|
|
17
|
+
|
|
18
|
+
`skills/workflow/run-pipeline-stage/scripts/trail-entry.mjs` appends one checkpoint to a bead's
|
|
19
|
+
notes with `bd note` and records the refs the caller names as provenance events. Every entry
|
|
20
|
+
carries the three mandatory fields — Outcome (`done`/`blocked`/`partial`), Evidence (a test or lint
|
|
21
|
+
result, the commit, command output), and What is left — so a fresh session resumes from
|
|
22
|
+
`bd show <id>` alone.
|
|
23
|
+
|
|
24
|
+
A `--commit` ref is resolved through `git rev-parse` to the full 40-character lowercase SHA before
|
|
25
|
+
recording, because `bd provenance record --ref-kind git-sha` refuses an abbreviated one; a ref that
|
|
26
|
+
does not resolve records nothing. Transient database failures — `failed to open database ...
|
|
27
|
+
context canceled`, the shape two concurrent writers produce on embeddeddolt — are retried with
|
|
28
|
+
bounded backoff, each retry re-reads the bead first so a write that landed before its call reported
|
|
29
|
+
failure is never duplicated, and no call holds the database across a long operation. Recording is
|
|
30
|
+
idempotent for one writer: the entry carries a fingerprint of its own content, so a repeated fire
|
|
31
|
+
appends nothing. Two concurrent fires of one transition can each append — `bd note` has no
|
|
32
|
+
conditional append — so the pipeline fires each transition from one worker.
|
|
33
|
+
|
|
34
|
+
`run-pipeline-stage` and `ralph` now call that script at every stage transition, and no shipped
|
|
35
|
+
skill, agent, or stage template writes a per-parent log file or a rendered progress view any more.
|
|
36
|
+
Ralph's log polling, its `state.json` `logLine` bookmark, and both wake sections' log-flush
|
|
37
|
+
procedure go with them: progress is read from the bead (`bd show`, `bd provenance log`), which is
|
|
38
|
+
the record the worker writes directly.
|
|
39
|
+
|
|
40
|
+
- 4e1bcc5: Add `implement-task`, the skill that owns the task around the loop: criteria, scope, and proof.
|
|
41
|
+
|
|
42
|
+
`tdd` owns the red-green loop and the `style-*` skills own the standards, but nothing owned the task
|
|
43
|
+
— reading the acceptance criteria, proving each one, staying in scope, and taking only pragmatic
|
|
44
|
+
boy-scout fixes. `implement-task` fills that gap with four load-bearing sections: the criteria →
|
|
45
|
+
evidence table, written before code and filled with observable evidence at Finish; the scope rule,
|
|
46
|
+
where an out-of-scope finding becomes a bead instead of an edit; the boy-scout rule, which allows a
|
|
47
|
+
fix only inside a file the task already touches and only where it serves the task; and the mutation
|
|
48
|
+
check, inherited from `style-tests` and applied to every test that claims a behaviour. A criterion
|
|
49
|
+
with no named check is a blocker, not a guess.
|
|
50
|
+
|
|
51
|
+
The `code` stage playbook now invokes `implement-task` as its first step and routes through it to
|
|
52
|
+
`tdd` and the style skills, `tdd` links to it for criteria and scope rather than carrying those
|
|
53
|
+
rules itself, and `using-agent-skills` routes a task-implementation request to it while leaving a
|
|
54
|
+
bare "write a test for X" on `tdd`.
|
|
55
|
+
|
|
56
|
+
- 27b513b: Fork the planner ↔ ralph peer channel per harness instead of describing it as PI-only. The channel
|
|
57
|
+
now renders through `token-map.json`: `{{TOOL:peer_send}}` and `{{TOOL:peer_list}}` become
|
|
58
|
+
`peer_send` and `peer_list` in a pi install, and Claude Code's built-in `SendMessage` and
|
|
59
|
+
`ListAgents` in a claude install. Both harnesses carry the same seven message kinds and the same
|
|
60
|
+
acknowledgement rule — the kinds table and the reply rule are byte-identical between the two
|
|
61
|
+
renders, and only the `### Transport` subsection differs.
|
|
62
|
+
|
|
63
|
+
Claude Code's cross-session messaging is built in from v2.1.224 (v2.1.234 on native Windows):
|
|
64
|
+
`ListAgents` returns the peers a session can reach with the address of each, and `SendMessage`
|
|
65
|
+
delivers to that address, so a named peer session is addressable and no manual-handoff-only fork is
|
|
66
|
+
needed. `pi-peer`'s `peer_get` and `peer_await` have no Claude Code counterpart, so they are named
|
|
67
|
+
only inside the harness-labelled `pi-peer` runbook: a null mapping would drop the token and leave
|
|
68
|
+
the sentence that named it broken.
|
|
69
|
+
|
|
70
|
+
`test/skill-transport-render.test.mjs` stages both installs and asserts the per-harness rendered
|
|
71
|
+
text, so a harness that loses its mechanism fails the suite rather than silently degrading.
|
|
72
|
+
|
|
73
|
+
- 49b34d7: Document the planner ↔ ralph message convention on top of `@cryptolibertus/pi-peer`. The `ralph`
|
|
74
|
+
skill now publishes its peer identity at start (`PI_PEER_ID=ralph`), answers inbound `handoff`,
|
|
75
|
+
`get` and `ask` messages, and reports `update`/`done`/`blocked`/`failed` to the planner as work
|
|
76
|
+
dispatches, finishes, parks on a human gate or fails. The `plan` skill sends a `handoff` message
|
|
77
|
+
naming the handoff bead once it exists, treats ralph's `blocked` messages as its pending-human
|
|
78
|
+
surface, and keeps the manual instruction as the handoff path for a session with no reachable
|
|
79
|
+
receiver.
|
|
80
|
+
|
|
81
|
+
The shared convention — the kind-to-intent table, the acknowledgement rule, the two-entry
|
|
82
|
+
`.pi/peers.json` requirement and the one-way discovery failure a single entry causes, the
|
|
83
|
+
`.pi/peers.json` and `.pi/peer-*` paths to gitignore, and the rule to send through `peer_send` rather than typing into a
|
|
84
|
+
busy session — lives once in `skills/workflow/ralph/REFERENCE.md` and is cross-referenced from
|
|
85
|
+
`plan`. pi-peer keeps ownership of discovery, delivery, idle wake and the ledger; no registry,
|
|
86
|
+
inbox, watcher or transport is implemented here. The tools are named through `{{TOOL:...}}` tokens so
|
|
87
|
+
one skill text serves both harnesses; the per-harness fork is its own changeset.
|
|
88
|
+
|
|
89
|
+
- 2610b78: Add the `post-merge` pipeline stage and the deterministic check it runs.
|
|
90
|
+
`skills/workflow/ralph/scripts/post-merge-check.mjs` reads `gh run list` for the base branch's merge
|
|
91
|
+
commit and exits `0` passed, `1` failed, `2` inconclusive — no model, no tokens, zero runtime
|
|
92
|
+
dependencies, async only. A failing run files exactly one P1 escalation bead carrying the run URL
|
|
93
|
+
and the failing job name; the `post-merge-run:<id>` marker in its description makes a second run
|
|
94
|
+
file nothing. It never retries, never re-runs the workflow, never reopens the parent, and is
|
|
95
|
+
GitHub-only in v1 (a repository `gh` cannot resolve to a GitHub host, or a commit with no run, is
|
|
96
|
+
inconclusive and files nothing). `create-chores.mjs` pre-creates the chore labelled
|
|
97
|
+
`lifecycle:post-merge`, blocked behind the `lifecycle:feature-pr` gate rather than behind a stage,
|
|
98
|
+
so it becomes ready only once a human merges and closes the gate; a re-run still creates nothing.
|
|
99
|
+
The script reads the repository slug and base branch from `gh repo view`, so no slug or branch is
|
|
100
|
+
baked in. `housekeeping` and `post-merge` are siblings on the gate and neither waits on the other,
|
|
101
|
+
because an inconclusive check must not strand the worktree reclamation.
|
|
102
|
+
- 241ab8f: Add the `post-merge-watch` pi extension: poll the post-merge check and wake an idle session with
|
|
103
|
+
the verdict.
|
|
104
|
+
|
|
105
|
+
`pi --post-merge-watch <bead>` polls
|
|
106
|
+
`skills/workflow/ralph/scripts/post-merge-check.mjs` every 15 s (up to 40 checks) and, when the
|
|
107
|
+
script reports a verdict, sends one message with
|
|
108
|
+
`pi.sendMessage(..., { deliverAs: "followUp", triggerTurn: true })`, so a session that is idle
|
|
109
|
+
starts a turn with the result. The message names the bead, the verdict, the exit code, the reason,
|
|
110
|
+
the run URL, the project, and the number of checks; the same fields ride along as message
|
|
111
|
+
`details`.
|
|
112
|
+
|
|
113
|
+
The extension owns no verdict logic: the check's exit code is the verdict (`0` passed, `1` failed,
|
|
114
|
+
anything else inconclusive, including a timeout kill), and the run URL is forwarded from the
|
|
115
|
+
script's JSON report. It makes no model call, imports pi as types only, registers its CLI flag in
|
|
116
|
+
the extension factory, and spawns no process or writes no state when the flag is absent. Each
|
|
117
|
+
invocation passes `--wait 0`, so the poll interval and the bound live in the extension and a
|
|
118
|
+
stopped watch never blocks on a child process.
|
|
119
|
+
|
|
120
|
+
State lives under `~/.pi/agent-cortex/post-merge-watch/`, one file per project path and bead (the
|
|
121
|
+
name carries a digest of both, so two projects watching one bead never collide), and is removed
|
|
122
|
+
when the watch settles or the session shuts down. The pending timer is unref'd and cancelled on
|
|
123
|
+
shutdown, so an abandoned watch leaves no orphan timer and no state file. The default check script
|
|
124
|
+
is resolved relative to the extension file, so the staged pi package (`extensions/` beside
|
|
125
|
+
`skills/`) needs no hardcoded absolute path; `AGENT_CORTEX_POST_MERGE_CHECK` overrides it. PI only:
|
|
126
|
+
Claude Code uses its own watch tools.
|
|
127
|
+
|
|
128
|
+
- ee5d09f: Fork the post-merge stage's watch per harness instead of leaving a long run unwatched. The stage
|
|
129
|
+
playbook now carries a `## Watch transport` section whose single mechanism name renders through
|
|
130
|
+
`token-map.json`: `{{TOOL:post_merge_watch}}` becomes `post-merge-watch` — this package's own
|
|
131
|
+
extension, which re-runs the check on a timer and wakes an idle session with the verdict — in a pi
|
|
132
|
+
install, and Claude Code's built-in `ScheduleWakeup` tool in a claude install. The stage
|
|
133
|
+
instructions, the three verdicts, the never-retry rule, the escalation rule and the close rule stay
|
|
134
|
+
one authored copy: the two renders differ on exactly one line.
|
|
135
|
+
|
|
136
|
+
The Claude capability is established from the installed binary (2.1.294), not assumed.
|
|
137
|
+
`ScheduleWakeup` is a registered tool whose own description names the case in point — "when actively
|
|
138
|
+
polling external state the harness can't notify you about (a CI run, a deploy, a remote queue), pick
|
|
139
|
+
the delay from how fast that state actually changes" — it takes `delaySeconds` clamped to
|
|
140
|
+
60–3600, `prompt`, `reason`, `noop` and `stop`, and a built-in system reminder says "If polling in a
|
|
141
|
+
loop, use ScheduleWakeup instead of retrying". A live probe was impossible: `claude -p` in this
|
|
142
|
+
environment reports "Not logged in · Please run /login". Because availability is a property of the
|
|
143
|
+
session rather than of the tool's existence, the section also states the fallback in prose — one run
|
|
144
|
+
with `--wait 1800` — so no harness is assumed to have a watcher and neither render loses a name.
|
|
145
|
+
|
|
146
|
+
`test/post-merge-transport-render.test.mjs` stages both installs and asserts the per-harness rendered
|
|
147
|
+
playbook, the byte-identical remainder, and the no-watcher fallback, so a harness that loses its
|
|
148
|
+
mechanism fails the suite rather than silently degrading.
|
|
149
|
+
|
|
150
|
+
- b698f2d: Read a half-finished bead in one bounded command, without opening the transcript.
|
|
151
|
+
|
|
152
|
+
`skills/workflow/run-pipeline-stage/scripts/recover-brief.mjs` is the read side of the bead trail
|
|
153
|
+
that `trail-entry.mjs` writes. One invocation prints what a session needs to continue: status and
|
|
154
|
+
state labels, the newest trail entries with their Evidence and What is left, the provenance refs,
|
|
155
|
+
the blocking dependencies, and the acceptance criteria.
|
|
156
|
+
|
|
157
|
+
The bound is enforced, not promised. `bd show` returns the whole note — no option asks it for the
|
|
158
|
+
last few entries — and it prints 89 lines and about 6.5 KB for a bare bead carrying 20 entries,
|
|
159
|
+
about 120 lines and about 8 KB for a realistic one with acceptance criteria, a blocker, provenance
|
|
160
|
+
refs and a description. The brief prints the newest `--trail` entries (default 3), summarises the
|
|
161
|
+
rest by count, clips any single field, and
|
|
162
|
+
holds its whole output to a line budget (default 40) even when the requested window is wider than
|
|
163
|
+
that: it shrinks the window, names what it left out, and never prints more lines than `--max-lines`.
|
|
164
|
+
|
|
165
|
+
It reads only. Every `bd` call is one of the read subcommands and carries `--readonly`, and a call
|
|
166
|
+
that is not on the allow-list is refused before it reaches the binary, so the brief cannot write a
|
|
167
|
+
note, a status or a provenance event. Each section states plainly when a bead has no trail, no
|
|
168
|
+
refs, no acceptance criteria or no blockers, instead of printing an empty heading.
|
|
169
|
+
|
|
170
|
+
The note is one text blob, so the brief splits it itself: a writer header starts a stamped entry
|
|
171
|
+
whose body runs only over the writer's `Field: value` lines, and any other text is an entry of its
|
|
172
|
+
own. A note appended by hand therefore prints wherever it lands — before a stamped entry, between
|
|
173
|
+
two of them, or after the last one — and the trail count includes it. `next:` claims "no trail
|
|
174
|
+
entry" only when the bead carries no trail, and says the entries record no next step when they
|
|
175
|
+
exist without a `What is left` field.
|
|
176
|
+
|
|
177
|
+
`run-pipeline-stage`, `ralph` and the stage-runner prompt now document the brief as the first read of
|
|
178
|
+
a bead's trail, with `bd show` and `bd provenance log` reserved for the history the window left out.
|
|
179
|
+
|
|
180
|
+
- 1e97223: Rejections now carry data. A review that rejects a bead applies exactly one `defect:<class>` label
|
|
181
|
+
from a closed list of eight classes — `test-unproven`, `test-cannot-fail`, `criteria-unmet`,
|
|
182
|
+
`scope-creep`, `style-violation`, `missing-proof`, `regression`, `docs-drift` — plus the specific
|
|
183
|
+
reason in the rejection text.
|
|
184
|
+
|
|
185
|
+
The new `review-defects` skill defines the vocabulary, with one worked example per class in
|
|
186
|
+
`EXAMPLES.md`. The review playbook instructs one label per rejection, states that a class outside
|
|
187
|
+
the list is a review defect in itself, and says the review that confirms a fix removes the label and
|
|
188
|
+
records the removal in its trail entry. The label classifies the defect; the bead's status still
|
|
189
|
+
says where the work is, so no state label is added. Because the rejected chore is normally already
|
|
190
|
+
closed, the two queries that read the vocabulary pass `--all`: one class with
|
|
191
|
+
`bd list -l defect:<class> --all`, and every defect with `bd list --label-pattern 'defect:*' --all`.
|
|
192
|
+
`bd-tool` indexes the label and points at `review-defects` for the vocabulary and the queries.
|
|
193
|
+
|
|
194
|
+
- 7ce04e0: Add `agent-cortex self-update` (and its `ctx` / `cortex` aliases): update the globally installed CLI
|
|
195
|
+
through the manager that owns the install, then refresh the harness installs with the newly
|
|
196
|
+
installed binary. The owner is inferred from the running entry point's real path — pnpm's
|
|
197
|
+
`global/<v>` and `store/<v>/links` layouts, or npm's `lib/node_modules` — then confirmed by asking
|
|
198
|
+
that manager for its own global listing and matching this package's name and version, so a manager
|
|
199
|
+
on `PATH` is never used in place of the real owner: an unidentified or unconfirmed owner prints the
|
|
200
|
+
exact command and exits non-zero. It reports the installed version (read from the manifest beside
|
|
201
|
+
the entry point), the published version (from the confirmed manager's `view`), the owner, and the
|
|
202
|
+
command, and `--check` stops after the report writing nothing. A registry error is a distinct
|
|
203
|
+
failure that offers no update, and a failed install reports the manager's stderr and runs nothing
|
|
204
|
+
after it. Every process is spawned with an argv array (`execFile` / `spawn`), never a shell string.
|
|
205
|
+
- 2624dce: `self-update` now reports the version boundary and only refreshes when the CLI changed. After a
|
|
206
|
+
successful install it reads the version the newly installed binary reports and prints
|
|
207
|
+
`cli <before> → <after>`, then hands the terminal to that binary's `update -a` and exits with
|
|
208
|
+
the refresh's own exit code, so a failed refresh is visible to the caller. The refresh is skipped in
|
|
209
|
+
three cases: `--check`, a failed update, and an install already at the published version (which now
|
|
210
|
+
also installs nothing and points at `agent-cortex update -a` instead). A refresh that cannot start
|
|
211
|
+
prints the reason and the exact command to run by hand instead of exiting 1 silently. The README,
|
|
212
|
+
`docs/dev-loop.md` and `--help` document the act-by-default behaviour, `--check`, the owner
|
|
213
|
+
detection rule, and the re-exec chain with its failure output.
|
|
214
|
+
- 8925019: Add the `session-clear` extension, which registers `/clear` in pi: keep the session display name,
|
|
215
|
+
model, thinking level, and active agent, and drop the transcript context. It captures the identity
|
|
216
|
+
as plain data, replaces the session with `ctx.newSession({ parentSession })` so the cleared session
|
|
217
|
+
stays the parent in `/tree` and `/resume`, then the replacement instance re-applies the name and
|
|
218
|
+
restores the model and thinking level only when they differ from the replacement's own values. It
|
|
219
|
+
appends a `session-clear` provenance entry, reports the clear in one line, never prompts, never
|
|
220
|
+
summarises, and never deletes the cleared session file. PI-only: Claude Code already ships `/clear`,
|
|
221
|
+
so the audit in `docs/claude-hooks.md` records no hook port.
|
|
222
|
+
- 0936de5: Make a test's name an assertion contract, and require a mutation check before a test is done.
|
|
223
|
+
|
|
224
|
+
`style-tests` now states that every clause of a test name must be an assertion: a count in the name
|
|
225
|
+
asserts a count, a state asserts that state, and a "not" asserts the absence. The Workflow gains the
|
|
226
|
+
mutation check — disable the claimed behaviour and confirm each named test fails — and Red Flags
|
|
227
|
+
names the case that motivated it, a test named "one notice" proven only by `toBeDefined()`. The
|
|
228
|
+
worked pair lives in `EXAMPLES.md` under _A test name is a claim_. The review playbook now requires
|
|
229
|
+
the reviewer to map each clause of a changed test's name to the assertion that proves it, to reject a
|
|
230
|
+
test whose name outruns its assertions, and to block a test change that carries no evidence the
|
|
231
|
+
mutation check ran.
|
|
232
|
+
|
|
233
|
+
### Patch Changes
|
|
234
|
+
|
|
235
|
+
- 82dbed0: A stop that needs a human decision becomes a bead, not a label: `bd-tool` and `AGENTS.md` now say
|
|
236
|
+
to create an `execution:hitl` task carrying the question, then make the waiting bead depend on it
|
|
237
|
+
with `bd dep add <waiting> <decision>`. The waiting bead leaves `bd ready` while the decision
|
|
238
|
+
becomes work a human can take, so one answer releases work that is already scoped. `--status
|
|
239
|
+
blocked` is kept for a stop no bead can carry, such as a fix-round cap, and `bd note` records the
|
|
240
|
+
stop and its reason.
|
|
241
|
+
|
|
242
|
+
## 2.7.0
|
|
243
|
+
|
|
244
|
+
### Minor Changes
|
|
245
|
+
|
|
246
|
+
- 464c761: Add `ctx update`, which refreshes installed harnesses by re-running their installers. Bare
|
|
247
|
+
`ctx update` lists every harness with its installed version and the CLI version, then asks which
|
|
248
|
+
to refresh; a non-interactive shell prints the same table plus the flags and exits non-zero
|
|
249
|
+
instead of blocking. `ctx update pi claude` refreshes exactly the named harnesses, `ctx update -a`
|
|
250
|
+
refreshes every harness that is not at the CLI version, and `ctx update -a -f` re-runs every
|
|
251
|
+
installer regardless of version. The report gives each harness its previous and new version and
|
|
252
|
+
the artifacts the installer wrote. Selection and reporting are the only additions: every refresh
|
|
253
|
+
goes through the existing `bin/installers/` entry points, so update-vs-install stays the
|
|
254
|
+
installer's decision.
|
|
255
|
+
|
|
256
|
+
### Patch Changes
|
|
257
|
+
|
|
258
|
+
- bfce679: Add a `housekeeping` pipeline stage that runs after the human merge gate. `create-chores.mjs` now
|
|
259
|
+
creates a `stage:housekeeping` chore labelled `lifecycle:housekeeping` and blocked behind the
|
|
260
|
+
`lifecycle:feature-pr` gate bead, so it stays out of `bd ready` until a human merges the PR and
|
|
261
|
+
closes the gate. A dispatched worker then runs `prune-worktrees.mjs` from the main checkout, retries
|
|
262
|
+
once on a non-zero exit, and fails the chore without closing it when a closed-bead worktree is still
|
|
263
|
+
refused. The four existing stages and the gate are unchanged.
|
|
264
|
+
- 8d11154: Ship the skill anatomy doc into both installs. `write-a-skill` and `refactor-skill` read
|
|
265
|
+
`docs/skills/skill-anatomy.md`, but neither install contained it, so the reference was dead on any
|
|
266
|
+
machine without the checkout. Both installers now copy the document into the staged tree once per
|
|
267
|
+
install (`scripts/lib/docs.mjs`), and the skills name it through a new `{{PATH:skill_anatomy}}` entry
|
|
268
|
+
in `token-map.json`, so the token map stays the single source of the per-harness path. A new test
|
|
269
|
+
stages both installs and fails when a rendered skill references a repository doc the install does
|
|
270
|
+
not contain.
|
|
271
|
+
|
|
3
272
|
## 2.6.0
|
|
4
273
|
|
|
5
274
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -81,7 +81,8 @@ temp-dir install plus structural checks:
|
|
|
81
81
|
the whole plugin — every skill and agent in it — with that one field. Hand-authored
|
|
82
82
|
extras — `.mcp.json` and `scripts/` — are copied into every install from the `claude-extras/`
|
|
83
83
|
dir, which is their canonical store. See `docs/claude-hooks.md` for the
|
|
84
|
-
extension→hook mapping and the rejections (auto-name, agent-guardrails, skill-stats, subagent, agent-modes
|
|
84
|
+
extension→hook mapping and the rejections (auto-name, agent-guardrails, skill-stats, subagent, agent-modes,
|
|
85
|
+
session-clear, post-merge-watch).
|
|
85
86
|
|
|
86
87
|
Edit the sources (`agents/<name>/` composable dirs, `skills/**`,
|
|
87
88
|
`hooks/claude/`, `claude-extras/`, `package.json`), never anything under the materialised
|
|
@@ -209,6 +210,7 @@ The staged package contains:
|
|
|
209
210
|
| `package.json` | pi manifest — `keywords: ["pi-package"]`, `pi.extensions` + `pi.skills`; the version tracks the package |
|
|
210
211
|
| `agents/` | composed flat agents (ralph, plan, ralph-plan, strategy) with `{{TOOL:...}}` / `{{PATH:...}}` substituted — the shipped `agent-modes` extension resolves them from the package root |
|
|
211
212
|
| `skills/` | token-substituted skill copies (real files, never symlinks) |
|
|
213
|
+
| `docs/` | the repository documents those skills read (currently `docs/skills/skill-anatomy.md`), copied verbatim once per install so the reference resolves on a machine without the checkout |
|
|
212
214
|
| `extensions/` | copy of the repo `extensions/` tree — imports nothing from pi's runtime except the host-aliased `typebox`, so pi loads it from any directory |
|
|
213
215
|
| `token-map.json` | the token map `agent-modes` reads from the package root |
|
|
214
216
|
| `node_modules/` | the required third-party pi packages and their transitive closure |
|
|
@@ -243,9 +245,9 @@ never removes an entry you added. Each report gives the `pi remove` command that
|
|
|
243
245
|
resolves it, with the resolved path, because `pi remove` resolves a relative
|
|
244
246
|
argument against the current directory.
|
|
245
247
|
|
|
246
|
-
Re-run `agent-cortex install pi` after every `git pull` to refresh
|
|
247
|
-
package; registration is already in place, so that re-run changes nothing in
|
|
248
|
-
|
|
248
|
+
Re-run `agent-cortex install pi` (or `agent-cortex update pi`) after every `git pull` to refresh
|
|
249
|
+
the staged package; registration is already in place, so that re-run changes nothing in pi's
|
|
250
|
+
settings. Verify with `pi list` and `pi config` (restart pi to apply).
|
|
249
251
|
|
|
250
252
|
Refreshing the installed runtime after a release, and trying uncommitted work without
|
|
251
253
|
overwriting it, are recorded in [`docs/dev-loop.md`](docs/dev-loop.md).
|
|
@@ -408,8 +410,9 @@ from a different root is refreshed in place rather than re-pointed at the fresh
|
|
|
408
410
|
install. Re-point it with
|
|
409
411
|
`claude plugin marketplace remove jaybeeuu` and re-run the install.
|
|
410
412
|
|
|
411
|
-
The plain install IS the update — there is no separate build step
|
|
412
|
-
|
|
413
|
+
The plain install IS the update — there is no separate build step, and `agent-cortex update claude`
|
|
414
|
+
is the same materialise-and-register run selected by name. (`--output <dir>` only generates a
|
|
415
|
+
preview and never refreshes an installed plugin.)
|
|
413
416
|
|
|
414
417
|
#### Uninstall
|
|
415
418
|
|
|
@@ -455,7 +458,8 @@ extension→hook audit.
|
|
|
455
458
|
#### Not ported / follow-ups
|
|
456
459
|
|
|
457
460
|
- Only `session-start` and `notify` had Claude equivalents (both ported to hooks); the other
|
|
458
|
-
pi `extensions/` (auto-name, agent-guardrails, skill-stats, subagent, agent-modes
|
|
461
|
+
pi `extensions/` (auto-name, agent-guardrails, skill-stats, subagent, agent-modes,
|
|
462
|
+
post-merge-watch) have none — `output-style`
|
|
459
463
|
reaches Claude through the managed `CLAUDE.md` section instead; the audit and
|
|
460
464
|
rejection rationale live in `docs/claude-hooks.md`.
|
|
461
465
|
- Ralph follow-ups: multi-feature epic branches, and a GitHub-trigger routine to auto-resume
|
|
@@ -474,7 +478,7 @@ version — picked up at install time) — then run
|
|
|
474
478
|
`agent-cortex install claude` (re-materialises the home plugin, merges settings, and
|
|
475
479
|
re-registers it; `--output <dir>` generates a preview only). The only committed file under
|
|
476
480
|
`claude/` is the settings template; `~/.agent-cortex/claude` is generated in full
|
|
477
|
-
(`.claude-plugin/plugin.json`, `agents/`, `skills/`, `hooks.json`, `.mcp.json`, `scripts/`)
|
|
481
|
+
(`.claude-plugin/plugin.json`, `agents/`, `skills/`, `docs/`, `hooks.json`, `.mcp.json`, `scripts/`)
|
|
478
482
|
so never edit anything under it. CI validates the Claude materialiser (structural checks on
|
|
479
483
|
a temp-dir install) so sources and installer can never silently diverge.
|
|
480
484
|
|
|
@@ -502,6 +506,96 @@ Only plain release versions are compared, so a prerelease on either side also re
|
|
|
502
506
|
The command is read-only: it stats and reads those manifests, and never installs, writes, or
|
|
503
507
|
reaches the network.
|
|
504
508
|
|
|
509
|
+
## Updating the CLI itself (`agent-cortex self-update`)
|
|
510
|
+
|
|
511
|
+
`agent-cortex self-update` updates the globally installed CLI through the manager that installed it,
|
|
512
|
+
then refreshes the harness installs with the newly installed binary.
|
|
513
|
+
|
|
514
|
+
```sh
|
|
515
|
+
agent-cortex self-update # report, update, then refresh the harness installs
|
|
516
|
+
agent-cortex self-update --check # report the versions and the command, write nothing
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
The owning manager is inferred from the running entry point's real path, then confirmed — never
|
|
520
|
+
assumed. A pnpm install lives under `<prefix>/global/<v>/…` (and the store link that path resolves
|
|
521
|
+
into), an npm install under `<prefix>/lib/node_modules/…`, and the manager binary is taken from that
|
|
522
|
+
`<prefix>` rather than from `PATH`. That matters because two managers can be installed and only one
|
|
523
|
+
of them owns this copy: running the manager on `PATH` would update the wrong store or fail. The
|
|
524
|
+
confirmation asks the inferred manager for its own global listing and matches this package's name
|
|
525
|
+
and version. An owner that cannot be inferred or confirmed prints the exact command and exits
|
|
526
|
+
non-zero — both managers' commands when it cannot even infer the layout, because that choice is
|
|
527
|
+
the user's. The CLI never falls back to a manager found on `PATH`.
|
|
528
|
+
|
|
529
|
+
The report gives the installed version (read from the manifest beside the entry point, so even a
|
|
530
|
+
stale process reports what is on disk), the published version (from the confirmed manager's `view`),
|
|
531
|
+
the owner, and the command it would run. A registry error is its own failure: it prints the
|
|
532
|
+
manager's error, offers no update, and exits non-zero. A failed install reports the manager's stderr
|
|
533
|
+
and runs nothing after it. Once the install succeeds, the command reports the CLI version before and
|
|
534
|
+
after (`cli 1.2.3 → 1.4.0`, read from the binary the update just installed, because the
|
|
535
|
+
running process is still the old code), then hands the terminal to the new binary's `update -a`. One
|
|
536
|
+
command brings the CLI and the harness installs to the same version, and the exit code is the
|
|
537
|
+
refresh's.
|
|
538
|
+
|
|
539
|
+
The refresh spawns `<prefix>/bin/agent-cortex` from that same inferred prefix with an argv array and
|
|
540
|
+
inherits the terminal, so the refresh's own output is what the user reads. It is skipped in three
|
|
541
|
+
cases: `--check`, a failed update, and an install already at the published version (where
|
|
542
|
+
`agent-cortex update -a` is the refresh that is left). A refresh that cannot start — the path is
|
|
543
|
+
POSIX-shaped, while native Windows pnpm and npm write `.cmd` shims it does not match, and Node cannot
|
|
544
|
+
start a `.cmd` without a shell — prints the reason and the exact command to run by hand, and exits
|
|
545
|
+
non-zero. The CLI update has already succeeded by then, so `agent-cortex update -a` finishes the job.
|
|
546
|
+
|
|
547
|
+
```sh
|
|
548
|
+
# what it reports, for a copy installed by a pnpm that is not the one on PATH
|
|
549
|
+
agent-cortex self-update --check
|
|
550
|
+
# installed 1.2.3
|
|
551
|
+
# published 1.4.0
|
|
552
|
+
# owner pnpm (/opt/pnpm-home/bin/pnpm)
|
|
553
|
+
# status update available: 1.2.3 → 1.4.0
|
|
554
|
+
# command /opt/pnpm-home/bin/pnpm add -g @jaybeeuu/agent-cortex@latest
|
|
555
|
+
|
|
556
|
+
# what a bare run adds after that report
|
|
557
|
+
agent-cortex self-update
|
|
558
|
+
# ✓ /opt/pnpm-home/bin/pnpm add -g @jaybeeuu/agent-cortex@latest
|
|
559
|
+
# cli 1.2.3 → 1.4.0
|
|
560
|
+
# → refreshing installed harnesses with /opt/pnpm-home/bin/agent-cortex update -a
|
|
561
|
+
# …the new binary's own update report…
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
## Refreshing installed harnesses (`agent-cortex update`)
|
|
565
|
+
|
|
566
|
+
`agent-cortex update` re-runs a harness installer and reports what changed. It installs nothing
|
|
567
|
+
itself: every refresh goes through the same path as `agent-cortex install <harness>`, so update and
|
|
568
|
+
install can never disagree about what is out of date.
|
|
569
|
+
|
|
570
|
+
```sh
|
|
571
|
+
agent-cortex update # list the harnesses, then ask which to refresh
|
|
572
|
+
agent-cortex update pi claude # refresh exactly these, no prompt
|
|
573
|
+
agent-cortex update -a # refresh every harness not at the CLI version
|
|
574
|
+
agent-cortex update -a -f # re-run every installer regardless of version
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
The prompt lists every supported harness with its installed version, the CLI version, and a status
|
|
578
|
+
marker (`current`, `stale`, `ahead`, `unknown`, or `missing`) — the data `agent-cortex version`
|
|
579
|
+
reports, plus a row for a harness with no install. Answer with row numbers counted from the top
|
|
580
|
+
row, `a` for every harness, or blank to cancel.
|
|
581
|
+
|
|
582
|
+
A harness named on the command line always refreshes, whatever version it reports, and takes
|
|
583
|
+
precedence over `-a`. `-a` refreshes every harness that does not report `current`, so an
|
|
584
|
+
uninstalled, stale, ahead, or unreadable harness is refreshed. `-f` requires `-a`: alone it says
|
|
585
|
+
nothing about which harnesses to touch. An unknown name fails before any installer runs.
|
|
586
|
+
|
|
587
|
+
A shell that is not a terminal cannot answer the prompt, so a bare `agent-cortex update` there
|
|
588
|
+
prints the same table plus the flags above and exits non-zero — a script can never mistake
|
|
589
|
+
"nothing chosen" for "nothing to do".
|
|
590
|
+
|
|
591
|
+
The report gives each refreshed harness its previous version, its new version, and the artifacts
|
|
592
|
+
the installer wrote; harnesses already at the CLI version are listed as skipped. A harness's new
|
|
593
|
+
version is read back from the manifest its installer wrote, so a refresh that failed to
|
|
594
|
+
materialise reports `unknown` rather than claiming the CLI version.
|
|
595
|
+
|
|
596
|
+
This refreshes the installs, not the CLI. `agent-cortex self-update` does both in one step; the
|
|
597
|
+
[`docs/dev-loop.md`](docs/dev-loop.md) page records what a global reinstall has to fix.
|
|
598
|
+
|
|
505
599
|
## Migrating a beads workspace
|
|
506
600
|
|
|
507
601
|
`agent-cortex migrate` brings the `.beads` workspace it runs in — any repo, not just this
|
package/agents/README.md
CHANGED
|
@@ -44,13 +44,13 @@ agents/ralph/
|
|
|
44
44
|
`{{SECTION:wake}}` is the one seam where harness differences belong: the shared `agent.md`
|
|
45
45
|
names no harness and no harness-specific tool, and every one of those facts lives in a
|
|
46
46
|
`wake.md` that states its mechanism in one sentence, then covers **spawn** (tool and argument
|
|
47
|
-
shape), **completion arrival**, **id tracking**, **
|
|
47
|
+
shape), **completion arrival**, **id tracking**, **trail reading**, and **stop** behaviour.
|
|
48
48
|
`token-map.json`'s `wake.mechanism` table records the same fact machine-readably.
|
|
49
49
|
|
|
50
50
|
| Harness | `wake.mechanism` | Completion arrives via | Id tracking | Stop means |
|
|
51
51
|
|---------|------------------|------------------------|-------------|------------|
|
|
52
52
|
| `pi` | `blocking-wait` | `wait_for_agents` returns as soon as a worker finishes, result inline | `agentId` only | stop calling `wait_for_agents` — nothing to kill |
|
|
53
|
-
| `claude` | `event-driven` | harness re-invokes ralph with the result inline | task ID only
|
|
53
|
+
| `claude` | `event-driven` | harness re-invokes ralph with the result inline | task ID only | simply stop — nothing to kill |
|
|
54
54
|
|
|
55
55
|
### Example: plan agent (no per-harness sections)
|
|
56
56
|
|
package/agents/ralph/agent.md
CHANGED
|
@@ -14,14 +14,14 @@ Harness-agnostic rules (tool names and completion detection differ per harness
|
|
|
14
14
|
- ALWAYS set the subagent's working directory to the feature worktree path when running stage chores.
|
|
15
15
|
- ALWAYS keep the returned agent/task id in memory so you can read the result later.
|
|
16
16
|
|
|
17
|
-
Each pipeline stage is a separate **chore bead**, pre-created by `create-chores.mjs` from the `create-task` skill's `pipeline.json` when the task is expanded, with `blocks` deps that encode the stage order. Ralph never creates a stage chore — dispatch is always "claim what `bd ready -l execution:afk` returns". Stage tags (`stage:*`) live on chore beads, not on the parent feature bead. Loop counts are derived by querying chore children of the parent, not stored in state. Orchestration state is derived entirely from beads — the only local state is `state.json
|
|
17
|
+
Each pipeline stage is a separate **chore bead**, pre-created by `create-chores.mjs` from the `create-task` skill's `pipeline.json` when the task is expanded, with `blocks` deps that encode the stage order. Ralph never creates a stage chore — dispatch is always "claim what `bd ready -l execution:afk` returns". Stage tags (`stage:*`) live on chore beads, not on the parent feature bead. Loop counts are derived by querying chore children of the parent, not stored in state. Orchestration state is derived entirely from beads — the only local state is `state.json`, holding the worker-ID-to-bead mapping plus whatever wake-loop handle the wake section tracks. Progress lives in the bead trail the workers write, never in a file Ralph tails.
|
|
18
18
|
|
|
19
19
|
## Branching model
|
|
20
20
|
|
|
21
21
|
- **Single-feature epics** (epic has exactly one feature task child): skip the epic branch entirely. The feature branch (`feature/<parent-id>`) is based directly from `origin/main`. The HITL PR targets `main` directly. No epic PR is required.
|
|
22
22
|
- **Multi-feature epics** (epic has two or more feature task children): each epic runs on `epic/<epic-id>` (base: `origin/main`, never local `main`). Each feature branch is based from its epic branch. Completed features PR into `epic/<epic-id>`; the completed epic PRs into `main`.
|
|
23
23
|
- Each parent feature task runs on `feature/<parent-id>` in `.agent-cortex/worktrees/<parent-id>`.
|
|
24
|
-
- Each implemented bead owns a child HITL PR-gate task bead (`lifecycle:feature-pr`, blocked by its own `document` chore) for PR review/merge.
|
|
24
|
+
- Each implemented bead owns a child HITL PR-gate task bead (`lifecycle:feature-pr`, blocked by its own `document` chore) for PR review/merge, plus a `stage:post-merge` chore and a `stage:housekeeping` chore, each blocked behind that gate.
|
|
25
25
|
- Completed features must be reviewed by PR merge from the agent branch (`feature/<parent-id>`) into its base (epic branch for multi-feature epics, `main` for single-feature epics), then the HITL PR task bead must be closed by a human before Ralph continues feature scheduling.
|
|
26
26
|
- Completed multi-feature epics must be reviewed by PR merge into `main`.
|
|
27
27
|
|
|
@@ -63,7 +63,7 @@ A ready `execution:afk` bead of type `feature` with **no** children is not dispa
|
|
|
63
63
|
2. Dispatch a **decomposition worker** in the feature worktree (`.agent-cortex/worktrees/<feature-id>`) whose whole job is to run the `create-task` hierarchy flow (`prd-to-tasks` → `create-task`) for that one **existing** feature — its planning bead and impl children only, never a second feature bead — and report the IDs it created. The worker builds one `execution:hitl` planning bead (`--parent <feature-id>`) plus `execution:afk` implementation task children (`--parent <feature-id>`, `--no-inherit-labels`), each wired with `bd dep add <impl-child> <planning-bead>` so the dependency — not an extra label — is the readiness gate. `create-task`'s feature path (its `SKILL.md` steps 5–6) is the authority for this shape.
|
|
64
64
|
3. Record the worker in `inflight` as a **decomposition** entry — it holds no chore, so `choreId` is `null`:
|
|
65
65
|
```json
|
|
66
|
-
{ "kind": "decompose", "choreId": null, "parentId": "<feature-id>", "title": "<feature title>", "agentId": "<agent-id>"
|
|
66
|
+
{ "kind": "decompose", "choreId": null, "parentId": "<feature-id>", "title": "<feature title>", "agentId": "<agent-id>" }
|
|
67
67
|
```
|
|
68
68
|
4. On completion, confirm the children exist (`bd children <feature-id> --json`) rather than trusting the report, and surface the created IDs in chat. An empty list means the decomposition failed: record the feature for the shutdown summary and continue — do **not** re-dispatch.
|
|
69
69
|
5. **Never re-dispatch a decomposition.** The bead creation it runs is not idempotent, so a second run duplicates the planning bead and every implementation child beside the first.
|
|
@@ -90,14 +90,18 @@ A ready `execution:afk` task bead with no `stage:*` chore children has nothing t
|
|
|
90
90
|
The command is idempotent: it adopts an existing child by its `stage:<id>` or `lifecycle:feature-pr` label, creates only what is missing, skips deps that are already wired, and prints the resolved mapping either way. Re-running it is the recovery path for a failed expansion.
|
|
91
91
|
3. Record the worker in `inflight` as an **expansion** entry — it has no chore to key on, so `choreId` is `null`:
|
|
92
92
|
```json
|
|
93
|
-
{ "kind": "expand", "choreId": null, "parentId": "<parent-id>", "title": "<parent title>", "agentId": "<agent-id>"
|
|
93
|
+
{ "kind": "expand", "choreId": null, "parentId": "<parent-id>", "title": "<parent title>", "agentId": "<agent-id>" }
|
|
94
94
|
```
|
|
95
95
|
That entry is what keeps it in the wait set and makes its completion attributable to the parent.
|
|
96
|
-
4. The worker reports the returned mapping — `code`, `verify`, `review`, `document`, `featurePrReview` — and closes nothing. It emits **no** `---REPORT---` block and owns no bead, so there is nothing to parse and no close to confirm.
|
|
96
|
+
4. The worker reports the returned mapping — `code`, `verify`, `review`, `document`, `post-merge`, `housekeeping`, `featurePrReview` — and closes nothing. It emits **no** `---REPORT---` block and owns no bead, so there is nothing to parse and no close to confirm.
|
|
97
97
|
5. Its completion means the parent now has a `stage:*` chain: the event loop's next `bd ready -l execution:afk` pass picks up the `stage:code` chore (event loop step 7).
|
|
98
98
|
|
|
99
99
|
**Expansion completion contract.** An expansion worker is dispatched like a stage worker but is not one: no chore claim, no `---REPORT---`, no leaf-bead close. Handle its completion with the expansion branch in event-loop step 3, which confirms the chain exists (`bd children <parent-id> --json | grep -c '"stage:'` prints one match per stage chore — the gate carries `lifecycle:feature-pr` and is not counted) and dispatches the ready `stage:code` chore. A count below the stage total in `pipeline.json` is a partial chain, whose missing stages never arrive, so re-dispatch the expansion instead of dispatching on. If the parent still has no `stage:*` children the expansion failed: surface the worker's output in chat, record the parent for the shutdown summary, and re-dispatch the expansion — `create-chores.mjs` is idempotent, so a second run adopts the chores that exist, creates only the missing ones, and reports the whole mapping. Either way, create nothing and close nothing yourself.
|
|
100
100
|
|
|
101
|
+
**Housekeeping chore.** One stage runs outside the pipeline's ordering: `stage:housekeeping`, labelled `lifecycle:housekeeping` and blocked behind the PR gate bead, so it becomes ready only after a human merges the PR and closes the gate. Dispatch it with the **main checkout** as cwd — not the feature worktree — because the worktree it removes can be the parent's own. The worker runs `prune-worktrees.mjs`, retries once on a non-zero exit (exit `1` is normal: an open bead counts as survival), and then decides from the per-worktree report. It fails the chore and leaves it **open** when a `closed-bead` worktree is still `refused`; a `kept` or `refused` entry for an open bead is a normal report. Never close a chore over a worktree the script did not remove.
|
|
102
|
+
|
|
103
|
+
**Post-merge check.** The `stage:post-merge` chore, labelled `lifecycle:post-merge`, is the other stage blocked behind the PR gate, so it too becomes ready only after a human merges and closes the gate. Dispatch it with the **main checkout** as cwd: the commit it reads landed on the base branch. The worker runs `post-merge-check.mjs` once and reports the exit status — `0` passed, `1` failed, `2` inconclusive. Exit `1` has already filed one P1 escalation bead (`lifecycle:post-merge-escalation`, carrying the run URL and the failing job); the worker leaves its chore **open** and closes nothing else. Exit `2` also leaves the chore open, with nothing filed. The stage never retries, never re-runs the workflow, never reverts the merge, never reopens the parent, and builds no `stage:fix` chain — no fix round repairs a commit that already merged. It and `stage:housekeeping` are siblings on the gate: neither waits on the other, because an inconclusive check must not block the worktree reclamation.
|
|
104
|
+
|
|
101
105
|
**Never expand an existing bead by running `create-task`** (or any other command that creates a bead). `create-task` creates a bead first and expands second, so running it for an existing bead leaves a **second parent** beside the original, which stays chore-less and never gets dispatched. `create-chores.mjs` expands a bead that already exists; it never creates parents.
|
|
102
106
|
|
|
103
107
|
---
|
|
@@ -106,11 +110,11 @@ A ready `execution:afk` task bead with no `stage:*` chore children has nothing t
|
|
|
106
110
|
|
|
107
111
|
Chores already exist and their deps already encode the order, so dispatch is claim-and-spawn — claim the ready chore (`bd update <chore-id> --claim`) and skip to the prompt.
|
|
108
112
|
|
|
109
|
-
Load the universal stage runner prompt from the `run-pipeline-stage` skill's `prompts/stage-runner.md`, fill in all placeholders (including `<stage>` from the bead label, parent task description from `bd show <parent-id>`, prior SUMMARY/FILES_CHANGED from the last REPORT, chore bead ID,
|
|
113
|
+
Load the universal stage runner prompt from the `run-pipeline-stage` skill's `prompts/stage-runner.md`, fill in all placeholders (including `<stage>` from the bead label, parent task description from `bd show <parent-id>`, prior SUMMARY/FILES_CHANGED from the last REPORT, chore bead ID, and the trail writer's path `<run-pipeline-stage-scripts>/trail-entry.mjs`), and spawn a subagent in **background** mode using the spawning mechanism described in the wake section, running from the feature worktree. Stage-specific policy comes from that skill's `playbooks/<stage>.md`. The prompt's lifecycle, remediation, and REPORT sections are the worker's contract — pass them through verbatim, never restate or trim them.
|
|
110
114
|
|
|
111
115
|
Add the entry to `inflight` in `state.json`:
|
|
112
116
|
```json
|
|
113
|
-
{ "kind": "stage", "choreId": "<chore-id>", "parentId": "<parent-id>", "title": "<parent title>", "agentId": "<agent-id>"
|
|
117
|
+
{ "kind": "stage", "choreId": "<chore-id>", "parentId": "<parent-id>", "title": "<parent title>", "agentId": "<agent-id>" }
|
|
114
118
|
```
|
|
115
119
|
|
|
116
120
|
---
|
|
@@ -128,16 +132,16 @@ bd show <id> # full detail, including the worker's notes
|
|
|
128
132
|
Report status in chat from those commands. The only files Ralph owns are:
|
|
129
133
|
|
|
130
134
|
- **`.agent-cortex/ralph/state.json`** — runtime bookkeeping only (worker-ID→bead mapping plus the wake loop's own handle).
|
|
131
|
-
-
|
|
135
|
+
- **The bead trail** — not a file Ralph writes: each worker appends its own entries with `trail-entry.mjs`, and Ralph reads them from `bd show` and `bd provenance log`.
|
|
132
136
|
|
|
133
137
|
All orchestration state is derived from beads:
|
|
134
138
|
|
|
135
139
|
```json
|
|
136
140
|
{
|
|
137
141
|
"inflight": [
|
|
138
|
-
{ "kind": "stage", "choreId": "xyz-456", "parentId": "abc-123", "title": "Add auth", "agentId": "agent-xyz-456"
|
|
139
|
-
{ "kind": "stage", "choreId": "def-789", "parentId": "ghi-101", "title": "Fix cache", "agentId": "agent-def-789"
|
|
140
|
-
{ "kind": "expand", "choreId": null, "parentId": "jkl-202", "title": "Expand billing", "agentId": "agent-jkl-202"
|
|
142
|
+
{ "kind": "stage", "choreId": "xyz-456", "parentId": "abc-123", "title": "Add auth", "agentId": "agent-xyz-456" },
|
|
143
|
+
{ "kind": "stage", "choreId": "def-789", "parentId": "ghi-101", "title": "Fix cache", "agentId": "agent-def-789" },
|
|
144
|
+
{ "kind": "expand", "choreId": null, "parentId": "jkl-202", "title": "Expand billing", "agentId": "agent-jkl-202" }
|
|
141
145
|
]
|
|
142
146
|
}
|
|
143
147
|
```
|
|
@@ -145,8 +149,7 @@ All orchestration state is derived from beads:
|
|
|
145
149
|
- **inflight[].kind**: `"stage"` for a dispatched stage chore (the only shape that carries a `choreId`), `"decompose"` for a feature-decomposition worker and `"expand"` for an expansion worker (both no chore — `choreId` is `null`). Every dispatched agent has an entry; anything missing from `inflight` is invisible to the wait set and to the HITL-pause check.
|
|
146
150
|
- **inflight[].agentId**: the worker id the spawn call returned — the key every completion is correlated to its bead against, and the identifier the wake section's read/wait path takes (see that section).
|
|
147
151
|
- **inflight[].choreId**: the chore bead currently being worked by the subagent.
|
|
148
|
-
- **inflight[].parentId**: the parent feature task bead
|
|
149
|
-
- **inflight[].logLine**: the next line number to read from the parent's log file (1-based; start at 1). Updated after every poll.
|
|
152
|
+
- **inflight[].parentId**: the parent feature task bead — the id every trail entry is read under (`bd show <parentId>`, `bd children <parentId>`).
|
|
150
153
|
- **Loop counts are not stored here** — derive them from beads:
|
|
151
154
|
- Fix round count = number of `stage:fix` chore children of `<parentId>` (closed ones count)
|
|
152
155
|
|
|
@@ -164,7 +167,7 @@ After initialization, Ralph waits for background agents to complete. Completions
|
|
|
164
167
|
|
|
165
168
|
### If a background agent completed
|
|
166
169
|
|
|
167
|
-
1. **
|
|
170
|
+
1. **Read the worker's bead trail** — `bd show <chore-id>` for its entries and `bd provenance log <chore-id>` for the refs — and use it for the chat summary. There is no log file to flush.
|
|
168
171
|
2. **Read** the completed agent's full output the way the wake section describes.
|
|
169
172
|
3. **Re-read** `.agent-cortex/ralph/state.json` to identify the entry for that agent ID, then branch on its `kind`:
|
|
170
173
|
- **`kind: "expand"` — expansion completion branch.** The worker claimed no chore, emits no `---REPORT---`, and owns no bead to confirm, so steps 4-6 **do not apply**: remove the entry from `inflight`, confirm the parent now has `stage:*` chore children (`bd children <parent-id> --json | grep -c '"stage:'`) and surface the reported mapping in chat, then go straight to step 7 — the new `stage:code` chore is ready to dispatch. If the count is `0` — or below the stage total, which is a partial chain whose later stages never arrive — the expansion failed: surface the worker's output, record the parent for the shutdown summary, remove the entry, and re-dispatch the expansion — re-running `create-chores.mjs` is idempotent and is the recovery path, so it repairs the tree instead of duplicating it. Never create or close a bead for an expansion.
|
|
@@ -173,9 +176,9 @@ After initialization, Ralph waits for background agents to complete. Completions
|
|
|
173
176
|
4. **Parse** the agent's `---REPORT---` block (see report format in the `run-pipeline-stage` skill).
|
|
174
177
|
5. **Confirm** the worker closed its own leaf execution bead: `bd show <chore-id>` should read `closed`. If it is still open the worker died mid-stage — read its notes and re-dispatch. Never close it yourself.
|
|
175
178
|
6. **Advance** the parent using the routing guidance in the `run-pipeline-stage` skill:
|
|
176
|
-
- **Success paths** (code → verify, verify SUCCESS → review, review SUCCESS → document): create nothing — closing the chore already unblocked the next stage of the pre-created chain. Point the parent's inflight entry at that newly ready `stage:*` chore and dispatch it (see _Dispatching a stage chore_ above)
|
|
179
|
+
- **Success paths** (code → verify, verify SUCCESS → review, review SUCCESS → document): create nothing — closing the chore already unblocked the next stage of the pre-created chain. Point the parent's inflight entry at that newly ready `stage:*` chore and dispatch it (see _Dispatching a stage chore_ above).
|
|
177
180
|
- **Documenting → done**: close the parent feature bead (`bd close <parent-id>`), remove it from inflight, open/update the feature PR immediately (agent-branch → feature branch), report the PR URL in chat, then update the HITL PR gate bead with the PR URL.
|
|
178
|
-
- **Failure paths** (`OUTCOME: BLOCKED` from any stage): create nothing. The worker already closed its failed chore and built its own remediation — a `stage:fix` chore plus a fresh instance of the failed stage blocked on it. Run the cap backstop (see below); if the parent is at `maxFixRounds`, block the parent instead and record it for shutdown. Remove the inflight entry for this chore; the worker's beads appear in `bd ready` and are picked up in step 7.
|
|
181
|
+
- **Failure paths** (`OUTCOME: BLOCKED` from any stage): create nothing. The worker already closed its failed chore and built its own remediation — a `stage:fix` chore plus a fresh instance of the failed stage blocked on it. Run the cap backstop (see below); if the parent is at `maxFixRounds`, block the parent instead and record it for shutdown. Remove the inflight entry for this chore; the worker's beads appear in `bd ready` and are picked up in step 7. `post-merge` and `housekeeping` are the exceptions: neither builds a chain, and each leaves its chore **open**, so remove the inflight entry and hand the chore to a human — never re-dispatch it, and for `post-merge` report the escalation bead the check filed.
|
|
179
182
|
7. **Check for newly ready beads**: run `bd ready -l execution:afk`. For each bead not yet tracked:
|
|
180
183
|
- **Chore bead with `stage:*` label** (a worker-built remediation chore or a pre-created stage): find its parent via `bd show <chore-id>` (follow the `parent-child` dep). Run the cap backstop (see below). If under cap: dispatch it via _Dispatching a stage chore_. If at cap: block the parent (`bd update <parent-id> --status blocked --append-notes "<cap> reached"`) and record it for shutdown — create nothing.
|
|
181
184
|
- **Childless `feature` bead, in-flight count < 5, no pending human action**: dispatch a decomposition worker (see _Feature decomposition_ above). Check `pendingHumanAction` with `node skills/workflow/ralph/scripts/pending-gates.mjs` — an unblocked `lifecycle:feature-pr` gate means a feature is awaiting a human merge, so hold new parent features. Gates still blocked behind their own pipeline are parked and do not count.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## Wake mechanism (Claude Code — event-driven)
|
|
2
2
|
|
|
3
|
-
**Mechanism: event-driven — the harness re-invokes you automatically when a background worker completes and delivers that worker's result inline, so there is no poll timer
|
|
3
|
+
**Mechanism: event-driven — the harness re-invokes you automatically when a background worker completes and delivers that worker's result inline, so there is no poll timer and no sleep.**
|
|
4
4
|
|
|
5
5
|
### Spawn
|
|
6
6
|
|
|
@@ -29,11 +29,11 @@ A completion is **delivered, not observed**: Claude Code re-invokes you automati
|
|
|
29
29
|
Initialize `.agent-cortex/ralph/state.json` as `{ "inflight": [] }` — there is no timer handle to track.
|
|
30
30
|
|
|
31
31
|
- **inflight[].agentId** — the task ID `Task` returned for that worker; it is the key the delivered completion is correlated to its bead, and the equivalent of `TaskGet`'s identifier when you need to inspect one worker.
|
|
32
|
-
- **
|
|
32
|
+
- **No trail bookmark** — nothing to track. Progress is read from the bead itself (`bd show <chore-id>`, `bd provenance log <chore-id>`): the worker writes it, so the harness delivers the completion with the result already in hand.
|
|
33
33
|
|
|
34
|
-
###
|
|
34
|
+
### Trail reading
|
|
35
35
|
|
|
36
|
-
None. There is **
|
|
36
|
+
None beyond the completion itself. There is **nothing to tail and nothing to flush** on Claude: read the completed worker's bead once for its entries and refs, and produce the shared chat summary from the delivered result.
|
|
37
37
|
|
|
38
38
|
### Stop
|
|
39
39
|
|