Specify Workflow
IMPORTANT: All tasker working files go in $TARGET_DIR/.tasker/. Do NOT create any other directories like project-planning/, planning/, or schemas/ at the target project root. The .tasker/ directory is the ONLY location for tasker artifacts (including .tasker/schemas/ for JSON schemas).
An agent-driven interactive workflow that transforms ideas into actionable specifications with extracted capabilities, ready for /plan to decompose into tasks.
Core Principles
- Workflows and invariants before architecture - Never discuss implementation until behavior is clear
- Decision-dense, not prose-dense - Bullet points over paragraphs
- No guessing — Uncertainty becomes Open Questions
- Minimal facilitation — Decide only when required
- Specs are living; ADRs are historical
- Less is more — Avoid ceremony
Artifacts
Required Outputs (in TARGET project)
- README —
{TARGET}/README.md(project overview - what it is, how to use it) - Spec Packet —
{TARGET}/docs/specs/<slug>.md(human-readable) - Capability Map —
{TARGET}/docs/specs/<slug>.capabilities.json(machine-readable, for/plan) - Behavior Model (FSM) —
{TARGET}/docs/state-machines/<slug>/(state machine artifacts, for/planand/execute) - ADR files —
{TARGET}/docs/adrs/ADR-####-<slug>.md(0..N)
Working Files (in target project's .tasker/)
- Session state —
$TARGET_DIR/.tasker/state.json(persistent, primary resume source) - Spec draft —
$TARGET_DIR/.tasker/spec-draft.md(working draft, written incrementally) - Discovery file —
$TARGET_DIR/.tasker/clarify-session.md(append-only log) - Stock-takes —
$TARGET_DIR/.tasker/stock-takes.md(append-only log of vision evolution) - Decision registry —
$TARGET_DIR/.tasker/decisions.json(index of decisions/ADRs) - Spec Review —
$TARGET_DIR/.tasker/spec-review.json(weakness analysis)
Archive
After completion, artifacts can be archived using tasker archive for post-hoc analysis.
MANDATORY: Phase Order
Initialization → Scope → Clarification Loop (Discovery) → Synthesis → Architecture Sketch → Decisions/ADRs → Gate → Spec Review → Export
NEVER skip or reorder these phases.
Phase 0 — Initialization
Goal
Establish project context and session state before specification work begins.
STEP 1: Auto-Detect Session State (MANDATORY FIRST)
Before asking the user anything, check for existing session state files.
1a. Determine Target Directory
Check in order:
- If user provided a path in their message, use that
- If CWD contains
.tasker/state.json, use CWD - Otherwise, ask:
What is the target project directory?
1b. Check for Existing Session
TARGET_DIR="<determined-path>"
STATE_FILE="$TARGET_DIR/.tasker/state.json"
if [ -f "$STATE_FILE" ]; then
# Read state to determine if session is in progress
PHASE=$(jq -r '.phase.current' "$STATE_FILE")
if [ "$PHASE" != "complete" ] && [ "$PHASE" != "null" ]; then
echo "RESUME: Found active session at phase '$PHASE'"
# AUTO-RESUME - skip to Step 1c
else
echo "NEW: Previous session completed. Starting fresh."
# Proceed to Step 2 (new session)
fi
else
echo "NEW: No existing session found."
# Proceed to Step 2 (new session)
fi
1c. Auto-Resume Protocol (if active session found)
If .tasker/state.json exists and phase.current != "complete":
- Read state.json to get current phase and step
- Inform user (no question needed):
Resuming specification session for "{spec_session.spec_slug}" Current phase: {phase.current}, step: {phase.step} - Read required working files for the current phase (see Resume Protocol section)
- Jump directly to the current phase - do NOT re-run earlier phases
This is automatic. Do not ask the user whether to resume.
STEP 2: New Session Setup (only if no active session)
2a. No Guessing on Reference Materials
You MUST NOT:
- Scan directories to infer what files exist
- Guess spec locations from directory structure
- Read files to detect existing specs
- Make any assumptions about what the user has
The user tells you everything. You ask, they answer.
2b. Ask About Reference Materials
Ask using AskUserQuestion:
Do you have existing specification reference materials (PRDs, requirements docs, design docs, etc.)?
Options:
- No reference materials — Starting from scratch
- Yes, I have reference materials — I'll provide the location(s)
If "Yes, I have reference materials":
Ask for the location(s):
Where are your reference materials located? (Provide path(s) - can be files or directories)
Free-form text input. User provides path(s) (e.g., docs/specs/, requirements.md, PRD.pdf).
Validate path exists:
EXISTING_SPEC_PATH="<user-provided-path>"
if [ ! -e "$TARGET_DIR/$EXISTING_SPEC_PATH" ] && [ ! -e "$EXISTING_SPEC_PATH" ]; then
echo "Warning: Path not found. Please verify the path."
fi
2c. Initialize Session State
Create .tasker/ directory structure in target project:
TASKER_DIR="$TARGET_DIR/.tasker"
mkdir -p "$TASKER_DIR"/{inputs,artifacts,tasks,bundles,reports,fsm-draft,adrs-draft}
Create $TARGET_DIR/.tasker/state.json:
{
"version": "3.0",
"target_dir": "<absolute-path>",
"phase": {
"current": "initialization",
"completed": [],
"step": null
},
"created_at": "<timestamp>",
"updated_at": "<timestamp>",
"spec_session": {
"project_type": "new|existing",
"existing_spec_path": "<path-from-step-2-or-null>",
"spec_slug": "<slug>",
"spec_path": "<target>/docs/specs/<slug>.md",
"started_at": "<timestamp>",
"resumed_from": null
},
"scope": null,
"clarify": null,
"synthesis": null,
"architecture": null,
"decisions": null,
"review": null
}
CRITICAL: Update state.json after EVERY significant action. This enables resume from any point.
The phase-specific state objects are populated as each phase progresses (see phase definitions below).
If user provided existing spec path in Step 2b, store it in spec_session.existing_spec_path for reference during Scope phase.
Output (New Session Only)
For new sessions (Step 2 path):
.tasker/directory structure created in target project- Session state initialized in
$TARGET_DIR/.tasker/state.json - Existing spec path captured (if provided)
- Proceed to Phase 1 (Scope)
For resumed sessions (Step 1c path):
- State already exists - no initialization needed
- Jump directly to
phase.currentphase - Read working files as specified in Resume Protocol
Phase 1 — Scope
Goal
Establish bounds before discovery.
Pre-Scope: Load Existing Spec (if provided)
If spec_session.existing_spec_path was set during initialization:
- Read the existing spec file to understand prior context
- Extract initial answers for the scope questions below (Goal, Non-goals, Done means)
- Present extracted context to user for confirmation/refinement rather than asking from scratch
if [ -n "$EXISTING_SPEC_PATH" ]; then
echo "Loading existing spec from: $EXISTING_SPEC_PATH"
# Read and analyze existing spec
# Pre-fill scope questions with extracted information
fi
Required Questions (AskUserQuestion)
Ask these questions using AskUserQuestion tool with structured options. If existing spec was loaded, present extracted answers for confirmation rather than blank questions:
Question 1: Goal
What are we building?
Free-form text input.
Question 2: Non-goals
What is explicitly OUT of scope?
Free-form text input (allow multiple items).
Question 3: Done Means
What are the acceptance bullets? (When is this "done"?)
Free-form text input (allow multiple items).
Question 4: Tech Stack
What tech stack should be used?
Free-form text input. Examples:
- "Python 3.12+ with FastAPI, PostgreSQL, Redis"
- "TypeScript, Next.js, Prisma, Supabase"
- "Go with Chi router, SQLite"
- "Whatever fits best" (let /specify recommend based on requirements)
If user says "whatever fits best" or similar:
- Note this for Phase 2 (Clarify) to recommend based on gathered requirements
- Ask clarifying questions: "Any language preferences?", "Cloud provider constraints?", "Team expertise?"
Question 5: Entry Point (CRITICAL for W8/I6 compliance)
How will users invoke this? What makes it available?
Options to present:
- CLI command — User runs a command (specify command name)
- API endpoint — User calls an HTTP endpoint (specify URL pattern)
- Claude Code skill — User invokes /skillname (specify trigger)
- Library/module — No direct invocation, imported by other code
- Other — Custom activation mechanism
If user selects CLI/API/Skill: Follow up: "What specific steps are needed to make this available to users?"
If user selects Library/module: Note in spec: "Installation & Activation: N/A - library/module only"
Why this matters: Specs that describe invocation without activation mechanism cause W8 weakness and I6 invariant failure. Capturing this early prevents dead entry points.
Output
1. Update State (MANDATORY)
Update $TARGET_DIR/.tasker/state.json:
{
"phase": {
"current": "scope",
"completed": ["initialization"],
"step": "complete"
},
"updated_at": "<timestamp>",
"scope": {
"goal": "<user-provided-goal>",
"non_goals": ["<item1>", "<item2>"],
"done_means": ["<criterion1>", "<criterion2>"],
"tech_stack": "<tech-stack-or-TBD>",
"entry_point": {
"type": "cli|api|skill|library|other",
"trigger": "<command-name or /skillname or endpoint>",
"activation_steps": ["<step1>", "<step2>"]
},
"completed_at": "<timestamp>"
}
}
2. Write Spec Draft (MANDATORY)
Write initial spec sections to $TARGET_DIR/.tasker/spec-draft.md:
# Spec: {Title}
## Goal
{goal from scope}
## Non-goals
{non_goals from scope}
## Done means
{done_means from scope}
## Tech Stack
{tech_stack from scope}
## Installation & Activation
**Entry Point:** {entry_point.trigger from scope}
**Type:** {entry_point.type from scope}
**Activation Steps:**
{entry_point.activation_steps from scope, numbered list}
**Verification:**
<!-- To be filled in during Clarify or Synthesis -->
<!-- Remaining sections will be added by subsequent phases -->
IMPORTANT: All spec content is built in this file, NOT in conversation context. Read from this file when you need prior spec content.
Phase 2 — Clarify (Ralph Iterative Discovery Loop)
Purpose
Exhaustively gather requirements via structured questioning.
Setup
1. Initialize Clarify State in state.json (MANDATORY)
Update $TARGET_DIR/.tasker/state.json:
{
"phase": {
"current": "clarify",
"completed": ["initialization", "scope"],
"step": "starting"
},
"updated_at": "<timestamp>",
"clarify": {
"current_category": "core_requirements",
"current_round": 1,
"categories": {
"core_requirements": { "status": "not_started", "rounds": 0 },
"users_context": { "status": "not_started", "rounds": 0 },
"integrations": { "status": "not_started", "rounds": 0 },
"edge_cases": { "status": "not_started", "rounds": 0 },
"quality_attributes": { "status": "not_started", "rounds": 0 },
"existing_patterns": { "status": "not_started", "rounds": 0 },
"preferences": { "status": "not_started", "rounds": 0 }
},
"pending_followups": [],
"requirements_count": 0,
"stock_takes_count": 0,
"started_at": "<timestamp>"
}
}
2. Create Discovery File
Create $TARGET_DIR/.tasker/clarify-session.md:
# Discovery: {TOPIC}
Started: {timestamp}
## Category Status
| Category | Status | Rounds | Notes |
|----------|--------|--------|-------|
| Core requirements | ○ Not Started | 0 | — |
| Users & context | ○ Not Started | 0 | — |
| Integrations | ○ Not Started | 0 | — |
| Edge cases | ○ Not Started | 0 | — |
| Quality attributes | ○ Not Started | 0 | — |
| Existing patterns | ○ Not Started | 0 | — |
| Preferences | ○ Not Started | 0 | — |
## Discovery Rounds
3. Create Stock-Takes File
Create $TARGET_DIR/.tasker/stock-takes.md:
# Stock-Takes: {TOPIC}
Started: {timestamp}
This file tracks how the vision evolves as discovery progresses.
---
CRITICAL: Resume Capability
On resume (after compaction or restart):
- Read
$TARGET_DIR/.tasker/state.jsonto getclarifystate - Read
$TARGET_DIR/.tasker/clarify-session.mdto get discovery history - Resume from
clarify.current_categoryandclarify.current_round - If
clarify.pending_followupsis non-empty, continue follow-up loop first
DO NOT rely on conversation context for clarify progress. Always read from files.
Loop Rules
No iteration cap - Continue until goals are met
Category Focus Mode - Work on ONE category at a time until it's complete or explicitly deferred
Each iteration:
- Read discovery file
- Select ONE incomplete category to focus on (priority: Core requirements → Users & context → Integrations → Edge cases → Quality attributes → Existing patterns → Preferences)
- Ask 2–4 questions within that focused category
- Get user answers
- Run Follow-up Sub-loop (see below) - validate and drill down on answers
- Only after follow-ups are complete: update discovery file, extract requirements, update category status
- Repeat within same category until goal is met OR user says "move on from this category"
Clarity Before Progress - If user response is anything except a direct answer (counter-question, confusion, pushback, tangential), provide clarification FIRST. Do NOT present new questions until prior questions have direct answers.
Stop ONLY when:
- ALL category goals are met (see checklist), OR
- User says "enough", "stop", "move on", or similar
Follow-up Sub-loop (MANDATORY)
After receiving answers to a question round, DO NOT immediately move to the next round. First, validate each answer:
Answer Validation Triggers
For each answer, check if follow-up is required:
| Trigger | Example | Required Follow-up |
|---|---|---|
| Vague quantifier | "several users", "a few endpoints" | "How many specifically?" |
| Undefined scope | "and so on", "etc.", "things like that" | "Can you list all items explicitly?" |
| Weak commitment | "probably", "maybe", "I think" | "Is this confirmed or uncertain?" |
| Missing specifics | "fast response", "secure" | "What's the specific target? (e.g., <100ms)" |
| Deferred knowledge | "I'm not sure", "don't know yet" | "Should we make a default assumption, or is this blocking?" |
| Contradicts earlier answer | Conflicts with prior round | "Earlier you said X, now Y. Which is correct?" |
Sub-loop Process
For each answer in current round:
1. Check against validation triggers
2. If trigger found:
a. Add to pending_followups in state.json
b. Ask ONE follow-up question (not batched)
c. Wait for response
d. Remove from pending_followups, re-validate the new response
e. Repeat until answer is concrete OR user explicitly defers
3. Only after ALL answers validated → proceed to next round
MANDATORY: Persist Follow-up State
Before asking a follow-up question, update state.json:
{
"clarify": {
"pending_followups": [
{
"question_id": "Q3.2",
"original_answer": "<user's vague answer>",
"trigger": "vague_quantifier",
"followup_question": "<the follow-up question being asked>"
}
]
}
}
After receiving follow-up response, remove from pending_followups and update the round in clarify-session.md.
Follow-up Question Format
Use AskUserQuestion with context from the original answer:
{
"question": "You mentioned '{user_quote}'. {specific_follow_up_question}",
"header": "Clarify",
"options": [
{"label": "Specify", "description": "I'll provide a specific answer"},
{"label": "Not critical", "description": "This detail isn't important for the spec"},
{"label": "Defer", "description": "I don't know yet, note as open question"}
]
}
Handling Non-Direct Responses (MANDATORY)
If the user's response is anything other than a direct answer, assume clarification is required. Do NOT present new questions until the original question is resolved.
| Response Type | Example | Required Action |
|---|---|---|
| Counter-question | "What do you mean by X?" | Answer their question, then re-ask yours |
| Confusion | "I'm not sure what you're asking" | Rephrase the question with more context |
| Pushback | "Why do you need to know that?" | Explain why this matters for the spec |
| Tangential | Talks about something else | Acknowledge, then redirect to the question |
| Partial answer | Answers part, ignores rest | Note the partial, ask about the unanswered part |
| Meta-comment | "This is getting detailed" | Acknowledge, offer to simplify or defer |
Process:
1. Detect non-direct response
2. Address the user's concern/question FIRST
3. Only after clarity achieved → re-present the original question (or confirm it's now answered)
4. Do NOT batch new questions until all prior questions have direct answers
Example:
Agent: "What authentication method should users use?"
User: "What options are there?"
[NON-DIRECT: User asked a counter-question]
Agent: "Common options are: (1) Email/password, (2) OAuth (Google, GitHub),
(3) Magic link, (4) SSO/SAML. Which fits your use case?"
User: "Email/password for now, maybe OAuth later."
[NOW DIRECT: Can proceed]
When NOT to Follow Up
- User explicitly says "that's all I know" or "let's move on"
- The answer is already concrete and specific
- The detail is genuinely non-blocking (implementation detail, not spec-level)
- You've already asked 2 follow-ups on the same answer (avoid interrogation)
Example Interaction
Agent: "What integrations are required?"
User: "We need to connect to a few external services and maybe some APIs."
[FOLLOW-UP REQUIRED: "a few" is vague, "maybe" is weak commitment]
Agent: "You mentioned 'a few external services'. Can you list all the external systems this will integrate with?"
User: "Stripe for payments, SendGrid for email, and our internal user service."
[ANSWER NOW CONCRETE: specific services named]
Agent: "You said 'maybe some APIs'. Are there additional API integrations beyond Stripe, SendGrid, and the user service?"
User: "No, that's all."
[CATEGORY GOAL PROGRESS: Integrations now has concrete list]
Category Checklist (Goal-Driven Coverage)
Each category has concrete "done" criteria. Track completion in the discovery file.
| Category | Goal (Done When) |
|---|---|
| Core requirements | Primary workflows enumerated with inputs, outputs, and happy path steps |
| Users & context | User roles identified, expertise levels known, access patterns clear |
| Integrations / boundaries | All external systems named, data flows mapped, API contracts sketched |
| Edge cases / failures | Error handling defined for each workflow step, retry/fallback behavior specified |
| Quality attributes | Performance targets have numbers (or explicit "not critical"), security requirements stated |
| Existing patterns | Relevant prior art identified OR confirmed none exists, conventions to follow listed |
| Preferences / constraints | Tech stack decided, deployment target known, timeline/resource constraints stated |
Tracking Format
Update discovery file with completion status:
## Category Status
| Category | Status | Notes |
|----------|--------|-------|
| Core requirements | ✓ Complete | 3 workflows defined |
| Users & context | ✓ Complete | 2 roles: admin, user |
| Integrations | ⋯ In Progress | DB confirmed, auth TBD |
| Edge cases | ○ Not Started | — |
| Quality attributes | ○ Not Started | — |
| Existing patterns | ✓ Complete | Follow auth module pattern |
| Preferences | ⋯ In Progress | Python confirmed, framework TBD |
Completion Criteria
A category is complete when:
- The goal condition is satisfied (see table above)
- User has confirmed or provided the information
- All answers have passed follow-up validation (no vague quantifiers, no weak commitments, no undefined scope)
- No obvious follow-up questions remain for that category
- User has explicitly confirmed or the agent has verified understanding
Do NOT mark complete if:
- User said "I don't know" without a fallback decision
- Information is vague (e.g., "fast" instead of "<100ms")
- Dependencies on other categories are unresolved
- Follow-up validation has not been run on all answers
- Any answer contains unresolved triggers (vague quantifiers, weak commitments, etc.)
Category Transition Rules
Before moving to a new category:
- Summarize what was learned in the current category
- Confirm with user: "I've captured X, Y, Z for [category]. Does that cover everything, or is there more?"
- Run Stock-Take (see below)
- Only then move to the next incomplete category
This prevents the feeling of being "rushed" through categories.
Stock-Taking (Big Picture Synthesis)
Purpose
As questions are answered and categories complete, periodically synthesize the "big picture" - what's emerging, the shape of the vision. This helps users see how their answers are building toward something coherent and provides calibration moments.
Trigger
Stock-take is triggered after each category completes (before transitioning to the next category). This creates a natural rhythm of ~5-7 stock-takes during Phase 2.
Content
A stock-take is NOT a list of answers. It's a synthesis of meaning - what's taking shape:
- What we're building (1-2 sentences, evolving as understanding deepens)
- Key constraints/boundaries that have emerged from answers
- The shape becoming visible (patterns, tensions, tradeoffs surfacing)
- Direction check - light confirmation the vision still feels right
Format
**Taking stock** (after {category_name}):
{1-3 sentence synthesis of what's emerging - not a summary of answers, but the picture forming}
{Any notable patterns, tensions, or tradeoffs becoming visible}
Does this still capture where we're heading?
Example
After completing "Integrations" category:
Taking stock (after Integrations):
We're building a CLI skill system where specs drive task decomposition. The emphasis is on preventing incomplete handoffs - every behavior must trace back to stated requirements. The system is self-contained except for Git (for state persistence) and Claude Code (as the execution runtime).
There's tension between thoroughness and workflow friction that keeps surfacing - users want comprehensive specs but not interrogation.
Does this still capture where we're heading?
Tone
- Reflective, not interrogative
- Synthesizing, not summarizing
- Calibrating, not gate-checking
The question at the end is light - "Does this still feel right?" not "Please confirm items 1-7."
Process
After category completion:
- Read accumulated state from
spec-draft.md(scope),clarify-session.md(discovery so far) - Synthesize the emerging picture (not regurgitate answers)
- Present the stock-take to user
- Listen for any course correction or "that's not quite right"
- Append to
$TARGET_DIR/.tasker/stock-takes.md - Update
state.jsonwithstock_takes_count
Stock-Takes File Format
Append each stock-take to $TARGET_DIR/.tasker/stock-takes.md:
---
## Stock-Take {N} — After {Category Name}
*{timestamp}*
{The synthesis content}
**User response:** {confirmed | adjusted: brief note}
---
State Update
After each stock-take, update state.json:
{
"clarify": {
"stock_takes_count": N
},
"updated_at": "<timestamp>"
}
When NOT to Stock-Take
- Early exit: If user says "move on" mid-category, skip stock-take for that category
- Minor category: If a category yielded very little new information, stock-take can be brief or combined with next
- User impatience: If user explicitly wants to skip calibration, respect that
AskUserQuestion Format
Primary Questions (Category-Focused)
Use AskUserQuestion with 2-4 questions per iteration, all within the same category:
questions:
- question: "How should the system handle [specific scenario]?"
header: "Edge case" # Keep headers consistent within a round
options:
- label: "Option A"
description: "Description of approach A"
- label: "Option B"
description: "Description of approach B"
multiSelect: false
IMPORTANT: Do NOT mix categories in a single question batch. If you're asking about "Edge cases", all 2-4 questions should be about edge cases.
Follow-up Questions (Single Question)
For follow-ups during the validation sub-loop, ask ONE question at a time:
questions:
- question: "You mentioned '{user_quote}'. Can you be more specific about X?"
header: "Clarify"
options:
- label: "Specify"
description: "I'll provide details"
- label: "Not critical"
description: "This isn't spec-relevant"
- label: "Defer"
description: "Note as open question"
multiSelect: false
Open-ended Questions
For open-ended questions, use free-form with context:
questions:
- question: "What integrations are required?"
header: "Integrations"
options:
- label: "REST API"
description: "Standard HTTP/JSON endpoints"
- label: "Database direct"
description: "Direct database access"
- label: "Message queue"
description: "Async via queue (Kafka, RabbitMQ, etc.)"
multiSelect: true
Updating Discovery File AND State (MANDATORY)
After each Q&A round AND its follow-ups are complete:
1. Append to Discovery File
Append to $TARGET_DIR/.tasker/clarify-session.md:
### Round N — [Category Name]
**Questions:**
1. [Question text]
2. [Question text]
**Answers:**
1. [User's answer]
2. [User's answer]
**Follow-ups:**
- Q1 follow-up: "[follow-up question]" → "[user response]"
- Q2: No follow-up needed (answer was specific)
**Requirements Discovered:**
- REQ-NNN: [Req 1]
- REQ-NNN: [Req 2]
**Category Status:** [✓ Complete | ⋯ In Progress | User deferred]
2. Update State (MANDATORY after every round)
Update $TARGET_DIR/.tasker/state.json:
{
"phase": {
"step": "round_N_complete"
},
"updated_at": "<timestamp>",
"clarify": {
"current_category": "<category>",
"current_round": N+1,
"categories": {
"<category>": { "status": "in_progress|complete", "rounds": N }
},
"pending_followups": [],
"requirements_count": <total REQ count>
}
}
3. Update Category Status Table
Also update the Category Status table at the top of clarify-session.md to reflect current state.
NOTE: Do NOT proceed to next round until both files are updated. This ensures resumability.
Completion Signal
When ALL category goals are met:
- Verify all categories show "✓ Complete" in the status table
- Confirm no blocking questions remain
- Update state.json:
{
"phase": {
"current": "clarify",
"completed": ["initialization", "scope"],
"step": "complete"
},
"updated_at": "<timestamp>",
"clarify": {
"status": "complete",
"completed_at": "<timestamp>",
"categories": { /* all marked complete */ },
"requirements_count": <final count>
}
}
- Output:
<promise>CLARIFIED</promise>
If user requests early exit: Accept it, mark incomplete categories in state.json with status: "deferred", and note in discovery file for Phase 3 to flag as assumptions.
Phase 3 — Synthesis (Derived, Not Asked)
Purpose
Derive structured requirements AND capabilities from discovery. No new information introduced here.
This phase produces TWO outputs:
- Spec sections (human-readable) - Workflows, invariants, interfaces
- Capability map (machine-readable) - For
/planto consume
CRITICAL: State-Driven, Not Context-Driven
On entry to Phase 3:
- Read
$TARGET_DIR/.tasker/state.jsonto confirmclarify.status == "complete" - Read
$TARGET_DIR/.tasker/clarify-session.mdfor ALL discovery content - Read
$TARGET_DIR/.tasker/spec-draft.mdfor existing spec sections (Goal, Non-goals, etc.)
DO NOT rely on conversation context for discovery content. Read from files.
Initialize Synthesis State
Update $TARGET_DIR/.tasker/state.json:
{
"phase": {
"current": "synthesis",
"completed": ["initialization", "scope", "clarify"],
"step": "starting"
},
"updated_at": "<timestamp>",
"synthesis": {
"status": "in_progress",
"spec_sections": {
"workflows": false,
"invariants": false,
"interfaces": false,
"open_questions": false
},
"capability_map": {
"domains_count": 0,
"capabilities_count": 0,
"behaviors_count": 0,
"steel_thread_identified": false
},
"fsm": {
"machines_count": 0,
"states_count": 0,
"transitions_count": 0,
"invariants_validated": false
}
}
}
Process
- Read
$TARGET_DIR/.tasker/clarify-session.mdcompletely - Extract and organize into spec sections (update spec-draft.md after each)
- Decompose into capabilities using I.P.S.O.A. taxonomy
- Everything must trace to a specific discovery answer
Part A: Spec Sections
Workflows
Numbered steps with variants and failures:
## Workflows
### 1. [Primary Workflow Name]
1. User initiates X
2. System validates Y
3. System performs Z
4. System returns result
**Variants:**
- If [condition], then [alternative flow]
**Failures:**
- If [error], then [error handling]
**Postconditions:**
- [State after completion]
Invariants
Bulleted rules that must ALWAYS hold:
## Invariants
- [Rule that must never be violated]
- [Another invariant]
Interfaces
Only if a boundary exists:
## Interfaces
- [Interface description]
(or "No new/changed interfaces" if none)
Open Questions
Classified by blocking status:
## Open Questions
### Blocking
- [Question that affects workflows/invariants/interfaces]
### Non-blocking
- [Question about internal preferences only]
Part A Output: Update Files (MANDATORY)
After synthesizing each spec section:
1. Append section to $TARGET_DIR/.tasker/spec-draft.md:
## Workflows
[Synthesized workflows content]
## Invariants
[Synthesized invariants content]
## Interfaces
[Synthesized interfaces content]
## Open Questions
[Synthesized open questions content]
2. Update state.json after EACH section:
{
"synthesis": {
"spec_sections": {
"workflows": true,
"invariants": true,
"interfaces": false,
"open_questions": false
}
},
"updated_at": "<timestamp>"
}
Part A.5: Behavior Model Compilation (FSM)
After synthesizing Workflows, Invariants, and Interfaces, compile the Behavior Model (state machine).
Purpose
The FSM serves two purposes:
- QA during implementation - Shapes acceptance criteria, enables transition/guard coverage verification
- Documentation - Human-readable diagrams for ongoing system understanding
CRITICAL INVARIANT: Canonical Truth
FSM JSON is canonical; Mermaid is generated.
/planand/executemust fail if required transitions and invariants lack coverage evidence.
- Canonical artifacts:
*.states.json,*.transitions.json,index.json - Derived artifacts:
*.mmd(Mermaid diagrams) - generated ONLY from canonical JSON - NEVER manually edit
.mmdfiles - regenerate from JSON usingfsm-mermaid.py - If Mermaid is ever edited manually, the system loses machine trust
Compilation Steps
- Identify Steel Thread Flow: The primary end-to-end workflow
- Derive States: Convert workflow steps to business states
- Initial state from workflow trigger
- Normal states from step postconditions
- Success terminal from workflow completion
- Failure terminals from failure clauses
- Derive Transitions: Convert step sequences, variants, and failures
- Happy path: step N → step N+1
- Variants: conditional branches with guards
- Failures: error transitions to failure states
- Link Guards to Invariants: Map spec invariants to transition guards
- Validate Completeness: Run I1-I6 checks (see below)
- Resolve Ambiguity: Use AskUserQuestion for any gaps
Completeness Invariants
The FSM MUST satisfy these invariants:
| ID | Invariant | Check |
|---|---|---|
| I1 | Steel Thread FSM mandatory | At least one machine for primary workflow |
| I2 | Behavior-first | No architecture dependencies required |
| I3 | Completeness | Initial state, terminals, no dead ends |
| I4 | Guard-Invariant linkage | Every guard links to an invariant ID |
| I5 | No silent ambiguity | Vague terms resolved or flagged as Open Questions |
| I6 | Precondition reachability | If initial transition requires external trigger (e.g., "user invokes X"), the preconditions for that trigger must be specified in the spec |
I6 Detailed Check: If the first transition's trigger describes user invocation (e.g., "user runs /command", "user invokes skill"):
- Check if spec has "Installation & Activation" section
- Verify the activation mechanism makes the trigger possible
- If missing, flag as W8 weakness (missing activation requirements)
Example I6 failure:
- FSM starts:
Idle --[user invokes /kx]--> Running - Spec has NO section explaining how
/kxbecomes available - I6 FAILS: "Precondition for initial transition 'user invokes /kx' not reachable - no activation mechanism specified"
Complexity Triggers (Splitting Rules)
Create additional machines based on structural heuristics, not just state count:
State Count Triggers:
- Steel Thread exceeds 12 states → split into domain-level sub-machines
- Any machine exceeds 20 states → mandatory split
Structural Triggers (split even with fewer states):
- Divergent user journeys: Two or more distinct journeys that share only an initial prefix, then branch into unrelated flows → separate machines for each journey
- Unrelated failure clusters: Multiple failure states that handle different categories of errors (e.g., validation errors vs. system errors vs. business rule violations) → group related failures into their own machines
- Mixed abstraction levels: Machine combines business lifecycle states (e.g., Order: Created → Paid → Shipped) with UI microstates (e.g., Modal: Open → Editing → Validating) → separate business lifecycle from UI state machines
- Cross-boundary workflows: Workflow that spans multiple bounded contexts or domains → domain-level machine for each context
Hierarchy Guidelines:
steel_threadlevel: Primary end-to-end flowdomainlevel: Sub-flows within a bounded contextentitylevel: Lifecycle states for a specific entity
Ambiguity Resolution
If the compiler detects ambiguous workflow language, use AskUserQuestion:
{
"question": "The workflow step '{step}' has ambiguous outcome. What business state results?",
"header": "FSM State",
"options": [
{"label": "Define state", "description": "I'll provide the state name"},
{"label": "Same as previous", "description": "Remains in current state"},
{"label": "Terminal success", "description": "Workflow completes successfully"},
{"label": "Terminal failure", "description": "Workflow fails with error"}
]
}
FSM Working Files (Written Incrementally)
During synthesis, write FSM drafts to $TARGET_DIR/.tasker/fsm-draft/:
index.json- Machine list, hierarchy, primary machinesteel-thread.states.json- State definitions (S1, S2, ...)steel-thread.transitions.json- Transition definitions (TR1, TR2, ...)steel-thread.notes.md- Ambiguity resolutions and rationale
Update state.json after each FSM file:
{
"synthesis": {
"fsm": {
"machines_count": 1,
"states_count": 8,
"transitions_count": 12,
"files_written": ["index.json", "steel-thread.states.json"],
"invariants_validated": false
}
},
"updated_at": "<timestamp>"
}
FSM Final Output Structure
Final FSM artifacts are exported to {TARGET}/docs/state-machines/<slug>/ in Phase 8:
index.json- Machine list, hierarchy, primary machinesteel-thread.states.json- State definitions (S1, S2, ...)steel-thread.transitions.json- Transition definitions (TR1, TR2, ...)steel-thread.mmd- Mermaid stateDiagram-v2 for visualization (DERIVED from JSON)steel-thread.notes.md- Ambiguity resolutions and rationale
ID Conventions (FSM-specific)
- Machines:
M1,M2,M3... - States:
S1,S2,S3... - Transitions:
TR1,TR2,TR3...
Traceability (Spec Provenance - MANDATORY)
Every state and transition MUST have a spec_ref pointing to the specific workflow step, variant, or failure that defined it. This prevents "FSM hallucination" where states/transitions are invented without spec basis.
Required for each state:
spec_ref.quote- Verbatim text from the spec that defines this statespec_ref.location- Section reference (e.g., "Workflow 1, Step 3")
Required for each transition:
spec_ref.quote- Verbatim text from the spec that defines this transitionspec_ref.location- Section reference (e.g., "Workflow 1, Variant 2")
If no spec text exists for an element:
- The element should NOT be created (likely FSM hallucination)
- Or, use AskUserQuestion to get clarification and document the decision
Part B: Capability Extraction
Extract capabilities from the synthesized workflows using I.P.S.O.A. decomposition.
I.P.S.O.A. Behavior Taxonomy
For each capability, identify behaviors by type:
| Type | Description | Examples |
|---|---|---|
| Input | Validation, parsing, authentication | Validate email format, parse JSON body |
| Process | Calculations, decisions, transformations | Calculate total, apply discount rules |
| State | Database reads/writes, cache operations | Save order, fetch user profile |
| Output | Responses, events, notifications | Return JSON, emit event, send email |
| Activation | Registration, installation, deployment | Register skill, deploy endpoint, write config |
Activation Behaviors
If the spec describes user invocation (e.g., "user runs /command"), extract activation behaviors:
- Registration: Skill/plugin registration with runtime
- Installation: CLI or package installation steps
- Deployment: API endpoint or service deployment
- Configuration: Config files or environment setup
Missing activation = coverage gap. If spec says "user invokes X" but doesn't specify how X becomes available, add to coverage.gaps.
Domain Grouping
Group related capabilities into domains:
- Authentication - Login, logout, session management
- User Management - Profile, preferences, settings
- Core Feature - The primary business capability
- etc.
Steel Thread Identification
…(truncated)