Stages
The three kinds of stage in RoutineOS. Lifecycle stages a routine moves through, phases a run writes in, and workflow stages a pack declares.
RoutineOS uses “stage” in three places. They nest: a routine moves through lifecycle stages; once live, each run follows its workflow stages; and the write at the end of each run lands in phases.
| Kind | Scope | Where it is declared |
|---|---|---|
| Lifecycle stage | The whole life of a routine | The RoutineOS skill |
| Workflow stage | One run’s work, in order | stages in a routine pack (since 0.6.0), and the Steps in prompt.md |
| Run phase | One run’s store write | The write contract |
Lifecycle stages
Discover (optional), Design, Build, Verify, Deploy, Operate, Improve, Retire. Each has exit evidence. See Routines.
Workflow stages
Since 0.6.0 (routine packs). The prompt’s Steps exist today; the
stageslist is part of the pack format.
What it is
A workflow stage is one step of a run, with a kind that says who does it.
| Kind | Who does it | Needs |
|---|---|---|
code |
A deterministic command | command: one line starting python3 , naming skills/routineos/scripts/routineos.py or a .py file the pack ships under lib/ |
model |
The model, guided by the prompt | nothing extra |
skill |
The model, guided by a skill file shipped in the pack | skill: a name with skills/<name>/SKILL.md in the pack’s files |
gate |
A person approves before the next stage | routine.gate.enabled = true |
A stage is {id, kind, title, does, connectors?, reads?, writes?, command?, skill?}. connectors names connector ids declared in the pack. reads and writes name store collections and may never name a people collection. Stage ids are unique slugs. The prompt’s Steps follow the stage order; that is a review rule, not a parsed one.
Why it exists
Stages make the split between code and the model visible before anything runs. A reader can see that filtering and writing are code, searching and judging are the model, and sending waits for a person.
Worked example
Hiring Signals’ prompt has seven Steps. As workflow stages they read:
| Stage | Kind | Does |
|---|---|---|
search |
model | Search each market for postings inside the lookback window |
record |
model | Record each role and its company, with a short summary |
inbox |
model | Pick the roles worth a look today, within max_inbox_per_run |
intro-gate |
gate | Any intro note waits for approval by email, 48 hours |
build-input |
model | Build the run input for the write contract |
learn |
code | python3 skills/routineos/scripts/routineos.py learn ... |
write |
code | python3 skills/routineos/scripts/routineos.py write ... |
The stage ids above illustrate the shape; they are not copied from a shipped pack. When the jobs-watch pack lands, its pack.json holds the authoritative list.
Run phases
What it is
Every run’s writes are planned in order, as batches, each tagged with a phase. A batch is applied whole, in order.
| Phase | Writes |
|---|---|
seed |
One-time setup: meta/workspace, meta/definition, default settings (written by seed, not by runs) |
learning |
state/learning, the tallies (written by learn, applied before write) |
started |
runs/<runId> with phase: "started" |
entities |
Every record seen, with a new sighting |
summary |
runs/<runId> with counts, drops, settings used; agent views and columns created if absent |
inbox |
pending/<id> gates, then inbox/<runId>--<n> messages |
done |
runs/<runId> with phase: "done" |
Empty phases are skipped.
Why it exists
A run can fail halfway. Because the run document records its phase, a half-applied run re-planned from a fresh snapshot finishes in the same state as a clean run, and a rerun of a run already marked done is a no-op. The Desk can also show a run that started and never finished as failed or late.
Worked example
The Quickstart run produced five batches: started, entities (three records), summary, inbox (one message) and done. See Quickstart.
Common pitfalls
- Appending proposals after write. The order is learn, append, write. A run already marked done writes nothing more, so proposals appended later are lost.
- Applying batches out of order. Apply
batch-001.jsonfirst. The inbox phase writes gates before messages so a message never points at a missing gate. - Treating a stage as a security boundary. A
gatestage is a review point; the write contract and lint are what enforce rules.