Skip to content

Rebuild: strip the agent harness, pivot to a tmux plugin - #22

Closed
apriendeau wants to merge 3 commits into
mainfrom
rebuild/tmux-plugin
Closed

apriendeau wants to merge 3 commits into
mainfrom
rebuild/tmux-plugin

Conversation

@apriendeau

Copy link
Copy Markdown
Contributor

Throws out the RPC/provider agent harness and repoints the repo at a much smaller tool: a
tmux plugin that spawns isolated coding-agent instances in a polyglot monorepo.

41,319 deletions, 647 insertions. Rust goes from ~34k lines to 538.

Why

The harness was solving model orchestration. The actual problem is running several agent
CLIs (Claude Code, Codex, Grok, whatever) in parallel against one monorepo without them
colliding — and the parts of that worth building are worktree lifecycle and environment
materialization, not panes or provider APIs.

tmux already owns panes, input, resize, scrollback, and detach/reattach.
opensessions already owns the sidebar and
agent-state display. Neither materializes a usable instance of a monorepo, and that gap is
the whole product.

Design

Full write-up in DESIGN.md. Two properties are load-bearing:

  • No daemon. Every invocation is transactional and exits. No server, no socket, nothing
    with a lifecycle.
  • tmux is the state store. Instance metadata lives in window options (@phx_worktree,
    @phx_branch, …) and the window id is the primary key. No registry file, nothing to desync.

Shape is a phx.tmux shim binding four keys (new, done, discard, rename) plus a
small binary those bindings invoke. Arguments arrive via tmux format substitutions; there is
no human-facing CLI.

The core is materialization — APFS clonefile for node_modules and target, copied
.env and MCP config, and per-instance env for ports, COMPOSE_PROJECT_NAME, and sccache.
Without copy-on-write cloning, worktree-per-agent isn't viable on a real monorepo.

Removed

  • All fourteen superseded src/ modules plus crash.rs
  • The five example plugins and the cargo workspace around them
  • DESIGN.md and SPAWN_AGENT_SPEC.md (superseded), plugin/rpc/miri justfile recipes
  • Eight dependencies: ratatui, crossterm, reqwest, syntect, uuid, chrono, and friends
  • beads entirely — .beads/, the bd prime SessionStart and PreCompact hooks, the
    bd-init recipe, gitignore entries, and the tracker sections of CLAUDE.md / AGENTS.md.
    Work is tracked in Jira and Linear; the repo carries no local tracker. This also removes
    the old mandatory-push session protocol.

Kept

src/worktree.rs and its tests — create/remove/list/diff/merge, zero internal dependencies,
all six tests still green. It maps directly onto the new design.

CI

  • Miri job dropped: no unsafe remains, and Miri can't spawn the git subprocesses the
    tests need
  • crates.io publish dropped: TPM is the distribution channel now
  • Windows release target dropped: tmux is unix-only
  • CI now runs on macOS as well as Linux, since clonefile is macOS-specific
  • Release assets keep the phx-<target>.tar.gz name — that's the contract with phx.tmux,
    which downloads a binary on first load

Not in this PR

src/main.rs is a clap skeleton; every subcommand returns "not implemented". Per
DESIGN.md §11 the next step is materialize standalone, proven against a real monorepo —
that's where all the risk sits. Four open questions are tracked in §9, the sharpest being
clone freshness when lockfiles drift.

Replaces the RPC/provider agent harness with the design for a tmux plugin
that spawns isolated coding-agent instances in a polyglot monorepo.

Removed:
- src/{commands,http,otel,plugin,providers,remote,rpc,sdk,session,shared,
  store,tools,tui,config}, src/crash.rs — superseded
- examples/plugins and the cargo workspace around them
- beads: .beads/, bd hooks in .claude/settings.json, bd-init recipe,
  gitignore entries, and the tracker sections of CLAUDE.md / AGENTS.md.
  Work is tracked in Jira and Linear; the repo carries no local tracker.
- DESIGN.md and SPAWN_AGENT_SPEC.md, both superseded by the new DESIGN.md

Kept:
- src/worktree.rs and its tests — create/remove/list/diff/merge, standalone
  and directly reusable by the new design

Added:
- DESIGN.md: full design, collision matrix, open questions, sequencing
- src/main.rs: clap skeleton for menu-spec/new/done/discard, all unimplemented

Cargo.toml drops ratatui, crossterm, reqwest, syntect and the rest of the
harness dependencies. just check passes.
- drop the Miri job: no unsafe remains, libc is gone, and Miri cannot spawn
  the git subprocesses worktree_tests depends on
- drop the crates.io publish job: TPM is the distribution channel now, and
  it called the deleted 'just publish' recipe
- drop the Windows release target: tmux is unix-only
- run CI on macOS as well as Linux; clonefile behaviour is macOS-specific and
  the primary target
- configure a git identity in CI so worktree_tests can commit
- release notes now document TPM install instead of cargo install

Release asset names are the contract with phx.tmux, which downloads the
matching binary on first load. Noted inline.
Tested against bun 1.3.14 on APFS with a two-package workspace.

Bun 1.3 uses the isolated linker, not hoisting: a content-addressed
node_modules/.bun store plus per-package node_modules of relative symlinks.
Two findings that change the design:

- every symlink bun writes is relative, so cp -Rc into a worktree is safe --
  verified that a worktree resolves @acme/core to its own packages/core while
  the primary still resolves to its own, and that no symlink under the
  worktree escapes it
- deps live in per-package node_modules, not just the root, so the clone list
  must cover packages/*/node_modules or the worktree resolves nothing

Also downgrades open question 1: bun install against an already-correct tree
took 7ms, so reconciling unconditionally after clone is close to free and
beats hashing lockfiles. Still open for Rust and codegen.

Flags what is still unverified: the toy case has a handful of symlinks where
a real workspace has tens of thousands, and cp -Rc recreates each one
individually. Needs measuring against the real monorepo.
@apriendeau apriendeau closed this Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant