The loop
The mechanism is small. Plan a task into steps; then run a fail-safe loop until every step is done. Each cycle picks the first step that isn't done, executes it, and persists the outcome. A cut, a crash, a restart — all re-enter at the first non-done step. See the first code block for the shape.
Three properties carry the whole design:
- Fail-safe by construction. State is durable and the loop is idempotent over
donesteps. Nothing completed is ever recomputed. - The judge at every tick is Pippa, not dumb Python. The Python loop is scaffolding — it holds the step list and the statuses. The intelligence (execute this step, did it succeed, what's the output, is the plan still right) is a Pippa turn at each tick.
- Each tick is one short step, so it lands well under the ~6-minute ceiling and doesn't cut. The loop bounds every model invocation to a single step.
아빠: "각 루프에서 판단하는 게 어차피 피파야. 그냥 멍때리는 python code가 아니고."
("The thing judging in each loop is Pippa anyway. It's not just dumb, spaced-out Python code.")
The right primitive: an explicit state machine
The loop is really a state-machine driver, and naming it as such turns the fail-safe property from a hope into a guarantee. This isn't a foreign import — cwkPippa already runs this exact pattern in production. The coop letters lifecycle is a 6-state machine (unread → read → working → done, with abandoned / superseded branches); cinder's JobState is queued → running → completed / failed. We adopt the house pattern.
Two nested machines. The step machine: pending → running → done, with running → blocked (needs Dad) and running → failed (attempt cap exceeded). A cut leaves a step in running with its attempt count bumped, re-entered on resume. The task machine: planning → running → done, with paused (Dad interrupts), blocked (a step blocked), and failed (terminal).
It also collapses two hard questions
Pippa's entire per-tick job reduces to emit the next transition: done, needs-more, or blocked. That's the success-signaling question, answered. And the infinite-loop backstop becomes structural, not a bolted-on counter: failed and blocked are bounded terminal states the machine is forced to reach. It cannot spin forever, because every state has finite outgoing edges and running re-entry is attempt-capped.