Goals and stop conditions
A goal is the session’s definition of done. It’s the mechanism behind closed-loop autonomy: an agent should verify its work before it comes back to you.
The four goals that ship
Section titled “The four goals that ship”From config/goals.json:
| ID | What it demands |
|---|---|
codebase-question | Research and answer inline. Do not create files, PRs, or branches. Stop in needs_input. |
open-reviewed-green-pr | Open a PR, block until CI is green, run an independent fresh-eyes review, address all its feedback, re-check CI, write a ## Verification section with checked boxes and proof. Then stop. The default for most roots. |
open-reviewed-green-pr-with-version-bump | Same, plus a mandatory version bump when server source changed. |
e2e-verified-green-pr | Same, plus: state the critical path up front, spin up a real dev server, drive it with browser automation, record video and screenshots, embed them in the PR. |
Every one of them ends with the same two instructions: stop and wait in needs_input, and
do not archive yourself — because an open session with an unreviewed PR is the user’s to-do
list.
How a goal is applied
Section titled “How a goal is applied”That is the entire mechanism. AgentSessionJob#build_prompt_with_goal resolves the goal id to
its description (or passes an unknown string through verbatim as free text) and appends it to
the prompt.
A blank base prompt short-circuits the whole thing — a guard against spawning an agent whose entire prompt is a bare goal string.
Where a goal comes from
Section titled “Where a goal comes from”Precedence, in order:
- Explicit
goalparam at session creation (UI form orPOST /api/v1/sessions). - The agent root’s
default_goalfromroots.json. - Nothing — the column is nullable, and the goal suffix is simply not appended.
It can be changed after the fact: PATCH /api/v1/sessions/:id accepts goal, and a follow-up
prompt can carry a new one.
The column is validated on length only (GOAL_MAX_LENGTH). Any string is a legal goal.
The heartbeat
Section titled “The heartbeat”A session can have heartbeat_enabled with an interval (30–86,400 seconds). HeartbeatSweepJob
runs every 30 seconds and, for each due needs_input session with a heartbeat, injects an
automated nudge prompt and resumes it — the “keep working toward your goal” loop.
It deliberately skips sessions that are blocked on an elicitation or that have pending enqueued messages, because resuming those would spawn a second process against the same clone.
needs_input vs archived
Section titled “needs_input vs archived”This trips people up. A session reaching needs_input is normal — it means the agent finished
a turn. A session reaching archived means someone (or something) explicitly archived it:
- You archived it in the UI.
- The agent called
action_sessionwitharchivethrough Zimmer’s self-session MCP server. - A health monitor archived it.
Agents are told, in the goal text and in OrchestratorSystemPromptBuilder, not to self-archive
when a human still needs to read their output. Whether they comply is, again, a matter of the
model obeying English.