Creating a story — the path from draft to done
A story is a unit of work. In satelle it travels a gated lifecycle: each edge is judged by an isolated reviewer before it is enacted, so quality is managed at the boundary rather than self-asserted by the executor.
1. Draft and create
CLI:
satelle story create \
--title "Ship the thing" \
--body "What done looks like / the outcome sought" \
--acceptance "1. first testable criterion
2. second testable criterion" \
--priority high --tags mvp,web
A well-formed draft needs three things (the required structure):
- a specific title (names the change, not just a noun),
- a body stating the goal / what done looks like, and
- numbered, testable acceptance criteria.
satelle init seeds [review] gate_create = true (opt out with
false). Creation always runs the deterministic structure check (title,
goal body, numbered ACs, non-empty category). When the active workflow declares
create_review (the embedded default is satelle-story-create-review), an
isolated reviewer also judges content/alignment and classification
against [[satelle-story-classification]] — e.g. reject an epic draft filed as
category: feature (use epic-parent). A reject pushes back with notes;
nothing is persisted until the draft is sound. With gate_create = false, only
the structure of an unguarded create path remains — the standard is the same,
the enforcement is not.
2. Begin work (backlog → in_progress)
Move the story into work:
satelle story set <id> --status in_progress
On the seeded default workflow this edge carries one CODED gate: the
estimate/actual check rejects begin-work until a plan estimate is recorded
(satelle story estimate <id> --time <dur> --tokens <n>). A repo that authors
richer gates (e.g. satelle-story-intent-review, judging the story is
well-formed enough to start) adds them to its workflow; a reject keeps the story
in backlog with notes on what to clarify.
On first entry into a performing/engaging state (e.g. backlog → plan or
backlog → in_progress), satelle records an engagement baseline ledger row
(engagement_baseline) with the current git HEAD (and whether the worktree was
dirty). Re-entry after park/blocked does not overwrite it. Gates that judge
slice scope consume the baseline via enumeration only:
satelle story diff <id> # changed files + diffstat since baseline
satelle story diff <id> --patch # plus full unified diff
The command never decides pass/fail — it only lists. A story with no baseline
(never engaged, or created before this feature) errors clearly. Gate authors
invoke it from functional checks or reviewer prompts (Bash(satelle:*)). The
embedded satelle-story-scope-review gate (implementation exit / close)
consumes this enumeration to reject bundled sibling work.
A repo may render --patch compact (noise/index-line stripped, see satelle help compact-output) — --json always gets the plain form.
3. Reach done through the workflow's gates
The exact path to done is whatever the active workflow declares — done is
always the terminal state, and every gate on the path runs before it (see
satelle help reviewer-checks). The seeded default project workflow is the most
basic lifecycle — it closes directly (in_progress → done) with no LLM
reviewers; only the coded estimate/actual check (the actual cost must be
recorded before the close) and the per-transition step summary run. Reviewer
gates like satelle-story-done-review — an isolated, read-only reviewer
that reads the repository and works through the numbered acceptance criteria one
by one — are authored substrate a repo layers into its own workflow (the parent
workflow and this repo's workflow both declare it).
A repo may layer extra steps onto the path before done — this repo's workflow
adds one in-loop release step: the executor bumps the version, commits the
slice, pushes to main, and — rather than block watching CI — refreshes the
service during the CI window and records the test + version-gated release run
URLs, their conclusions, and the published tag as evidence. The
satelle-story-release-review gate is the authority on CI-green, judging that
recorded evidence before close:
satelle story set <id> --status release # executor: bump .version, commit, push, record CI evidence
satelle story set <id> --status done # gate: release evidence (CI green) + acceptance review
Drive each transition and let its gate judge it; a reject blocks the move and records why. You never self-enact a gated edge.
4. Correct a wrong definition mid-flight (amend)
title, body, acceptance_criteria and category freeze once a story
leaves its entry state, so an agent cannot quietly weaken its own acceptance
criteria to make a gate pass. satelle story set refuses them from then on. When
the definition itself turns out to be wrong — a gate demands a criterion the ACs
never named, or an AC is factually false — amend it rather than cancelling and
re-raising (which retires the id, its ledger, and its accepted plan):
satelle story amend <id> --acceptance - --reason "AC2 asserted behaviour the system does not have" < ac.md
The freeze is not lifted, it is judged: --reason is mandatory, the repo's
amend_review lifecycle hook names the reviewer that accepts or rejects the
correction (a reject changes nothing), and an accepted amendment records every
field's old and new value on the ledger as definition_amended. A repo that
declares no amend_review hook has no amend path — with nothing to judge the
correction, the freeze holds.
Amend never moves status. It runs from a performing state and from the parked
(blocked) state, so a story parked over a wrong definition is corrected and
resumed in place. Terminal and cancelled stories are refused: their record is
history — raise a new story carrying supersedes:<id>.
5. Cancel (any → cancelled)
To abandon an item, record why:
satelle story set <id> --status cancelled
What you see
Every transition writes evidence to the ledger (visible on the story detail
page and timeline). A per-transition summariser (satelle-step-summary) records
a short prose recap of each step. The web project page shows a Progress
column of numbered stage lights folded from the ledger: green = accepted,
red = rejected, slate = ungated checkpoint, amber pulsing = current stage.
See also: satelle help reviewer-checks.
Mirrored from satelle’s built-in help. Read it in the binary with
satelle help create-story, or see the canonical source in the
satelle repo.