Components
The gaffer and the loop
The gaffer is the parent agent for one factory, and its loop is the beat. Each beat reads the RFCs you approved, breaks them into tasks, dispatches a worker per task into its own tmux session, checks what came back, and reports what needs you. Beats are five minutes apart, so that is the wait between approving something and hearing about it.
Its instructions are contracts/factory-loop.md: one iteration
written out in prose, a file you read and edit. Changing how a factory operates
is a commit, not a setting.
Every beat reads the world fresh, so nothing carries forward to be wrong and
any worker can be killed and replaced mid-task. There is no step four of seven
to be stuck on, only a gap that is either closed or not. Knowledge is the one
exception to that freshness: every worker reads docs/learnings/ in the repo
it is about to touch before it starts, and leaves at most one behind when it
finishes (contracts/learnings.md). A factory whose
four-hundredth worker is as ignorant as its first is forgetful.
Work that crosses repos is the case this shape is for. The gaffer holds one
RFC across every repo in its scope, opens the pull requests in an order that
accounts for what depends on what, and keeps a per-repo concurrency lane so two
agents never collide in the same tree. Each dispatch posts a line reading
▶ acme dispatched: … to the Slack channel you named at setup, if you named
one, so the RFC you approved answers back on its own. The first beat after a
fresh boot reports what it found and dispatches nothing, so the beat after it
is the first that builds anything.
How a beat runs is a per-factory setting. runtime = "resident" keeps a
claude session alive in tmux and lets the agent schedule its own next beat.
runtime = "one-shot" moves the loop out of the agent: each beat is a
claude -p process that runs an iteration and exits, so liveness becomes an
exit code and a timestamp instead of a guess about what a pane is doing.