spec-to-plan — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited spec-to-plan (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The skill is named `spec-to-plan`; the product/CLI it drives is the `devague plan` command group. (The prior leg — turning a vague idea into a spec — is the sibling `/think` skill.) It is the forward peer of the working-backwards spec engine: where /think converges on what to build, /spec-to-plan converges on how to build it.
A plan is seeded from a converged frame and tracks tasks against the spec's coverage targets. The CLI is deterministic and move-driven — you (the agent) choose the next move; the CLI tracks state and tells you what's still missing. Run devague plan learn for the method and devague plan explain <move> for any single move.
The entry point is scripts/spec-to-plan.sh. Invoke it from the repository you are speccing (plans persist under .devague/ in the current directory, alongside the frames they derive from):
bash .claude/skills/spec-to-plan/scripts/spec-to-plan.sh <move> [args...]
bash .claude/skills/spec-to-plan/scripts/spec-to-plan.sh statusIt resolves the CLI portably — an installed devague on PATH (the normal case), falling back to uv run devague inside the devague checkout, else an install hint. Every move — including status — is forwarded verbatim as devague plan <move>, so you can equally call the CLI directly (devague plan <move> …).
| Move | What it does |
|---|---|
new --frame <slug> | Seed a plan from a converged frame. Derives the coverage targets (c*/h*) the plan must satisfy. Refuses an unconverged frame. |
task "<summary>" | Add a task. --accept "<crit>", --dep <tN>, --covers <c*/h*> (each repeatable); --origin llm lands it proposed. |
accept <tN> "<crit>" | Add an acceptance criterion to a task. |
depend <tN> --on <tM> | Record that task tN depends on tM. |
cover <tN> --target <c*/h*> | Mark a task as covering a coverage target. |
confirm <tN> / reject <tN> | Resolve a task. User-only decision. |
risk "<text>" --kind <kind> | Record a first-class plan risk (--task <tN> to attach). |
converge | Evaluate the gate against the live source frame; list remaining gaps. |
export | Write the buildable plan to docs/plans/ — only after converge passes. |
waves | Emit deterministic dependency waves ({plan, waves}) — scheduling metadata only, not orchestration. Read-only, works on an in-progress plan; refuses a cyclic/dangling graph. Devague describes the graph; an operator decides how to run it (#20). |
status | Read-only: where the plan stands + the recommended next move, re-checked against the live frame (--json too). |
show / list | Render a plan / list plans (--json for raw state). |
learn / explain <move> | Teach the method / explain one move. |
Risk kinds (shared with the frame engine): unknown_nonblocking, unknown_blocking, out_of_scope, follow_up.
status — the next-move verbstatus is a first-class, read-only CLI verb (devague plan status, internalised from this wrapper in 0.11.0 — issue #30). It composes devague plan list + devague plan converge and prints where the current plan stands, the remaining gaps, and the recommended next move derived from the first gap. Like converge/export it re-checks the live source frame (so frame drift surfaces as an error), but it never mutates state. Pass --json for the structured payload ({plan, total, ready_for_plan, blockers, warnings, parked_items, required_next_moves}).
plan: my-feature (1 plan total)
convergence: NOT passed — 2 gap(s):
- coverage target c5 (boundary) has no confirmed task
- task t2 has no acceptance criteria
recommended next move (first gap):
cover c5: devague plan task "<summary>" --covers c5 --accept "<...>"Run it whenever you're unsure what to do next.
These are the point of the method — convergence must mean something.
plan new refuses a frame that hasn'tconverged. The plan's coverage targets are the spec's confirmed claims and honesty conditions — there is nothing honest to plan against until the spec converges.
--origin llm lands asproposed. Never `confirm` your own proposal. Confirmation is a user-only decision — surface the proposed task and let the user confirm or reject it.
coverage target to be covered by a confirmed task, and every confirmed task to carry at least one acceptance criterion. Don't hand-wave a task as "done-ish."
acyclic graph; the gate rejects dangling deps and cycles.
decision is an unknown_blocking risk — it holds back convergence, by design.
converge/export re-load the sourceframe every time. If the frame was deleted or has regressed below convergence, they refuse — re-converge the spec (in /think) first.
When authoring a plan that will be built via parallel execution (fanned out to multiple agents via the downstream /assign-to-workforce skill), prefer the following discipline to maximize parallelism and minimize merge friction:
Each task should be small enough for a simpler or cheaper model to build test-first without re-deriving the full design. If a task spans multiple files or architectural layers, split it — narrow scope forces you to write sharp acceptance criteria and keeps waves wide.
Prefer tasks that touch non-overlapping files. When two same-wave tasks modify the same file, merge collision becomes inevitable. The dependency graph alone does not guarantee file disjointness — it only sequences task content dependencies; same-wave tasks with overlapping file-writes must be split across waves or given explicit dependencies.
Check devague plan waves output: if a wave is wide but all tasks touch src/core.py, the wave is formally parallel but operationally serialized at merge. Reorder task boundaries so wide waves operate on disjoint file sets.
Every confirmed task must carry at least one acceptance criterion, phrased as a testable condition (not a vague outcome). For example:
data loss"
Acceptance criteria are the contract between the main agent (who merges) and the subagent (who builds). A test suite derived from these criteria validates each task's output before merge, independent of model capability. This is not optional: devague plan converge warns (non-blocking) when a confirmed task lacks criteria.
A plan built in parallel must yield identical results to building it serially. This is guaranteed only if:
waves).passes them independent of whether it was built in isolation or alongside other tasks.
The TDD gate — tests pass before and after the merge — is the main agent's proof that parallelism didn't break correctness.
Once your plan converges, devague plan waves emits the dependency-graph as scheduling metadata (ordered batches of task IDs). This feeds directly into the /assign-to-workforce skill, which:
assignments).
wave).
to the next wave.
Plan for workforce execution early: narrow task scope, write crisp acceptance criteria, and strive for wide waves with disjoint files.
Results go to stdout, diagnostics and errors to stderr — a strict split you can rely on when parsing. Pass --json to any move for a structured payload. Exit code 0 on success, non-zero on user error (with a hint: line). Plans live under .devague/plans/ in the current directory; the exported plan-md lands in docs/plans/.
Picking up after /think exported a spec for the frame my-feature:
p() { bash .claude/skills/spec-to-plan/scripts/spec-to-plan.sh "$@"; }
p new --frame my-feature # seeds the plan + its coverage targets
p show # see the c*/h* targets you must cover
p task "Build the core engine" --accept "engine has a convergence gate" \
--covers c1 --covers c3
p task "Pressure-test honesty conditions" --dep t1 --covers h1 --covers h2 \
--accept "every honesty condition maps to a test"
# Park a genuine unknown instead of guessing:
p risk "exact rollout sequencing" --kind unknown_nonblocking
p status # what's left + the next move
p converge # gate; resolve any listed gaps
p export # writes docs/plans/my-feature.md once convergedThe exported plan-md is a buildable artifact: topologically ordered tasks, each with acceptance criteria and the spec targets it covers. It feeds directly into implementation (or superpowers:writing-plans).
This is a first-party skill — its origin is agentculture/devague, where the devague agent maintains it alongside the tool it operates (dogfooding), next to its sibling /think. It is the inverse of the other skills under .claude/skills/, which devague vendors from steward. When ready, steward pulls it from devague and broadcasts it to the rest of the AgentCulture mesh. The cite, don't import policy still holds: downstream repos copy it, they don't symlink or depend on it. See docs/skill-sources.md.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.