Skip to content

Make SDD flow aware of inter-feature dependencies via stacked PRs #16

Description

@nicolehaugen

Summary

Teach the SDD flow about inter-feature dependencies, and let the existing pr-stack skill turn those dependencies into stacked PRs automatically — no new stack tooling, just SDD-driven orchestration.

Declare that one feature depends on another — Spec Kit and stacked PRs do the rest.

The problem

Spec Kit walks users through one feature at a time. But real features often build on each other: Feature B needs code from Feature A. Today that means:

  • Wait for Feature A to be reviewed and merged before starting Feature B (blocks parallel work).
  • Start B anyway without visibility into A''s code, inventing placeholders that get thrown away.
  • Combine both into one giant PR that reviewers can''t follow.

Real example — issues logged on github/spec-kit:

  • #4210 — Add deterministic contribution IDs and stack lookup IDs for resolved artifacts
  • #4212 — Add specify artifact command exposing composition stacks as JSON

#4212 depends on #4210. Running each in its own Copilot session today, the #4212 session branched off main and had no visibility into #4210''s in-flight work.

What already exists

  • Stacked pull requests — GitHub feature that lets PR B target PR A before A is merged; reviews happen in parallel; upstream changes auto-rebase; merging the top lands the whole stack.
  • pr-stack skill — already ships in the Copilot app; wraps gh-stack for creating/managing stacks.
  • Spec Kit + spec-kit-copilot — handle intra-feature dependency ordering (phases, [P] markers, Dependencies & Execution Order in tasks.md) but have no first-class notion of feature-to-feature dependencies.

Gap

Spec Kit has no way to say "Feature #4212 depends on Feature #4210" such that any command acts on it. The spec.md "Assumptions" section is prose, not machine-readable, and assumes the dependency is already merged.

Proposal

Extend the existing spec-kit-copilot SDD skills (primarily speckit-workflow-step / speckit-workflow) to be stacks-aware. Delegate all Git/PR mechanics to the existing pr-stack skill. No new skill, no new user-visible commands in the MVP, no changes to core spec-kit.

Dependency declaration (any of these, unified internally)

Read whichever is available, in priority order:

  1. Explicit prompt at kickoff — "stack on #4210."
  2. GitHub sub-issue / tracked-by links on the issue.
  3. Depends on: #NNNN line in the issue body.
  4. dependencies: frontmatter in spec.md (persists after issue is closed).

All resolve to {feature_id, upstream_prs, upstream_branches}.

Hooks into each SDD phase

Phase New behavior when a dependency exists
Session kickoff Detect deps → if unmerged upstream PR exists, prompt to stack → call pr-stack to check out on top of upstream branch.
/specify Load upstream spec.md as context. Write structured ## Dependencies into new spec.
/plan Load upstream plan.md and contracts. Do not re-plan interfaces upstream owns.
/tasks Skip tasks upstream delivers; tag consuming tasks with [upstream:#NNNN].
/analyze Cross-check assumptions against upstream contracts. Flag drift.
/implement Runs against a working tree that already includes upstream code — real APIs, no stubs.
PR creation Call pr-stack submit → PR targets upstream branch; stack map included in body.
Upstream changes Auto-call pr-stack restack → rerun /analyze to flag invalidated assumptions.

SDD canvas changes

  • Stack lane — features in a stack render as connected columns in dependency order.
  • Layer badge on each card: "Layer 2 of 3, base: #4210".
  • Merge-readiness indicator per layer.
  • Base preview — clicking the base opens the upstream feature''s canvas in a side panel.

Worked example — #4210 → #4212

  1. #4212 issue body says Depends on: #4210.
  2. Session opens on #4212. Plugin detects the dep, calls pr-stack to base the branch on #4210''s branch.
  3. /specify runs with #4210''s spec as context.
  4. /plan and /tasks reference #4210''s ContributionId API directly.
  5. /implement writes real code against real APIs.
  6. pr-stack submit opens PR #4212 targeting #4210''s branch.
  7. #4210 reviewer renames ContributionIdArtifactRef; force-pushes.
  8. Plugin auto-triggers pr-stack restack on #4212 → reruns /analyze → flags affected tasks → /implement patches them.
  9. #4210 merges. #4212 auto-retargets to main. Merge queue lands it.

Delivery plan

MVP (small)

  • Extend speckit-workflow-step to read deps from issue body + spec.md frontmatter.
  • Auto-call pr-stack add at kickoff, pr-stack submit at end of /implement.
  • Write dependencies: into spec.md.

Phase 2

  • Upstream context injection into /specify, /plan, /tasks, /analyze.
  • Auto pr-stack restack + /analyze rerun on upstream change.

Phase 3

  • SDD canvas stack lane.
  • Sub-issue / tracked-by detection.
  • Content-based inference fallback in /analyze.
  • Optional /speckit.stack escape hatch command if users request explicit control.

Non-goals

  • No changes to core spec-kit templates or commands.
  • No reimplementation of stack mechanics — pr-stack owns that.
  • No new user-visible skill or command surface in the MVP.
  • No non-GitHub host support (stacked PRs are GitHub-only).

Framing

Spec Kit already handles dependencies inside a feature. This makes it aware of dependencies between features — and lets stacked PRs carry that awareness all the way through review and merge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions