Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
db1b583
feat: the join wave rule in js and python with shared fixtures
noderaven Oct 15, 2026
580eed8
feat: ledger append lock, partial-line tolerance and wave events
noderaven Oct 15, 2026
02ef65b
feat: ledger restarts, join_started, unit branches and join_tip
noderaven Oct 15, 2026
6825e26
feat: run-checks sets PL_PHASE for every check
noderaven Oct 15, 2026
28eb855
feat: start-task runs a join unit on its own branch in a lane worktree
noderaven Oct 15, 2026
77c43e7
feat: setup and cleanup handle join unit branches
noderaven Oct 15, 2026
fa16d82
feat: merge-wave merges a join wave by recorded sha
noderaven Oct 15, 2026
8b71496
feat: the engine runs join waves on unit branches
noderaven Oct 15, 2026
0643d29
feat: wave merges, resolver and last-wave checks
noderaven Oct 15, 2026
fdce1e6
feat: a relaunch recovers reviewed wave work and finishes the join fr…
noderaven Oct 15, 2026
678f6e5
feat: pre-flight checks the join waves for hidden dependencies
noderaven Oct 15, 2026
a79c1dd
feat: owners read same-wave join tasks as alongside
noderaven Oct 15, 2026
d6acb46
feat: dry run, worth-it and autopsy know the join waves
noderaven Oct 16, 2026
23d33f7
test: join waves end to end on real git
noderaven Oct 16, 2026
e8b88a6
docs: join waves, the phase marker and relaunch fields
noderaven Oct 16, 2026
258f599
fix: a relaunch after waves reviews stale merged units in place, keep…
noderaven Oct 16, 2026
ca7fa14
fix: import the lock module before the io test fakes Windows, so POSI…
noderaven Oct 16, 2026
1e716b2
fix: load the ledger in the waves tests without load_module, which Py…
noderaven Oct 16, 2026
25ad906
ci: test on Python 3.15 on purpose, and name the pinned Python in job…
noderaven Oct 16, 2026
cc45775
ci: drop the Node 22 job
noderaven Oct 16, 2026
9325815
docs: the test suite needs Node 24 or later
noderaven Oct 16, 2026
0492733
chore: release 1.6.5
noderaven Oct 16, 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
13 changes: 9 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,35 @@ permissions:

jobs:
test:
name: ${{ matrix.os }} / Node ${{ matrix.node }}
name: ${{ matrix.os }} / Node ${{ matrix.node }}${{ matrix.python && format(' / Python {0}', matrix.python) || '' }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
# Without python, a job uses the runner's own python3 (macOS's moves
# with the runner image). The 3.15 job tests the newest Python on
# purpose rather than waiting for an image to move.
include:
- os: ubuntu-latest
node: 24
- os: ubuntu-latest
node: 22
node: 24
python: '3.15'
- os: macos-latest
node: 24
- os: windows-latest
node: 24
python: '3.12'
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node }}
- uses: actions/setup-python@v6
if: matrix.os == 'windows-latest'
if: matrix.python
with:
python-version: '3.12'
python-version: ${{ matrix.python }}
- name: Tool versions
shell: bash
run: |
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Fedora:
sudo dnf install -y git jq python3 nodejs
```

The test suite needs Node 22 or later (`node --version`). If your distribution's `nodejs`
The test suite needs Node 24 or later (`node --version`). If your distribution's `nodejs`
package is older, install a current release from https://nodejs.org instead; the skill
itself does not use Node.

Expand All @@ -98,7 +98,7 @@ too: install it there and follow the Linux steps.
winget install OpenJS.NodeJS.LTS
```

Node is optional (tests only; Node 22 or later). Any Python 3.8 or later works: the skill looks for
Node is optional (tests only; Node 24 or later). Any Python 3.8 or later works: the skill looks for
`python3`, then `python`, then `py -3`, and skips the Microsoft Store `python3` stub.
- **Git in another place:** the skill finds Git Bash on PATH (also through the `Git\cmd` folder
the Git installer puts there) or under `C:\Program Files\Git`.
Expand Down Expand Up @@ -281,7 +281,8 @@ session lists it, and you can resume with one word. Finished tasks are skipped.
`scripts/setup` also locks the project checkout in git mode (two runs cannot switch one
checkout to their feature branches), creates the feature branch and lane worktrees, saving any changes it has
to discard under a git ref first. The phases run: pre-flight conflict check, prelude,
lanes in parallel, integration, join, E2E, a final review with three lenses and one fix
lanes in parallel, integration, join (its tasks in waves: those whose `depends_on` allow it
run side by side on their own branches and are merged after each wave), E2E, a final review with three lenses and one fix
round, and a verify step that reruns the project checks (every lane's checks included) and any stale E2E or
post-integration check on the exact revision delivered. The full pre-flight stops the run,
naming the move that fixes it, when a task needs code from a task scheduled after it.
Expand Down
22 changes: 15 additions & 7 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ manual.
- Worth-it check, only when the Offer will be shown (not when the user already chose Parallel
lanes by name, never on Resume): with the layout just built, run
`<python> <skill_dir>/scripts/worth-it <plan> --max-lanes <cap> --prelude <ids> --lane <ids>
[--lane <ids> ...] --join <ids> --project <project folder>` (comma-separated task ids, one
`--lane` per lane in lane order; an empty prelude or join is `''`). It prints JSON:
[--lane <ids> ...] --join <ids> [--join-deps <id>:<deps> ...] --project <project folder>`
(comma-separated task ids, one `--lane` per lane in lane order; an empty prelude or join is
`''`; one `--join-deps` per join task, its earlier join ids joined by `+`, so the join counts in
waves). It prints JSON:
`recommend` is `direct` when running in parallel saves 1 task-time or less (always for a
single-lane plan), else `parallel`; a non-zero exit or any `status` other than `ok` leaves the Offer as it was.
The rule, its evidence and the output: reference.md "Worth it".
Expand Down Expand Up @@ -133,7 +135,9 @@ Fields: reference.md "Manifest fields". In order:
- Git identity: `git -C <project> var GIT_COMMITTER_IDENT` must print one, or every task
commit fails partway through the run. If it fails: reference.md "Git identity".
3. Lanes, prelude, join, hooks, `depends_on`, `overlaps`, `excluded`: reference.md "Building
lanes" (`prelude` and `join` are not lane ids).
lanes" (`prelude` and `join` are not lane ids; no lane id starts with `u-`). Give every join
task `depends_on` (`[]` when it needs no earlier join task): the join then runs in waves, and
a join task without it waits for every earlier one (reference.md "Join waves").
4. `profile` and tiers: reference.md "Profiles", "Tiers", "Batching". `profile: "lite"` only
for one lane, at most 8 tasks, no security task, and no `hooks.post_integrate`; else
`full`. Tiers `standard`, `sonnet`, `light` (security tasks always `standard`); `batch`
Expand Down Expand Up @@ -163,7 +167,8 @@ and `usage_limit_pause` gives its usage-limit line (reference.md "Usage limit").
Each check and what it means: reference.md "Doctor" and "Launch conditions".

1. Dry run: call the Workflow tool as in Launch step 1, with `args` = the manifest with
`dry_run: true`. It returns `{dry_run, errors, agents, lanes_effective, notices, checks}` and
`dry_run: true`. It returns `{dry_run, errors, agents, lanes_effective, notices, checks,
join_waves}` and
spawns nothing. If `errors` is non-empty, fix the manifest and repeat; never launch a manifest
with errors. Then set `limits.max_agents` = 2 x `agents.length` and `limits.max_rulings` =
25 (reference.md "Budgets") so the table shows them.
Expand Down Expand Up @@ -251,7 +256,7 @@ earlier snapshot belongs to the earlier launch.
Relaunch once with the relaunch notice: carry budgets over (reference.md "Transient stops"). Set
`repairs_spent` to the repairs in the stopped run's `final.repairs` plus the earlier value.
First recompute `done`, `reviewed`, `deferred`, the `carry` notes, `carried_minors`,
`inputs_changed` and `backfill` as in Resume
`inputs_changed`, the join wave fields and `backfill` as in Resume
steps 2-3, then rerun `scripts/setup --owner <token>` and take `start_points`; if validation
rejects its `setup_skipped`, rerun setup. Launch again. No second table. A second transient
stop is a real stop, unless it is a usage-limit stop (reference.md "Usage limit").
Expand Down Expand Up @@ -318,12 +323,15 @@ first, show its plan, and add `--yes` only on the user's yes. Keep the manifest
file> [--spec <spec>]`. Set `done`, `reviewed`, and `deferred` from it (taking a deferred
task up: reference.md "Backfill"), and `repairs_spent` from earlier reports' `final.repairs`;
put each `carry` entry into `notes`; copy `minors` into `carried_minors`, and `inputs` into
`inputs_changed` as `{plan: plan_changed, spec: spec_changed}` (reference.md "Carry-over"). Tasks in `stale`
`inputs_changed` as `{plan: plan_changed, spec: spec_changed}` (reference.md "Carry-over").
Copy `join_started`, `unit_branches`, `wave_merges` and `start_bases` as they are
(reference.md "Join waves"). Tasks in `stale`
(with their dependents) or `unbound` are left out of `reviewed`, so they are reviewed
again: tell the user which and why, and say so when `inputs` reports a changed plan or
spec. `<python> <skill_dir>/scripts/coverage <plan> <manifest file>` must exit 0 again
(else fix the manifest's tasks or `excluded`).
3. `backfill`: `<python> <skill_dir>/scripts/ledger backfill <ledger_dir> <manifest file>`.
3. `backfill`: `<python> <skill_dir>/scripts/ledger backfill <ledger_dir> <manifest file>`,
and its `join_tip` when not null.
Exit 3 lists records git does not confirm: show them and stop (reference.md "Backfill").
4. Blocked tasks: show each reason; get the user's answer or plan fix before relaunching.
Record an answer in `notes` as `{"<task id>": "<answer>"}`; a plan fix needs
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.6.4
1.6.5
39 changes: 39 additions & 0 deletions manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,45 @@
},
"additionalProperties": false
},
"join_started": {
"description": "1.6.5: ledger status join_started, a join task started in an earlier launch (the join then runs serially). Required once start_points.join is set.",
"type": "boolean"
},
"unit_branches": {
"description": "1.6.5: ledger status unit_branches, the join units that ran on their own branch pl-<run_id>-u-<unit> in a lane worktree.",
"type": "object",
"additionalProperties": {
"type": "object",
"required": ["branch", "dir"],
"properties": {
"branch": {
"type": "string",
"pattern": "^pl-[a-z0-9-]+-u-[A-Za-z0-9_]"
},
"dir": {
"$ref": "#/$defs/text"
}
}
}
},
"wave_merges": {
"description": "1.6.5: ledger status wave_merges, the wave_merged events of earlier launches ({wave or recovery, units, head, overlaps, conflict_files}).",
"type": "array",
"items": {
"type": "object"
}
},
"join_tip": {
"description": "1.6.5: ledger backfill join_tip, the join's last commit; integration's history audit allows final-fix commits after it.",
"$ref": "#/$defs/text"
},
"start_bases": {
"description": "1.6.5: ledger status start_bases, the base each task not done started its latest attempt from; a join task resumed on the feature checkout after waves starts there.",
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/text"
}
},
"done": {
"$ref": "#/$defs/textList"
},
Expand Down
Loading
Loading