SPEC-0007: Sprint Planning
Overviewโ
A standalone skill that resolves an existing specification, detects the user's issue tracker, and decomposes spec requirements into trackable work items (epics, tasks, sub-tasks). Supports six trackers (Beads, GitHub, GitLab, Gitea, Jira, Linear), persists tracker preferences to .claude-plugin-design.json, and falls back to tasks.md generation when no tracker is available. See ๐ ADR-0008.
Requirementsโ
Requirement: Spec Resolutionโ
The /sdd:plan skill SHALL accept a spec identifier as its primary argument. The identifier MAY be a SPEC number (e.g., <a href="/specs/init-and-priming/spec#spec-0003" className="rfc-ref">SPEC-0003</a>) or a capability directory name (e.g., web-dashboard). The skill MUST resolve the identifier to the corresponding spec directory under docs/openspec/specs/.
Scenario: Resolution by SPEC numberโ
- WHEN a user runs
/sdd:plan <a href="/specs/init-and-priming/spec#spec-0003" className="rfc-ref">SPEC-0003</a> - THEN the skill SHALL scan
docs/openspec/specs/*/spec.mdfor a file whose title contains<a href="/specs/init-and-priming/spec#spec-0003" className="rfc-ref">SPEC-0003</a>and use the containing directory
Scenario: Resolution by capability nameโ
- WHEN a user runs
/sdd:plan web-dashboard - THEN the skill SHALL look for
docs/openspec/specs/web-dashboard/spec.mdand use that directory
Scenario: No argument providedโ
- WHEN a user runs
/sdd:planwith no spec identifier (ignoring flags) - THEN the skill SHALL list all available specs by globbing
docs/openspec/specs/*/spec.md, reading each title, and usingAskUserQuestionto let the user choose
Scenario: Spec not foundโ
- WHEN the provided identifier does not match any existing spec
- THEN the skill SHALL inform the user and suggest running
/sdd:specto create one
Requirement: Spec Readingโ
The skill MUST read both spec.md and design.md from the resolved spec directory before creating any issues. The skill MUST NOT create issues based on partial information.
Scenario: Both files readโ
- WHEN the skill resolves a spec directory
- THEN it SHALL read both
docs/openspec/specs/{capability-name}/spec.mdanddocs/openspec/specs/{capability-name}/design.mdto understand the full scope of requirements, scenarios, and architecture
Requirement: Tracker Detectionโ
The skill SHALL detect the issue tracker following this strict precedence order, where each step short-circuits the next when it produces an unambiguous answer: (1) saved preference, (2) git-remote inference, (3) tooling probe, (4) tasks.md fallback. Step 1 is covered by the Preference Persistence requirement and step 4 by the tasks.md fallback requirement; this requirement specifies steps 2 and 3.
When step 1 finds a saved preference whose tooling is no longer available, the skill MUST skip directly to step 3 โ it MUST NOT fall through to step 2. A saved Jira/Linear/Beads preference must not be silently replaced by whatever the git remote happens to point to.
Step 2 โ Git-remote inference. When the project is a git repository, the skill SHALL run git remote get-url origin, parse the URL, normalize the host, and match against the host-pattern table below. A unique match MUST be used directly without prompting.
URL parsing. The skill MUST handle URL-style remotes (https://, ssh://, git://) and SSH scp-form remotes (git@host:owner/repo.git) with form-specific host extraction:
- URL-style: After the scheme
://, strip any userinfo (everything up to and including the first@) โ this prevents auth tokens from leaking into matches or logs. The host is the next segment up to/or:. Discard any:portsuffix. - SSH scp-form: The portion before
@is the SSH login user (typicallygit), NOT auth credentials โ discard it but do not treat it as a token. The host is between@and the first:. The path follows the first:.
After host extraction, the skill MUST: (a) lowercase the host and strip any trailing dot; (b) strip any trailing .git from the path; (c) extract owner and repo from the path. Both owner/repo (after the first : for scp form) and /owner/repo (after the first / for URL form) MUST be supported. These populate tracker-specific configuration without a follow-up prompt.
Host matching rule. Match the normalized host against patterns using exact-FQDN or leading-label matching, NOT substring or unanchored matching:
| Pattern | Matches | Tracker |
|---|---|---|
Host equals github.com | github.com only | GitHub |
Host equals gitlab.com OR FQDN leading label is gitlab | gitlab.com, gitlab.example.com | GitLab |
FQDN leading label is gitea | gitea.com, gitea.stump.rocks, etc. | Gitea |
"FQDN leading label is X" is defined as: split the normalized host on . to obtain a list of labels; match if and only if (a) the first label exactly equals X, and (b) the host has at least two labels (i.e., not bare X alone). This rule MUST be implemented by label-list comparison, NOT by regex against the full host string. Examples: gitlab.example.com matches; gitlab (single label) does not; notgitlab.example.com does not. A host like gitlab.com.malicious.example does technically match the leading-label rule โ this is acceptable because (a) a developer whose origin points to such a host configured it themselves, (b) the tracker pick does not transmit credentials, and (c) attackers cannot register gitlab.com itself.
Hosts that fall through to step 3 include but are not limited to: GitHub Enterprise on a custom domain, codeberg.org, git.sr.ht, corporate forges, and any host not matching the table above. The table is a conservative whitelist โ growth happens via explicit additions, not regex laxity.
Inference SHALL also fall through to step 3 when: the project is not a git repository; the project has multiple remotes pointing to different platforms and origin's host does not match a known pattern (the skill MUST NOT silently use a non-origin remote); the project uses a non-VCS-derivable tracker (Jira, Linear, Beads).
Step 3 โ Tooling probe. When inference does not yield an unambiguous tracker, the skill SHALL probe for available trackers via ToolSearch and CLI availability checks. The six supported trackers are:
- Beads: Detect via
.beads/directory in the project root orbd --versionCLI check - GitHub: Detect via
ToolSearchformcp__*github*tools orgh --versionCLI check - GitLab: Detect via
ToolSearchformcp__*gitlab*tools orglab --versionCLI check - Gitea: Detect via
ToolSearchformcp__*gitea*tools - Jira: Detect via
ToolSearchformcp__*jira*tools - Linear: Detect via
ToolSearchformcp__*linear*tools
The full precedence flow is documented in references/shared-patterns.md ยง "Tracker Detection".
Scenario: Inferred from HTTPS GitHub originโ
- WHEN the project's
originremote URL ishttps://github.com/joestump/example.gitand no saved preference exists - THEN the skill SHALL use GitHub as the tracker without prompting, and SHALL pre-populate
owner=joestumpandrepo=examplein the tracker configuration
Scenario: SSH scp-form URL parsedโ
- WHEN the project's
originremote URL isgit@gitea.example.com:team/repo.git - THEN the skill SHALL infer Gitea as the tracker, extract
owner=teamandrepo=repo, and strip the trailing.git
Scenario: SSH URL form with portโ
- WHEN the project's
originremote URL isssh://git@gitlab.example.com:2222/team/repo.git - THEN the skill SHALL infer GitLab via the leading-label rule, extract
owner=teamandrepo=repo, and ignore the port
Scenario: HTTPS URL with auth token strippedโ
- WHEN the project's
originremote URL ishttps://x-access-token:TOKEN@github.com/owner/repo.git(CI environment) - THEN the skill SHALL strip the userinfo before host matching, infer GitHub from the bare host, and SHALL NOT log or save the token
Scenario: Substring match rejectedโ
- WHEN the project's
originremote URL ishttps://notgitlab.example.com/owner/repo.git - THEN the host matching rule SHALL reject this โ the first label is
notgitlab, notgitlabโ and the skill SHALL fall through to step 3
Scenario: Remote host unknown โ fall through to probeโ
- WHEN the project's
originremote URL ishttps://corporate-forge.example.com/team/repo.git(no host pattern match) - THEN the skill SHALL fall through to step 3 (tooling probe) and detect available trackers there
Scenario: Codeberg falls throughโ
- WHEN the project's
originremote URL ishttps://codeberg.org/owner/repo.git - THEN the skill SHALL fall through to step 3 โ codeberg.org is a Gitea-based forge but its hostname does not match the conservative whitelist
Scenario: Not a git repositoryโ
- WHEN the project root has no
.git/directory - THEN the skill SHALL skip step 2 entirely and proceed directly to step 3
Scenario: Multiple remotes โ origin matchesโ
- WHEN the project has
origin โ github.com/...andmirror โ gitea.example.com/... - THEN the skill SHALL use
originfor inference and pick GitHub, treatingmirroras informational only
Scenario: Multiple remotes โ origin does not matchโ
- WHEN the project has
origin โ corporate-forge.example.com/...andmirror โ github.com/... - THEN the skill SHALL fall through to step 3 โ it MUST NOT silently use the
mirrorremote's GitHub host
Scenario: Saved tracker tooling vanished โ skip step 2โ
- WHEN a saved preference names
linearbut the Linear MCP server is no longer available, and the project'soriginremote points togithub.com - THEN the skill SHALL warn the user and skip directly to step 3 (tooling probe), NOT to step 2 โ silently switching from Linear to GitHub via remote inference is not permitted
Scenario: Multiple trackers detected (probe step)โ
- WHEN step 2 does not produce a unique tracker and the probe in step 3 detects more than one
- THEN the skill SHALL use
AskUserQuestionto let the user pick one and SHALL include an option to save the choice as the default
Scenario: Exactly one tracker detected (probe step)โ
- WHEN step 2 does not produce a unique tracker and the probe in step 3 detects exactly one
- THEN the skill SHALL use it and ask the user if they want to save it as the default
Scenario: No tracker detectedโ
- WHEN no tracker is detected after both steps 2 and 3
- THEN the skill SHALL fall back to generating
tasks.mdper the tasks.md fallback requirement
Requirement: Preference Persistenceโ
The skill SHALL persist tracker preferences to .claude-plugin-design.json in the project root when the user opts in. On subsequent invocations, the skill MUST check for a saved preference before running tracker detection.
Scenario: Saved preference exists and tracker is availableโ
- WHEN
.claude-plugin-design.jsonexists with a"tracker"key and the saved tracker's tools are still available - THEN the skill SHALL use the saved tracker and configuration directly without prompting
Scenario: Saved preference exists but tracker is unavailableโ
- WHEN
.claude-plugin-design.jsonexists with a"tracker"key but the saved tracker's tools are no longer available - THEN the skill SHALL warn the user ("Your saved tracker '{name}' is no longer available. Detecting other trackers...") and fall through to tracker detection
Scenario: Saving preferenceโ
- WHEN the user agrees to save their tracker choice
- THEN the skill SHALL write or merge into
.claude-plugin-design.json:The{
"tracker": "{tracker-name}",
"tracker_config": {}
}tracker_configobject SHALL store tracker-specific settings:- GitHub/Gitea/GitLab:
{ "owner": "...", "repo": "..." } - Jira:
{ "project_key": "..." } - Linear:
{ "team_id": "..." } - Beads:
{}(no extra config needed)
- GitHub/Gitea/GitLab:
Scenario: Merging with existing .claude-plugin-design.jsonโ
- WHEN
.claude-plugin-design.jsonalready exists with other keys - THEN the skill SHALL merge the tracker keys without overwriting the entire file
Requirement: Issue Creation Flowโ
The skill SHALL create issues following an epic-to-task-to-sub-task hierarchy derived from the spec's requirements.
Scenario: Epic creationโ
- WHEN the skill begins creating issues for a spec
- THEN it SHALL first create an epic (or tracker equivalent) titled "Implement {Capability Title}" with a body referencing the spec number and linking to the spec and design files
Scenario: Task creation from requirementsโ
- WHEN the spec contains
### Requirement:sections - THEN the skill SHALL create one task per requirement as a child of the epic, with the requirement name as the title
Scenario: Acceptance criteriaโ
- WHEN a task is created for a requirement
- THEN the task body MUST include acceptance criteria derived from the requirement's WHEN/THEN scenarios in the format:
## Acceptance Criteria
- [ ] Per SPEC-XXXX REQ "Requirement Name": {normative statement}
- [ ] Per SPEC-XXXX Scenario "Scenario Name": WHEN {trigger} THEN {outcome}
- [ ] Governing: ADR-XXXX ({decision title})
Scenario: Sub-task creation for complex requirementsโ
- WHEN a requirement has three or more scenarios
- THEN the skill MAY create sub-tasks for individual scenarios as children of the requirement task
Scenario: Dependency orderingโ
- WHEN requirements have logical ordering (setup before implementation, core before extensions)
- THEN the skill SHALL set up dependency relationships using the tracker's native features
Requirement: Project Groupingโ
The /sdd:plan skill SHALL organize created issues into tracker-native projects. The default behavior SHALL be one project per epic. The user MAY override this behavior with flags or .claude-plugin-design.json configuration. See ๐ ADR-0009.
Scenario: Default project grouping (one project per epic)โ
- WHEN the skill creates an epic and its associated tasks
- THEN the skill SHALL create a tracker-native project named after the epic title and SHALL add the epic and all child tasks to that project
Scenario: Single combined project via --project flagโ
- WHEN the user runs
/sdd:plan SPEC-XXXX --project "Q1 Sprint" - THEN the skill SHALL create or locate a project with the specified name and SHALL add all created issues (epics, tasks, sub-tasks) to that single project
Scenario: Skip project creation via --no-projects flagโ
- WHEN the user runs
/sdd:plan SPEC-XXXX --no-projects - THEN the skill SHALL skip project creation entirely and SHALL NOT attempt to group issues into any project
Scenario: Tracker without project supportโ
- WHEN the detected tracker does not support native projects (or the project API is unavailable)
- THEN the skill SHALL skip project creation, log a note in the planning report ("Project grouping skipped: {tracker} does not support projects"), and continue with issue creation
Requirement: Branch Naming Conventionsโ
The /sdd:plan skill SHALL include a "Branch" section in each created issue's body with a recommended branch name. Branch names SHALL follow a deterministic pattern derived from the issue number and a slug. See ๐ ADR-0009.
Scenario: Default branch names for tasks and epicsโ
- WHEN the skill creates a task issue with number
{N}for a requirement named{name} - THEN the issue body SHALL include a Branch section with
feature/{N}-{slug}where{slug}is the kebab-case form of{name} - AND WHEN the skill creates an epic issue with number
{N}for a capability named{name} - THEN the issue body SHALL include a Branch section with
epic/{N}-{slug}
Scenario: Custom branch prefix via --branch-prefix or .claude-plugin-design.jsonโ
- WHEN the user provides
--branch-prefix work/on the command line or has"branches": { "prefix": "work/" }in.claude-plugin-design.json - THEN the skill SHALL use the custom prefix instead of
feature/for tasks (epics SHALL still useepic/) - AND command-line flags SHALL take precedence over
.claude-plugin-design.jsonvalues
Scenario: Omit branch sections via --no-branchesโ
- WHEN the user runs
/sdd:plan SPEC-XXXX --no-branches - THEN the skill SHALL omit the Branch section and the PR Convention section from all created issue bodies
Scenario: Slug derivationโ
- WHEN deriving a slug from a requirement or epic name
- THEN the skill SHALL convert the name to lowercase, replace non-alphanumeric characters with hyphens, collapse consecutive hyphens, trim to a maximum of 50 characters, and strip trailing hyphens
Scenario: Issue number required for branch names (two-pass creation)โ
- WHEN the skill creates an issue that needs a branch name in its body
- THEN the skill SHALL first create the issue with core content (title, acceptance criteria), obtain the issue number from the tracker's response, and then update the issue body to add the Branch and PR Convention sections referencing that number
Requirement: PR Conventionsโ
The /sdd:plan skill SHALL include a "PR Convention" section in each created issue's body with tracker-specific close keywords. The close keywords SHALL automatically resolve the issue when the PR/MR is merged. See ๐ ADR-0009.
Scenario: GitHub and Gitea PR conventionsโ
- WHEN the detected tracker is GitHub or Gitea
- THEN the PR Convention section SHALL contain
Closes #{issue-number}and SHALL reference the parent epic and governing spec (e.g., "Part of #{epic-number} | SPEC-XXXX")
Scenario: GitLab MR conventionsโ
- WHEN the detected tracker is GitLab
- THEN the PR Convention section SHALL contain
Closes #{issue-number}formatted for inclusion in the MR description
Scenario: Beads conventionsโ
- WHEN the detected tracker is Beads
- THEN the PR Convention section SHALL contain
bd resolveas the close command
Scenario: Jira and Linear conventionsโ
- WHEN the detected tracker is Jira or Linear
- THEN the PR Convention section SHALL contain the tracker-native key reference format (e.g., Jira issue key
PROJ-123, Linear issue identifier) for auto-linking and resolution
Requirement: Tasks.md Fallbackโ
When no issue tracker is detected, the skill SHALL generate a tasks.md file at docs/openspec/specs/{capability-name}/tasks.md, co-located with spec.md and design.md. The file MUST follow the format specified in SPEC-0006.
Scenario: Fallback file generationโ
- WHEN no tracker is detected and the skill falls back to
tasks.md - THEN the skill SHALL generate
docs/openspec/specs/{capability-name}/tasks.mdwith tasks derived from spec requirements, using numbered section headings and checkbox format
Scenario: Fallback task formatโ
- WHEN
tasks.mdis generated - THEN every task SHALL be a checkbox item matching
- [ ] X.Y Task descriptionand SHALL reference the governing requirement
Requirement: Review Modeโ
When the --review flag is present, the skill SHALL spawn a planning team for peer review of the issue breakdown.
Scenario: Team creationโ
- WHEN the user runs
/sdd:plan SPEC-XXXX --review - THEN the skill SHALL create a team with a planner agent and a reviewer agent using
TeamCreate
Scenario: Reviewer validationโ
- WHEN the reviewer receives the issue breakdown
- THEN the reviewer SHALL verify that every spec requirement has at least one corresponding issue, acceptance criteria correctly reference WHEN/THEN scenarios, dependency ordering is logical, and issue scope is session-sized
Scenario: Revision roundsโ
- WHEN the reviewer requests revisions
- THEN a maximum of 2 revision rounds SHALL be allowed, after which the reviewer approves with noted concerns
Scenario: TeamCreate failureโ
- WHEN
TeamCreatefails - THEN the skill SHALL fall back to single-agent mode and proceed without review
Requirement: Planning Reportโ
After creating issues (or generating tasks.md), the skill SHALL present a summary to the user.
Scenario: Report contentsโ
- WHEN planning is complete
- THEN the skill SHALL report: which tracker was used (or tasks.md fallback), the number of epics, tasks, and sub-tasks created, where the user can find them, and a suggestion to run
/sdd:primebefore starting implementation
Requirement: Tracker-Specific Configurationโ
When a tracker requires configuration not already saved in .claude-plugin-design.json (e.g., repo owner/name for GitHub, project key for Jira), the skill SHALL use AskUserQuestion to gather it. The skill SHALL offer to save the configuration to .claude-plugin-design.json.
Scenario: GitHub/GitLab/Gitea config neededโ
- WHEN GitHub, GitLab, or Gitea is selected and no
owner/repoconfig is saved - THEN the skill SHALL ask the user for the repository owner and name
Scenario: Jira config neededโ
- WHEN Jira is selected and no
project_keyconfig is saved - THEN the skill SHALL ask the user for the Jira project key
Scenario: Linear config neededโ
- WHEN Linear is selected and no
team_idconfig is saved - THEN the skill SHALL ask the user for the Linear team ID
Requirement: Gap Analysis Mode (Proposed)โ
This requirement is OPTIONAL and describes a future capability.
When invoked as /sdd:plan SPEC-XXXX --gaps, the skill MAY read the spec's requirements, scan the codebase for implementation, and identify requirements that are unimplemented or partially implemented. The skill MAY then create issues for the gaps found.
Scenario: Gap analysis invocationโ
- WHEN a user runs
/sdd:plan <a href="/specs/init-and-priming/spec#spec-0003" className="rfc-ref">SPEC-0003</a> --gaps - THEN the skill MAY read the spec requirements, scan the codebase for implementations matching each requirement, and report which requirements lack implementation
Scenario: Gap issue creationโ
- WHEN gaps are identified
- THEN the skill MAY create issues only for unimplemented or partially implemented requirements, rather than for all requirements
Requirement: Code Quality Analysis Mode (Proposed)โ
This requirement is OPTIONAL and describes a future capability.
When invoked as /sdd:plan --analyze (no spec argument required), the skill MAY scan the codebase for DRY violations, dead code, untested code paths, and security issues, and create issues for findings.
Scenario: Code quality invocationโ
- WHEN a user runs
/sdd:plan --analyze - THEN the skill MAY scan the codebase without requiring a spec argument and identify DRY violations, dead code, untested paths, and security issues
Scenario: Code quality issue creationโ
- WHEN code quality issues are identified
- THEN the skill MAY create issues categorized by type (DRY, dead code, untested, security) with evidence from the codebase
Related Artifactsโ
Direct relationships declared in YAML frontmatter (per ADR-0023 / SPEC-0018). Run /sdd:graph chain SPEC-0007 for the transitive view.