| name | blueprint |
| description | "/blueprint", "blueprint", "task graph", "contract derivation", "execution plan",
"plan tasks from requirements", "contract-first planning"
Turn requirements.md into an executable blueprint (plan.json + contracts.md).
Five phases: Contracts → Tasks → Journeys → Verify Plan → Commit.
Sits between /specify and /execute. Scope-adaptive (greenfield → bugfix).
Uses hoyeon-cli (plan.json only; requirements.md is read as-is via Read tool).
|
blueprint: Requirements → Executable Plan
Overview
Transform <spec_dir>/requirements.md (from /specify) into an executable blueprint that /execute can run without rework:
- Contract Synthesis — derive cross-module agreements (types, interfaces, invariants) that keep parallel work safe
- Task Graph — layered DAG (L0 Foundation → L1 Feature → L2 Integration → L3 Deploy) where every sub-requirement has ≥1 fulfilling task
- Journey Detection — identify multi-sub-req user flows that need end-to-end coverage
- Verify Plan — assign verification gates (1=machine, 2=agent_semantic, 3=agent_e2e, 4=human) per sub-req and per journey
- Commit — run cross-ref validation and hand off to /execute
Contract-first principle: lock "how modules talk" before anyone writes code. Parallel workers can't break each other's shapes; required invariants are called out explicitly.
Ask-only-when-owned principle: prompt the user only at decisions they actually own — missing inputs (no spec_dir), conflicting signals with no safe default (meta.type conflict), or real commitments they must make (G4 playtests, flagged time/confidence ambiguities). Task-graph correctness and final summaries are not user decisions: the coverage gate (2.2) and cross-ref validator (5.1) enforce them mechanically. Print, don't ask.
Not blueprint's job: writing source code, running tests, interviewing for missing requirements. If requirements are incomplete, run /specify first.
Runtime Surface
Claude Code
- Use
Agent(subagent_type="...") for Hoyeon logical subagents such as
code-explorer, contract-deriver, and taskgraph-planner.
- Use
AskUserQuestion only for user-owned decisions described by this skill.
- Claude hooks may add session context, but blueprint must still leave a valid
plan.json on disk through hoyeon-cli.
Codex
- Use the same Hoyeon logical subagent names in prompts, but dispatch through
Codex adapters when installed:
hoyeon-code-explorer, hoyeon-worker,
hoyeon-verifier, and hoyeon-code-reviewer.
- Use Bash-first state operations. Do not use MCP in v1.
- Mutate
plan.json only through hoyeon-cli plan init|merge|validate.
- Prefer temporary JSON payload files or fixture files over inline complex JSON.
- Do not rely on hooks for session guards or stop transitions.
Input / Output
Input
<spec_dir>/requirements.md — required (produced by /specify)
- Optional: existing
plan.json — treated as prior state, patched additively
Output
<spec_dir>/
├── requirements.md # unchanged (input)
├── plan.json # NEW/UPDATED: tasks + journeys + verify_plan + contracts summary
└── contracts.md # NEW: cross-module surface (markdown). Optional for trivial bugfix.
Only those three files. No rendered view file, no language-specific stubs.
File role separation
- requirements.md — specify owns. Human-editable markdown with sub-requirements (GWT).
- plan.json — blueprint owns. Machine state. Schema:
plan/v1 (see cli/schemas/plan.schema.json).
- contracts.md — blueprint creates. Sibling artifact referenced by
plan.contracts.artifact. Markdown, language-agnostic.
Prerequisite: cli
All plan.json operations go through hoyeon-cli (NOT legacy hoyeon-cli):
| Command | Purpose |
|---|
hoyeon-cli plan init <spec_dir> --type <t> | Create empty stub (if missing) |
hoyeon-cli plan merge <spec_dir> --json '<payload>' [--patch|--append] | Merge JSON with schema validation |
hoyeon-cli plan get <spec_dir> --path <dotted> | Read field |
hoyeon-cli plan validate <spec_dir> | Schema + internal cross-ref integrity |
cli never parses requirements.md. Reading the markdown is the blueprint agent's job (via Read tool). cli only validates plan.json self-consistency. Coverage against requirements.md is enforced semantically by the LLM (Phase 2 / Phase 4 of this skill).
Scope Adaptation (meta.type)
meta.type | Contract artifact shape (when written) | Task graph |
|---|
greenfield | Full surface: types + interfaces + invariants (~50-200 lines) | L0-L3, parallel L1 |
feature | Delta only: new types/interfaces this feature adds (~10-50 lines) | L0-L2, parallel if multi-module |
refactor | Pin-style: ## Frozen Public API + ## Allowed Churn + ## Invariants | Flat list with invariant guards |
bugfix | Minimal: typically just an ## Invariants section | Single chain (1-3 tasks) |
Approval is not meta.type-scaled anymore — the ask-only-when-owned rule governs every type uniformly (see top-level principle).
contracts.md is content-driven, not type-driven. Write it whenever contract-deriver finds any cross-module content (≥1 invariant or interface) — regardless of meta.type. Skip the file (return artifact: null) only when the agent genuinely has nothing to pin. A bugfix with 3 load-bearing invariants gets a file; a feature that only adds a config flag may not. meta.type decides the template shape, not the file's existence.
meta.type normally comes from /specify (written into requirements.md frontmatter). If the field is missing — manual authoring, legacy spec, etc. — infer it using this priority (stop at the first matching rule):
-
Keywords in goal (highest signal, author's stated intent)
- Contains
refactor / migrate / restructure / rewrite → refactor
- Contains
fix / bug / regression / broken → bugfix
-
Repo state (hard physical signal — either empty or not)
spec_dir's parent repo has no source files (empty / fresh scaffold) → greenfield
-
Size (weakest heuristic — only when 1 and 2 are silent)
< 5 sub-reqs → bugfix
< 15 sub-reqs → feature
≥ 15 sub-reqs → greenfield
On conflict, stop and ask. If signals point to different types (e.g., keyword says refactor but repo is empty → greenfield), do NOT silently pick one. Emit AskUserQuestion with the top 2 candidates and let the user decide. Do not proceed to Phase 1 until confirmed.
Phase 0: Init
Step 0.1: Resolve spec_dir
- If user passed a path, use it. Otherwise ask: "Which spec_dir? (e.g.,
.hoyeon/specs/my-thing/)"
- Error if
<spec_dir>/requirements.md does not exist — tell user to run /specify first.
Step 0.2: Read requirements.md
Use Read tool directly. Do not shell out to cli for parsing — cli has no such command.
Extract (you, the main agent, parse this from the markdown):
- Frontmatter:
type, goal, non_goals (YAML between --- delimiters)
- Sub-requirements: every
## R-X<num>: parent + each #### R-X<num>.Y: child with given/when/then fields
- Open decisions (optional): any
### OD-N: blocks
Build an internal list:
reqs = [
{ parent: "R-B1", title: "...", subs: [
{ id: "R-B1.1", title: "...", given: "...", when: "...", then: "..." },
...
]},
...
]
Step 0.3: Init plan.json stub
hoyeon-cli plan init <spec_dir> --type <meta.type>
If plan.json already exists (re-run), skip init and treat as patch-merge mode.
Step 0.4: Patch meta with real goal/non_goals
cat > /tmp/bp-meta.json << 'EOF'
{"meta": {"type": "<t>", "goal": "<goal>", "non_goals": ["..."]}}
EOF
hoyeon-cli plan merge <spec_dir> --patch --json "$(cat /tmp/bp-meta.json)"
Phase 0.5: Codebase Reconnaissance (non-greenfield only)
Skip if meta.type == greenfield. For feature, refactor, and bugfix, scan the existing codebase so that contract derivation and task planning are grounded in real code structure — not just requirements text.
Step 0.5.1: Dispatch code-explorer (parallel)
Agent(subagent_type="code-explorer",
prompt="Goal: {meta.goal}. Find: project structure, modules, existing interfaces/types
relevant to this change. Report as file:line with brief summary.",
run_in_background=true)
Agent(subagent_type="code-explorer",
prompt="Goal: {meta.goal}. Find: existing test infrastructure (test runner, test dirs,
fixture patterns) and build/lint commands. Report as file:line.",
run_in_background=true)
Agent(subagent_type="code-explorer",
prompt="Goal: {meta.goal}. Blast radius analysis:
1. Find all callers/consumers of the modules being changed
2. Find existing tests that cover these modules (test files + test names)
3. Identify existing user-facing or API flows that pass through these modules
4. Flag flows that have NO existing test coverage
Report as: affected_flows (name + file:line entry), existing_tests (file:line),
untested_flows (name + why no test found).",
run_in_background=true)
Step 0.5.2: Build code context summary
Consolidate agent results into a short context block (keep in memory, not a file):
code_context = {
modules: ["src/api/", "src/storage/", "src/ui/"],
existing_interfaces: ["StorageAPI (src/storage/types.ts:12)", ...],
test_infra: "vitest, src/__tests__/, no E2E setup",
entry_points: ["src/main.ts", "src/api/router.ts"],
blast_radius: {
affected_flows: ["checkout flow (src/api/orders.ts:45 → src/payment/charge.ts:12)"],
existing_tests: ["test/checkout.test.ts", "test/payment.integration.ts"],
untested_flows: ["admin refund flow (no test found)"]
}
}
Pass code_context to Phase 1 (contract-deriver), Phase 2 (taskgraph-planner), and Phase 3 (journey detection) agent prompts alongside requirements.md content. This helps agents ground their output in actual file structure rather than inventing module names.
Phase 1: Contract Synthesis
Goal: produce the minimal cross-module surface area.
Step 1.1: Dispatch contract-deriver agent
Pass:
- Full
requirements.md content (you already read it in 0.2 — inline into agent prompt)
- Detected
meta.type
spec_dir absolute path
code_context summary from Phase 0.5 (if non-greenfield; omit for greenfield)
The agent writes <spec_dir>/contracts.md (markdown) and returns:
{
"artifact": "contracts.md",
"interfaces": ["InputAPI", "StorageAPI", "RendererAPI"],
"invariants": ["INV-1: ...", "INV-2: ..."],
"ambiguities": []
}
File existence is content-driven (all types). If the agent produces any invariants[] or interfaces[], it writes contracts.md. If there is genuinely nothing cross-module to pin, it returns "artifact": null and the invariants (if any) live in plan.contracts.invariants. This rule is the same for every meta.type; the type only decides the file's internal shape.
Step 1.2: Merge contracts into plan.json
cat > /tmp/bp-contracts.json << 'EOF'
{"contracts": {"artifact": "contracts.md", "interfaces": [...], "invariants": [...]}}
EOF
hoyeon-cli plan merge <spec_dir> --patch --json "$(cat /tmp/bp-contracts.json)"
Phase 2: Task Graph
Goal: every sub-requirement is fulfilled by ≥1 task; parallelism is explicit.
Step 2.1: Dispatch taskgraph-planner agent
Pass:
- Full
requirements.md content
- Phase 1 contracts summary (artifact name + interfaces + invariants)
meta.type
code_context summary from Phase 0.5 (if non-greenfield; omit for greenfield)
Expected output:
{
"tasks": [
{
"id": "T1",
"layer": "L0",
"action": "write contracts.md + storage sig util",
"fulfills": ["R-T2.1", "R-T7.1"],
"depends_on": [],
"parallel_safe": false
},
...
],
"ambiguities": []
}
Tasks carry WHAT, not HOW. The action string is the only description field; it must capture intent, not file paths / function names / estimated time. Workers decide implementation detail — locking HOW into plan.json causes drift when the worker discovers the real shape mid-implementation.
Step 2.2: Coverage gate (semantic, by you)
cli does NOT verify coverage against requirements.md. You must ensure:
-
Every R-X.Y sub-requirement appears in at least one tasks[].fulfills. Build a set diff:
uncovered = { all sub_req_ids } − union(tasks[].fulfills)
If uncovered is non-empty, re-dispatch taskgraph-planner with the list as a constraint. Max 2 retries. If still uncovered, surface to user.
-
No task references a non-existent sub-req ID (orphan). Drop orphans before merging.
-
Parallel safety: for each L1 task pair with parallel_safe: true, double-check they touch different modules and share only L0 contract state. If uncertain → set parallel_safe: false (serial is safe default).
Step 2.3: Preview task graph (informational)
Print the table so the user can see what got planned — but do not ask for approval. The coverage gate in 2.2 already verifies the graph is well-formed; asking "is this right?" forces the user to re-judge agent output they can't usefully correct without seeing code.
[blueprint] Task Graph (Phase 2)
| # | Layer | Action | Fulfills | Depends | Parallel |
|---|-------|--------|----------|---------|----------|
| T1 | L0 | write contracts.md + storage sig | R-T2.1, R-T7.1 | — | no |
| T2 | L1 | implement auth flow | R-U1.1, R-U1.2 | T1 | yes |
| ...
Coverage: 12/12 sub-reqs fulfilled (0 uncovered)
Only prompt when taskgraph-planner.ambiguities[] contains items with user_impact of time or confidence (see "Ambiguity Handling"). Otherwise proceed to 2.4 silently.
Step 2.4: Merge tasks into plan.json
cat > /tmp/bp-tasks.json << 'EOF'
{"tasks": [ ... ]}
EOF
hoyeon-cli plan merge <spec_dir> --append --json "$(cat /tmp/bp-tasks.json)"
Use --append on first write. Use --patch later if you need to update individual task fields by id.
Phase 3: Journey Detection
Goal: identify multi-sub-req user flows that need E2E coverage.
A journey composes ≥2 sub-requirements into a single linear user flow, with its own given/when/then. Example: "user signs up → confirms email → sees dashboard" might compose R-U1.1 (signup form) + R-U1.2 (email confirm) + R-U2.1 (dashboard initial render).
Step 3.1: Heuristic detection (inline by you)
Scan the sub-req list for clusters where:
- 2+ sub-reqs share a common actor (user, admin, API client)
- Their
when clauses chain naturally (next action follows prior outcome)
- There is a meaningful top-level outcome only visible after running them together
Not every spec has journeys. Bugfix specs usually have 0. Greenfield user-facing specs usually have 2-5.
Step 3.1b: Regression journey detection (non-greenfield only)
Skip if meta.type == greenfield or code_context.blast_radius is empty.
Scan code_context.blast_radius.affected_flows for existing flows that pass through modules being changed. For each affected flow, generate a regression journey with [regression] prefix in the name:
Heuristic: an affected flow becomes a regression journey when:
- It passes through ≥1 module that a task in the task graph modifies
- It represents a user-visible or API-facing behavior (not internal-only)
Link to tasks: identify which tasks (T1, T2, ...) touch the affected modules, and list them in the journey's composes field alongside any related new sub-req IDs.
Prioritize untested flows: flows from blast_radius.untested_flows are higher priority — they have no safety net and MUST become regression journeys if they are user-facing.
Regression journeys use the same schema as regular journeys — no schema change needed.
Step 3.2: Emit journey entries
For each detected journey:
{
"id": "J1",
"name": "new user onboarding",
"composes": ["R-U1.1", "R-U1.2", "R-U2.1"],
"given": "no prior account",
"when": "user completes signup → confirms email → lands on dashboard",
"then": "dashboard shows welcome state with 0 items"
}
Regression journey example (from Step 3.1b):
{
"id": "J3",
"name": "[regression] checkout flow preserved after payment module change",
"composes": ["R-T1.1", "R-T1.2"],
"given": "existing checkout flow works with valid payment",
"when": "user completes purchase after code changes from T3/T5",
"then": "checkout succeeds identically to pre-change behavior"
}
Constraints (enforced by schema):
id matches ^J\d+$
composes has ≥2 items, each is a valid R-X.Y id
given, when, then all non-empty strings
- Regression journeys use
[regression] prefix in name — same schema, no special type field
Step 3.3: Merge journeys
cat > /tmp/bp-journeys.json << 'EOF'
{"journeys": [ ... ]}
EOF
hoyeon-cli plan merge <spec_dir> --append --json "$(cat /tmp/bp-journeys.json)"
Phase 4: Verify Plan
Goal: every sub-req AND every journey gets a gate assignment.
4-Gate model (cumulative; each gate adds, never replaces)
| Gate | Name | What it means | Typical cost |
|---|
| 1 | machine | Deterministic check: unit test, type check, file contents, shell exit code | seconds, free |
| 2 | agent_semantic | LLM reads code/output and judges "does this match the described intent?" | ~1 minute, model call |
| 3 | agent_e2e | Real runtime observation: browser, computer-use, CLI run, API call | minutes, sandbox |
| 4 | human | Subjective judgment: playtest, aesthetic review, "feels right" | hours, blocking on user |
Baseline rules (always apply)
- Every sub-req and journey gets Gate 1 + Gate 2 as minimum.
- Journeys additionally get Gate 3 by default (journeys exist precisely because E2E flow matters).
- Regression journeys (name starts with
[regression]) get Gate 1 (run existing tests from blast_radius.existing_tests) + Gate 3 (E2E confirmation). Gate 1 is especially important here: if existing tests exist for the affected flow, running them IS the regression check. Gate 2 is optional for regression journeys (semantic review adds less value when the behavior should be identical to pre-change).
Add Gate 3 (agent_e2e) when sub-req involves:
- Visible UI behavior (
visible, rendered, displayed, shown, animation, screen shake, transition)
- User interaction (
click, tap, swipe, drag, hover, keyboard)
- External system calls (
fetch, request, API, database query, file IO where contents matter beyond schema)
- Platform-specific behavior (
mobile, desktop, browser tab, window)
Add Gate 4 (human) when sub-req involves:
- Subjective quality (
feel, good UX, intuitive, natural, fun, pleasant)
- Statistical/behavioral metrics requiring real users (
average retry rate, time-on-task, % of users who, sample size, playtest)
- Judgement calls no model can ground (
appropriate, reasonable, tasteful)
Step 4.1: Dispatch verify-planner agent
Pass:
- Full
requirements.md content (for GWT text)
- Full
journeys[] from Phase 3
- The 4-gate rules above
Expected output:
{
"verify_plan": [
{ "target": "R-T2.1", "type": "sub_req", "gates": [1, 2] },
{ "target": "R-U5.1", "type": "sub_req", "gates": [1, 2, 3] },
{ "target": "R-B3.1", "type": "sub_req", "gates": [1, 2, 4] },
{ "target": "J1", "type": "journey", "gates": [1, 2, 3] }
],
"ambiguities": []
}
Step 4.2: Self-check (by you)
- Every sub-req id from requirements.md appears exactly once as a
type: sub_req target.
- Every journey id appears exactly once as a
type: journey target.
- Every entry has
gates containing at least [1, 2].
gates is a sorted unique integer array, each element in [1..4].
If mismatch, re-dispatch verify-planner with the gap list. Max 2 retries.
Step 4.3: Preview verify plan for user
Translate gate counts into user-facing consequences. The user should not have to decode G1/G2/G3/G4 labels — only understand what the plan will cost them and where their attention is actually required.
[blueprint] Verify Plan
{N_all} checks will run automatically (code review + agent semantic)
{N_e2e} of those also run in the browser/sandbox (visible UI, interaction, external calls)
{N_human} items require YOU (playtest, sampled metrics, aesthetic review)
What you need to do: {none | <bullet list of G4 items with their GWT>}
Example with no G4:
[blueprint] Verify Plan
46 checks will run automatically
26 of those also run in the browser sandbox
0 items require you
What you need to do: nothing — fully machine/agent-verifiable.
Example with G4:
[blueprint] Verify Plan
18 checks will run automatically
7 of those also run in the browser sandbox
1 item requires you:
• R-B4.1 "retry rate averages 3+ per session" — needs a playtest with 3+ users
What you need to do: 1 playtest session.
Default = silent. Print the preview block and proceed to Step 4.4 unless one of the following user-owned decisions exists:
verify_plan contains any G4 target — the user has to commit real time (playtest, sampled metrics, aesthetic review)
ambiguities[] (collected across phases, after filtering — see "Ambiguity Handling") contains any item with user_impact of time or confidence
If neither applies, log auto-approving (no user-owned commitments) and continue. No generic "proceed?" prompt.
When to actually ask: only when the user has something real to decide. Build the question from the filtered ambiguities queue (see "Ambiguity Handling" section) and/or G4 confirmations:
AskUserQuestion(
# one question per user-impact ambiguity, phrased in user terms, NOT gate labels
# Example (time-impact):
question: "R-B4.1 needs real-user data ('retry rate averages 3+') — commit to a 3-user playtest, or relax this requirement to code-review only?",
options: [
{ label: "Commit to playtest", description: "Add human verification — you run a session with 3+ users before ship" },
{ label: "Relax the bar", description: "Drop the sampled-user requirement, rely on code review of the difficulty curve formula" }
]
)
Never expose "G1/G2/G3/G4", "gates: [1,2,3]", or "drop redundant G3" to the user. If the planner flagged an ambiguity that way, restate it: what real thing does the user gain/lose by each option?
If the user chooses to revise: apply the chosen option to verify_plan (add/drop gates as implied), re-preview once. Max 2 rounds, then proceed with the last-confirmed plan.
Step 4.4: Merge verify_plan
cat > /tmp/bp-verify.json << 'EOF'
{"verify_plan": [ ... ]}
EOF
hoyeon-cli plan merge <spec_dir> --append --json "$(cat /tmp/bp-verify.json)"
Phase 5: Commit
Step 5.1: Full validation
hoyeon-cli plan validate <spec_dir>
This runs schema validation AND these internal cross-ref checks:
tasks[].fulfills ⊆ verify_plan sub_req targets
journeys[].composes ⊆ verify_plan sub_req targets
- Every
journeys[].id has a verify_plan entry of type: journey
- Every
verify_plan type: journey target matches a declared journey id
tasks[].depends_on ⊆ tasks[].id
If validation fails, diagnose the specific rule violation and re-merge corrected JSON. Never ignore a validation failure.
Step 5.2: Summary (informational)
Print a compact summary and proceed. No approval prompt — Phase 4.3 already handled every user-owned decision (G4 commitments, time/confidence ambiguities). A final "y/n" here adds nothing the user can act on without reading code.
[blueprint] Plan complete.
Summary:
Type: greenfield
Tasks: 11 (L0:2, L1:5 parallel, L2:3, L3:1)
Journeys: 2
Verify: 18 entries (G1:18, G2:18, G3:7, G4:1)
Contracts: 5 interfaces, 3 invariants (contracts.md)
Next: /execute <spec_dir>/
Skip the summary entirely under --no-summary (used by /execute's inline call).
Step 5.3: Handoff
✅ Blueprint committed.
plan.json ← 11 tasks, 2 journeys, 18 verify entries
contracts.md ← 5 interfaces, 3 invariants
Next: /execute <spec_dir>/
Exit skill.
Ambiguity Handling (strict)
Rule: surface ambiguities to the user only when they own the decision — i.e., the outcome changes what they must do, pay for, or commit to. Planner-internal optimizations (redundant gates, CSS-vs-measurement, pure-logic gate sufficiency) are NOT user decisions; apply the agent's recommendation silently and log it.
All three agents return ambiguities[] with this shape:
{ "concern": "...", "affects": ["...", "..."], "recommendation": "...", "user_impact": "time" | "confidence" | "none" }
user_impact semantics (see verify-planner.md for the canonical definition):
time — forces human work (playtest, sampled metrics, aesthetic review). Always prompt.
confidence — meaningfully swings verification confidence with no safe default. Prompt unless --auto.
none — planner-internal call. Never prompt; apply recommendation and log.
Sources collected across phases:
- requirements.md
## Open Decisions section (OD-N blocks) — include if still unresolved (treat as user_impact: confidence by default)
- contract-deriver return field
ambiguities[]
- taskgraph-planner return field
ambiguities[]
- verify-planner return field
ambiguities[]
Agents that do not yet emit user_impact (older contract-deriver / taskgraph-planner outputs) default to confidence unless the concern is obviously planner-internal.
Protocol
- Collect — after each agent returns, extract its
ambiguities[] into a single queue.
- Filter — drop every item with
user_impact: none. Apply its recommendation to the in-progress artifact and record one line in the run log: auto-resolved: <concern> → <recommendation>.
- Dedupe — merge semantically overlapping items (e.g., OD-2 + a contract-deriver concern about the same decision). Prefer requirements.md wording as canonical.
- Translate — rewrite each remaining item in user-impact language: what does the user gain/lose from each option? Do NOT expose internal labels (G1-G4, gate ids, dispatch types) in the question or options.
- Prompt — emit
AskUserQuestion for the translated queue. AskUserQuestion tops out at ~5 questions per call; batch across multiple calls in order. Each option must include the agent's recommendation marked (recommended).
- Apply answers — patch the in-progress plan.json (or regenerate the affected section) before proceeding to the next phase.
Trust the filter. If the agent labeled something user_impact: none, do not second-guess and promote it to a prompt. The agents are instructed to be conservative; items that reach the queue with time or confidence already passed a "does the user own this?" test.
Flags
--auto → skip all prompts, apply every recommendation silently (including time / confidence items), log applied decisions in the final summary
- Default (no flag): prompt only for
user_impact in (time, confidence); always auto-resolve none
Agent Roster
| Agent | Phase | Owns |
|---|
contract-deriver | 1 | Writes contracts.md; returns interfaces + invariants + ambiguities |
taskgraph-planner | 2 | Returns tasks[] + ambiguities |
verify-planner | 4 | Returns verify_plan[] + ambiguities |
Agents are globally registered at plugin-root /agents/{name}.md. Dispatch via the Agent tool with subagent_type: "<name>".
Command Reference (blueprint-only subset)
All state changes go through cli with one --json per merge. Never hand-write plan.json.
hoyeon-cli plan init <spec_dir> --type greenfield
hoyeon-cli plan merge <spec_dir> --patch --json '{"meta":{...}}'
hoyeon-cli plan merge <spec_dir> --append --json '{"tasks":[...]}'
hoyeon-cli plan merge <spec_dir> --patch --json '{"tasks":[{"id":"T3","status":"in_progress"}]}'
hoyeon-cli plan validate <spec_dir>
JSON passing: always write to /tmp/bp-<step>.json via heredoc first, then pass with --json "$(cat ...)". Direct inlining breaks on zsh glob expansion ([, {, $).
Failure Modes
| Failure | Recovery |
|---|
requirements.md missing | Tell user to run /specify; abort |
plan validate schema error | Diagnose (cli prints specific path + message), re-merge corrected JSON |
plan validate cross-ref error (e.g., task fulfills missing from verify_plan) | Re-dispatch verify-planner with the missing ids |
| Uncovered sub-req after taskgraph-planner | Re-dispatch with uncovered list (max 2 retries), then surface to user |
| User rejects after blueprint commits | Do NOT revert files. User can edit requirements.md and re-run /blueprint, or edit plan.json directly via cli. |
Mode B: Inline call from /execute
When /execute is invoked without a plan.json, it may call this skill inline with --auto --no-summary. Same phases, no approval prompts. This is a flag combination, not a separate code path.
Non-Goals
- Re-interviewing requirements (that's /specify)
- Implementation work in src/ (contracts.md at spec_dir/ is the only artifact blueprint produces)
- Running verifications (that's /execute)
- Parsing requirements.md inside cli (LLM reads directly via Read tool)
- Rendering a human-readable view file (read
plan.json directly — it's structured and small)