next
Recommend what to do next on the product — read the product model (the spine `_spine.yaml` plus each slice's lens docs), build the list of every runnable or blocked action with a deterministic decisio
SKILL.mdcore/components/plays/next/SKILL.md
GitHubnext
Read the product model, build the list of everything that could happen next — strategy (vision, understand, shape, roadmap), realization (the seven lens docs across the functional and non-functional tracks, then /measure), grilling, execution (implement, validate, launch), learning (learn), and strategy refresh once everything is delivered — put it in the finish-the-slice-first order, and show it: one next-best-action plus the ordered list, every entry carrying the exact command and a plain-language line on why.
The recommendation is advice, never action. The play writes nothing to the model, opens nothing, launches nothing. Its only durable products are the recommendation it presents and — when evidence recording is on — the evidence record; every transient working file is deleted once the recommendation has been presented (C10).
Compiled From
This play was compiled from the next ICE (reference/ice.md) by play-creator and
recompiled by play-editor (#466 Batch D, Level 3 rollout per ADR 025; #533 spine read;
#533 simplification). Intent defines constraints (C1–C6, C8–C14) and failure conditions
(F1–F3, F5–F11); the expectation defines success scenarios (S1, S4–S8), a Done means
(D1–D2, baked to stop-condition.yaml), and one recovery entry per failure condition.
To modify this play, update reference/ice.md and recompile with play-editor.
Do NOT edit this file manually — it is a compiled artifact.
Role
You are the orchestrator. Three things happen, in order: a script reads the model, a script builds and orders the list, and you present it. Every mechanical part is a bundled script — the model scan, the decision tree and the ordering — never re-reasoned prose. Your one piece of judgment is wording the presentation; you never reorder, add, or drop an entry. At close you delete the working folder yourself — the play leaves no scratch behind; the evidence record is never deleted.
Forbidden: writing anything under the product model; creating issues, branches, or
work items; launching another play from this one; deriving or ordering candidates by
reasoning instead of scripts/derive_candidates.py; consulting any backlog or project
store (none exists — the model is the only source).
Agent boundaries: none. This play dispatches no agents and no skills — there is no judgment step a script cannot own, and no git/issue machinery (read-only, position none).
Pre-flight
| Check | Constraint | Action on Failure |
|---|---|---|
Resolve config (.garura/core/config.yaml) via scripts/preflight.py |
— | Hard halt |
Product model present under <product_base>/product-os/ |
— | Not a failure — feeds the tree's cold-start branch |
python3 scripts/preflight.py --play next --config .garura/core/config.yaml
preflight.py returns the config facts (product_base, stm_base,
evidence_record). The working dir is <working> = ${product_base}_status/next/ (a
play-lifecycle folder; the model tree itself is never written). /next has no branch or
issue resolution (position none): it runs on whatever branch it finds, including main,
and leaves it untouched.
Record the session identity stamp's start marker (#463 — soft-fail, never a halt). The marker lives in the working folder and is removed by the self-clean; its durable copy is the evidence record:
python3 scripts/session_stamp.py --phase start \
--marker "<working>/session-stamp-next.json" \
--cwd "$(pwd)" --branch "$(git branch --show-current)"
Resume check: /next is cheap and advisory — a re-run is always a fresh run. If
<working>/ holds artifacts from a prior run, overwrite them; never resume a stale
recommendation against a model that may have moved.
Task DAG
Create ALL tasks immediately after resolving config — before any other work.
[T1] Scan the model blockedBy: []
[T2] Build and order the list blockedBy: [T1]
[T3] Scenario Validation (quick) blockedBy: [T2]
[T4] Present recommendations blockedBy: [T3]
[T5] Close blockedBy: [T4]
[T6] Self-clean (delete working dir) blockedBy: [T5]
Mark each task in-progress before its step and completed right after its eval passes. No runtime reordering.
Workflow
Phase: Preparation
Step 1 — Scan the model · Owner: play · Depends on: pre-flight
Snapshot the model's state, read-only. The scan reads the model the way the
model-writing plays write it (C13, ADR 026): the spine _spine.yaml is the index of
record for the profile, domains, capability detail, slices (status / order / effort /
depends_on) and epics; lens presence is the seven lens/<type>.md docs per slice; a
slice record is read only for its name and functionalities, never for its status. A tree
with files but no spine is recorded as spine_exists: false — never read from legacy
per-node files:
python3 scripts/scan_model.py --product-base <product_base> \
--out <working>/model-state.json
A missing model is a valid snapshot (model_exists: false — the /vision branch), never
an error.
SE-1 (C1/C2/C13, F3): model-state.json exists and was read from <product_base>
only (C1); the scan and every later script write only their --out file under
<working> and the play has no model-write step and launches nothing, so nothing under
product-os/ changes (F3/C2); the snapshot's profile, slices and epics come from the
spine (C13).
Step 2 — Build and order the list · Owner: play · Depends on: Step 1
Run the decision tree and the ordering as one pure function of the snapshot. The tree
spans strategy → both realize tracks of standards/rules/pipeline-next.md (the
functional track ux → agentic → marketing and the non-functional track arch → quality →
run, each offering its first missing lens doc) → /measure once both are done (it stamps
the slice realized, so a planned slice with all seven docs is a /measure repair) → grill
→ execute → learning → refresh. Track order is pipeline-next's recommendation, not a
readiness gate. The ordering then finishes a slice first: repair anywhere → every step
of the focus slice (the lowest roadmap-order slice with work left) → strategy → other
slices' steps by roadmap order, flagged parallel → learning → refresh:
python3 scripts/derive_candidates.py --state <working>/model-state.json \
--out <working>/candidates.json
SE-2 (F1, F2, F6 / C6, C8, C9): candidates.json exists carrying the ordered
candidates and the inconsistencies report (present even when empty — F2's detection
always runs); every candidate cites the gates that admit it, matching its target play's
own readiness rule (F1/F6); other-slice steps cite the roadmap order that permits them
(C6); the tree's branches span the full loop (C9); the file records a derivation_hash
so the same model state is shown to give the same ordered list (C8).
SE-3 (F11 / C5, C14): checkable from candidates.json alone — every repair
candidate ranks above every non-repair candidate (C5); every step of focus_slice ranks
above every strategy step, every other slice's step, and every learning or refresh step
(C14); every other slice's step carries parallel_lane: true. On a GAP apply REC11.
SE-4 (F5 / C3, C4): entries holds at most 11 candidates in rank order, each with a
command and a plain-language why sentence (C3/C4); cut_for_cap names every
candidate id past the cap — nothing is silently dropped (F5).
SE-5 (F8/C11): for every slice with a delivered epic that declares a user-facing
surface (web_dashboard/server_api/cli) and is not surface_verified, the
inconsistency report carries a surface-debt entry for that slice, a
repair/{slice}/surface candidate is present in the repair lane, and EVERY live
execute epic of that slice is blocked naming the surface debt — no runnable execute
candidate survives for a slice in surface debt. A delivered user-facing epic that is
surface_verified raises no debt. On a GAP, apply REC8 and re-run derivation.
Phase: Scenario Validation
Step 3 — Scenario evals (quick) · Owner: play · Depends on: Step 2
One call, well under a second — the regression file builds small spine-shaped models in
a temp folder and checks the read, the tree and the order. It carries the independent
reader (scripts/check_model_agreement.py, which does not import the scanner), so a
wrong read cannot confirm itself. It runs before the list is shown, so a failure halts
the run before anything is presented:
python3 scripts/test_derive_candidates.py
SE-7 (F1, F6, F10, F11 / C13): the file exits 0 — the read cases prove the spine and lens-doc read against the independent reader (F10/C13), the tree cases prove each branch offers the action its target gate admits (F1/F6), and the order cases prove a slice is finished first (F11). On a failing read case apply REC10; on a failing order case apply REC11 — either way halt before Step 4.
- SCE-1 (S1 — builder, product mid-delivery):
case_realized_missing_lens_s1— with a realized-but-lens-missing slice and a ready epic behind it, rank 1 is the repair (the missing lens play) and the blocked epic names the missing lens. - SCE-4 (S4 — founder, fresh start):
case_cold_start— with no product model, the only and first command is/vision. - SCE-5 (S5 — product owner, everything delivered):
case_all_delivered_learn_s5— with the slice realized and every epic delivered, the list holds/learn. - SCE-6 (S6 — team running parallel agents):
case_focus_slice_firstandcase_griffin_like_s7— slice 2's step appears, flagged parallel, ranked below every slice-1 step, its gates citing roadmap order 2. - SCE-7 (S7 — product owner, roadmap merged):
case_griffin_like_s7— profile set, four planned slices at order 1–4, the functional-track docs on the order-2 slice: no strategy action, the order-2 slice's action is/arch, and the independent reader agrees with the snapshot. - SCE-8 (S8 — builder finishing a slice):
case_ready_epic_outranks_next_slice— slice 1 realized with a ready epic and slice 2 planned: rank 1 is slice 1's/implement, and slice 2's/uxranks below it.
Phase: Present
Step 4 — Present recommendations · Owner: play · Depends on: Step 3
Write <working>/recommendations.md from candidates.json entries and output it to
the user inline: the next-best-action (rank 1) as the lead, then the list in rank
order with one plain-language line each (built from why), the slice being finished
named once, parallel lanes marked as such, a short repair section when
inconsistencies is not empty, and a count of cut_for_cap when it is not empty. The
operator (or each parallel agent) picks an entry and runs its command themselves.
SE-6 (C2, C3, C8): recommendations.md exists; its entries appear in the same rank
order as entries, every command in it is a command from entries, and none is added
or dropped (C8); every entry has its plain-language line (C3); nothing was launched (C2).
Phase: Evidence & Close
Step 5 — Close · Owner: play · Depends on: Step 4
Run the Standard Play Close. /next is a product-scoped play (no issue) — use the
product-scoped evidence base and slug. Evidence recording is play-only and config-gated
per the D1 evidence rule (standards/rules/evidence-recording.md).
This phase ends with Step 6 — Self-clean (after the close): once the evidence record
and delivery report are written, the working folder is deleted as the terminal action.
SE-8 (C10/F7): after Step 6, ${working} no longer exists on disk while the
evidence folder (when evidence recording is on) is intact. On a GAP (working files
remain), apply REC7 and re-run Step 6.
SE-9 (F9/C12): the close is stop-condition gated — check_stop_condition.py over the
baked stop-condition.yaml (D1 the ordered candidate set exists; D2 the presented
report exists) reads held before the run closes COMPLETED; anything else closes
HALTED with the unmet clauses named. The gate runs at Step 5, BEFORE Step 6's self-clean
removes the working folder. This play has no checkpoint, so there are no gates to class
under gate-config.md.
# --- Standard Play Close (shared; see ../_shared/play-close.md) ---
# Run the close in ../_shared/play-close.md. Its Step L loads the templates through
# template-manager and sets ts and evidence_dest; then run this play's own lines below;
# then Steps C0-C2.
# evidence_base, slug:
# project-scoped play : evidence_base="${stm_base}${issue}/evidence/next/" ; slug="#${issue}"
# product-scoped play : evidence_base="${product_base}_evidence/next/" ; slug="${product_slug}"
# Session identity stamp (#463) — close phase; start phase ran at pre-flight
session_stamp=$(python3 scripts/session_stamp.py --phase close \
--marker "<working>/session-stamp-next.json")
# Stop-condition gate (#464) — Step C0: this play carries a baked manifest, so the
# gate is LIVE. Evaluate the Done means here — BEFORE Step 6's self-clean deletes
# the working folder — as the close's authoritative input.
python3 scripts/check_stop_condition.py \
--manifest "<play-dir>/stop-condition.yaml" \
--base "<working>/" \
--out "<working>/stop-condition-next.yaml"
sc_exit=$? # 0 held · 1 unmet · 2 error
/next is product-scoped: evidence_base="${product_base}_evidence/next/" and
slug="${product_slug}" (the product, e.g. token-burn-dash).
Step C0 — bind the verdict. sc_exit == 0 (held) permits status: COMPLETED.
Anything else closes HALTED with exit_reason: stop_condition_unmet and the
evidence's Stop Condition section names every unmet clause. An unevaluable verdict
is never a pass.
Step C1 — Write evidence file. Gated by the resolved evidence.record flag
(global + per-play evidence.plays.next; first match wins, absent ⇒ record).
When false, skip the write and record evidence skipped (record=false) in the
report's pointer line. Otherwise fill the evidence-file.md slots (play next,
run_id next-${ts}, product_slug, started_at/completed_at, status per C0,
exit_reason; artifacts produced: the model-state snapshot, the ordered candidate set,
the presented report, the stop-condition verdict; step and scenario eval results
SE-1…SE-9 / SCE-1, SCE-4…SCE-8; checkpoint decisions: none — this play has no gates;
the session identity stamp fields from $session_stamp (#463): session_id, ledger_file,
ledger_start_offset, ledger_end_offset (null when unresolved — never blocks the close);
and stop_condition per C0 with the Stop Condition section filled) and write to
$evidence_dest. Do NOT hand-author the body.
Step C2 — Render delivery report. Also render the Next line: resolve this play in the Next-line map ($next_map, from template-manager) and emit **Next:** /<command> — <why>. Or run /next to see all recommended actions. (only /next pointer, or omit, when the mapped command is null), per play-close.md. Fill the delivery-report.md slots and
output the report: ## next Delivered — ${product_slug}, the Run Summary table,
the Pipeline Steps table from the task DAG, the Artifacts Produced table (the
next-best-action, the ordered entries, the focus slice, the inconsistency count),
Next Steps (the next-best-action's command — the whole point), and a pointer to
$evidence_dest. Always emitted; never gated.
# --- end Standard Play Close ---
Step 6 — Self-clean · Owner: play · Depends on: Step 5 (declared above; SE-8)
The terminal action. Delete ONLY the working folder so the run leaves no scratch behind;
never touch the evidence folder (${product_base}_evidence/next/), the durable record.
rm -rf "${working}" # working = ${product_base}_status/next/
Scenario Validation
| Scenario | Persona | Eval |
|---|---|---|
| S1 — product mid-delivery, broken gate | builder | SCE-1 |
| S4 — fresh start | founder | SCE-4 |
| S5 — everything delivered | product owner | SCE-5 |
| S6 — parallel lanes below the focus slice | team running parallel agents | SCE-6 |
| S7 — roadmap merged, read from the spine | product owner | SCE-7 |
| S8 — finish the slice first | builder | SCE-8 |
Recovery
| For | Trigger | Direction | Handoff |
|---|---|---|---|
| F1 | a recommended command would halt at its own gate | record the divergence between the tree's rule and the target play's gate, fix the tree, and add a regression case | human |
| F2 | downstream work halts on an inconsistency the run reported nothing about | record the missed inconsistency class, extend the consistency scan, add a regression case | human |
| F3 | anything in the model changed, or a play was launched, during the run | halt immediately and surface exactly what changed — nothing is auto-reverted | human |
| F5 | more than 11 entries, or an entry with no explanation | re-run the ordering script, which caps the list and templates every explanation | autonomous |
| F6 | the readiness gates admit an action the list lacks | re-run derivation; if the action is still missing, the derivation rules are incomplete — record the gap and add a regression case | autonomous |
| F7 | working files remain after the run completes | delete the working folder; the already-presented recommendation is the only product | autonomous |
| F8 | a slice has surface debt (a delivered epic with unmet required user-facing surface) and /next would recommend its next execute epic | surface the debt as a blocking inconsistency, recommend the surface-repair action for that slice in the next-best-action slot, and withhold every further execute epic of that slice until the debt clears | autonomous |
| F9 | the close would report COMPLETED without the Done means held | evaluate the stop condition and surface the unmet clauses; re-run the producing step (derivation or presentation) to restore the missing artifact, or close HALTED with the verdict recorded | autonomous |
| F10 | the regression test file fails a read or agreement case | halt before presenting — nothing built on the wrong read is shown; surface the failing cases so the scanner is fixed | human |
| F11 | an ordering case fails, or a presented list ranks another slice's step above the focus slice's | halt before presenting, surface the mis-ordered entries, and fix the ordering script | human |
Pause and Resume
Steps run top to bottom. /next does not resume — a recommendation is only as good as
the model state it was derived from, so any interruption means a fresh run: re-scan,
re-derive. Prior artifacts in <working>/ are overwritten. There is no status marker.
Compilation Metadata
| Field | Value |
|---|---|
| fingerprint | sha256:47abfbc27a373eaf59eb4512875b19476d42b2f3196cb7f050e14c1a8d2603d0 (of reference/ice.md) |
| compiled_by | play-editor (#533 simplification + slice-first order; #533 spine read; #466 Batch D, Level 3 rollout per ADR 025); prior: play-creator |
| pipeline_position | none |
| structural_constraints | C1 (scan + derivation read only the model tree — by construction of scan_model.py/derive_candidates.py); C9 (the tree's branches span strategy → both realize tracks + /measure → repair → grill → execute → learning → refresh — derive_candidates.py); C11 (surface debt detected mechanically from the spine epics index's surface_type + surface_verified); C13 (the spine is the index of record in scan_model.py, proven by the independent reader inside test_derive_candidates.py); C14 (the order is order_candidates() in derive_candidates.py) |
| workflow_structure | readiness-only (analysis, no generation; no checkpoint — the output is advice; nothing to class under gate-config.md) |
| stop_condition | stop-condition.yaml (D1–D2), gate live at Step C0 — evaluated BEFORE the Step 6 self-clean |
| domain_agents | 0 |
| utility_agents | 0 |
| skills_used | none |
| scripts | 7 (preflight.py, scan_model.py, derive_candidates.py, test_derive_candidates.py, check_model_agreement.py — called only by the test file, check_stop_condition.py, session_stamp.py) |
| step_evals | 9 (SE-1…SE-9; every failure condition covered: F1→SE-2+SE-7, F2→SE-2, F3→SE-1, F5→SE-4, F6→SE-2+SE-7, F7→SE-8, F8→SE-5, F9→SE-9, F10→SE-7, F11→SE-3+SE-7) |
| scenario_evals | 6 (SCE-1, SCE-4…SCE-8) |
| recovery_entries | 10 (one per failure condition; 5 autonomous / 5 human) |
Recompile note (#533)
Two intent changes under #533, both via reference/ice.md → recompile.
Spine read. /next still read the pre-ADR-026 model layout (profile.yaml, per-slice
record status, lens/<type>.yaml, six lenses, top-level ice: files, epics/*.yaml)
and recommended finished work. scan_model.py now reads the spine and
lens/<type>.md; derive_candidates.py walks both realize tracks from
standards/rules/pipeline-next.md, recommends /measure when both are done, repairs an
unstamped slice with /measure (was /run), reports model-has-no-spine and
slice-not-indexed, and uses the spine domain id for /shape.
Simplification + slice-first order (user direction, 2026-09-11). /next is now read →
build and order → show. Removed: operator fit (the git-history capture, the
work-intelligence map check, classify_work.py, the former fit constraint, failure,
two scenarios and recovery), the ranking agent dispatch (product-os-keeper →
rank-recommendations), the runtime re-scan / re-derive / output enforcer
(check_output.py) and the runtime agreement step. The independent agreement reader
(check_model_agreement.py) now runs only inside the quick regression file, which is
the play's scenario validation and runs before presenting. Added C14 (finish the slice
first), F11 + REC11, S8; S6 now places other slices' steps below the focus slice.
derive_candidates.py orders the list (order_candidates()), stamps rank, focus,
parallel_lane and a templated why, and emits entries (cap 11), cut_for_cap and
focus_slice. Done means rebaked to D1 (candidates.json) and D2
(recommendations.md). Constraint, failure and scenario ids kept stable, so the declared
sets have gaps where removed items were. Fingerprint recomputed over the edited ICE.