From sweetclaude
Manages roadmap targets (milestones) that span strategy and product work. Invoked by the SweetClaude framework to track or pause milestone state.
How this skill is triggered — by the user, by Claude, or both
Slash command
/sweetclaude:product-milestonesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
!`bash ${CLAUDE_SKILL_DIR}/../../hooks/read-state.sh session-state`
!bash ${CLAUDE_SKILL_DIR}/../../hooks/read-state.sh session-state
Manage milestones: $ARGUMENTS
A milestone is a roadmap target — a named strategic outcome the project is driving toward. Not a release, not a sprint, not an epic. Examples: "Exit Stealth", "Paid Pilot Live", "Series A Readiness", "MVP Shipped".
Read .sweetclaude/state/skills.yaml.
Schema migration: If skills.yaml exists with schema_version: 1, migrate this skill's entry before proceeding:
enabled: true → status: active, last_changed_at: {onboarded_at or today}, last_changed_by: migratedenabled: false with onboarded_at set → status: paused, last_changed_at: {offboarded_at or onboarded_at or today}, last_changed_by: migratedenabled: false with onboarded_at: ~ → status: uninitialized, last_changed_at: ~, last_changed_by: ~
Drop onboarded_at/offboarded_at. Set schema_version: 2. Write atomically (see write protocol below).Dependency check:
Read ${CLAUDE_PLUGIN_ROOT}/config/skills-registry.yaml. Find skills.product-milestones.dependencies. This skill has no dependencies — skip.
If skills.yaml does not exist, OR exists but has no entry for skills.product-milestones:
{base_path}/milestones/MILESTONES-INDEX.md existsstatus: active, last_changed_at: {today}, last_changed_by: migratedstatus: uninitialized, last_changed_at: ~, last_changed_by: ~If skills.yaml exists and has an entry for skills.product-milestones:
status: active → proceed normallystatus: paused AND $ARGUMENTS not in [onboard, offboard, pause]:
"Milestones are currently paused. Resume? [yes/no]" If yes: write
status: active,last_changed_at: {today},last_changed_by: resume(using write protocol). Proceed normally. If no: stop.
status: uninitialized AND $ARGUMENTS not in [onboard, offboard, pause]:
→ Run lightweight first-invocation flow (see below)$ARGUMENTS is pause → run pause operation$ARGUMENTS is offboard and status: uninitialized: "Milestones aren't set up yet. Nothing to offboard." Stop.$ARGUMENTS is pause and status: paused: "Already paused." Stop.$ARGUMENTS is pause and status: uninitialized: "Not set up yet. Nothing to pause." Stop.Write protocol — all skills.yaml writes must follow this:
.sweetclaude/state/skills.yaml (or start from default v2 structure if absent).sweetclaude/state/.skills.yaml.tmpmv .sweetclaude/state/.skills.yaml.tmp .sweetclaude/state/skills.yamlState writes (use write protocol for all):
status: active, last_changed_at: {today}, last_changed_by: first-invocationstatus: active, last_changed_at: {today}, last_changed_by: onboardstatus: paused, last_changed_at: {today}, last_changed_by: pausestatus: active, last_changed_at: {today}, last_changed_by: resumestatus: uninitialized, last_changed_at: {today}, last_changed_by: offboardBefore writing any artifact file:
Read .sweetclaude/artifact-privacy.yaml. If it does not exist, stop and say:
"No artifact privacy manifest found. Run
/sweetclaude:setupto configure artifact privacy, then return here." Do not guess a path. Do not fall back to a default.
Read categories.product.base_path. This is the base directory for all product artifacts.
Construct full paths as {base_path}/{subfolder}/{filename}, preserving existing subdirectory structure (e.g. if base is .sweetclaude/product, milestones go to .sweetclaude/product/milestones/MS-001.md).
Write artifacts to those paths.
Classify the invocation by the first word of $ARGUMENTS:
| First word | Operation |
|---|---|
onboard | First-time setup — scan for existing data and migrate |
offboard | Export data and optionally remove SweetClaude artifacts |
add | Create a new milestone |
review | List milestones grouped by Now / Next / Later |
link <ISSUE-NNN> <MS-NNN> | Attach an issue to a milestone |
status <MS-XXX> | Detail view of one milestone |
blockers <MS-XXX> | List what's unfinished on a milestone |
complete <MS-XXX> | Mark a milestone achieved + chain follow-ups |
unassigned | Find work items with no milestone |
If $ARGUMENTS is empty or doesn't match, default to review.
{base_path}/milestones/
MILESTONES-INDEX.md Master index (one row per milestone)
MS-001-short-name.md One file per milestone
MS-002-short-name.md
...
MS-XXX. Read the index, find the highest number, increment by 1.# MS-XXX: Title
**Status:** proposed | active | achieved | dropped | superseded
**Sequence:** ~
**Owner:** [name/role]
**Depends on:** (other MS-XXX refs, if any)
## Outcome
One paragraph describing what this milestone represents and why it matters.
## Measuring success
- [ ] Criterion 1 (each evaluable as true/false)
- [ ] Criterion 2
- [ ] Criterion linked to artifact: `strategy/narrative-arc.md` finalized
## Non-goals
- What this milestone is explicitly NOT
- Second explicit exclusion
## Contributing work items
- ISSUE-012 — Landing page redesign
- ISSUE-007 — Analytics tracking
## Notes
Free-form log of decisions, scope changes, blockers encountered.
---
## Changelog
| Version | Date | Change summary |
|---------|------------|----------------------|
| 1.0 | YYYY-MM-DD | Initial draft |
| Status | Meaning |
|---|---|
proposed | Drafted, not yet committed. Appears in "Later". |
active | Currently being driven. Appears in "Now". Can be multiple. |
achieved | All criteria met; user confirmed. Terminal state. |
dropped | Abandoned with rationale in Notes. Terminal state. |
superseded | Replaced by a newer milestone. Links to successor in Notes. Terminal. |
Routes by $ARGUMENTS first word (see Routing above) into one of 11 sub-operations defined in operations.md:
| Sub-op | Purpose |
|---|---|
pause | Set status to paused — leave files intact |
offboard | Export to GitHub / markdown / CSV, then optionally delete |
| Lightweight first-invocation | Auto-runs when status = uninitialized; creates index, optional GitHub import |
onboard | Explicit first-time setup; scans for existing milestone/roadmap data |
add | Create a new MS-XXX milestone |
review | List milestones grouped Now / Later (and Achieved / Dropped if --all) |
link <ISSUE-NNN> <MS-NNN> | Bidirectional attach an issue to a milestone |
status <MS-XXX> | Detail view: criteria, contributing work items, recent notes |
blockers <MS-XXX> | List unmet criteria, open work items, unmet dependencies |
complete <MS-XXX> | Mark achieved, prompt for follow-ups (delegated to product-parking-lot) |
unassigned | Hygiene scan — work items without a Milestone header |
Read operations.md and execute the matching sub-section.
The milestones skill is the single source of truth for milestone data. Other skills should follow this protocol rather than writing their own milestone logic:
sweetclaude:project-issues: after creating an issue, prompt "Assign this issue to a milestone? [list of active + proposed milestones, or 'none / later']". On user selection, invoke sweetclaude:product-milestones link <ISSUE-NNN> <MS-NNN>.sweetclaude:product/sprint-plan: after stories are chosen for a sprint, read each story's **Milestone:** header. Report which milestones the sprint advances and count unassigned stories. If > 50% of sprint stories are unassigned, flag it as a scope concern.sweetclaude:status: in the orient view, include an "Active milestones" section showing each active milestone with its criterion-met count.Strategy skills (strategy/narrative-arc, product/market-messaging, etc.) are not modified. Milestones reference their canonical artifacts by path as Measuring-success criteria; the milestones skill reads those files directly.
The product/backlog skill is not modified, but is invoked indirectly by the complete operation's follow-up chain.
{base_path}/milestones/. The index is an index only.MS-XXX IDs are permanent. Never renumber. Gaps are fine.link updates both sides. Any skill that adds or removes a work item from a milestone must do the same.achieved, dropped, superseded) are never edited back to non-terminal. To re-activate a deprecated goal, create a new milestone that references the old one in its Notes.## Non-goals.These are documented in docs/milestones-skill-design-v1-2026-04-20.md as open for a follow-up iteration:
proposed milestones.achieved milestones to docs/milestones/archive/.npx claudepluginhub carson-sweet/sweetclaude --plugin sweetclaudeCreates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.