epic-workflow
Skill1 starsChanged 38 days agoMITView on GitHub
Breaks an initiative too big for one PLAN.md into ordered, independently shippable units, then dispatches them one at a time through task-workflow. Triggers: 'break this epic down', 'too big for one task', /epic-workflow.
In this repository23 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- harness-auditSkill
- skill-benchSkill
- ask-biginSkill
- bigin-harness-setupSkill
- contract-syncSkill
- debug-workflowSkill
- discovery-workflowSkill
- flutter-figma-handoffSkill
- go-scaffoldSkill
- knowledge-distillSkill
- model-routerSkill
- napkinSkill
- next-scaffoldSkill
- nodejs-scaffoldSkill
- nuxt-marketing-scaffoldSkill
- nuxt-scaffoldSkill
- nuxt-ui-figma-handoffSkill
- project-scaffoldSkill
- session-handoffSkill
- sprint-distillSkill
- task-workflowSkill
- write-testsSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 23
Triage: Run the ladder in ${CLAUDE_PLUGIN_ROOT}/skills/discovery-workflow/references/triage-ladder.md.
- Very specific: line 27
Clarify — conditional on an approved PRD: Check docs/product/prd.md first.
- Distinctive: line 53
Decompose: Every unit must satisfy all four:
- Very specific: line 95
Rebuild the graph: if graphify-out/graph.json exists: propose graphify update ..
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
epic-workflow
The layer above task-workflow. task-workflow takes one task to shipped code; this decides what the tasks are and in what order, then feeds them in one at a time.
It adds no gate of its own. Every unit still goes through task-workflow's spec gate — approving an epic approves the decomposition, never a unit's spec, and .claude/memory/EPIC.md deliberately does not satisfy spec-gate-guard.mjs. Don't try to make it: the guard reads PLAN.md at the repo root, and an epic-level approval standing in for five unwritten specs is exactly the drift the gate exists to stop.
When not to use
- The request fits one
PLAN.md— one spec, one implement/verify loop, one mergeable diff. That'stask-workflow. Decomposing it costs a session and buys nothing. - A bug, however tangled.
debug-workflowtriages it; the fix is one task. - Nobody can write acceptance criteria for it yet. Rung 3 —
discovery-workflowruns first, and its PRD comes back here. - A roadmap. More than ~8 units isn't an epic — see the ceiling in step 3.
Steps
Triage. Run the ladder in
${CLAUDE_PLUGIN_ROOT}/skills/discovery-workflow/references/triage-ladder.md. It is stated once and shared by all three entry points, so a request typed here lands on the same rung it would have reached throughtask-workflowordiscovery-workflow.Only rung 2 continues. This skill is rung 2, and it refuses in both directions. Below the bar the work is rung 1 — say so in one sentence and hand straight to
task-workflow, don't decompose to justify the invocation. Where the initiative is stated but its product shape isn't settled it is rung 3, and there is nothing here to decompose from: hand todiscovery-workflow, whose PRD comes back to this skill at step 2.Clarify — conditional on an approved PRD. Check
docs/product/prd.mdfirst.epic-workflowonly ever reads this file — it never writes or amends it, at any step.A PRD exists, is
Status: approved(or has noStatus:line), and the initiative is what it covers: read it and ask zero clarifying questions — the PRD already answers everything this step is allowed to ask about, through a fixed mapping:PRD field Answers The requirement index The unit candidates — one unit per FR, or one unit per tight FR cluster sharing a Surface:; never one unit spanning two unrelated FRs. An FR with two surfaces (Surface: web, api) becomes one unit per surface, ordered by step 3's last rule, each citing the same FRDepends on:Blocked by— the only legitimate source of a Blocked-by edge when decomposing from a PRDSurface:The two-plus-surfaces half of step 1's triage bar Priority:(must/should/could)What the first epic-sized slice contains when the PRD exceeds the ~8-unit ceiling — mustfirstEach FR's acceptance criteria That unit's Acceptancecell, quoted from the PRD, never paraphrased, so the unit's own spec gate is audited against the PRD's own words. A quoted criterion inherits the PRD's roles-never-people rule — a real name surfacing in one is fixed in the PRD, never edited out ofEPIC.mdCite the FR IDs a unit covers so the decomposition is traceable back to the contract, and name out loud any active requirement no unit covers, as deferred.
Edge cases:
Status: draft— not a decomposition source. Report it and ask: approve it throughdiscovery-workflowfirst, or proceed with the questions below. Don't silently decompose a draft; a draft PRD's IDs can still move.- No
Status:line — treat as approved, same rulediscovery-workflowalready uses. Status: withdrawnrequirement — never becomes a unit, and never becomes aBlocked by.- PRD exists but the initiative is unrelated to it — say so in one sentence and fall through to the questions below. A PRD on disk is not a claim that every later epic derives from it.
- PRD yields more than ~8 units — the existing ceiling in step 3 still wins; slice by
Priority:,mustfirst, and say what was deferred. - Index and FR blocks disagree — the block wins (already the PRD's own rule); say which line was stale rather than reconciling silently.
- An FR's acceptance criteria can't hold without a later unit — it is not one unit; split or reorder it. Step 3's four decomposition rules still govern; a PRD does not exempt a unit from them.
- Resuming an in-flight
EPIC.md(step 8) — unchanged: never re-read a PRD to re-decompose an approved queue.
No PRD, a draft one, or an unrelated one: Up to 3 questions, and only about what changes the decomposition: sequencing, what's explicitly out, which surface is authoritative when two disagree. Not implementation detail — each unit's own spec gate asks those later, with the relevant code in front of it. Never invent a decomposition over an unasked question.
Decompose. Every unit must satisfy all four:
- One plan's worth — one spec, one implement/verify loop, one reviewable diff, one surface. If a unit needs two specs or touches two surfaces, it's two units:
task-workflowonly accepts rung 1 of the ladder, so a two-surface unit would be handed straight back here. - Independently verifiable — it has acceptance criteria that hold without any later unit existing. A unit whose only test is "unit 4 works" isn't a unit.
- Leaves the repo green and shippable —
mainmust be able to ship with units 1..k done and k+1..n absent. Dead-but-tested code behind a flag is fine; a half-applied migration or a contract with no implementation is not. - Ordered by artifact dependency, not by convenience — contracts and migrations first, consumers after. Set
Blocked byonly where a real artifact dependency exists; units with none are parallelizable, and say so (see${CLAUDE_PLUGIN_ROOT}/skills/task-workflow/references/parallelization.mdfor the worktree rule).
Ceiling: ~8 units. Past that the scope is a roadmap, not an epic. Say so, then propose the first epic-sized slice of it and note what you've deferred — don't queue twenty rows nobody will reach.
- One plan's worth — one spec, one implement/verify loop, one reviewable diff, one surface. If a unit needs two specs or touches two surfaces, it's two units:
3b. Design doc — when the epic earns one. The decomposition says what the units are; nothing else in this harness says how the initiative is built or what was rejected, and that reasoning otherwise survives only in merged PR descriptions. Draft docs/design/{slug}.md to the template in references/design-doc.md, which carries the bar for when one is warranted.
Three of its rules matter enough to state here. **Skipping is normal** — an obvious shape, or every unit following a pattern the repo already has, means no doc — **but a silent skip is not**: say in one sentence that you skipped it and why, in the same message as the decomposition. **The Design section opens with a `mermaid` diagram**, because this is a document humans read and a system's shape lands in a picture faster than in three paragraphs. And it is **drafted, not written** — step 4's gate covers it, step 5 writes it.4. Approval gate. Present the unit table — and the design doc, where step 3b drafted one — in chat and wait. This is the epic's one gate, and it now covers both artifacts. Write nothing to disk before approval — an unapproved queue file on disk is indistinguishable from an approved one on the next session's resume.
- Write the queue to
.claude/memory/EPIC.md. Format and worked example:references/epic-queue.md. When the decomposition came from a PRD, the queue gains aPRD:header line and aCoverscolumn, both PRD-derived-only. If a file is already there with open rows, that's step 8, not this step. Where step 3b drafted a design doc, write it todocs/design/{slug}.mdin the same step, same slug — the two are read together. - Dispatch one unit. Take the first row that is neither
DonenorBlockedand whose everyBlocked byrow isDone. If no row qualifies, don't dispatch: when every row isDone, go to step 10; when rows remain but each isBlockedor waiting on an unfinished dependency, stop and say which rows are held and on what — that is a decomposition problem for step 9, not something to work around. State the unit number, its acceptance criteria, and any epic-level constraint it inherits — then runtask-workflowon that unit as the task statement. Iftask-workflowis already loaded in this session, follow it as loaded rather than invoking the skill again; each re-invocation re-injects its whole body.task-workflowowns it completely from there: its own spec gate, its ownPLAN.md, its own verifier rounds. Close the unit, then decide whether to continue. Once
task-workflowreaches cleanup and archivesPLAN.mdout of the repo root, flip the row toDone(in this checkout, never inside a unit's commit — seereferences/epic-queue.md) and put a one-line outcome inNotes— what shipped, and anything it changed for a later unit (a renamed field, a decision the next unit inherits).Then go straight to step 6 for the next eligible unit — or to step 10 if that was the last row, which runs before any stop below — unless one of these holds — in which case stop, say which one, and tell the user to
/clearand re-invoke:- This session has closed 2 units. Count the rows this session flipped to
Done; at 2, stop. It is a count, not a judgment of how full the context feels:task-workflow's step 4 isolates the implementer and verifier in subagents, but each unit still leaves its spec, plan, verdicts, reports and review in this session, and a model judging "tight" for itself let sessions run to ~950k tokens. - Context is already heavy before the count. One unit can spend a session on its own — a review that pulled a lot of code into this thread, a long course correction. Stop after that unit rather than waiting for the second.
- The unit changed something a later unit inherits. A renamed field, a contract that landed differently, a
Blocked bythat turned out unnecessary. The user should see that inNotesbefore the next spec is drafted against it, and an amendment (step 9) may be the real next move rather than the next unit. - The next unit's spec gate now needs a decision the last unit just changed. Drafting a spec in the same breath as the outcome that invalidated its premise is how a plan gets approved against a stale assumption.
Continuing is the common case below the count.
/clearbetween every pair of units was the old default;task-workflow's step 4 subagents carry enough of a unit that two fit in one session. What has not changed: one unit at a time, each through its own spec gate,task-workflowowning it end to end. Step 8's resume path is unchanged, so a/clearat any point — asked for or not — costs nothing.A genuinely independent tail can run in parallel worktrees instead. When two or more remaining rows have no
Blocked bybetween them and touch disjoint surfaces, they can run as one instance per worktree rather than in sequence here — the rules are in${CLAUDE_PLUGIN_ROOT}/skills/task-workflow/references/parallelization.md, and they are not optional: one worktree and one branch per instance, never two instances in one working tree. Say the row numbers and stop; this skill dispatches sequentially and does not orchestrate that fan-out. Each parallel instance is still a fulltask-workflowrun with its own routing, so its implementer isbigin-skills:workerorarchitectby score, never ageneral-purposeagent handed the unit. Two things make it the exception rather than the default — each unit still needs its own human spec gate, andspec-gate-guard.mjsreadsPLAN.mdat the repo root, so two units sharing a working tree would compete for one path.- This session has closed 2 units. Count the rows this session flipped to
- Resume. On invocation, check
.claude/memory/EPIC.mdfirst. If it exists with rows notDone: report the queue state in one table, then go to step 6 for the next eligible unit (step 6 handles the case where none is eligible). Never re-decompose over an in-flight epic, and never overwrite the file without asking — if the user wants a different decomposition, that's step 9. - Amend, when the epic itself moves. A unit's work sometimes invalidates a later unit — a contract lands differently, a dependency turns out unnecessary. Amend rather than restart: add, remove, or reorder rows, log it in the file's
## Amendmentssection, and re-approve only the changed rows (don't re-paste the whole table). If the epic's goal moved rather than its units, stop and re-decompose from step 2 — a queue patched past recognition is worse than an honest second epic. Cap: 2 amendments. A third means the original decomposition was wrong; say that and re-decompose. Epic cleanup. Once every row is
Done, archive.claude/memory/EPIC.md. It stops being a working file, but it doesn't stop being the only written record of why the initiative was cut into these units — so it moves rather than being deleted.Two things happen before the archive, both proposed rather than run silently:
- Distill, and expect to find something. This is the layer where durable decisions actually live — a single
PLAN.mdusually establishes nothing worth keeping, but an epic that settled a contract, a boundary, or an invariant did. Propose the specificknowledge/edit (which concept file, what line), preferring an amendment to an existing concept over a new file; every new file needs a summary line inknowledge/index.md. Read the## Amendmentslog before proposing — a decomposition that had to change usually changed because of something worth writing down. Skip if the repo has noknowledge/bundle. - The design doc's decisions become records. Where step 3b wrote
docs/design/{slug}.md, each decision it actually settled becomes one file underknowledge/architecture/, in the MADR shape inreferences/design-doc.md. The doc itself stays where it is and is never archived — it is the entry point for whoever touches this system next. Update itsStatus:line, and the sections reality diverged from, before proposing the records. - Rebuild the graph if
graphify-out/graph.jsonexists: proposegraphify update ..
Then archive it, to exactly one of two destinations — never both:
- The repo has
knowledge/implementation/— createknowledge/implementation/{YYYY-MM-DD}-{slug}.md: theRecordfrontmatter from${CLAUDE_PLUGIN_ROOT}/skills/bigin-harness-setup/references/knowledge-bundle.md(source: epic,shipped:the versions its units landed in) followed byEPIC.mdverbatim — goal, constraints, the unit table with itsNotes,## Not in scope, and the## Amendmentslog if there is one. Append one line toknowledge/implementation/index.md, newest first. Then delete.claude/memory/EPIC.md. - It doesn't — no
knowledge/bundle at all, or a bundle predatingimplementation/— copy it to.claude/memory/EPIC.archive.{ISO}-{slug}.mdwith the same verbatim body, then delete.claude/memory/EPIC.md. Don't createknowledge/implementation/just to have somewhere to put it: one record in a folder with no bundle around it is harder to find than the memory file, and it half-scaffolds a bundle nobody asked for.
Write the record with this one command, never through
Write. It works the same in bash and PowerShell, prepends theRecordfrontmatter from the values you pass as arguments, copies.claude/memory/EPIC.mdverbatim after it, and refuses to overwrite an existing record (take the-2suffix then). Don't read the record back.node -e "const [src,out,title,desc,source,shipped,by,at,tags]=process.argv.slice(1),fs=require('fs'),q=JSON.stringify,l=s=>'['+s.split(',').filter(Boolean).map(q).join(', ')+']';fs.writeFileSync(out,['---','type: Record','title: '+q(title),'description: '+q(desc),'source: '+source,'shipped: '+l(shipped),'generated: { by: '+q(by)+', at: '+q(at)+' }','tags: '+l(tags),'---','',''].join('\n')+fs.readFileSync(src,'utf8'),{flag:'wx'})" .claude/memory/EPIC.md knowledge/implementation/{YYYY-MM-DD}-{slug}.md "{title}" "{one-line description}" epic {v1,v2,...} {generated-by, e.g. human:alice} {YYYY-MM-DD} {tag1,tag2}Lists (
shipped,tags) are comma-separated with no spaces. The memory-file fallback is a plain file copy (cp/Copy-Item), with no frontmatter.Verbatim is the whole point, and more of it survives here than for a task: the
Notescolumn is where each unit recorded what it changed for the units after it, and the## Amendmentslog is the only place the decomposition's own history exists. Slug from the epic's title; if that slug already exists for that date, suffix-2.The record and the concept must not restate each other. The distill bullet moves the invariant into a concept — "rate limits are per-key, not per-IP". The record keeps the narrative that produced it — the unit that got reordered, the amendment that nearly hit the cap, the decomposition that lost. A record that repeats its own concept, or a concept that recounts the epic, means one of the two was written in the wrong place.
- Distill, and expect to find something. This is the layer where durable decisions actually live — a single
Interaction with session-handoff
session-handoff writes .claude/memory/SESSION.md alongside the queue. Keep them in their lanes: EPIC.md holds the unit queue and its amendment log, SESSION.md holds whatever is in flight right now. When saving a session mid-unit, name the epic and the unit number in SESSION.md rather than copying rows across — two records of the same queue drift within a day.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

