Draft child Epics for the Jira Value Increment: the argument (text following the epics: trigger)
epics: is the Jira-driven Epic-writing workflow. Given a Value Increment key, it reads the VI plus its existing Epics from pre-exported markdown in the user's Obsidian vault, optionally scans code repos to identify reusable capabilities and gaps, drafts child Epic definitions as markdown files under the resolved output directory, and gates the result on an Opus review.
Key distinction from document: (Jira mode): the VI being Epic-ized is not yet implemented — there are no PRs to diff. Code scanning (when enabled) is a plain filesystem search to understand what exists and what needs to be built.
epics: never branches and never commits the Epic drafts (still true — the run's git writes are confined to $SPECS_PATH, per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md; the run does make read-only git calls elsewhere — Phase 4's git remote get-url origin per candidate clone and Phase 8's git diff --stat from project_root — but none of them writes), and writes only to the resolved output directory — jira-drafts/<jira_key>/ under $VAULT_PATH, or a derived epic-drafts/<jira_key>/ dir beside the imported hierarchy when $VAULT_PATH is unset. Git hygiene of the write target is the user's responsibility — they may or may not have it under version control. The run commits only inside $SPECS_PATH, and only its bounded session-artifact paths (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md §2.1) — via the specs-preflight flush at run start (§3.4) and the terminal commit-artifacts step (§4); never the drafts, never the write target. It still creates no branch (still true — specs-preflight switches $SPECS_PATH only between branches that already exist, and only plugin-created ones (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md §2.2); it creates none).
Phase 0 — Load
Resolve the Jira input via the shared front-end. Execute
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/jira-input-resolution.mdagainst the argument (text following theepics:trigger).epics:is jira-driven only: expectmode: jira-drivenwithjira_key(the input Value Increment key),jira_export_root(the VI export dir —$VAULT_PATH/jira-products/<KEY>for a JiraID, or the passed directory), andsource. The front-end owns the$VAULT_PATH/jira-productsvalidation and Fallbacks A/B. Carryjira_key,jira_export_root, andfocus_keyforward. Downstream,<JIRA_KEY>and<VI-KEY>both denote thisjira_key.If the front-end returns
mode: direct(no Jira input), stop withEPICS_NEEDS_JIRA: epics: needs a Jira key or an imported-Jira directory.—epics:has no direct-prompt behavior.
epics: is cwd-agnostic: it writes Epic drafts to an absolute output
directory (resolved in Phase 1), so it does not require cwd to be inside the
vault.
Specs-repo preflight. Cite
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md
and execute its specs-preflight entry point (§3) inline: flush any leftover
session artifacts from an earlier run, retry an artifact commit that failed to
push, and settle the branch. Prompt-free and silent when the specs repo is clean
and on its default branch. If a guard fires, emit its §5 notice; if it returns
specs_git: blocked (§3.3 G0), carry that flag for the whole run — the
terminal commit-artifacts step skips on it.
Phase 1 — Clarification
Rule: Ask, don't guess. This rule is absolute.
Group questions where possible; use choices arrays; the last choice in every array MUST be "Other… (describe)".
Ask about:
Output directory. One
.mdfile per Epic, filename<NEW-EPIC-SLUG>.md(drafted Epics have no Jira ID yet, so they are slug-named files inside the VI-keyed folder). The default depends on$VAULT_PATH:$VAULT_PATHset →$VAULT_PATH/jira-drafts/<jira_key>/. This lives outsidejira-products/by design —jira-products/is re-created on every Jira import, so drafts written there would be lost;jira-drafts/is a sibling reserved for PM/PO work-in-progress that survives re-imports.$VAULT_PATHunset (directory input) →<parent-of-jira_export_root>/epic-drafts/<jira_key>/. Path-safety guard: warn and offer another path if this dir would fall insidejira_export_root(wiped and regenerated on every import). A pre-existing dir that already holds drafts is normal — not a warning. The directory is auto-created if missing. Recordoutput_dir, and recordproject_root=$VAULT_PATHwhen set, elseoutput_dir. Ask:
choices: ["Use <output_dir> (Recommended)", "Use a different path (you'll be prompted)", "Cancel", "Other… (describe)"]Code examination on/off (default ON). If ON, ask which repos under
$REPOS_PATHto scan:choices: ["Scan repos referenced by sibling/parent Epics under this VI (Recommended — auto-derived)", "Let me list the repos manually (you'll be prompted)", "Turn code scan off — produce Epic drafts from Jira content alone", "Other… (describe)"]When "auto-derived" is chosen, inspect the sibling/parent Epics'
## Pull Requestssections (if any) for repo references; if none, fall back to asking the user to list repos.Repo refresh policy (only if code scan is ON):
choices: ["fetch + pull default branch (Recommended)", "fetch only", "no refresh", "Other… (describe)"]The
fetch + pull default branchdefault matchescode-scanner's default (refresh.switch_to_default_branch: true, refresh.pull: true) — capability scans target present-day code and want the default-branch tip. This is deliberately different fromdocument:(Jira mode), which keepspull: falsebecause historical merged commits must not move.Repos search base (
$REPOS_PATH) (only if code scan is ON). Read${REPOS_PATH:-/workspace}(the container mounts every repo under/workspace).$REPOS_PATHmay be a single directory or a colon-separated list. Ask:choices: ["Use $REPOS_PATH (default /workspace) (Recommended)", "Use a different path (you'll be prompted)", "Cancel", "Other… (describe)"]If "different path", take free-text input (single dir or colon-separated list) and validate that at least one directory exists under it. Record the resolved value as
$REPOS_PATH. Individual clones are located in Phase 4 by matching theirgit remoteagainst each repo slug — not by assuming a<base>/<slug>directory name.
Also display (for user context):
- Resolved cwd absolute path
- Resolved output directory
- Resolved
$REPOS_PATH(or "N/A — code scan off") - Resolved
jira_export_rootandjira_key(plus$VAULT_PATHwhen set)
No branching context is shown — this command never branches (still true — specs-preflight only switches $SPECS_PATH between branches that already exist, and only ones the plugin created, per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md §2.2; it creates none).
Phase 1.5 — Classify
Load and follow the model-routing policy at ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/model-routing.md, then classify the task as exactly one of: SIMPLE, MODERATE, SIGNIFICANT, or HIGH-RISK. Epic writing is typically MODERATE (bounded scope, single VI, vault-internal output). State the classification and a one-sentence reason.
MODERATE → no separate Opus planner; the epic-reviewer gate (Opus, dispatch-pinned to this chain) is mandatory. Resolve the per-step routing per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/model-routing.md §9:
model_routing:
classification: MODERATE # typical; SIGNIFICANT possible
reason: <one-line>
current_model: <the model this orchestrator is running under>
detection_model: <§2.1 detection chain: claude-sonnet-4.6, fallback claude-sonnet-4.5/gpt-5.4> # jira-reader, code-scanner, dt-style-checker, doc-fixer, epic-writer (MODERATE)
review_model: <§2 Opus chain> # epic-reviewer (dispatch-pinned to this chain; recorded, no override)
implementation_model: <= detection_model> # the epic-writer subagent (Phase 6); planning_model if SIGNIFICANT/HIGH-RISK
opus_available: <true if a §2 Opus model resolved, else false>
notes: <any §2/§2.1 fallback or degradation>
Each subagent dispatch below cites its chain (§9 role→chain map). No relaunch advisory for MODERATE — the writer runs on its detection pin and the gates run on current_model, which §3.1 allows (if a run is classified SIGNIFICANT/HIGH-RISK, the §9.1 advisory applies and epic-writer escalates to the §2 chain). If no Opus is available, epic-reviewer falls to the Sonnet floor — record the degradation in notes and the Phase 9 report.
Phase 2 — Plan + approval
Documentation grounding (optional, independent of code scan). Before presenting the plan below, run resolve-docs-grounding epics per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/docs-grounding.md — this is the run's only consent-bearing step (an index build or a capped refresh), so it must resolve here, before Phase 3's jira-reader, Phase 4's repo resolution, and Phase 5's parallel code scan do any of the run's real work. This runs ahead of Phase 2.5/2.6's require-on-main/ard-resolution.md gates — a deliberate exception to ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/phase-handoff.md §5 rule 2's ordering, kept here rather than moved because resolve-docs-grounding's only expensive step is itself behind its own consent prompt (docs-grounding.md step 3.5), and an index build it produces is a durable, run-independent artifact, not per-run work a later stop would waste.
Present a concise plan:
- Resolved
jira_keyand thejira_export_rootpath - Existing Epics identified under this VI (will NOT be duplicated)
- Repos to scan (or "code scan off")
- Docs grounding: the
docs grounding:line thatresolve-docs-groundingreturned, verbatim — including itsretrieval:value and any index-build, staleness, or shadowing clause (off switch: --no-docs) - Output directory with one file per new Epic; propose a name stub per Epic if the themes already suggest them
- Parallelism plan (up to 4
code-scannerinstances per batch, single task message per batch) - Proposed Epic sizing/sequencing — prefer fewer, larger Epics where the VI direction is validated; split only at a genuine risk / feedback-loop boundary; order so that no Epic depends on a later one
- Wide-refactor exception — a blast-radius-wide mechanical change (rename/retype a shared symbol, column, or type) that genuinely cannot be tracer-bulleted into independent vertical slices is sequenced expand → migrate-in-batches → contract: one Epic adds the new form alongside the old, one-or-more Epics migrate call sites in batches, and a final Epic removes the old form (blocked by every migrate-batch). Prefer this over forcing the change into an awkward vertical slice
Ask:
"Epic drafting plan ready. What would you like to do?"
choices: ["Approve & continue (Recommended)", "Revise plan", "Cancel"]
- Approve → proceed to Phase 3
- Revise → ask what to change, update, re-show, re-ask
- Cancel → stop and summarise what was planned
Phase 2.5 — Resolve applicable ARD (optional)
Resolve any VI-level ARD for this VI by citing
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/ard-resolution.md with vi = jira_key,
epic: null (Epics do not exist yet — VI-level ARD only), and $SPECS_PATH.
- On
status: none(including$SPECS_PATHunset/unresolvable) → skip and proceed exactly as before. No prompt, no extra output. - On
status: unmerged→ stop, naming the returnedbranchand anypr— an ARD that exists but has not landed on<default>is a weaker architectural basis than the one about to arrive, and Epics drafted against it would need re-doing once it does. - On
status: found→ carryinvariants+guidance_summaryforward: pass them toepic-writer(Phase 6 handoff, asapplicable_ard) so drafts stay consistent with theAD#N, and toepic-reviewer(Phase 7, asapplicable_ard) which then activates its ARD-conformance dimension. A necessary deviation is recorded by the writer in the Epic draft (- ARD deviation: … flag: architect) and surfaced in the Phase 9 report — never edit the ARD.
Phase 2.6 — VI-level spec enrichment (optional)
If a VI-level specification exists, fold its requirements into the coverage
inventory. Additive, zero-cost when absent — the common case, since
specify: usually runs per-Epic after epics:.
Resolve the VI dir:
$SPECS_PATH/specifications/<VI>-<vslug>/, matched by key-number, tolerating a stray-/_and a human-adjusted slug (the same rule~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/ard-resolution.mdstep 1 uses). If$SPECS_PATHis unset/unresolvable, or no VI dir matches → skip (setvi_spec_present: false).Detect: execute
require-on-main(~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/phase-handoff.md§3) against<VI-dir>/specification.md, mapping its §3.7 return value bystoppedfirst, never byon_mainalone. On any stopping state, stop per §4.4, naming$SPECS_PATHexplicitly — a spec that exists but has not yet landed on<default>is a weaker grounding basis than the one about to arrive, and Epics drafted against it would need re-doing. Otherwise (stopped: false): onpass/pass_amending, proceed to step 3 (pass_amendingprints §3.3's row-B message). Onunmanaged, behave exactly as before this feature — skip (setvi_spec_present: false). Onabsent, skip (setvi_spec_present: false); the run proceeds byte-identically to today — this is the common case, and VI-levelspecify:remains optional.Parse
<VI-dir>/specification.mddirectly (Read it — one file, a simple heading scan): extract its user stories[Uxx]and their nested acceptance criteria[ACxx]intovi_spec_requirements[]. Skip[TCxx]test cases (per-AC, non-unique, below Epic granularity) and the prose sections (Problem/Scope). Because[ACxx]numbering restarts per story, qualify eachspec-criterionid with its parent story (<Uxx>/<ACxx>) so everyReqid in_coverage.mdis unique;spec-story[Uxx]ids are document-unique and used as-is:vi_spec_requirements: - id: <Uxx (story) | <parent-Uxx>/<ACxx> (criterion)> # spec-story id is document-unique; qualify criterion ids with the parent story type: spec-story | spec-criterion text: <requirement text>Set
vi_spec_present: trueand record the resolvedspecification.mdpath for the Phase 9 report.
Phase 3 — Read Jira hierarchy
Invoke jira-reader with depth: vi-plus-epics. This depth is specifically designed for Epic writing: richer than vi-only so themes extracted for code-scanner aren't starved of context, but lighter than full so the agent doesn't read dozens of already-closed child Stories.
→ task(agent_type: "dev-workflows:jira-reader", model: <detection_model — §9 / §2.1 detection chain>):
"Return the structured handoff for this brief:
jira_export_root: [resolved jira_export_root] jira_key: [resolved jira_key] depth: vi-plus-epics"
Wait for the handoff. If status: NOT_FOUND or status: EMPTY, surface the Jira key dir not found rule in ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.md (["Re-enter key", "Cancel"]). On OK, carry the handoff requirements[] and requirements_source forward —
they are the coverage ground truth for Phases 6–7.
When Phase 2.6 set vi_spec_present: true, append its
vi_spec_requirements[] to this requirements[] — the VI's own rows are
unchanged; the appended rows carry type: spec-story / spec-criterion, which
separates them from the VI's story/criterion rows. The merged list flows
unchanged into the Phase 6 handoff and the Phase 7 reviewer brief. When
vi_spec_present: false, requirements[] is exactly what jira-reader returned.
On OK, identify the Epics already linked to the VI (filter linked_items to type == Epic) — the new Epic drafts MUST NOT duplicate their scope (enforced later by epic-reviewer).
Refinement target (focus_key). epics: always reads and analyses the whole VI
(the partition and non-duplication logic are inherently VI-holistic). When focus_key
is set (explicit <VI> <Epic>), validate it is among the linked Epics; if it is not,
surface EPICS_FOCUS_NOT_FOUND: <focus_key> is not a linked Epic of <jira_key>. and
offer choices: ["Proceed VI-level (draft the full partition)", "Re-enter the Epic key", "Cancel"].
When present, treat focus_key as the single refinement target: Phase 6 re-drafts
only that Epic's definition, and Phase 7 reviews only that file. The non-duplication
set (existing_epics) is the other linked Epics — exclude the focus Epic so Phase 6
re-emits it rather than skipping it as a duplicate. When focus_key is null, behaviour
is unchanged (draft the full partition of new Epics).
When focus_key is set, mode = refine and refinement_targets = [the focus Epic] — Phase 6 iterates on its current imported content (see epic-writer refinement mode) rather than regenerating from the VI alone.
Refinement candidates. From the same linked_items (type == Epic), read the additive per-Epic fields refinement_candidate, team, and scope_hint (emitted by jira-reader at vi-plus-epics). Collect refinement_candidates = every linked Epic with refinement_candidate: true. These are empty/almost-empty team-Epic shells the PE pre-created to encode team boundaries — refinement targets to fill in, not non-duplication constraints. This set drives the Phase 3.5 gate.
Phase 3.5 — Refinement-mode gate (conditional)
Runs only when focus_key is set OR refinement_candidates is non-empty. Otherwise skip silently — mode = generate, behaviour byte-identical to the legacy net-new flow.
Focus key set → mode = refine, refinement_targets = [focus Epic]; skip the mode question (the PE named the target explicitly).
No focus key, refinement_candidates non-empty → present the detected set as a CONFIRMABLE list (detection only proposes; the PE is the authority) and ask the mode:
Detected N empty/almost-empty team-Epic shells linked to <jira_key>:
- <EPIC-KEY> · <team, or "team: [NEEDS CLARIFICATION]"> · <scope_hint>
...
choices: ["Refine these N (partition the VI across them) (Recommended)", "Generate net-new Epics (ignore the shells)", "Both — refine the shells and draft net-new for leftover scope", "Let me adjust which shells to refine (you'll be prompted)", "Other… (describe)"]
Record mode (refine | generate | both) and the confirmed refinement_targets (empty for generate). A target whose team is empty carries a [NEEDS CLARIFICATION — team] note into the writer handoff.
Adaptive code-scan default (refine / both only). Re-surface the code-examination choice now that the target count is known — the Phase 1 answer was given before detection. Default ON when len(refinement_targets) >= 2 (a real cross-team boundary to draw), OFF when == 1:
choices: ["<adaptive default> (Recommended)", "<the other setting>", "Keep my Phase 1 choice", "Other… (describe)"]
with a one-line rationale ("2+ team-Epics → code context helps draw the boundary" / "single Epic → no cross-team boundary; scan off is faster"). This runs ONLY in the refine branch, so the generate / no-candidate path never sees it (no-regression).
Phase 3.6 — Documentation grounding dispatch
Documentation grounding dispatch (optional, independent of code scan). docs_grounding was already resolved in Phase 2 — consume that cached result here; never re-run resolve-docs-grounding. When docs_grounding: ON, dispatch-docs-grounder with feature_summary = the VI goal + Epic-set intent, jira_key = the VI key, themes = the jira-reader themes. Carry the digest into Phase 6 with writer-attach consumption. When OFF, skip silently.
This phase sits before the conditional repo-resolution and code-scanning phases deliberately. It needs only Phase 3's output — the VI goal and the jira-reader themes — and nothing from the code scan, and Phase 4 and Phase 5 both skip to Phase 6 when code scan is OFF. Dispatching from inside either of them would discard the digest on exactly the runs that turned code scanning off, after Phase 2 had already asked the user to consent to building an index for it.
Phase 4 — Resolve repos (conditional)
If code scan is OFF, skip to Phase 6.
If code scan is ON:
Derive the repo list:
- Auto-derived (Phase 1 default) — walk the
jira-readerlinked_itemsfiltered totype == Epic; for each Epic.mdfile (already read during Phase 3), collect repo names from its## Pull Requestssection URLs. Dedupe. If the auto-derived list is empty, fall back to asking the user. - Manual list — prompt for a free-text list of repo short names (one per line or space-separated). Resolve each against the
$REPOS_PATHslug→clone map built in step 2 below.
- Auto-derived (Phase 1 default) — walk the
Build a slug→clone map. For each top-level directory under each entry of
$REPOS_PATH, runtimeout 5 git -C <dir> remote get-url origin 2>/dev/null, strip a trailing.git, and take the URL's last path segment as that clone's slug. Skip directories with no.gitor whosegit remotecall fails/times out. Resolve each in-scope repo slug against the map: one match → use it; multiple matches → auto-prefer basename ending-repo, then_repo/_fast, then alphabetically last (show candidates at plan approval); zero matches → escalate per theRepo unresolved (zero matches) — epics:rule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.md:choices: ["Skip and continue without this repo's scan", "I'll clone it — wait", "Cancel", "Specify a different absolute path for this repo", "Other… (describe)"]If the final resolved repo list is empty (every repo was skipped or missing), escalate per the
No repos derivable — epics:rule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.md:choices: ["List repos to scan manually", "Proceed without code scan", "Cancel", "Other… (describe)"]
Phase 5 — Parallel code scanning (conditional)
If code scan is OFF, skip to Phase 6.
Spawn code-scanner instances in batches of up to 4 concurrent agents per task message. Wait for each batch before spawning the next.
For each repo in the batch:
→ task(agent_type: "dev-workflows:code-scanner", model: <detection_model — §9 / §2.1 detection chain>):
"Scan this repo for the brief:
repo_path: <resolved absolute path for this repo from Phase 4> repo_url_slug: <repo slug, e.g. "cluster"> capability_themes: [paste the themes array from jira-reader, plus any VI-goal-derived themes] context: | [3–5 sentences: VI goal, what the Epic-set is meant to achieve] search_hints: symbols: [class/function names inferred from VI/Epic descriptions, or []] paths: [directory globs inferred from themes, or []] keywords: [grep keywords extracted from themes] refresh: switch_to_default_branch: [true if Phase 1 chose 'fetch + pull default branch' (default) or 'fetch only'; false if 'no refresh'] pull: [true if 'fetch + pull default branch'; false otherwise]"
Handle per-repo status after the batch returns:
OK/PARTIAL/EMPTY— store the output, continue.REPO_MISSING— should not happen at this stage (Phase 4 already checked). If it does, escalate per theRepo missing (after resolution)rule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.md.DIRTY_TREE— escalate:choices: ["Stash changes and retry this repo", "Skip this repo", "Cancel"]REFRESH_BLOCKED— escalate:choices: ["Continue with current local state", "Skip this repo", "Cancel"]prep.read_only: true— not a failure. The scan ran atprep.scanned_ref. Escalate per theRead-only mount — ref stale or divergedrule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.mdonly whenprep.ref_committed_atis more than 14 days old orprep.head_divergence.ahead > 0; otherwise proceed silently and cite evidence atprep.scanned_ref.
Phase 6 — Write Epics
The drafting is delegated to the epic-writer subagent (pinned to the §2.1 detection chain for MODERATE; §2 Opus only if the run is SIGNIFICANT/HIGH-RISK — see ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/model-routing.md §9.2). The orchestrator prepares a handoff and dispatches; it does not write Epics itself, and nothing commits in this phase (still true — epics: never branches, and the Epic drafts it writes are never committed; git hygiene of the write target is the user's responsibility. The run commits only inside $SPECS_PATH, and only its bounded session-artifact paths, per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md §2.1).
Write the handoff file. Create a temp file (
mktemp— never the vault, never a repo) containing theepic-writerinput contract:jira_reader_handoff,code_scanner_outputs(empty if no scan),scope(Phase 2 in/out of scope),existing_epics(non-duplication),output_dir(resolved Phase 1 dir),vi_goal,jira_key,requirements+requirements_source(from Phase 3),applicable_ard(the Phase 2.5 invariants + guidance_summary, or omit when status was none),existing_epic_themes(themes of the already-linked Epics),mode(generate|refine|both— from Phase 3.5;generatewhen 3.5 skipped), andrefinement_targets(list of{key, team, scope_hint, current_body_path}, wherecurrent_body_path = <jira_export_root>/<EPIC-KEY>/<EPIC-KEY>.md; empty ingeneratemode), anddocs_grounding(the Phase 3.6 digest, or omit when OFF/EMPTY). Record its absolute path. Whenfocus_keyis set (the Phase 3 refinement target), setscopein-scope to just the focus Epic andexisting_epicsto the other linked Epics, soepic-writerre-drafts the single focus Epic's definition file;output_diris unchanged.Dispatch the writer:
→ task(agent_type: "dev-workflows:epic-writer", model: <detection_model — §9 / §2.1 detection chain; planning_model (§2 Opus) only if classification is SIGNIFICANT/HIGH-RISK>):
"Write the child Epic definitions for this brief.
handoff_file: [absolute path of the temp handoff file from step 1]"
Handle the return.
status: DONE→ recordfiles_writtenfor Phase 6.1 onward.status: BLOCKED→ surface the named gap:choices: ["Provide the missing input (you'll be prompted)", "Cancel"]On a provided value, rewrite the handoff and re-dispatch once. Nothing is committed here (still true — this step writes only Epic drafts into the vault / output directory, which
commit-artifactsnever stages; git management there is the user's responsibility).Also record
coverage_file(the_coverage.mdpath) andclarifications_needed[]for Phases 6.1 and 7.
Phase 6.1 — Resolve clarifications
If the writer returned a non-empty clarifications_needed[], resolve it BEFORE
the style check and review (so no review cycle is spent on known unknowns).
Present ONE batched prompt listing every marker grouped by Epic; for each:
choices: ["Use the writer's suggested answer", "I'll answer (you'll be prompted)", "Leave unresolved", "Other… (describe)"]
Fold each resolved answer into the affected Epic draft (Edit the file inline, or
re-dispatch epic-writer once with the resolutions). Markers the user chooses to
leave unresolved stay visible in the draft and become epic-reviewer
BLOCKERs in Phase 7. If clarifications_needed[] is empty, this phase is a
silent no-op (byte-identical to a run without it).
Leftover disposition (refine / both only). After the writer returns, read _coverage.md; every ❌ gap row is a VI requirement no team-Epic covers. In ONE batched prompt, ask per gap:
choices: ["Assign to team-Epic <KEY> (re-drafts that Epic to include it)", "Propose as a new (net-new, slug-named) Epic", "Defer (leave as an uncovered row)", "Other… (describe)"]
Fold the results back: assign → re-dispatch epic-writer once (or Edit inline) to add the requirement to the named target's ## Covers + scope; new Epic → add a slug-named net-new draft; defer → the row stays ❌ gap in _coverage.md and is listed in the Phase 9 report. Reuses the same batched-gate pattern as the clarification resolution above; no gaps → silent no-op.
Phase 6.2 — Dynatrace style check
Invoke dt-style-checker on the files written in Phase 6. Unlike document: (Jira mode), this does NOT use docs-style-checker (no repo linter for vault content). Instead, the Dynatrace corporate style guide checker validates terminology, trademarks, voice/tone, and inclusive language.
→ task(agent_type: "dt-style-guide:dt-style-checker", model: <detection_model — §9 / §2.1 detection chain>):
"Run the style check for this brief:
files: [absolute paths of every Epic file written in Phase 6] doc_type: epic emphasis: terminology and customer-facing captions, labels, messages, and text"
Act on the return:
status: OK— zero violations. Proceed to Phase 7.status: VIOLATIONS_FOUND— invokedoc-fixerwith the violations treated as per their severity. Afterdoc-fixercompletes, re-rundt-style-checkeronce:→ task(agent_type: "dev-workflows:doc-fixer", model:
<detection_model — §9 / §2.1 detection chain>):"Fix the style violations for this brief:
Task description: [Epic drafting for ] Reviewer or style-checker output: [paste full dt-style-checker output] Project root: [resolved project_root] Severities to fix: MAJOR only"
If violations remain after the re-run, proceed to Phase 7 — the remaining findings (mostly MINOR/NIT for epics) are informational and will appear in the Phase 9 report.
status: ERROR— surface the error reason. Proceed to Phase 7 regardless (style check is not a gate for Epics, but a quality enhancement).
If dt-style-checker is unavailable (agent file not found), proceed directly to Phase 7. The style check is optional but recommended.
Phase 6.3 — Structural pre-lint
Before the review gate, run the deterministic checks in
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/pre-lint.md against each drafted Epic file: the Universal checks,
the Jira-key collision check (run on the whole Epic file — the template has no frontmatter), and
the Epic block (required headings incl. ## Independent Test; Given/When/Then acceptance
criteria; [NEEDS CLARIFICATION] ≤ 3 per Epic; _coverage.md present). Surface every finding;
inline-fix the mechanical ones (delete a stray placeholder token); leave content gaps for the author.
Advisory — never blocks; proceed to Phase 7 once findings are surfaced. epic-reviewer remains the
gate.
Phase 7 — Epic review gate
Invoke epic-reviewer (Opus). This reviewer is Epic-specific — scope clarity, acceptance-criteria testability, non-duplication of existing Epics. docs-style-checker is NOT used here (no repo linter for vault content); Dynatrace corporate style is handled by the Phase 6.2 dt-style-checker step above.
→ task(agent_type: "dev-workflows:epic-reviewer"):
"Review the Epic drafts for this brief:
Task description: [one-paragraph: VI key, VI goal, number of Epics drafted] Written Epic file paths: [absolute paths of every Epic file written in Phase 6] jira-reader handoff: [paste full YAML from Phase 3] code-scanner output: [paste array of per-repo scanner outputs from Phase 5, or 'N/A — code scan off'] requirements: [paste the requirements[] array from Phase 3] _coverage.md path: [absolute path of the coverage file from Phase 6] applicable_ard: [the Phase 2.5 invariants, or omit if status was none]"
When mode is refine/both, include refinement_targets in the epic-reviewer brief so its conditional refinement dimensions (completeness, partition integrity, cross-team dependency sanity, team preserved) activate; omit it in generate mode so those dimensions report N/A.
Act on the verdict (same shape as document: Jira mode Phase 7):
Triage sub-step (before any fixer dispatch): follow ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/finding-triage.md. For each finding, verify its claimed consequence at the location it names; keep or dismiss; record every dismissal with a reason that disposes of that finding's own claim. Hand the fixer survivors only, and carry the dismissal list into this run's report.
BLOCK — invoke
doc-fixerwithSeverities to fix: BLOCKER and MAJOR. Write thedoc-fixerFix Report to a temp file (mktemp -t dw-epics-claims-XXXX.md, never inside a repo tree or the vault), record its path asclaims_file, then checkdoc-fixer'sStop condition flagbefore re-invoking anything. If it isNEEDS HUMAN, the fixer deferred at least one BLOCKER as needing a human decision: do NOT re-invokeepic-reviewer— a re-review can only re-find the BLOCKER the fixer has just reported it could not resolve — and instead surface each deferred BLOCKER with the reason the fixer gave, then escalate it individually per theReview verdict BLOCK (unresolved after one fix cycle) — epics:rule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.md, which names this entry point alongside the second-BLOCK one. Only when the flag isCLEARdo you re-invokeepic-revieweronce passingclaims_file— so the re-review falsifies the fixer's account rather than assuming it. If still BLOCK, escalate per theReview verdict BLOCK (unresolved after one fix cycle) — epics:rule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.mdfor each unresolved BLOCKER individually:choices: ["Provide manual fix notes (you'll be prompted)", "Defer to a follow-up issue (record in Phase 9 report)", "Override and accept the finding", "Cancel the whole run", "Other… (describe)"]For
epics:, "Defer" means the finding goes into an Epic-refinement note in the draft itself (appended as a## Refinement notessection) in addition to the Phase 9 report.PASS WITH RECOMMENDATIONS — invoke
doc-fixerfor MAJOR findings only:→ task(agent_type: "dev-workflows:doc-fixer", model:
<detection_model — §9 / §2.1 detection chain>):"Fix the review findings for this brief:
Task description: [Epic drafting for ] Reviewer or style-checker output: [paste the triaged survivor list from the triage sub-step above — the surviving
epic-reviewerfindings only, never the dismissed ones] Project root: [resolved project_root] Severities to fix: BLOCKER and MAJOR"MINOR / NIT findings are deferred to the Phase 9 report.
PASS — proceed to Phase 8.
Cap: one fix cycle + one re-review maximum.
Phase 8 — Post-write maintenance
First gather the change context:
a. project_root (the vault when $VAULT_PATH is set, else the resolved output directory) is the "project root" for this run. Run git diff --stat from project_root if it is a git repo; otherwise list the written files manually. This command never commits anything under project_root — just report what changed (the terminal commit-artifacts step commits ONLY $SPECS_PATH's bounded artifact paths, per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md §2.1).
b. Compose a change summary block:
Implementation: [one-sentence description: how many Epics drafted for <JIRA_KEY>, resolved output directory]
Change type: docs
Classification: MODERATE
Files changed:
<list of new Epic file paths, one per line>
Notable additions/removals: [new Epics by slug — one line each]
(In `refine`/`both` mode, refined Epics are identified by key `<EPIC-KEY>`, not slug.)
Epic-review verdict: [PASS | PASS WITH RECOMMENDATIONS | BLOCK]
Then spawn all four maintenance agents in a single task message. They are independent and run concurrently.
Agent 1 — Documentation (general-purpose):
"Post-write documentation review. Change summary: [paste change summary block]
The project root is an Obsidian vault when
$VAULT_PATHis set, else the resolved output directory; look only for internal documentation files that reference Epic drafts (e.g., ajira-drafts/README.mdor an index page enumerating active drafts). Determine if any such file needs updating — e.g., a new entry in a drafts index. Skip if: no such file exists or drafts aren't indexed centrally. If an update is warranted: apply minimal edits. Return: file updated and what changed, OR 'no update required (reason)'."
Agent 2 — Knowledge base (general-purpose):
"Post-write knowledge review. Change summary: [paste change summary block]
Check ~/.copilot/memory/ (global) and .copilot/memory/ (project-level, preferred for vault-specific knowledge) for existing knowledge files. Determine if a new knowledge entry is warranted — look for: reusable insights about this VI-family's Epic patterns, non-obvious scoping constraints uncovered, code-reuse discoveries from code-scanner, duplicate-Epic near-misses that required scope adjustment. If YES: append to the most appropriate existing file (never create a new file if an existing one fits) using this format:
[Short title]
- Context: what problem/situation triggered this
- Insight: the learned rule, pattern, or gotcha
- When it applies: conditions under which this matters
- Date: YYYY-MM-DD
- Ref: [first 60 chars of the Jira key + VI summary] Return: file updated/created and summary of entry, OR 'no update required'."
Agent 3 — Instructions (general-purpose):
"Post-write instructions review. Change summary: [paste change summary block]
Check .github/copilot-instructions.md in the project root and ~/.copilot/copilot-instructions.md (global). Determine if any Epic-drafting rules, guidance, or guardrails are missing because of what this run revealed (e.g., a domain-specific acceptance-criteria pattern, a naming convention for Epic files, a scope-boundary rule that caught you out). Skip if: the run followed existing conventions with no surprises. If YES: apply minimal, additive, scoped changes only. Return: what was changed and why, OR 'no update re
…(truncated)