CommunityCoding & Developmentgithub.com

br1anchen/pstack-pair

Run two coding agents in one Herdr or Rex session as a pair: a master that plans, briefs, reviews, and decides, and a sidekick that implements, tests, and diagnoses under pstack playbooks. Use for /pstack-pair, 'pair mode', 'spawn a sidekick', 'be the sidekick', a `pstack-pair PLAN|BRIEF|STEER|REPORT|STOP` message, or when work should be delegated to a second agent pane with a reviewable brief and report trail, periodic check-ins, and directional steers while it works. Requires Herdr (HERDR_ENV=1) or Rex (REX_BLOCK).

What is pstack-pair?

pstack-pair is a Claude Code agent skill that run two coding agents in one Herdr or Rex session as a pair: a master that plans, briefs, reviews, and decides, and a sidekick that implements, tests, and diagnoses under pstack playbooks. Use for /pstack-pair, 'pair mode', 'spawn a sidekick', 'be the sidekick', a `pstack-pair PLAN|BRIEF|STEER|REPORT|STOP` message, or when work should be delegated to a second agent pane with a reviewable brief and report trail, periodic check-ins, and directional steers while it works. Requires Herdr (HERDR_ENV=1) or Rex (REX_BLOCK).

Works with✓Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/br1anchen/open-pstack/tree/HEAD/skills/pstack-pair

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Read the runtime adapter before following this workflow. Its runtime mappings apply to all referenced playbooks and scripts.

Pstack pair

Two agents, one Herdr or Rex session, one repository. The master owns judgment and the sidekick owns the working tree. Every message between them is a file in the pair store plus a one-line prompt that names the file. The terminal is never the record, because agents on the alternate screen leave no scrollback.

Preconditions

  1. Inside Herdr (test "${HERDR_ENV:-}" = 1) or Rex (REX_BLOCK set). Outside both, say so and stop.
  2. Load the multiplexer's skill for pane and agent control: Herdr's ~/.agents/skills/herdr/SKILL.md (or herdr --skill when that file is absent), or Rex's rex skill show. Its safety rules apply throughout. In Rex, read Running in Rex.
  3. herdr or rex, and Python 3.11 or later (python3), on PATH. scripts/pair.sh help lists every store and channel operation; use it instead of hand-built herdr or rex calls for the pair.
  4. Start the master in auto mode. Devin defaults to bypass permissions with --permission-mode dangerous. Other kinds inherit the master's mode. pair.sh permission prints the detected master mode. Use --permission <mode> or native permission flags after -- to override the default; --permission auto selects Devin smart mode. Kinds without a translation take native flags after --. spawn also skips each kind's folder-trust prompt, which would hang an unattended agent in a folder it has not seen: pi gets --approve, Devin --respect-workspace-trust false. A trust flag after -- overrides it. Claude and Codex instead ask to trust a folder A spawned Claude also starts with no MCP servers (--strict-mcp-config and an empty configuration), since each server is a process per session; a --mcp-config after -- keeps yours. they have not seen; that decision is the human's, so spawn declines the dialog and stops with what to do: open that agent in the repo once and trust it.

Roles

MasterSidekick
Ownsplan, briefs, review, decisions, the humanthe working tree, tests, diagnosis, evidence
Runs pstack aspoteto-mode framing, how, architect, review skillsthe playbook each brief names, with its todolist
Writesthe pair store onlyfiles inside the brief's Scope, plus its progress log and report
Speaks throughbriefs, steers, reviews, standing orders, gatesprogress lines, reports

Enter your role. Master: references/master.md. Sidekick: references/sidekick.md.

Pair store

${XDG_STATE_HOME:-$HOME/.local/state}/pstack/pair/<slug>/, created by pair.sh init. One writer per file.

PathWriterContent
pair.jsonmaster via pair.shagent names, pane ids, cwd, git root, the sidekick's fallback and failovers, pane placement (split or tab)
standing-orders.mdmasternumbered constraints pasted by path into every brief
plans/NNN-<slug>.mdmasterone plan round, from the plan template
briefs/NNN-<slug>.mdmasterone unit, from the brief template
progress/NNN-<slug>.mdsidekick via pair.sh progressone timestamped line per completed step or change of approach; a check-in shows only the lines the master has not seen
steers/NNN-<slug>-s<k>.mdmastermid-brief direction k for unit NNN, from the steer template; supersedes: names the objected steer it answers
reports/NNN-<slug>-s<k>.mdsidekickobjection to steer k, from the steer response template
reports/NNN-<slug>.mdsidekickevidence for brief NNN, from the report template, or the agree/object response to plan NNN, from the plan response template
reviews/NNN-<slug>.mdmasterverdict on report NNN, from the review template; agreed on a plan unlocks its briefs
scratch/<id>master via pair.sh scratchlink to a throwaway worktree at a unit's commit for rerunning its checks, kept outside the repo under ${XDG_STATE_HOME:-~/.local/state}/pstack/scratch/ (PSTACK_SCRATCH_ROOT moves it), which Claude and Codex must trust once per host (kitchen.py doctor checks); removed after the review
gates.mdmasteropen questions for the human
decisions.tsvmaster via pair.sh logthe show-me-your-work trail
status.mdpair.sh statusderived table; never hand-edited
queuemaster via pair.sh queue and dispatchthe next brief's path, one slot
steps/NNN-<slug>.tsvsidekick via pair.sh stepone row per committed step: number, commit, time, notes it resolves, summary
notes/NNN-<slug>-n<k>.mdmaster via pair.sh new-note and notereview of the unit's steps through step k, from the note template: blocking items and follow-ups
followups.mdmaster via pair.sh notefollow-ups from every note, for a later brief or an issue
session-handoff.mdmastercompact recovery and next-task context, read at bootstrap
sessions/pair.sh spawn / rotateprior ready reports; retained session exports and timing evidence
events.tsvevery pair.sh commandone row per message, report, wake, and log entry, read by pair.sh metrics

NNN is a zero-padded sequence shared by plan or brief, report, and review, so the files for one unit sort together.

Messages

Prompt textDirectionSender's helperReceiver's move
bootstrap (names the skill and the store)master to sidekickpair.sh spawnbootstrap steps, reports/000-ready.md, reply READY
pstack-pair PLAN <plan-path>master to sidekickpair.sh discussground the plan in the code, write an agree or object response, end the turn
pstack-pair BRIEF <brief-path>master to sidekickpair.sh dispatchrun the brief, write its report, run pair.sh finish, then end the turn with the REPORT line
pstack-pair BRIEF <brief-path>, queuedmaster to a working sidekickpair.sh queuethe master dispatches it after a fresh session; pair.sh next refuses
pstack-pair STEER <steer-path>master to a working sidekick, or to one paused on an objectionpair.sh steerread it on arrival, between tool calls; agree and continue, or object with evidence and end the turn
pstack-pair REPORT <report-path>sidekick to masterpair.sh finish (or notify)read the report, review
pstack-pair STOP <store>master to sidekickpair.sh stoppause safely, write a stop report

The master's dispatch and wait return when the sidekick's reply lands: the report written since the message, or a blocked sidekick. A settle from the multiplexer alone is not trusted: a Devin sidekick shows idle as a prompt arrives and between steps, and in a narrow pane can show done for a whole run, so a settle is checked against the pane's "esc to interrupt" line; a settle with no report that holds for a minute ends the wait with report: missing. They also return when the check-in interval passes with the sidekick still working, printing a check-in digest instead of a report path. wait also returns the moment a dispatched brief's report lands, even when the sidekick has already taken the queued brief; running: then names the brief it is on. notify prompts the master only when the master is idle, so a waiting master is never interrupted. A message you receive after compaction still names this skill and the file to read, so reload the skill and continue from that file.

Plan first

Implementation starts only from a plan both agents agreed to. The master drives the implementation, architecture, and system design: it drafts plans/NNN-<slug>.md with the chosen design, the alternatives it weighed, and their pros and cons, then sends it with pair.sh discuss. The sidekick brainstorms against those trade-offs, checks every step against the code, and answers agree or object with evidence. The master revises in a new plan round or answers the objections, until a response says agree and the master writes a review with verdict agreed. pair.sh dispatch refuses a feature, bug-fix, refactoring, perf-issue, or pstack-tdd brief whose plan: line does not name an agreed plan. Read-only and forensic briefs need no plan; a bug's diagnosis brief runs before its plan, so the plan rests on runtime evidence. Three rounds without agreement become a gate for the human, with both positions in gates.md.

Check-ins and steers

The master drives the way a pairing driver does: it looks up on a cadence, not continuously, and corrects direction, not keystrokes.

  • The sidekick appends one line per completed todolist step and per change of approach to progress/NNN-<slug>.md through pair.sh progress. Before it writes outside Scope or departs from the plan, it writes the line first, so a check-in can catch it.
  • dispatch and wait return at the check-in interval (--every MIN, nine minutes by default) when the sidekick is still working, with a digest: elapsed against the timebox, the progress lines not yet seen, files touched and which fall outside Scope, commits since dispatch, and steer counts. When the sidekick switched branch or rebased, so HEAD no longer descends from the dispatch head, only the commits made since dispatch count as touched. That digest is all the master reads between reports; it reads the pane only when the digest marks the log STALE.
  • A steer is a mid-brief correction from the master: pair.sh new-steer, then pair.sh steer. It lands in the sidekick's input queue while it works; the harness hands it over between tool calls and the sidekick acts on it there, not at the end of the step. A Devin sidekick gets it as a STEER: line from its next pair.sh step, notes, or progress instead, since the Enter that delivers a queued message to Devin cancels its running command. --interrupt cancels the running tool call first, for a direction that cannot wait for it. Steers carry direction: an approach the agreed plan did not choose, scope drift, a step to skip, a Forbidden line about to be crossed, or news from the human. Anything the review can catch at the end waits for the review.
  • The sidekick agrees or objects, as with a plan. Agree: apply, acknowledge in the progress log, continue. Object: write the steer response with evidence and an alternative, notify, end the turn. The master answers with a steer that supersedes the objected one, revised or withdrawn, and pair.sh steer resumes the sidekick. Two rounds per steer; the decision stays with the master, and a standing disagreement goes to a plan round.
  • Two fresh steers per brief. A third means the brief was wrong: stop the unit and re-brief.

Task sessions of every kind

A sidekick of any kind (Claude, Codex, Devin, pi, Prime, Muse) uses a fresh conversation for each completed brief. Before spawning, queueing, rotating, or cleaning its storage, read the Devin session lifecycle for Devin or Pi, or the Prime adapter for Prime. Partial and blocked work stays in its session; a completed brief leaves the queue for the master to dispatch. dispatch and discuss rotate the sidekick themselves first (rotated: in their output); pair.sh rotate stays for the master to run by hand. The pstack store persists across sessions.

Muse Code

Use --kind muse for any role. Read the Muse adapter for its permission, trust, preflight and exit handling. Muse keeps one conversation per pane, so it is not rotated per brief.

Prime Agent

Use --kind prime-agent for the sidekick. Read the Prime Agent adapter for native model arguments, preflight, steering, exact daemon-session cleanup, and provider failover. Prime uses the shared store protocol and requires rotation after each completed brief.

Pi sidekick and fallback

A pi sidekick reports its state to Herdr (and, with the pstack extension, to Rex) through its own events and queues a steer without cancelling the running command. When its model sits behind a route that can fail, spawn it with --fallback devin: spawn checks the model first, and pair.sh failover swaps in the fallback mid-run. Read the Pi sidekick reference before spawning one.

Keeping the sidekick busy

The sidekick is the critical path: the master turns a report around in minutes, while a unit takes tens of minutes to hours. Three habits keep the sidekick from waiting on the master.

  • Queue the next brief. While a unit runs, the master drafts the next one and holds it with pair.sh queue. After a done report the sidekick starts a fresh session and the master dispatches that brief; pair.sh next refuses. The queue has one slot and holds only a unit that does not hinge on the running unit's review, so a revise becomes a follow-up brief, not a rework of the queued one.
  • Review at the commit. A brief that writes says commit: yes, and the report's head: names that commit. The master reads it with git show while the sidekick works on the next unit, and reruns checks in pair.sh scratch <store> NNN-<slug>-review --at <head>, never in the shared tree.
  • Amend instead of re-planning. An objection the master adopts becomes a numbered amendment in the agreed review. A new plan round is for a changed design, not a narrowed step.

pair.sh metrics <store> reads events.tsv and shows where the time went: sidekick busy and idle, master wakes, review latency, verdicts. Sidekick idle time is the number to drive down.

Draft-PR review

A brief is a draft PR that the master reads as it grows, not a diff it meets at the end. Review that arrives after hours of work returns long finding lists, and each fix round widens the change and reruns every check; review of each step catches the same blockers while they are one commit old.

  • The brief's Steps are commit-sized, twenty to forty-five minutes each. The sidekick commits each step, records it with pair.sh step, and goes straight on. It never waits for review.
  • The master's wait returns steps: when a step lands that no note covers. The master reads that range, writes a note with pair.sh new-note, and publishes it with pair.sh note, while the sidekick works on.
  • A note, like a review, splits its findings. Blocking is only what would make the unit wrong to land: wrong behaviour, a missed consumer of a changed value, data or schema safety, a rollback hazard, a broken contract, a test that does not test its claim. Everything else is a follow-up: note copies those to followups.md, and they never widen the unit or cause a revise.
  • At each step boundary the sidekick runs pair.sh notes, fixes the open blocking items first as fixup commits, and records them with pair.sh step --resolves. finish refuses a done report while one is open. A blocking note on a unit already done is fixed by the next brief, whose step names it qualified: --resolves 020-n1.
  • A problem that would waste the next steps, a wrong design rather than a wrong line, still goes out at once as a steer.
  • Each step runs the checks it names, and a brief's Verify runs the targeted tests plus the landing gate's fast checks. The full test battery runs once: in the landing brief, or, where the gate is slow, in the issue's last implementation unit.
  • The final review reads only the report's review-delta, the diff since the last note, and accepts unless it finds a new blocking item.

A brief without Steps runs as before, with one review at the end.

Pausing

pair.sh pause <store> --reason <why> stops the work at the next safe point, for a skill upgrade or anything else that needs all agents quiet. Anyone may run it, including the human or another session.

  • The sidekick sees PAUSE: in the output of its next pair.sh step, notes, or progress. It commits what is verified, writes the report as partial with where it stopped and the next step, runs pair.sh finish, and ends the turn. finish hands out no queued brief while paused.
  • The master's dispatch, queue, and discuss refuse while paused, and so do consult and answer where the skill has them. A wait prints paused:. The master finishes the step it is in, records where the work stands and the exact next step in gates.md, and ends its turn.
  • pair.sh resume <store> lifts the pause. The master re-reads the skill if it changed, then re-dispatches the paused brief; the sidekick's step log says where to continue.

pair.sh stop is the immediate variant, for a sidekick that must stop mid-step.

Shared rules

  • Facts about panes, agents, and states come from the multiplexer through pair.sh, never from memory or sidebar order.
  • Approval dialogs belong to the human unless the standing orders delegate a class of them to the master. Neither agent answers the other's dialogs.
  • Both agents share one working tree. The sidekick writes it. The master reads it and its history at any time and edits nothing under the repository; it runs builds and tests only in a scratch worktree from pair.sh scratch, so they never race the sidekick's edits.
  • Close only panes you created, and only when the human asked.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Related Skills