Announcement
Loaded skill: plan-milestone. Starting milestone planning workflow...
Core Principle
This workflow is:
filesystem-backed, deterministic, artifact-driven
No step relies on in-memory state.
All durable state is stored under:
/tmp/milestone-plan-{epic_issue_number}/
Execution Contract (NON-NEGOTIABLE)
This system operates as a strict pipeline.
Each step has:
- explicit file inputs
- explicit file outputs
- no reliance on conversational or in-memory state
At no point may a step:
- use unstored intermediate state
- modify outputs from previous steps unless explicitly allowed
- bypass filesystem artifacts
Phase Gate Contract (STRICT)
Gate 1 → Plan Complete
Step 3 cannot begin until:
- 00-skeleton.md exists
- all Test Intent Maps exist
- UI gating resolved or explicitly excluded
Gate 2 → UI Resolution Complete
A sub-issue is excluded from Step 3 if:
- ui_blocked = true AND ui_resolved != true
Gate 3 → Build Lock
Once Step 3 begins:
- Step 2 outputs are immutable
- Test Intent Maps cannot change
- no new sub-issues may be introduced
- UI state cannot be re-evaluated
Gate 4 → Approval Complete
GitHub creation only occurs if:
- ALL eligible sub-issues are approved
0) Resume / Initialize
If manifest exists:
- load
/tmp/milestone-plan-{epic}/manifest.json - ask: Resume or restart milestone plan?
If restart:
- delete directory
- reinitialize
1) Read Context (READ ONLY)
Fetch:
- Epic issue (
#{epic_issue_number}) - GitHub milestone metadata
.github/ISSUE_TEMPLATE/sub-issue.mddocs/coding-standards.md— git, commit, and PR conventions referenced during sub-issue draftingdocs/coding-standards-backend.mdanddocs/coding-standards-frontend.md— read for domain conventions, naming patterns, and layer boundaries. These inform## Context & Constraintsand## Domain & Datacontent, not implementation steps- Backend scope:
src/.editorconfig - Frontend scope:
frontend/.editorconfig - Any architectural decisions, stack choices, naming conventions, or design constraints established earlier in the current session
Extract:
milestone_title: fetch the epic's assigned GitHub milestone viagh issue view {epic_issue_number} --json title,body,milestone. Used only for the--milestoneflag when creating sub-issues in Step 4 — sub-issue titles never carry a milestone tag.- If the epic has no milestone assigned, stop and ask the user to assign one on GitHub first. Do not proceed until confirmed, and do not fall back to parsing a tag out of the epic's own title text.
Store into manifest.
If .github/ISSUE_TEMPLATE/sub-issue.md cannot be found, stop execution and
inform the user. This file is the authoritative structure for Step 3 (3.0,
3.2) and the workflow cannot proceed without it.
2) Plan Phase (Deterministic Output Generation)
This phase produces ONLY filesystem artifacts.
2.1 Sub-issue decomposition
Reason about what sub-issues are needed to fully deliver the milestone's acceptance criteria. Consider:
- Behaviour groupings — group by cohesive user-facing or system-facing behaviour, not by technical layer. A story that covers "user login" includes both the API contract and the login screen; it is not split into backend/frontend sub-issues.
- Logical sequencing and blocking dependencies — which stories must land before others can be started.
- Scope boundaries — what belongs in this milestone vs. a later one.
- Testability reasoning per sub-issue — for each derived sub-issue, reason
about what observable behaviours can be verified. Think in terms of: given a
state, when an action occurs, what outcome is guaranteed? This reasoning
drives the
## Acceptance Criteria (G/W/T)content captured in the Test Intent Map (2.2). If a sub-issue produces no testable behaviour (config-only, dependency updates, pure scaffolding), flag it as having empty criteria.
Do NOT plan sub-issues around layers (domain layer, infrastructure layer, etc.) unless the epic itself is purely technical scaffolding with no user-facing behaviour. For feature milestones, a story boundary is a behaviour boundary.
Important: Do NOT create separate "test" sub-issues. Every feature sub-issue owns its acceptance criteria. Testing-related AWAs copied from the epic are informational only and do not generate sub-issues.
Important: Do NOT create separate frontend-only sub-issues. Each screen must be part of the same sub-issue as its backend behaviour.
Output:
/tmp/milestone-plan-{epic}/00-skeleton.md
This file is the ONLY source of truth for sub-issue structure. It must record, per sub-issue:
- Proposed title (without milestone prefix yet)
- Proposed labels — chosen only from labels that already exist in the
repository. Run
gh label list --json nameand take the label set of two or three comparable recent issues (gh issue list --state all --json number,title,labels) as the pattern to follow; match their granularity rather than inventing a coarser umbrella name. Step 4 refuses to create labels, so a name invented here becomes a blocked hand-off later. - Blocking relationships / dependencies
- Whether it has testable behaviour (or is flagged empty)
2.2 Test Intent Map (SOURCE OF TRUTH)
For each sub-issue, create:
/tmp/milestone-plan-{epic}/issues/{id}/test-intents.json
This is the ONLY definition of behaviour.
It contains:
- UC codes
- GIVEN / WHEN / THEN
Derive one or more [UC_CODE] criteria using the placeholder form
{ISSUE}UC{n} (e.g. {ISSUE}UC1, {ISSUE}UC2) per epic AC this sub-issue
contributes to — {ISSUE} is resolved to this sub-issue's real issue number
in Step 4, once the issue exists. Each criterion maps to exactly one
verifiable behaviour. When a sub-issue spans both backend and frontend, group
entries under backend and frontend. If the sub-issue was flagged as
having no testable behaviour, this file contains an empty criteria set.
IT codes are not invented here — record which of the epic's own
## Acceptance Criteria codes (already {epic_issue_number}IT{n}, fixed at
epic-authoring time) this sub-issue covers, and copy them verbatim (code and
checkbox text). IT codes never use the {ISSUE} placeholder and never need
resolution in Step 4.
Test Intent Maps are IMMUTABLE after Step 2 completes.
2.3 UI Audit + Stitch Gate
This step consumes the ordered sub-issue list produced in 2.1. The "Sub-Issue" column in the audit table below references those sub-issues by title.
Audit every acceptance criterion in the epic. For each AC, ask: "Does a human interact with the system to satisfy this?"
Important distinctions the audit must apply:
- An admin is a human. If an AC says "Admin can create a user", the admin needs a screen — even if the result is delivered out-of-band.
- A user is a human. If an AC says "User can log in", the user needs a login screen.
- "Out-of-band delivery" refers to how a result reaches the human (email, SMS, etc.), but the human still needs a UI to trigger the action.
- Do NOT create separate frontend-only sub-issues. Each screen belongs in the same sub-issue as its associated behaviour.
Record the audit as a table in 00-skeleton.md:
| AC | Human Interaction? | Screen Required | Sub-Issue |
|---|
For each AC that requires a screen, ensure the corresponding sub-issue is
marked layer: frontend alongside its backend labels in 00-skeleton.md.
Sub-issues with no human interaction keep their existing labels.
If a sub-issue requires UI:
Generate Page Architecture:
- Screen description
- Component hierarchy (mermaid)
- User interaction flow (sequence diagram)
Then mark:
- ui_blocked = true
If Stitch output is returned:
- store in
/tmp/milestone-plan-{epic}/issues/{id}/ui.md - set ui_resolved = true
2.4 Step 2 Completion Rule (HARD GATE)
Step 2 is COMPLETE ONLY IF:
00-skeleton.md exists
all test-intents.json files exist
all UI-required issues are either:
- ui_resolved OR excluded
2.5 Step 2 Output Restrictions
Step 2 MUST NOT produce:
- GitHub issues
- draft markdown
- acceptance criteria
- G/W/T formatting
ONLY structured filesystem artifacts.
3) Build Phase (Strict File-Only Rendering)
3.0 Step 3 Input Contract (CRITICAL)
Step 3 may ONLY use:
- /tmp/milestone-plan-{epic}/00-skeleton.md
- /tmp/milestone-plan-{epic}/issues/*/test-intents.json
- /tmp/milestone-plan-{epic}/issues/*/ui.md
- .github/ISSUE_TEMPLATE/sub-issue.md
NO OTHER INPUTS ARE ALLOWED.
3.1 Hard Filter (UI Exclusion Rule)
Exclude from Step 3 any sub-issue where:
- ui_blocked = true
- AND ui_resolved != true
These issues are NOT visible to Step 3.
3.2 Template Authority Rule
All issues MUST be built from:
.github/ISSUE_TEMPLATE/sub-issue.md
Template is authoritative over all structure. Each issue body must strictly follow this structure. Sub-issue bodies do NOT include file paths, function signatures, or implementation steps — the sub-issue describes what and why; the implementing agent determines how.
3.3 Versioned Issue Model
Each sub-issue stored at:
/tmp/milestone-plan-{epic}/issues/{id}/
Versions:
- draft-v1.md
- draft-v2.md
- final.md
- meta.json
Each version is a FULL snapshot.
3.4 Drafting Rules
Each draft snapshot follows .github/ISSUE_TEMPLATE/sub-issue.md section-for-
section. Populate each template section from the Step 3 inputs (3.0) as
follows:
| Template section | Source |
|---|---|
| Title | [Feature] {title} from 00-skeleton.md |
| Overview | Authored from the sub-issue's behaviour grouping in 00-skeleton.md |
| Epic Reference | #{epic_issue_number}; Work Areas copied verbatim from epic AWA; Acceptance Criteria Covered = selective [IT_CODE] list from test-intents.json |
| Context & Constraints | Coding standards + prior session decisions; known constraints; related issues |
| Functional Requirements | Observable system behaviours only — no file names or signatures |
| Domain & Data | Entities/relationships/business rules — no schema or column types |
| API / Interface Contract | Endpoints, events/side-effects, UI entry points (frontend only) |
| Page Architecture | Only if layer: frontend and ui.md resolved — rendered directly from issues/{id}/ui.md |
| Acceptance Criteria (G/W/T) | Rendered directly from test-intents.json; grouped ### Backend / ### Frontend if both; empty if test-intents.json has empty criteria |
| Out of Scope | Scope boundaries from 00-skeleton.md; reference deferred work by #issue or future milestone |
Sub-issue bodies must not include file paths, function signatures, or implementation steps — the implementing agent determines how.
Anticipated Work Areas does not appear in sub-issues — it belongs to the epic only (Step 6).
3.5 Approval Loop
Drafts are reviewed on disk, never pasted into the conversation. Issue bodies run to hundreds of lines; echoing each revision of each sub-issue burns the context this workflow needs for the phases that follow.
For each sub-issue:
Write the full snapshot to
issues/{id}/draft-vN.mdbefore saying anything about it.Give the user the absolute path to that file and ask:
"Does this look correct, or do you have changes?"
Alongside the path, add a short summary — a few lines at most:
- what the story covers, in one sentence
- any judgement call worth the user's attention: an assumption made where the inputs were silent, a conflict found between the inputs and the current source, or a place where a design reference and the brief disagree
- nothing else — no section-by-section recap, no restating requirements that are in the file
Never render the drafted body, or excerpts of it, into the conversation. If the user asks about a specific part, answer the question rather than quoting the section back.
Wait for the user's response, then proceed according to one of:
APPROVE
- promote current draft to final.md
- mark approved in manifest
- confirm: "Draft for [Feature] {title} approved and stored."
- move to the next sub-issue
MODIFY
- incorporate all feedback
- generate a new full snapshot version, stored as
draft-vN.md - propagate the feedback to every artifact it touches, not just the draft in
hand —
00-skeleton.md, the affectedtest-intents.json,ui.md, and any later sub-issue carrying the same assumption. A role change, a renamed screen, or a new filter is rarely confined to one file. - re-present per the numbered steps above: path plus a short note naming only what changed
- repeat 3.5 until approved
CLARIFY
- ask one question
- no file changes
Verifying a suggestion before adopting it
When the user proposes a technical approach, check it against the current source before writing it into a draft. If the codebase already settles the question, say so with the evidence — file and line — recommend the option that matches what is there, and let the user decide. Adopting a suggestion that quietly contradicts an established convention costs more to unwind later than the question costs to ask now.
3.6 Step 3 Completion Rule
Step 3 is complete only when:
- all eligible issues have final.md
4) GitHub Creation Phase
Only after ALL approved:
- Pre-flight: verify every planned label already exists on GitHub.
- Collect every unique label across the sub-issues from
00-skeleton.md. - Run
gh label list --json nameand parse the existing labels. - Every planned label must match an existing one exactly. A label that does
not exist is a planning error, not a gap to fill — it almost always means
a coarser or invented name was chosen over the taxonomy the repo already
uses (e.g. a single
layer: backendwhere the repo distinguisheslayer: domain,layer: application,layer: api,layer: db,layer: infrastructure). - On any mismatch, stop and resolve it with the user before creating
anything: show the unmatched label alongside the closest existing labels
and the sets used by comparable recent issues, and recommend a
replacement drawn from what exists. Never run
gh label createon your own initiative — create a label only if the user explicitly asks for it. - Correct
00-skeleton.mdand the manifest to the agreed labels before proceeding, so the artifacts match what is actually applied.
- Collect every unique label across the sub-issues from
- Create issues via
gh issue create— iterate over thefinal.mdbodies in order:- Run
gh issue createwith--title,--milestone "{milestone_title}"(from Step 1 — omit the flag entirely if the epic has none),--label,--body-file. - Verify the exit code. If creation fails, notify the user with the error output and stop.
- On success, capture the created issue number.
- Resolve placeholders: substitute every
{ISSUE}occurrence in the just-created body with the real issue number (this only ever affects UC codes — IT codes already carry the epic's real number and need no substitution), then rungh issue edit {number} --body-filewith the patched body. Verify the exit code; if the edit fails, notify the user with the error output and stop — never leave an issue with an unresolved{ISSUE}placeholder in its body. - Confirm to the user: "Created #{number}: {title}"
- Run
- Store issue number + URL in manifest
5) Linking Phase (Robust Mode)
For each issue:
Attempt GraphQL:
- Fetch the GraphQL node IDs for the epic and all created sub-issues in a
single query:
gh api graphql -f query='{ repository(owner: "OWNER", name: "REPO") { epic: issue(number: EPIC) { id } i1: issue(number: N1) { id } ... } }' - For each sub-issue, run the
addSubIssuemutation:
Note: the REST API returns 404 for sub-issue linking — GraphQL is the only working approach.gh api graphql -f query='mutation { addSubIssue(input: {issueId: "PARENT_ID", subIssueId: "CHILD_ID"}) { issue { number } subIssue { number } } }'
Fallback:
- comment-based epic linking list
6) Epic AWA Safe Patch
6.1 Locate AWA block
/<!-- AWA_START -->(.*?)<!-- AWA_END -->/
6.2 Rules
- modify only inside markers
- idempotent inserts
- no reordering
- no deletions
- never uncheck or remove existing checked items
6.3 Entry format
- [ ] [Feature] Title (#{number})
6.4 Missing block
Append:
## Anticipated Work Areas
<!-- AWA_START -->
<!-- AWA_END -->
6.5 Atomic update
Single:
gh issue edit
7) Cleanup (Optional)
If enabled:
- delete
/tmp/milestone-plan-{epic}/
8) Final Output
Return:
- total issues created
- issue list (number + URL)
- epic update confirmation
- manifest path