| name | spec-kitty-runtime-next |
| description | Drive the canonical spec-kitty next --mission <handle> control loop for mission advancement. Load agent profiles at init, apply action-scoped doctrine context at each step boundary, and pull specific tactics/directives on demand. Triggers: "run the next step", "what should runtime do next", "advance the mission", "what is the next task", "continue the workflow", "what step comes next". Does NOT handle: setup or repair requests, purely editorial glossary or doctrine maintenance, or direct code review. |
spec-kitty-runtime-next
This skill teaches agents how to advance a Spec Kitty mission through the
canonical runtime control loop, including doctrine-aware context loading at
each step boundary.
When to Use This Skill
Use this skill when the user wants to:
- Advance a mission to its next step
- Understand what the runtime will do next
- Unblock a stalled mission
- Interpret runtime outcomes (step, blocked, decision_required, terminal)
How the Runtime-Next System Works
The spec-kitty next command is the single entry point for agent-driven mission
execution. Each call returns a deterministic decision about what action the
agent should take next.
Decision Algorithm
The runtime evaluates state in this order:
- Mission state machine — Current phase and available transitions (from
mission-runtime.yaml DAG)
- WP iteration check — For
implement and review steps, the CLI bridge
manages WP-level iteration WITHOUT advancing the runtime. The runtime only
advances when ALL WPs reach terminal/handoff lanes.
- Guard conditions — Required artifacts, prerequisites, dependency graph
- Priority ordering — Reviews before implementations, higher-priority WPs
first, dependency-free WPs before dependent ones
WP Iteration Logic (Critical)
The CLI bridge (not the runtime) manages WP-level iteration:
- If current step is
implement or review
- AND there are WPs in
planned or in_progress lanes
- THEN return a WP-level decision without advancing the runtime step
- The runtime step only advances when ALL WPs are in terminal/handoff lanes
(
done, approved, or for_review)
This means multiple calls to spec-kitty next during implementation will
return different WP IDs but the same step_id (e.g., "implement") until all
WPs are done.
Mission Runtime YAML Schema
Missions define steps as a DAG (directed acyclic graph) with dependencies:
mission:
key: software-dev
name: Software Dev Kitty
version: "2.1.0"
steps:
- id: discovery
title: Discovery & Research
depends_on: []
prompt_template: research.md
- id: specify
depends_on: [discovery]
prompt_template: specify.md
- id: plan
depends_on: [specify]
prompt_template: plan.md
- id: tasks
depends_on: [plan]
- id: implement
depends_on: [tasks]
prompt_template: implement.md
- id: review
depends_on: [implement]
prompt_template: review.md
- id: accept
depends_on: [review]
prompt_template: accept.md
Decision Kinds
Every call to spec-kitty next returns exactly one decision kind:
| Kind | Meaning | Agent Action |
|---|
step | Normal action available | Read prompt_file and execute |
query | Read-only current-state preview | Inspect state; do not execute a prompt or mark a result |
decision_required | Runtime needs input | Answer with --answer and --decision-id |
blocked | Guards failing, cannot proceed | Read reason + guard_failures, resolve blockers |
terminal | Mission complete | Run /spec-kitty.accept; if it passes, merge, then: mission review → author or verify retrospective (retrospect create) → surface findings (summary aggregates; synthesize reviews proposals) |
Decision Output Fields
{
"kind": "step",
"agent": "claude",
"mission_slug": "042-test-mission",
"mission": "software-dev",
"mission_state": "implementing",
"action": "implement",
"wp_id": "WP02",
"workspace_path": ".worktrees/042-test-mission-lane-b",
"prompt_file": "/tmp/spec-kitty-next-claude-042-test-mission-implement-WP02.md",
"reason": null,
"guard_failures": [],
"progress": {
"total_wps": 5,
"done_wps": 1,
"approved_wps": 0,
"in_progress_wps": 1,
"planned_wps": 3,
"for_review_wps": 0
},
"run_id": "abc123",
"step_id": "implement",
"decision_id": null,
"question": null,
"options": null
}
6 Guard Primitives
Guards block step transitions by returning failure descriptions:
| Guard | Syntax | Checks |
|---|
artifact_exists | artifact_exists("spec.md") | File exists relative to mission dir |
gate_passed | gate_passed("review_gate") | Gate event in mission-events.jsonl |
all_wp_status | all_wp_status("approved_or_done") | All WPs in a specific lane or named accepted-ready set |
any_wp_status | any_wp_status("for_review") | At least one WP in lane |
input_provided | input_provided("architecture") | Input exists in runtime model |
event_count | event_count("review", 1) | Minimum event count threshold |
Guards never raise exceptions — they return false on missing context.
Prompt File Generation
The runtime generates a temp file at:
/tmp/spec-kitty-next-{agent}-{mission_slug}-{action}[-{wp_id}].md
Template actions (specify, plan, tasks): Mission context header + governance
context + action-specific template content.
WP actions (implement, review): Full isolation-aware prompt containing:
- WP header with workspace path
- Governance context (paradigms, directives, tools)
- WP Isolation Rules — DO only modify this WP's status, DO NOT change
other WPs or react to their status changes
- Working directory and review commands
- WP file content (from
tasks/WP##.md)
- Completion instructions
Decision prompts: Question text, options, and the --answer command to run.
Run Persistence
Runtime state is persisted between calls:
.kittify/runtime/
├── feature-runs.json # Index: {"mission-slug": {"run_id": "...", "run_dir": "..."}}
└── runs/
└── <run_id>/
└── state.json # Runtime snapshot (current step, inputs, etc.)
Mission Detection
When --mission is omitted, the runtime detects the mission via (in order):
SPECIFY_MISSION environment variable
- Git branch name (mission and lane branches both encode the mission slug)
- Current directory path (walks up looking for
###-mission-name)
- Single mission auto-detect (only if exactly one mission exists)
- Error with guidance if ambiguous
NOTE: Always use --mission <slug> in multi-mission repositories.
Doctrine-Aware Step Execution
The runtime-next loop should load doctrine context iteratively — not all
at once. Each step boundary is a context loading opportunity.
Agent Profile at Init
At the start of a session, resolve the active agent profile. This scopes
your role, boundaries, and initialization context.
Load the profile using the Python API — do NOT read YAML files directly:
from doctrine.agent_profiles import AgentProfileRepository
from doctrine.service import DoctrineService
repo = AgentProfileRepository()
profile = repo.resolve_profile("<profile-id>")
print(profile.initialization_declaration)
profile.specialization.primary_focus
profile.specialization.avoidance_boundary
profile.collaboration.handoff_to
service = DoctrineService(shipped_root, project_root)
for ref in profile.directive_references:
directive = service.directives.get(f"DIRECTIVE_{ref.code}")
Discovery (if you don't know your profile-id):
spec-kitty agent profile list
spec-kitty agent profile show <profile-id>
Action-Scoped Context at Each Step
At each step boundary (when spec-kitty next returns a step decision),
load governance context scoped to the current action — not the full doctrine:
spec-kitty charter context --action implement --json
The context system uses two depth levels:
| Depth | When | Content |
|---|
bootstrap (depth-2) | First load for this action | Full policy summary + reference list |
compact (depth-1) | Subsequent loads | Resolved paradigms, directives, tools only |
First-load state is tracked per action in
.kittify/charter/context-state.json. This means implement and
review each get their own first-load bootstrap independently.
Pull Specific Doctrine On Demand
When you need governance guidance mid-step (e.g., how to structure tests,
which review criteria apply), pull the specific tactic or directive by ID
rather than re-loading the full context:
from doctrine.service import DoctrineService
service = DoctrineService(shipped_root, project_root)
tactic = service.tactics.get("tdd-red-green-refactor")
directive = service.directives.get("TEST_FIRST")
The action index (actions/<action>/index.yaml) tells you which doctrine
artifacts are relevant to the current step. Load the index to discover what
to pull:
from doctrine.missions.action_index import load_action_index
index = load_action_index(missions_root, "software-dev", "implement")
Anti-Pattern: Upfront Context Dump
Do NOT load all doctrine into context at session start. This wastes tokens
and dilutes relevance. Instead:
- At init: Load agent profile + initialization declaration.
- At each step boundary: Call
charter context --action <action>.
- When stuck or need guidance: Pull specific tactic/directive by ID.
- When reviewing: Pull review-scoped doctrine, not implement-scoped.
Step 1: Load Runtime Context
Before invoking the runtime, gather the current state.
Commands:
spec-kitty agent tasks status --mission <mission-slug>
spec-kitty agent context resolve --action implement --mission <mission-slug> --json
What to look for:
- Active mission slug and mission type
- Current WP lane status (planned, claimed, in_progress, for_review, in_review, approved, done, blocked, canceled)
- Whether there are WPs ready for implementation or review
- Any blocked WPs that need attention first
Step 2: Run the Next Command
spec-kitty next --agent <agent> --mission <mission-slug> --json
spec-kitty next --agent <agent> --mission <mission-slug> --result success --json
spec-kitty next --agent <agent> --mission <mission-slug> --result failed --json
spec-kitty next --agent <agent> --mission <mission-slug> --result blocked --json
Note: --mission is the sole selector. The legacy --feature alias has
been removed (#1060); passing --feature now exits with No such option.
The --result flag tells the runtime the outcome of the previous step.
If omitted, spec-kitty next returns current state without advancing (query mode).
It does not report success for the previous step.
Step 3: Interpret the Result
See references/runtime-result-taxonomy.md for the complete taxonomy.
| Kind | Next Action |
|---|
step | Read and execute prompt_file (always non-empty and resolvable on disk) |
decision_required | Answer with --answer and --decision-id |
blocked | Read reason + guard_failures, resolve blockers |
terminal | Run /spec-kitty.accept for final validation, then merge if acceptance passes |
Always check guard_failures — this field may appear on any decision kind,
not just blocked.
The kind="step" prompt-file contract is a hard runtime invariant (C1/C2).
A kind="step" envelope MUST carry a prompt_file (or its consumer-side
prompt_path alias) that is non-null, non-empty, and resolves on disk. If
the runtime cannot produce an actionable step (no composed action, guard
failure, blocked dependency, prompt build error, etc.), it returns
kind="blocked" with a non-empty reason (and optional machine-readable
code such as no_prompt_template). There is no third state: an agent loop
should never observe a kind="step" decision with prompt_file == null.
Always check progress for completion. If progress.done_wps equals
progress.total_wps but kind is not terminal, the mission is actually
complete (known issue #335). The runtime may not detect completion when no
prior run state exists. Treat this as terminal and run /spec-kitty.accept;
if acceptance passes, run /spec-kitty.merge, then run mission review and the
retrospective workflow.
Step 4: Handle decision_required
When the runtime needs input:
spec-kitty next --agent <agent> --mission <mission-slug> \
--result success --answer "<choice>" --decision-id "<decision_id>" --json
If the agent cannot determine the answer, escalate to the user with the
question and options.
Step 5: Handle Blocked States
See references/blocked-state-recovery.md for detailed recovery patterns.
Quick diagnostic:
spec-kitty agent tasks status --mission <mission-slug>
spec-kitty agent tasks list-dependents WP## --mission <mission-slug>
Common blockers:
| Blocker | Recovery |
|---|
| Missing artifacts (spec.md, plan.md) | Run the planning workflow first |
| Upstream WP not done | Implement or review the upstream WP |
| Review feedback not addressed | Re-implement, address feedback, move to for_review |
| Stale agent (WP in doing, no activity) | Move WP to planned with --force |
| Circular dependencies | Break cycle in WP frontmatter, re-run finalize-tasks |
Step 6: The Agent Loop
The complete agent loop pattern:
DECISION=$(spec-kitty next --agent claude --mission 042-mission --json)
KIND=$(echo "$DECISION" | jq -r '.kind')
while [ "$KIND" = "step" ] || [ "$KIND" = "decision_required" ]; do
DONE=$(echo "$DECISION" | jq -r '.progress.done_wps // 0')
TOTAL=$(echo "$DECISION" | jq -r '.progress.total_wps // 0')
if [ "$TOTAL" -gt 0 ] && [ "$DONE" -eq "$TOTAL" ]; then
break
fi
if [ "$KIND" = "step" ]; then
PROMPT=$(echo "$DECISION" | jq -r '.prompt_file')
RESULT="success"
elif [ "$KIND" = "decision_required" ]; then
RESULT="success"
fi
DECISION=$(spec-kitty next --agent claude --mission 042-mission --result "$RESULT" --json)
KIND=$(echo "$DECISION" | jq -r '.kind')
done
if [ "$KIND" = "terminal" ] || [ "$DONE" -eq "$TOTAL" ]; then
fi
The loop continues until:
terminal — mission complete, exit loop
query — read-only preview, no state mutation
blocked — cannot proceed without external resolution
decision_required — only if the agent cannot answer (escalate to user)
Important: Runtime Precedence Rules
- Always use
spec-kitty next rather than manually sequencing phases
- Always pass
--mission in multi-mission repositories
- Respect mission state machine transitions — do not skip steps
- Read the
prompt_file — it contains the full context the agent needs
- Check
guard_failures on every decision, not just blocked ones
- Reviews before implementations — the runtime prioritizes unblocking
downstream work
- WP isolation — only modify the WP you were assigned, ignore other WPs
Known Issues
#335 — Completed missions return step instead of terminal. When
spec-kitty next is called on a mission with all WPs done but no prior
runtime run state, it creates a new run starting at discovery instead of
recognizing the mission is complete. Workaround: Check
progress.done_wps == progress.total_wps as a secondary completion signal.
#336 — fixed. prompt_file is always non-empty and resolvable on disk
on kind: step decisions. When no prompt is available, the runtime now emits
a structured kind: blocked decision with a non-empty reason (and optional
machine-readable code such as no_prompt_template). Agent loops no longer
need to defensively null-check prompt_file; a kind: step decision with a
null prompt is a runtime bug.
Standalone Invocations (Outside Missions)
Not all governed work happens inside an active mission. When a user asks for
help with a task that has no active spec-kitty next loop — a code review, a
quick implementation, an ad-hoc analysis — you should still invoke Spec Kitty's
governance layer with standalone dispatch.
Spec Kitty never spawns a parallel LLM call. You are the host; Spec Kitty routes, assembles governance context, and records the trail.
When to use standalone dispatch
If the user says anything like "use spec kitty to ...", "hey spec kitty ...",
or "spec kitty ", run standalone dispatch unless they are clearly
asking for a full mission.
The governance injection loop
-
Get context:
spec-kitty dispatch "implement the login handler" --json
spec-kitty dispatch "review WP05" --profile reviewer --json
Response includes invocation_id, governance_context_text, and governance_context_available.
-
Inject governance:
Read governance_context_text and treat it as binding governance context for your task. Follow any directives and constraints it contains.
If governance_context_available is false, note this to the user but proceed with the task.
-
Execute:
Do the work. Generate the code, analysis, or plan.
-
Close the Op (mandatory — dispatch leaves it open):
spec-kitty profile-invocation complete \
--invocation-id <invocation_id> \
--outcome <done|failed|abandoned>
Use the real outcome: done for completed work, failed for work that did
not succeed, abandoned for dropped work. Never leave an Op open
deliberately — spec-kitty doctor ops reports and sweeps orphans.
Trail produced
Every standalone invocation writes a Tier 1 JSONL file to:
kitty-ops/<invocation_id>.jsonl
Viewable at any time with spec-kitty invocations list --json. No SaaS connection required.
For full CLI surface documentation, see src/doctrine/skills/spec-kitty/SKILL.md.
References
references/runtime-result-taxonomy.md -- Decision kinds, output fields, and precedence rules
references/blocked-state-recovery.md -- 6 blocked state patterns with diagnosis and recovery