6.3 KiB
Paperclip Harness
A terminal control room for an AI coding factory. Paperclip runs the work — tasks, blockers, agents, runs, cost and a git worktree per task. This is the surface a person uses to see it, direct it, and decide what lands.
Eight workspaces in TUIOS, one Go program in each, and a small set of commands for the parts that should not be a keystroke (merge, review, adopt a folder). No web UI, no database of our own, no second copy of any fact.
What it does
| Workspace | What it answers | What it shows |
|---|---|---|
| Board | what is the state of the work | tasks by group, the chosen task with its blockers and check, what needs a person |
| Work | what is happening and what changed | run timeline, the diff from the task's own worktree, review verdicts, the run's log, and a merge that asks before it acts |
| Agents | who is working, on what, for how much | agent roster with spend and budget, every run in the company, the run log, editable role/model/budget/heartbeat, per-agent skills and extensions |
| Reply | what was said and what I say back | the thread and a reply box that can also set the task's status |
| New task | what am I asking for | a five-field form, what each field means, and exactly the text the agent will receive |
| Project | which folder, which machine, what it costs | a dashboard (agents, tasks, money, run activity), costs as bars, the project's settings, adopted projects |
| Repair | is the layout sound | three-state health checks, the live TUIOS layout, the rebuild log, session cleanup |
| Shell | where am I | a prompt in the project folder, above a box naming every path that matters |
Keys follow TUIOS's rules: Tab moves between panels, ↑↓ or jk move, ( ) switch tabs,
R rebuilds the layout, ? lists the keys for the panel you are in. A bare Esc closes a box
and never quits.
The design decisions that matter
One owner per fact. Tasks, blockers, comments, approvals, runs, cost and worktrees belong to Paperclip. The interface reads them every time and stores none of them. Two screens cannot disagree because there is only one record.
One project is one folder on one machine. That is the only thing we keep: a small file in
<folder>/.harness/harness.toml naming the session, the machine and the task being watched.
Everything else is Paperclip's.
Choosing a task is one act. Enter on the board writes the choice into that file and every
other workspace follows within a second. No message bus, no second state to keep in sync.
A task is finished when the agent says so. A review stage or ocr can refuse the change. A
project's check.sh is a regression check at merge time — the same job a CI pipeline does — not
the definition of done.
Merging is a decision, so it asks. m names the branch, the base branch and the checks, and
waits for y. It takes a lock, rebases, runs the checks, runs the review, merges, then re-runs
the checks on the base branch and rolls back if they fail.
TUIOS owns the keyboard. h j k l z n and [ ] tab , . = ; and the digits are its. The
program navigates with arrows, jk, ( ), Space and Enter, and keeps Esc free.
Nothing hardcodes a size. Every pane re-asks the terminal for its size on each refresh, because a window manager can re-tile a pane without the program hearing about it.
Measured, not asserted
| Claim | Measurement |
|---|---|
| An assignment wakes the agent | wake recorded 46 ms after the assignment, run started 0.1 s later, task done in 28 s |
| Cost is readable per task | cost-summary: 1 cent, 101,002 input tokens, 1,515 output tokens, one run |
| Blockers are real answers | diagnostics/blockers returns unresolvedBlockerCount: 1 — and the task list never carries it, so the tree asks per task |
| Worktrees are Paperclip's | branch AUD-160-… at .paperclip/worktrees/…, cut from main |
| A review can refuse a merge | ocr found rm -rf "$HOME/tmp" deleting /tmp when HOME is empty; the merge was refused and the file never landed |
| A task can have several runs | AUD-166: assignment, then automation — Paperclip's corrective wake |
| Per-agent skills work | adding one skill changed that agent's list and no other |
| A new project can be adopted in one command | bin/office created the session, wrote the project file and built all eight panes |
Technology
- Go with Bubble Tea, Lipgloss, Bubbles and BubbleZone; one binary, one program per pane.
- TUIOS for sessions, workspaces and panes, including the control-protocol verbs used to create sessions and switch between them.
- Paperclip as the control plane: 685 API endpoints, isolated git worktrees per task, Pi as the agent runtime.
- ocr for code review over the diff; Lazygit, Hunk, Yazi, Neovim, fzf and a shell open as tool panes on demand instead of being rebuilt.
- Mouse-1 for one narrow job — labelling a failed run with one of four next actions.
What this demonstrates
- Integration under real constraints: a dozen independent systems (TUIOS, Paperclip, git worktrees, Pi agents, ocr, skills) joined so that each keeps its own job.
- Single-source-of-truth discipline: no cached facts, no second task list, no guessed state — and the API was measured until the traps were known (blockers absent from list endpoints, cross-issue writes refused outside a run).
- Failure-aware design: a merge that asks, a review that can refuse, a lock so two merges cannot overlap, a rollback when post-merge checks fail, and health checks that have three states because "not run" is not "pass".
- Terminal interface engineering: resize handling, a focus model, tabs, overlays that wrap instead of clipping, and keys chosen around another program's keymap.
- Evidence-based reporting: every claim in the docs names the command that showed it, and the unproven ones are marked unproven.
Repository
bin/ commands: office, board, merge, review, triage, project-reset
tui/ the Go program: one binary, eight screens
docs/ the plan, the measurements, the runbook, the test plan
docs/architecture.mmd the system diagram, rendered to docs/diagrams/
Start with HANDOVER.md, then docs/WORKSPACES.md, then docs/PLAN-INTERFACE.md.
