Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 27 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ Notable changes to the Swarm plugin. Format follows

## [Unreleased]

## [0.5.0] — 2026-10-04

The "pick the winner" release: Swarm now checks each slot, notices when a
slot is done, compares them, lands the winner, steers running agents, and
hands merge conflicts to a resolver, all without giving up review-first
merging. Exercised live end to end on Herdr 0.8.2 (see `docs/readiness.md`).

### Changed
- `scripts/harvest-step.sh` (1,863 lines, 23 verbs) is split into domain
modules it sources: `harvest-step-{merge,slot,publish,validate,settle,compare,broadcast,resolve}.sh`.
Expand All @@ -30,15 +37,6 @@ Notable changes to the Swarm plugin. Format follows
harvest preview. The plugin's own report holds Herdr's lifecycle authority,
which suppresses screen detection (live-verified on 0.8.2). Finish
detection now corrects it while the status pane is open.
- The shared test environment now supplies its fixture Git identity to stub
subprocesses too, avoiding hostname-based identity detection during commits
and reflog writes when user/system Git configuration is disabled (#11).
- Harvest now reconciles the completed slot's plugin-reported state before
automatic archive. On Herdr's pane-backed path, a successful merge could
previously leave the slot marked working and unnecessarily block cleanup.
Archive still verifies agent state and worktree contents before removal.
- Archive recognizes Herdr 0.8.2's `done` state (an unseen background idle
agent) as settled, instead of refusing cleanup until its tab is focused.

### Added
- Conflict resolver: `resolve <slot>` (`g` in the conflict view) hands a
Expand Down Expand Up @@ -97,6 +95,26 @@ Notable changes to the Swarm plugin. Format follows
`HERDR_SWARM_CANDIDATE_VALIDATION_FILE` still wins. The repo lock is released
while the hook runs. On `HERDR_SWARM_VALIDATE_TIMEOUT` the hook's whole
process group is killed. A slot that changes during the run records nothing.
- Strict candidate handoff (#15): `candidate-status <slot>` previews, and
`publish-candidate-pr <slot>` publishes, a clean slot only with passing
validation, a passing Browser QA result for the same SHA, and an operator
review bound to the run, slot, and SHA. Every input is re-read before any
push, and the handoff never merges.

## [0.4.0] — 2026-09-14

### Fixed
- The shared test environment now supplies its fixture Git identity to stub
subprocesses too, avoiding hostname-based identity detection during commits
and reflog writes when user/system Git configuration is disabled (#11).
- Harvest now reconciles the completed slot's plugin-reported state before
automatic archive. On Herdr's pane-backed path, a successful merge could
previously leave the slot marked working and unnecessarily block cleanup.
Archive still verifies agent state and worktree contents before removal.
- Archive recognizes Herdr 0.8.2's `done` state (an unseen background idle
agent) as settled, instead of refusing cleanup until its tab is focused.

### Added
- Opt-in `publish-pr <slot>` harvest verb (`g`, then slot in the pane) pushes
the audited commit and creates/reuses its exact GitHub draft PR. Existing
`publish` remains push-only. Optional SHA-bound validation JSON or Browser
Expand Down
35 changes: 32 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@ at a time. Agents commit locally and never push; the orchestrator merges.
is the practical guide to this plugin and its three siblings (Browser, Guard,
Conductor).

## The workflow (0.5.0)

Running N agents only pays off if you can pick the best result. From fan-out
to a landed winner:

| Step | What happens | Section |
| --- | --- | --- |
| **Fan out** | One task, or a different task per slot, into N worktrees. Each slot gets its dependencies (copy-on-write `node_modules`), its own ports, and its slot variables. Swarm warns up front when two slots' tasks name the same files | [Scripting fan-out](#scripting-fan-out), [Fresh worktrees](#fresh-worktrees-lack-your-env) |
| **Steer** | `broadcast` one message to every running agent | [Steering](#steering-a-running-swarm) |
| **Know when done** | The status pane records each slot finished (its marker, or its agent exiting), shows elapsed time, and notifies once when all are done | [Finish detection](#finish-detection) |
| **Check** | `validate.sh` runs on each slot's exact commit, automatically on finish if you opt in | [Validating slots](#validating-slots) |
| **Compare** | A ranked table (checks, commits, files, overlap, time) and a diff of any two slots | [Comparing slots](#comparing-slots-and-picking-a-winner) |
| **Land** | Merge the winner at the exact commit you compared; finished losers are skipped and archived, and branches are kept | [Comparing slots](#comparing-slots-and-picking-a-winner) |
| **Resolve** | A conflicting merge can go to a resolver agent. You review the resolution (including any change outside the conflicts) before it lands | [Resolving conflicts](#resolving-conflicts) |

Nothing merges without your explicit selection or confirmation. The merge
guarantees are unchanged: drift-checked, compare-and-swap, journaled, and
review-first.

## Requirements

- **herdr 0.7.4 or newer.** Fan-out works on both 0.7.4 and 0.7.5+, by two
Expand All @@ -39,6 +58,12 @@ Conductor).
Harvest, abort, and prune of an existing run work on every supported
version (they are mostly git). Versions above the newest tested get a
warning, never a refusal.

Two 0.5.0 features need the 0.7.5+ pane-built path: the **conflict
resolver** (refused on 0.7.4) and **slot variables inside the agent
process** (on 0.7.4 the agent learns its ports from the task file instead).
The whole 0.5.0 flow was exercised live on Herdr 0.8.2; see
[readiness](docs/readiness.md).
- **git >= 2.38** recommended (relies on `git worktree`, three-arg
`git update-ref` compare-and-swap, and `git merge-base --is-ancestor`).
- **Node.js >= 20** on your PATH (manifest handling, manifest validation, and
Expand Down Expand Up @@ -97,7 +122,8 @@ add your own, see below):
unreachable agents show as `unknown` with their committed work still
harvestable.
3. **Harvest** (`structupath.swarm.harvest`) — review-first merge-back. Keys:
`1`–`9` select a slot, `r` re-previews, `q` quits. Per slot:
`1`–`9` select a slot, `w` opens the compare view (diff two slots, merge a
winner), `v` validates a slot, `r` re-previews, `q` quits. Per slot:
- *Clean slot* — merged `--no-ff` with a templated message. The base ref is
drift-checked before **every** merge; if it moved, all slots re-preview.
When base is not checked out anywhere, the merge runs in a plugin-owned
Expand Down Expand Up @@ -343,12 +369,15 @@ not copied.
See [GitHub handoff contract and recovery](docs/github-handoff.md) for the file
schema, Console integration output, and failure handling.

### Strict candidate handoff (opt-in development path)
### Strict candidate handoff

For a selected **clean** slot HEAD, keep validation, Browser QA, and the
operator's review in three separate regular files. Validation checks must all
pass; Browser QA must pass for that same SHA; the review must approve the exact
run ID, slot, and SHA. Preview the readiness gaps locally before publishing:
run ID, slot, and SHA. The validation file can be the one `validate <slot>`
records: with `HERDR_SWARM_CANDIDATE_VALIDATION_FILE` unset, it's used
automatically (see [Validating slots](#validating-slots)). Preview the
readiness gaps locally before publishing:

```sh
export HERDR_SWARM_CANDIDATE_VALIDATION_FILE=/absolute/private/checks.json
Expand Down
55 changes: 42 additions & 13 deletions docs/readiness.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Swarm readiness

The plugin targets version 0.4.0; changes on this branch are recorded under
Unreleased in the changelog. The manifest still requires Herdr >=0.7.4.
The plugin is at version 0.5.0 (see the changelog). The manifest still
requires Herdr >=0.7.4. The broad compatibility baseline remains Herdr
0.7.4/0.7.5; Herdr 0.8.2 has the live evidence below. 0.7.4 does not support
the conflict resolver or agent-side slot variables.

## Repeatable validation

Expand Down Expand Up @@ -52,16 +54,43 @@ shell pid marks exit. Those shapes back finish detection's stubs. See
The session was stopped afterwards. No paid agent was run, so Herdr-native
detection after `release-agent` remains unverified.

## Live end-to-end smoke — 2026-10-04 (0.5.0)

A throwaway named Herdr 0.8.2 session (protocol 20) ran the whole 0.5.0 flow
against a disposable repository with temporary plugin state and config. Every
inherited `HERDR_*` routing variable was stripped, and `plugin …` calls were
refused so the installed plugin could not touch real state. Scripted
stand-in agents and a scripted resolver were used; no paid model agent ran.
Each step was exercised through the real verbs:

| Step | Live result |
| --- | --- |
| Scripted fan-out, per-slot task file | 3 created, 3 started; slot count from sections; conflict hint fired for two slots naming `app.txt` |
| Slot environment | Each agent saw its own `HERDR_SWARM_SLOT`, run id, and port base (via `pane split --env`), its own worktree, cloned `node_modules`, and its task file |
| Finish detection | `settle` recorded all three finished by marker; one notification; a second settle was a no-op |
| Validate | Two passed, one failed by design, each bound to its tip SHA |
| Compare | Passed slots ranked above the failed one; `app.txt` overlap shown |
| Broadcast | Delivered once to each running agent. After one agent exited, a second broadcast refused the bare shell |
| Merge | One slot landed at its compared tip through the detached locus and compare-and-swap |
| Conflict → resolve → conclude → land | Merge stopped with the merged tip journaled. The resolver ran in a pane split from the slot's pane, inside the merge tree, and made one commit. The read-only review recorded nothing; `apply` and `resume complete` landed exactly the reviewed commit |
| Review guards | A file slipped into the merge commit was flagged `outside_conflict`; applying the earlier-reviewed SHA after an amend was refused (exit 30) |
| Archive, prune | Exact one-use approvals removed worktrees holding cloned `node_modules`; branches kept; prune dry-run listed 2 merged and kept 1 unmerged |

Not covered: real agent quality (claude/codex), the status pane and its
periodic settle (opened through the plugin action, which was blocked; `settle`
was run directly), and Herdr 0.7.4. The session was stopped and every fixture
removed afterwards.

## Recommended next work

1. Add opt-in named-session integration coverage for released Herdr versions,
especially agent identity/state and worktree removal. Keep real-git fixture
coverage for drift, conflicts, snapshots, and interrupted-run recovery.
2. Validate each team's setup hook and agent preset against a small task before
increasing slot count. Fresh worktrees lack ignored dependencies and secrets;
setup-hook failure currently warns and still starts the agent.
3. Keep conflict resolution review-first. The resolver-agent document in
`docs/plans/` describes future work, not a shipped feature.
4. Use `publish-pr` for an explicit draft GitHub handoff with SHA-bound supplied
evidence, and `pr-status` for a current CI snapshot. Ordinary `publish` still
only pushes. The orchestrator remains responsible for the final review.
1. Run one live flow with real agent presets (`claude`, `codex`), including
an approval prompt during broadcast and a real resolver resolution.
Interpreter-launched agents (`node cli.js`) read as `unknown` to the
resolver and broadcast checks by design; confirm that is workable.
2. Add opt-in named-session integration coverage for released Herdr versions.
Keep real-git fixture coverage for drift, conflicts, snapshots, and
interrupted-run recovery.
3. Raise the "newer than tested" baseline once 0.8.x evidence is broad
enough; today it warns once per slot during fan-out.
4. Validate each team's `setup.sh`, `validate.sh`, and presets against a
small task before increasing slot count.
2 changes: 1 addition & 1 deletion herdr-plugin.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
id = "structupath.swarm"
name = "Swarm"
version = "0.4.0"
version = "0.5.0"
min_herdr_version = "0.7.4"
description = "Worktree-per-agent fan-out, per-slot change visibility, and review-first harvest for parallel coding agents"
platforms = ["macos", "linux"]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "herdr-swarm",
"version": "0.4.0",
"version": "0.5.0",
"private": true,
"type": "module",
"engines": { "node": ">=20" },
Expand Down
Loading