rafa pages
- rafa
- Stretches
Stretches
Run a batch of issues as one sprint, several loops on one integration branch and then one release, by hand or with the alpha operators.
Stretches are alpha: tested on rafa's own development, and the files and steps may change between versions.
A stretch is a sprint: a batch of issues, each run as its own loop, landed together on one integration branch, stretch/<n>, and then released as one version. It keeps a run of small fixes off the default branch until the whole batch is done, and it ends in one merge and one release instead of one per fix.
The design's picture is a pit stop: a fix in the middle of a stretch mends the one thing that stops the car and sends it back out, and never changes the route. The technical name is the stretch item's check after each merge, the pit-stop readings rafa stretch item --wait prints.
The flow
The subject actions it runs, in order:
rafa stretch startpushes the default branch asstretch/<n>, records the oldpr.baseand pointspr.baseat the stretch branch, so every pull request in the stretch targets it. It copies the operators into.rafa/stretch/<n>/operators/and starts them (below).rafa stretch item <issue>, once per issue in the batch. Each item is a small cycle of its own, drawn below.rafa stretch end, before the merge: it needs the stretch's report,.rafa/stretch/<n>/report.md, adds everyClosesline of the items to the pull request body, and opensstretch/<n>into the default branch.- You review and merge that pull request.
rafa stretch endagain, after the merge: it putspr.baseback to what it was.rafa release settlefolds every item's fragment into one version (The release flow).
Settle after step 5, not before. rafa release settle releases on the branch pr.base names, so while it still points at stretch/<n> it would cut the version on the integration branch.
One item
rafa stretch item <issue> plans the issue (keeping a plan of it already in plan.dir), starts its loop detached in its own worktree, and prints the loop's session id. With --wait it follows the loop to the end and lands the item: it refuses a pull request whose base is not a stretch/* branch, merges it with checks skipped, waits for CI on the merge commit, and appends the item to .rafa/stretch/<n>/items.ndjson. The checks the item skips run on the stretch branch instead, and on the stretch's own pull request into the default branch.
Each item's loop runs in its own worktree, so you can keep working in your checkout. The operators run the bucket one loop at a time. [TBD: running several items' loops at once; a stretch as a sprint with parallel lanes is an open spec, #1075]
The diagrams show the default sequence, the most common case. Workflows become configurable before 1.0, once workflow config lands (#71, #119). The config shape is [TBD: the workflow config shape].
By hand, or with the operators
By hand. One person batching a few fixes runs rafa stretch item <issue> --wait per issue and ends the stretch themselves. [verify: opening a stretch branch without starting the operators; rafa stretch start always starts them unless --dry-run, and --role starts one]
With the operators. An operator is a Claude Code agent that runs rafa the way a person does, instead of doing a loop's tasks. rafa stretch start opens three in one tmux session, stretch-<project>-<n>:
- the engineer sweeps the board, groups duplicate bugs, and proposes a bucket of up to 10 issues, bugs first. After you approve it, it runs the bucket one item at a time, checking effort, bugs, delivery and conflicts between items. It stops a second time for you to merge the stretch into the default branch, settles one version, and writes a report of the gaps it hit and what it would change about itself, which waits for your yes;
- the watchtower watches the engineer and its loops without writing anything, and alerts you when one needs you;
- the analyst reads the stretch's data (run records, loop logs, the effort store, the board) without changing anything, and tests your hunches against it: which the data supports, which it does not, and which it cannot answer yet. It writes only its own
analysis.md.
--remote-control starts each session with Remote Control, so you can approve the bucket and read the alerts from another device. Each stretch runs on its own copy of the operators, so a pull or an update of rafa never changes a stretch already running. The operators need permission rules in the project's .claude/settings.local.json; the README's "Operators (alpha)" section gives the block.
What a stretch spends
rafa stretch start spends one session per operator, and each item spends one planning session and its loop's sessions. --dry-run on start, item and end prints every step in order and runs none.
Coming
Coming, in open specs: a stretch becomes a sprint, with lanes naming parallel lines of sprints (#1075); a stretch can join another project, for a change that spans a library and the add-on using it (#1256).