Continue
Creates or reuses one open campaign, records the producing session, and stops. The producing session never initializes the pipeline itself.
Final implementation
This chapter covers one boundary in depth: the handoff out of the /grill-me interview and into create-prp, where a deliberately fresh session resumes from persisted state instead of a transcript.
Layer 1 - Orientation
/grill-me ends with a durable clarification result that a fresh agent session can consume without access to the interview conversation. The skill conducts the interview and proposes semantic choices. pipeline-transition.sh is the designated deterministic authority for campaign lifecycle and pipeline state in the supported workflow. Those two sentences are the whole split: one side judges, the other side writes.
The scope is narrow on purpose. This boundary may create or reuse one campaign bead (one tracked unit of work in the bd issue tracker). It does not decompose the campaign into implementation beads, generate a PRP (product requirements prompt — the approved plan a campaign enters on), or advance beyond entry into create-prp. Everything downstream of that entry belongs to other commands, and nothing in this boundary reaches into them.
There are no headless advisers here either. /grill-me presents the search evidence and its recommendation directly to the User, and the User's confirmed values become inputs to the deterministic transition operation. No model gets to decide the parent epic quietly, and no script gets to guess it.
Layer 2 - Mechanics
Five actors touch this boundary, and each one is defined as much by what it is refused as by what it does.
| Actor | Owns | Does not own |
|---|---|---|
/grill-me |
Interview, four-block draft brief, read-only bd search, and parent and duplicate proposals. | Bead lifecycle or pipeline mutations. |
| User | Confirm parent, duplicate handling, and continue, park or abandon. | Repairing state by hand. |
pipeline-transition.sh Grill handoff |
Create or reuse the confirmed campaign, apply its lifecycle, archive abandonment, and verify the result. | Parent or duplicate judgment. |
pipeline-transition.sh init |
Validate a continued handoff, approve the brief, and initialize create-prp. | Design-quality judgment. |
| Fresh consumer session | Invoke init and continue from persisted state. | Reliance on the interview transcript. |
The decision it makes
Semantic authority and write authority are held by different actors, and neither borrows from the other. The skill may look at the bead graph but may not touch it. The script may change the graph but may not decide which epic is the right parent. The User sits between them and supplies the one judgment a script cannot make.
The brief owns design content. Its frontmatter carries no bead or session backlink:
feature: <human-readable feature name>
date: <YYYY-MM-DD>
status: draft
source: /grill-me session
For continue or park, the campaign bead carries the other half of the contract:
The link runs one way. The brief does not identify the bead; the transition receives the campaign bead ID and validates the bead's one-way pointer before pipeline entry. That is what stops two editable fields from competing to identify the same relationship, which is the usual way a pointer pair goes wrong: someone edits one side, both sides now claim to be authoritative, and nothing in the system can say which is stale.
For abandon, no campaign bead is created, reused, changed, or closed. The brief is archived and remains unapproved.
Three decisions produce three terminal states, and a fourth state exists only after a different session has done work.
Creates or reuses one open campaign, records the producing session, and stops. The producing session never initializes the pipeline itself.
Creates or reuses one deferred campaign and creates no pipeline state. Resuming it records the resuming session as the new producer, opens the campaign, and stops again; initialization still requires another session.
Archives the brief and performs no bead mutation. It first rejects any brief that already has a campaign pointer, so abandonment cannot orphan a live campaign.
The Grill handoff operation checks the mechanical conditions required for its chosen lifecycle. The brief must exist, have parseable frontmatter, remain draft, occupy an agreed location, and resolve to a safe repository-relative path. Continue and park also require the User's confirmed parent and duplicate resolution; the operation creates or reuses only that campaign and verifies its status, parent, pointer, and absence of premature children or pipeline state. It does not judge the brief's design.
pipeline-transition.sh init performs the stronger entry check for continue. Before writing any state, it verifies that:
Only after all five hold may init proceed, and then it proceeds in a fixed order:
The fresh session then passes the exact campaign ID and resolved brief path to /create-prp. That command verifies both against pipeline.entry_artifact and grill_brief through the read-only entry-context operation before consuming the four blocks. It does not rediscover the entry brief by filename, which is the failure this check exists to prevent: a filename match is a guess dressed as a lookup, and it will happily bind the pipeline to the wrong brief. These checks establish structure and sequence, not design quality.
The invariants fall into three groups. First, single ownership: the supported workflow routes all Grill lifecycle and pipeline writes through pipeline-transition.sh, and no second helper owns part of the same state. The campaign bead's repository-relative grill_brief metadata is the only canonical link. /grill-me may search beads, but it does not create, reuse, defer, close, or add metadata to them directly.
Second, one writer at a time. Handoff operations for the same brief hold an exclusive local lock while checking and writing campaign state, which prevents two concurrent creators from both observing an unlinked brief and both deciding to create the campaign. Only init changes the brief from draft to approved and writes the initial pipeline state, and init rejects the session that produced the campaign handoff.
Third, failure is inert. Handoff and initialization operations validate their resulting state and are safe to retry against the explicitly selected campaign. A failed check reports the contradiction and does not guess, create a replacement campaign, or advance the pipeline. Retry is the recovery path, and it is a safe one precisely because a rejected transition leaves nothing behind to clean up.
The session check compares the producer identifier recorded at handoff with the consumer identifier supplied by the new session. It fails closed when either is missing or they match, but it is not cryptographic identity proof: a caller able to forge --session-id or mutate bead metadata can bypass it. When this boundary was built, bd did not block direct writes to the reserved metadata namespace; a guard hook now denies them (see the single writer).
Turning the session check into identity proof requires a trusted harness identity source, which does not exist yet. This implementation makes the supported path deterministic without pretending those external controls exist.
The one idea
Humans and models make semantic judgments; programs enforce lifecycle, artifact identity, and workflow order.
Every rule on this page follows from that split. The skill can see the bead graph and cannot write to it. The script can write to it and cannot decide what belongs where. The User supplies the parent and the duplicate call, and those confirmed values become inputs rather than suggestions. When the split is kept, a wrong judgment is a wrong judgment and a wrong write is impossible; when it is blurred, every failure becomes both at once and neither is recoverable.
Layer 3 - Contract
Paths are repository-relative.
feature: <human-readable feature name>
date: <YYYY-MM-DD>
status: draft
source: /grill-me session
Note the absence: no bead field, no session field. The brief does not identify the campaign.
| Key | Written by | Meaning |
|---|---|---|
| grill_brief | Grill handoff, continue and park | Normalized repository-relative brief path. The sole canonical artifact pointer. |
| grill.session_id | Grill handoff, continue and park; replaced on resume | Producing session id. Used only to enforce a fresh consumer. |
| pipeline.stage | init only | Set to create-prp. Absent before initialization. |
| pipeline.entry_artifact | init only | The resolved entry brief, verified by /create-prp through entry-context. |
A known project build/ path, or working/grills/<slug>.md. The path must resolve safely and repository-relative.
pipeline-transition.sh; no second helper owns part of the same state.