Retry limits
Control how long the agents keep working an issue before handing it back to a human.
Overview
A mission runs as a loop. The Builder pushes a commit, CI runs, the Reviewer reads the diff, and QA verifies the acceptance criteria. When any of those gates fails, the mission loops back to the Builder carrying that feedback, and goes round again.
Two kinds of limit end the loop and hand the issue to a human:
| Limit | What it counts | Default |
|---|---|---|
| Oscillation limits | Rounds where a gate keeps failing the same way | 2 |
| Outer ceiling | Total Builder attempts, regardless of outcome | 25 |
An oscillation is the same failure repeating: the Reviewer raising the identical blocking comment, or QA failing the identical criterion, on consecutive rounds. A gate that fails a different way each round is making progress, and does not count toward the limit.
The oscillation limits are the ones that actually stop missions, because a genuinely stuck run tends to get stuck the same way each time. The ceiling is a backstop, sitting far above them precisely so it rarely fires.
Raising maxRetries on its own usually changes nothing. If missions are stopping earlier than you want, the oscillation limits are almost always the reason.
Configuration
Add a retries block to the ship.yml at the root of your repository. Every field is optional, and an omitted field keeps the default.
version: 1
retries:
qaOscillationLimit: 5
reviewOscillationLimit: 4
deployments:
# ...| Field | Meaning | Default | Range |
|---|---|---|---|
reviewOscillationLimit | Review rounds requesting changes before stopping | 2 | 1 to 50 |
qaOscillationLimit | QA rounds failing before stopping | 2 | 1 to 50 |
ciOscillationLimit | Consecutive CI failures with the same signature before stopping | 2 | 1 to 50 |
maxReviewGrants | Extra review rounds granted when the work is judged to be progressing | 3 | 0 to 50 |
maxRetries | Outer ceiling on Builder attempts | 25 | 1 to 200 |
A value outside its range is clamped to the nearest bound, and a value that is not a number falls back to the default. A malformed entry can never switch a limit off.
When changes take effect
retries is read from ship.yml on your main branch, the same as the agents block. A pull request cannot change the limits that govern its own review, so a new value applies once it is merged.
Each mission captures its limits when it starts and keeps them for its whole life. Editing ship.yml while a mission is running affects the next mission, not the one already in flight.
Choosing values
Raise the oscillation limits when your codebase genuinely needs more rounds to converge, for example when acceptance criteria depend on integration behavior that takes a few attempts to get right. Every extra round is a full agent run, so the cost is real.
Leave them at the default when you would rather see a stalled issue early. Reaching a human after two identical failures is usually cheaper than five.
A higher limit does not make a stuck mission succeed. If the Reviewer keeps raising the same comment, more rounds normally produce more of the same. The limits buy time for genuine iteration, not for a problem the agents cannot solve.
What happens at the limit
The mission shows as Needs attention in the console, the Linear issue moves to In Review, and the reason is posted on the issue naming the gate that stopped it and the feedback from its last round. The pull request stays open, so you can take over the branch, or reply on the issue to send the agents back in with new direction.
A reply resets the counters. The limits apply to each stretch of autonomous work, not to the issue for all time.
How is this page?