Plan the Gas Town port instead of rebuilding it in herdr #9

Merged
forgejo-admin merged 1 commit from plan-gastown-herdr-port into main 2026-08-05 15:04:45 +00:00

Planning only — no code. Two OpenSpec changes, landing together because the second supersedes the first.

Why

Running ~8 concurrent agents produced three failures in a day:

  • Duplication — two agents independently diagnosed and fixed one signal-cli receive-mode bug. The second found the first only by reading git log origin/main after building its own version.
  • Stampede — CI went red and every agent noticed, all of them correctly. No way to pick one fixer cheaply, no way to stand the rest down.
  • Lost picture — agents A–I spawned each other transitively, rendered flat in the sidebar, impossible to collapse or clean up.

The operator's own memory was the only shared ledger, and it saturated.

What's here

add-town-scoped-coordination — towns, a provenance tree, a board, claims, and a per-town refinery, built as herdr plugins. Superseded, kept deliberately (see below).

Its tell: it specifies Towns from first principles — a concept Gas Town already has, alongside Beads, the Refinery, Wasteland, Witness/Deacon/Dogs, Convoys, and Escalation. It was rebuilding a mature system badly.

port-gastown-to-herdr — fork Gas Town and replace its tmux coupling instead.

Why the port is feasible

internal/tmux is 4,149 lines and ~110 exported functions, called directly from 232 of 1,194 Go files with no interface between them. Sorted by what a second backend actually needs:

category count disposition
semantic core ~30 becomes the interface
tmux chrome (themes, 8 keybinding setters, status format, mouse, banners) ~28 dropped — herdr's equivalent is config.toml
screen-scraping workarounds (AcceptWorkspaceTrustDialog, DismissStartupDialogsBlind, IsAtPrompt, IsZombie) ~12 dropped
tmux server plumbing (sockets, server PID, exit-empty, pane hooks) ~15 no analog

That third row is the argument the port is worth doing rather than merely possible: those functions exist only because tmux exposes no structured agent state. herdr answers those questions directly — herdr agent start already means "the expected agent was detected and is ready for input."

The riskiest dependency has a verified analog. Gas Town injects every agent's identity as environment variables at session creation (internal/polecat/session_manager.go:455 notes that setting them afterward is too late), and herdr pane split --cwd <path> --env K=V --no-focus covers it. Had it not, the port would have been blocked at the identity layer.

Section 0 is a spike with a real stop condition

Kill-agent-keep-pane, respawn-in-place, and unresponsive-agent detection are unverified. Witness, Deacon, and the Dogs are built on them. Task 0.10 says stop rather than proceed hopefully — Gas Town without its watchdog tier is a weaker system than the one being adopted.

Two decisions worth reviewing

Upstream is proposed at §2a, not §8. Staying synced is preferred but not required. Too early is a stranger asking a busy maintainer to accept an abstraction on faith; too late means 232 files were migrated against a shape upstream might want differently — the one part that's expensive to redo. At §2a the pitch is a working second backend plus a conformance suite proving tmux's behavior is preserved. §4 proceeds regardless of the answer or silence.

A Gas Town rig maps to a herdr workspace, not to panes in one. At 25 agents, rigs-as-panes is a flat 25-entry sidebar — precisely the failure that started this. Navigability at 25 agents is a requirement with a scenario, not an afterthought.

Why the superseded change is kept, not deleted

  • herdr-mail and herdr-spawn stay in service, unchanged, until the port reaches parity. They're the working system in the meantime and must not be dismantled for a port that hasn't landed.
  • Its three observed failures are the port's acceptance test. If the ported system doesn't kill all three, the port didn't earn its cost.

Both changes pass openspec validate --strict.

🤖 Generated with Claude Code

Planning only — no code. Two OpenSpec changes, landing together because the second supersedes the first. ## Why Running ~8 concurrent agents produced three failures in a day: - **Duplication** — two agents independently diagnosed and fixed one signal-cli receive-mode bug. The second found the first only by reading `git log origin/main` *after* building its own version. - **Stampede** — CI went red and every agent noticed, all of them correctly. No way to pick one fixer cheaply, no way to stand the rest down. - **Lost picture** — agents A–I spawned each other transitively, rendered flat in the sidebar, impossible to collapse or clean up. The operator's own memory was the only shared ledger, and it saturated. ## What's here **`add-town-scoped-coordination`** — towns, a provenance tree, a board, claims, and a per-town refinery, built as herdr plugins. Superseded, kept deliberately (see below). Its tell: it specifies **Towns** from first principles — a concept Gas Town already has, alongside Beads, the Refinery, Wasteland, Witness/Deacon/Dogs, Convoys, and Escalation. It was rebuilding a mature system badly. **`port-gastown-to-herdr`** — fork Gas Town and replace its tmux coupling instead. ## Why the port is feasible `internal/tmux` is 4,149 lines and ~110 exported functions, called directly from **232 of 1,194** Go files with no interface between them. Sorted by what a second backend actually needs: | category | count | disposition | |---|---|---| | semantic core | ~30 | becomes the interface | | tmux chrome (themes, 8 keybinding setters, status format, mouse, banners) | ~28 | dropped — herdr's equivalent is `config.toml` | | screen-scraping workarounds (`AcceptWorkspaceTrustDialog`, `DismissStartupDialogsBlind`, `IsAtPrompt`, `IsZombie`) | ~12 | dropped | | tmux server plumbing (sockets, server PID, exit-empty, pane hooks) | ~15 | no analog | That third row is the argument the port is worth doing rather than merely possible: those functions exist *only* because tmux exposes no structured agent state. herdr answers those questions directly — `herdr agent start` already means "the expected agent was detected and is ready for input." The riskiest dependency has a verified analog. Gas Town injects every agent's identity as environment variables **at session creation** (`internal/polecat/session_manager.go:455` notes that setting them afterward is too late), and `herdr pane split --cwd <path> --env K=V --no-focus` covers it. Had it not, the port would have been blocked at the identity layer. ## Section 0 is a spike with a real stop condition Kill-agent-keep-pane, respawn-in-place, and unresponsive-agent detection are **unverified**. Witness, Deacon, and the Dogs are built on them. Task 0.10 says stop rather than proceed hopefully — Gas Town without its watchdog tier is a weaker system than the one being adopted. ## Two decisions worth reviewing **Upstream is proposed at §2a, not §8.** Staying synced is preferred but not required. Too early is a stranger asking a busy maintainer to accept an abstraction on faith; too late means 232 files were migrated against a shape upstream might want differently — the one part that's expensive to redo. At §2a the pitch is a working second backend plus a conformance suite proving tmux's behavior is preserved. §4 proceeds regardless of the answer or silence. **A Gas Town rig maps to a herdr workspace, not to panes in one.** At 25 agents, rigs-as-panes is a flat 25-entry sidebar — precisely the failure that started this. Navigability at 25 agents is a requirement with a scenario, not an afterthought. ## Why the superseded change is kept, not deleted - `herdr-mail` and `herdr-spawn` stay in service, unchanged, until the port reaches parity. They're the working system in the meantime and must not be dismantled for a port that hasn't landed. - Its three observed failures are the port's **acceptance test**. If the ported system doesn't kill all three, the port didn't earn its cost. Both changes pass `openspec validate --strict`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Running ~8 agents produced three failures in a day: duplicated work (two
agents independently fixing one signal-cli bug, the second discovering the
first only from git log after building its own version), a stampede (every
agent correctly noticing red CI, with no way to pick one and stand the rest
down), and a lost picture (agents A-I spawned transitively, rendered flat,
impossible to collapse). The operator's memory was the only shared ledger,
and it saturated.

Two changes land together because the second supersedes the first.

add-town-scoped-coordination specified towns, a provenance tree, a board,
claims, and a per-town refinery as herdr plugins. Its tell is that it
specifies Towns from first principles -- a concept Gas Town already has,
along with Beads, the Refinery, Wasteland, Witness/Deacon, and Convoys. It
was rebuilding a mature system badly.

port-gastown-to-herdr forks Gas Town and replaces its tmux coupling instead.
internal/tmux is 4,149 lines and ~110 exported functions called directly from
232 of 1,194 Go files with no interface, but sorted by what a second backend
needs, only ~30 are semantic; ~28 are tmux chrome, ~15 are server plumbing,
and ~12 exist solely because tmux exposes no structured agent state -- which
herdr does. That last group is the argument the port is worth doing rather
than merely possible.

The riskiest dependency has a verified analog: Gas Town injects agent
identity as environment variables at session creation
(internal/polecat/session_manager.go:455 notes that setting them afterward is
too late), and `herdr pane split --cwd --env K=V --no-focus` covers it.

Section 0 is a spike with a real stop condition. Kill-agent-keep-pane,
respawn-in-place, and unresponsive-agent detection are unverified, and the
watchdog tier is built on them.

add-town-scoped-coordination is kept rather than deleted: herdr-mail and
herdr-spawn stay in service until the port reaches parity, and its three
observed failures are the port's acceptance test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo-admin/herdrmastr!9
No description provided.