| name | spec-kitty-runtime-next |
| description | Drive the canonical spec-kitty next --agent <name> 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_outline
depends_on: [plan]
prompt_template: tasks.md
- id: tasks_packages
depends_on: [tasks_outline]
- id: tasks_finalize
depends_on: [tasks_packages]
- id: implement
depends_on: [tasks_finalize]
prompt_template: implement.md
- id: review
depends_on: [implement]
prompt_template: review.md
- id: accept
depends_on: [review]
prompt_template: accept.md
The 4 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 |
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/
āāā mission-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: --feature is a hidden deprecated alias for --mission.
Always use --mission in new scripts.
The --result flag tells the runtime the outcome of the previous step.
Defaults to success if omitted.
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> \
--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
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 via the profile invocation surface.
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 which command
| Situation | Command |
|---|
| Request is clear, profile unknown | spec-kitty do "<request>" --json |
| Request is clear, profile known | spec-kitty ask <profile> "<request>" --json |
| Need routing decision only (no implementation) | spec-kitty advise "<request>" --json |
The governance injection loop
-
Get context:
spec-kitty do "implement the login handler" --json
spec-kitty ask pedro "review WP05" --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 record:
spec-kitty profile-invocation complete \
--invocation-id <invocation_id> \
--outcome done
Use failed or abandoned as appropriate.
Trail produced
Every standalone invocation writes a Tier 1 JSONL file to:
.kittify/events/profile-invocations/<invocation_id>.jsonl
Viewable at any time with spec-kitty invocations list --json. No SaaS connection required.
For full CLI surface documentation, see .agents/skills/spec-kitty.advise/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