Architecture
How romp works under the hood.
romp is a Go CLI that drives your local coding agent. It is deliberately minimal: the durable source of truth is GitHub, and romp adds only the machinery to claim, isolate, and verify work.
Job lifecycle
- Poll —
watchlists open issues carrying the trigger label every 60 seconds. The label is the entire queue; there is no local backlog. - Claim — atomic insert (unique on repo + issue), claim label, assign
@me. Concurrent watchers on other machines skip claimed issues. - Worktree — each job runs in a fresh
git worktreebranched from the default branch. Never the local tree; the base is deterministic. - Agent — the goal contract is rendered and handed to the harness (Claude, Codex, or OpenCode).
- Verify — romp re-runs every
[verify]command itself. The agent’s own “tests pass” is never trusted. - Push and PR — after verification passes, romp pushes the builder commit and opens the PR. PR creation must succeed before review starts.
- Review — code changes go through one concurrent read-only reviewer call
per routed lens in the same job slot. Romp merges all lens outcomes into one
pass and posts one PR comment. Any failed lens fails the whole pass instead
of allowing partial approval. Blocking findings get up to
review.max_fix_roundsbuilder rounds on the same branch. Each round includes fresh verification, push, and a fresh lens fan-out. If verification fails and the budget has another round, the next builder receives the failed command, exit code, and captured output before Romp tries verification again. Re-review receives the prior findings and builder reports, but still sweeps for newly introduced defects. Documentation-only changes skip review but still open a PR. - Complete or recover — approval removes the trigger label. Unresolved
review findings become
changes-requested. Review failures leave the PR and worktree available with a distinct failure comment.
Components
romp/
├── cmd/romp/ # Cobra commands (init, watch, run, status, ...)
├── internal/
│ ├── config/ # TOML layering, language detection, effort/variant handling
│ ├── harness/ # Claude, Codex, and OpenCode adapters behind a Run/Name interface
│ ├── prompt/ # goal-contract template rendering
│ ├── runner/ # job pipeline: worktree → agent → verify → PR → review
│ ├── watch/ # poll loop + claim + cancel socket
│ ├── job/ # SQLite job table + outcome history
│ ├── gh/ # GitHub client with rate-limit retry
│ ├── git/ # worktree and branch management
│ └── codename/ # deterministic adjective_name per job
└── docs/adr/ # design decisions
Isolation and concurrency
- Worktree isolation — concurrent jobs never share a checkout.
- Width — an in-memory semaphore bounds concurrent jobs per repo.
- Cross-machine dedupe — the claim label, not any local state, is the authority across machines.
- Crash recovery — a fresh watcher clears only its own stale in-flight
rows and reconciles issues whose
romp-Nbranch already has an open PR.
Observability
Every job gets a codename — an adjective_name pair like sunny_naruto,
derived deterministically from the repo and issue number. The codename prefixes
every log line, names the per-job log file, and is the primary column in
status.
State lives in one SQLite file per machine: ~/.local/state/romp/romp.db. The
jobs table holds exactly the in-flight set; finished jobs move to the
append-only outcomes table in one transaction.
Failed verification output is written to the per-job log. The phase timeline
shows the failed command and any transition into another builder round.
romp history --review aggregates re-verification failures across the selected
history window.
Design decisions (ADRs)
| # | Decision | Status |
|---|---|---|
| 0001 | An explicit verify command, independently re-run | accepted |
| 0002 | Prompt contract; outcomes via .romp/ files |
accepted |
| 0003 | GitHub is the source of truth; ephemeral worktrees | accepted |
| 0004 | TOML layered with a zero-means-default overlay | accepted |
| 0005 | Atomic claim, configurable claim label, in-flight job table | accepted |
| 0006 | Job codenames, status, per-job logs, and gc | accepted |
| 0007 | Poll the trigger label in v0; webhooks deferred | accepted |
| 0008 | Shared SQLite file and append-only outcome history | accepted |
| 0009 | Cancel over a Unix socket; logs tail files | superseded by 0010 |
| 0010 | One machine-wide daemon, one socket, HTTP clients | accepted |