From spade
Generate a structured SPADE Plan from a Scope. Use when a Scope exists and the human wants to move to planning, when someone says "plan this", "generate a plan", "break this down", or when an issue is in "Scoped" status and needs a plan. Also triggers when a human references a Linear issue and asks the AI to plan against it.
How this skill is triggered — by the user, by Claude, or both
Slash command
/spade:spade-planThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Before doing anything else, run `~/.spade/bin/spade-update-check` using the
Before doing anything else, run ~/.spade/bin/spade-update-check using the
Bash tool and show the output to the user if it is non-empty. If the script
does not exist or fails, skip silently and continue with the skill.
Read .spade/config in the current project directory. This file specifies
which Linear team, project, and default assignee to use. Use these values
for all Linear operations. If the file doesn't exist, ask the human which
team and project to use, or suggest running /spade-onboard first.
Before any tracker call or local-file access, resolve the operating mode
once per docs/FRAMEWORK.md § Mode Resolver:
mode: from .spade/config. An explicit value (linear,
local, or hybrid) wins immediately.mode: is absent, auto-detect: probe with a list_teams MCP call
(try/skip, 5-second timeout). Resolve linear if it returns a team
set containing linear.team_id; otherwise resolve local.mode with a configured team_id and a
failing probe is a fail-loud abort; an absent mode with a
failing probe degrades quietly to local.Do not embed the resolver algorithm — it is single-sourced in FRAMEWORK.md. The resolved mode governs every tracker-vs-local branch in this skill:
linear — the tracker is canonical; operate against Linear MCP.local — .spade/ files are canonical; make zero Linear MCP
calls; read and write the paths in FRAMEWORK.md § Local Layout.hybrid — the tracker is canonical; after a successful tracker
write, mirror to .spade/ best-effort per FRAMEWORK.md § Hybrid Mode.You are generating a structured Plan for an approved Scope. The Plan is a first-class artefact that gets documented and attached to the parent issue. It is not something that happens invisibly.
Planning is collaborative, not a monologue. You generate the Plan, but the human validates it before anything gets created in Linear.
How to run this conversation:
Read the Scope carefully. Understand the intent, acceptance criteria, and constraints.
Read ARCHITECTURE.md, PATTERNS.md, and ANTI-PATTERNS.md if they exist in the repository. Your Plan must conform to these documents.
Check .spade/learnings/ for prior learnings. If the directory
exists, glob .spade/learnings/*.md (ignore private/ unless the
human explicitly opts in). For each file, read the frontmatter and
surface entries that match the current Scope.
Cold-start threshold (v1.1.1). Count the number of active
non-archived entries under .spade/learnings/ (exclude
status: archived and the private/ subdirectory unless
opted-in). Call this count N.
N < 20, the tag-match threshold is 1 — a single shared
tag is enough to surface a learning. This is the cold-start
regime: a repo adopting SPADE starts with zero learnings, so
≥ 2 means the loop looks dead on day one.N ≥ 20, the tag-match threshold is 2 — require at
least two matching tags to surface a learning. At this volume
single-tag coincidence becomes noise; the higher bar filters it.scope_ref equals the current Scope's Linear identifier
always surfaces, regardless of N.So the match rule is: an entry surfaces if its scope_ref equals
the current Scope's identifier OR at least T of its tags appear
(case-insensitive, word-boundary match) in the Scope title or the
tech stack row of ARCHITECTURE.md, where T = 1 if N < 20 else 2.
Skip entries with status: archived.
The 20 is a deliberate, named number. Changing it requires a new
Scope. The rationale is documented in
docs/FRAMEWORK.md#learnings.
If the Scope references specific systems or components, review the relevant code or documentation to understand the current state.
If the Scope is missing required fields, flag this and suggest running
/spade-scope to complete it before planning.
Every Plan must include:
Break the Scope into 3-7 discrete tasks. Each task must be:
For each task, specify:
ai-delivered or human-deliverytest-first, characterization-first,
refactor-first, spike, or straight-through. This is a required
field on every task — see the posture selection guide below.Posture declares the delivery strategy for a task: not what to build
but how to approach the build. The canonical vocabulary and definitions
live in docs/FRAMEWORK.md#execution-posture. Quick selection:
test-first — the desired behaviour is well-specified; write
failing tests first, then satisfy them. Default for new features with
clear acceptance criteria.characterization-first — touching existing code without adequate
tests; pin down current behaviour in tests before changing it.
Default for bug fixes and refactors of untested code.refactor-first — the area can't cleanly absorb the new behaviour;
reshape it first, then add the new behaviour. The Plan must name the
refactor explicitly so reviewers can confirm it's in scope.spike — the correct approach is genuinely unknown; the task's
output is learning, not shippable code. A spike-postured task should
produce a decision record or follow-up task, not a merged PR.straight-through — the change is mechanical enough that extra
ceremony adds no value (typo fixes, config bumps, docs edits, one-liners
covered by existing tests). Not a silent default. If you choose
this, state the justification in the task body (usually "covered by
existing tests" or "mechanical change"). If you can't justify it,
pick a different posture.A task may declare mixed posture when the work naturally splits — e.g.
characterization-first on the existing module; test-first on the new behaviour. Write it on a single line.
For each task, explain the technical approach:
If any .spade/learnings/*.md entries matched the Scope (see "Before You
Start" step 3), include a Prior Learnings Considered section near the
top of the Plan. Each matched learning gets:
(2026-04-22-onboarding-must-be-idempotent.md).Match reason: scope_ref=<ID> when the scope_ref path fired.Match reason: tags matched [<tag1>, <tag2>, ...] when the tag
path fired — list only the tags that actually matched the Scope
title / tech stack, not the entry's full tag set.If a matched learning has status: archived, do not include it.
(The framework has no "supersedes" field — /spade-learn --refresh
resolves conflicts by archiving the superseded entry explicitly, so
the archived filter is the single source of truth.)
If no entries match, do not include the section at all. Silence is cheaper than padding — no "no matches found" line.
Example (cold-start regime, one-tag match):
### Prior Learnings Considered
- *Any write into a consumer file must be idempotent via delimited markers*
(`2026-04-22-onboarding-must-be-idempotent.md`) — Plan Bundle A extends
the existing `spade-marker-replace` contract rather than inventing a
new mechanism.
Match reason: tags matched [markers]
Example (scope_ref match):
### Prior Learnings Considered
- *For review and evaluation gates, a panel of persona-specific reviewers
beats one generalist*
(`2026-04-22-single-reviewer-is-weaker-than-panel.md`) — this Scope
preserves the panel shape; only adds verifiability layers.
Match reason: scope_ref=M-323
Identify risks and assumptions:
For each task:
Present the tasks in recommended execution order, noting which can run in parallel and which are sequential.
Group the tasks into delivery bundles. A bundle is the unit of shipping: one branch, one pull request, closing every sub-issue assigned to it.
Default: a single bundle containing every task in the Scope. Six interlinked tasks should not produce six PRs. Reviewers want the whole story in one place, and interlinked code that moves together should land together.
Only split into multiple bundles when all of these hold:
If you are unsure, use one bundle. You can always split later; you cannot easily re-merge six PRs.
For each bundle, specify:
etl-corespade/M-68-etl-corePresent the Plan in this format:
## Plan for: [Scope Title]
**Technical Approach Summary:**
[2-3 sentence overview of the overall approach]
**Risks and Assumptions:**
- [Risk 1]
- [Risk 2]
### Tasks
#### Task 1: [Title]
- **Mode:** ai-delivered | human-delivery
- **Depends on:** none | Task N
- **Effort:** brief | moderate | significant
- **Execution posture:** test-first | characterization-first | refactor-first | spike | straight-through
- **Description:** [What needs to be done]
- **Approach:** [How it will be done]
- **Tests:** [What tests / what evidence of completion]
[Repeat for each task]
### Delivery Sequence
1. [Task X] (no dependencies, start immediately)
2. [Task Y] (depends on Task X)
3. [Task Z] and [Task W] (parallel, both depend on Task Y)
### Delivery Bundles
#### Bundle 1: [name]
- **Branch:** spade/[issue-id]-[name]
- **PR title:** [title]
- **Tasks:** Task 1, Task 2, Task 3, Task 4
- **Rationale:** Single bundle — all tasks share the ETL module and must
land together to keep the pipeline coherent.
[If splitting, repeat per bundle with rationale for the split]
In linear and hybrid mode the Plan is canonically stored in the
tracker (today: Linear). In local mode .spade/plans/ is canonical;
it also serves as a fallback when a tracker write fails and a
read-path for historical archives written under v1.0–v1.1. Saving
happens when (and only when) the human approves the Plan, never before.
The behaviour gate is whether the tracker can accept the Plan, not merely "is the MCP tool present":
Tracker-path — the resolved mode is linear or hybrid, the
Scope has a parent issue ID, and posting the Plan as a comment on that
parent issue succeeds. In this path the Plan lives in Linear (as the
parent-issue comment + the sub-issues); in hybrid mode it is also
mirrored to .spade/plans/ best-effort. In pure linear mode do
not write to .spade/plans/.
Fallback-path — the resolved mode is local; or, in linear
mode, the Scope has no tracker parent or the Linear write fails. (A
tracker-write failure in hybrid mode aborts instead — there is no
local fallback; see FRAMEWORK.md § Hybrid Mode.) Write the Plan to
.spade/plans/<issue-id>-plan.md using the Scope's tracker
identifier; if the Scope has no issue ID — the local-mode case —
use the Scope's slug (its name field and .spade/scopes/
filename) so the file is .spade/plans/<scope-slug>-plan.md and
/spade-status and /spade-list can locate it.
Prepend a banner at the top of the body marking it a fallback
artefact, e.g.:
> **Fallback artefact.** Linear was unavailable when this Plan was
> approved; this file is the canonical Plan until it is promoted to
> the tracker.
After writing, suggest the human commit it:
git add .spade/plans/M-68-plan.md
git commit -m "SPADE plan for M-68 (Linear-less fallback)"
The plan-file frontmatter schema is unchanged — historical archives under v1.0–v1.1 and fallback writes under v1.2+ are schema-compatible:
---
issue: M-68
title: Build ETL pipeline for device telemetry
date: 2026-04-08
status: approved
---
Create .spade/plans/ lazily only when the fallback-path triggers; do
not pre-create the directory in tracker-path runs. If a fallback file
already exists for this issue (from a previous revision or a pre-v1.2.0
archive), overwrite it — git history preserves the old version.
In linear or hybrid mode, the tracker-path runs as follows:
ai-plannedai-delivered or human-delivery as appropriateneeds-arch-review if the task touches architecturebundle:<bundle-name> so delivery can group them under one PRIf any of those steps fails — MCP unreachable, parent issue missing,
comment write rejected — fall through to the fallback-path above and
write .spade/plans/<issue-id>-plan.md instead. Do not retry
indefinitely.
Surface partial state explicitly. If the failure happened mid-flow (for example: parent status moved to Planning, 3 of 7 sub-issues created, comment write then failed), tell the human exactly which steps succeeded and which did not — by sub-issue ID where applicable. The Plan in the fallback file is the single source of truth at that point; the half-created Linear state is something the human decides to clean up, complete manually, or leave as-is. Do not auto-delete partially-created sub-issues — destructive cleanup of shared tracker state is a human decision.
After presenting the Plan, explicitly ask the human to review and approve it. Do not begin delivery. Do NOT save the plan locally or create sub-issues until the human approves. Say something like:
"The Plan is ready for your review. Please check it against architecture alignment, completeness, feasibility, risk, task granularity, and delivery bundling. Let me know if you want changes, or approve it so I can begin delivery."
Once approved, follow the rule in "Saving the Plan" above:
.spade/plans/<issue-id>-plan.md with the fallback
banner.Either way, the Plan is now stored canonically and delivery can begin.
You must wait for explicit approval before proceeding to Deliver.
If the human requests changes:
plan-rejected label to the parent issue (if Linear available).spade/plans/<issue-id>-plan.mdplan-rejected and update status to "Approval" when readyWhen a Plan is written locally (fallback-path, or — anticipating M-879's hybrid mode — the local mirror path), invoke the SPADE renderer and surface a clickable browser link:
Run ~/.spade/bin/spade-render <path-to-plan.md> via Bash.
On success (exit 0), the renderer prints the absolute path of the
rendered .html to stdout. Print a closing line to the human in
the exact form:
View in browser: file://<absolute-path>.html
Modern terminals (iTerm2, Warp, VS Code, Terminal.app) auto-linkify
the file:// URL for cmd-click.
On render failure with exit code 2 (pandoc not installed), print instead:
(HTML render unavailable: install pandoc — https://pandoc.org/installing.html — to enable. .md at <path>)
Surface this hint on every Plan write until pandoc is installed (not one-time-per-session).
On any other render failure (exit 1 or 3), report the renderer's
stderr and continue. Never abort the Plan flow on render
failure — the .md file is the canonical artefact and must always
succeed.
In the pure tracker-path (Linear-canonical, no local file written), there is no markdown to render and no terminal link is emitted.
The renderer's mechanism (Pandoc invocation, template, stylesheet,
CSP, palette) is documented once in docs/FRAMEWORK.md §HTML
Rendering. Do not re-specify it here.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub chrisfmlyc/spades --plugin spades-anywhere