Author a product specification for the Jira item: the argument (text following the specify: trigger)
specify: is the PE-phase specification-authoring workflow — the specification step of the PM→PA→PE→Dev pipeline
(specify: → specification.md; then design: → design.md + plan.md). Given a Jira Epic (or VI)
key or an imported-Jira directory, it reads the item from pre-exported markdown, lightly scans code to
ground feasibility, and authors an org-standard specification.md through a relentless
round-by-round grill — resolving open questions live instead of stopping. It gates on the
Opus spec-reviewer and offers to land the spec on the specs repo's main branch (via branch + PR) as
Published: no.
Key distinction from epics:: epics: splits a VI into Epic drafts; specify: authors one
specification for a single item (typically an Epic). Run epics: first, then specify: per Epic.
Phase 0 — Resolve input
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 thespecify:trigger).specify:is jira-driven only: expectmode: jira-driven. The front-end owns the$VAULT_PATH/jira-productsvalidation, Fallbacks A/B and D/E, and the VI-selector (key-or-directory) + focus-Epic grammar. Carry forward:jira_key— the resolved top-level key: the VI when a focus Epic is present, or the stand-alone top-level item's own key otherwise.focus_key— the Epic to center on withinjira_export_root, ornullfor a bare VI / stand-alone item / directory.jira_export_root,source.
Define
<VI>=jira_keyand<EPIC>=focus_key(may benull). Downstream steps use these two symbols in place of the old single<KEY>.If the front-end returns
mode: direct(no Jira input), stop withSPECIFY_NEEDS_JIRA: specify: needs a Jira key or an imported-Jira directory.—specify:has no direct-prompt behavior.Resolve
$SPECS_PATH.specify:writes specifications under$SPECS_PATH/specifications/(exact layout resolved in step 3) — the specs repo, not the vault. If$SPECS_PATHis unset, stop with a clear error namingSPECS_PATH(choices: ["Set SPECS_PATH (enter the path)", "Cancel"]) — there is no vault-relative fallback for this write target the way there is for reads.Resolve the feature folder. Derive provisional kebab-case slugs from the relevant Jira item title(s) (from the index/summary — finalized once
jira-readerruns in Phase 2, but a provisional slug is enough to check for existing folders now):<vslug>for the<VI>title, and<eslug>for the<EPIC>title whenfocus_keyis set.- Resolve/derive the VI (top-level) dir:
specifications/<VI>-<vslug>/. Look for an existing dir atspecifications/<VI>{-|_}<vslug-or-other-slug>/— honor an existing dir matched by key-number (tolerate a stray-/_after the key, and a pre-existing slug that doesn't exactly match a freshly-derived one — a human may have adjusted it). Create<VI>-<vslug>(hyphen) only if no such dir exists yet. - Resolve the feature folder itself, by case:
focus_keyset (an Epic nested under a VI) →specifications/<VI>-<vslug>/<EPIC>-<eslug>/— a per-Epic subfolder under the VI dir (<eslug>= kebab of the Epic title). Apply the same honor-an-existing-dir tolerance to the<EPIC>-<eslug>segment.focus_keynull and the item is a VI for which the broad-VI-spec choice is made (Phase 2, Step A) →specifications/<VI>-<vslug>/specification.md— flat at the VI-dir level, no per-Epic subfolder; the feature folder is the VI dir itself.focus_keynull and the item is a stand-alone top-level Epic (no parent VI) →specifications/<EPIC>-<eslug>/, where<EPIC>here is this item's own key (==jira_key, sincefocus_keyis null) — top-level, keyed by the Epic, no VI wrapper. Physically this is the same dir the VI-dir step above already resolved (specifications/<VI>-<vslug>/with<VI>=<EPIC>=jira_key), so no separate resolution step is needed: the two null-focus_keycases share one physical target,specifications/<jira_key>-<slug>/, withspecification.mdwritten flat inside it either way.
- All delimiters this step writes are hyphens; matching an existing dir tolerates a stray
-/_. Neither the VI dir nor the feature folder is created here — the first phase that writes to it (Phase 2'sidea.mdwrite, in a fresh run) creates it.
- Resolve/derive the VI (top-level) dir:
Detect a prior run. If a
_session.mdexists in the resolved feature folder, record that a resume is available — Phase 1 asks the user resume-vs-fresh. If no_session.mdexists, this is a fresh run.
specify: is cwd-agnostic, like epics: — it reads Jira from the vault/export and writes specs to
an absolute $SPECS_PATH-rooted directory, so it does not require cwd to be inside either.
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.
Gate the VI. Execute require-on-main (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/phase-handoff.md §3) against the VI file in specifications/<VI>-<vslug>/ — resolve its actual name on the ref first: git -C "$SPECS_PATH" ls-tree --name-only "origin/<default>" "specifications/<VI>-<vslug>/" filtered to <VI>_*.md, falling back to the derived <VI>_<vslug>.md only when that listing is empty. A human-adjusted slug is a supported state — create-vi: and this skill's own Phase 2 reader both locate the VI by glob plus frontmatter, and the feature folder is matched by key-number for the same reason — so gating an exact derived filename would report absent for a VI that is present, and would let a slug-drifted file on a plugin branch escape the rows D/E stop entirely. Map its §3.7 return value by stopped first, never by on_main alone. Any stopping state → stop per §4.4. Otherwise (stopped: false): on pass/pass_amending, proceed — Phase 2 still reads the item from Jira via jira-reader exactly as today; the merged VI is a grounding confirmation, not a new content source; on absent, specify:'s existing Jira-export behaviour is unaffected — but report it: "No authored VI on <default> for <VI> — specifying from the Jira export at <path>. If a VI exists on a branch, this run would have stopped; it does not, so none does."; on unmanaged, behave exactly as before this feature — reachable here even after step 2's own $SPECS_PATH check, since that check only rejects an unset value, never an invalid path or a non-git directory.
Phase 1 — Configure
Rule: Ask, don't guess. This rule is absolute.
Use choices arrays; the last choice in every array MUST be "Other… (describe)".
At plan/approval, show the docs grounding: line in the form ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/docs-grounding.md resolved — ON <root> (retrieval: …) or OFF (<reason>) — verbatim, including any index-build, staleness, or shadowing clause it carries (off switch: --no-docs).
Feature folder. Confirm the path resolved in Phase 0:
choices: ["Use <feature_folder> (Recommended)", "Use a different path (you'll be prompted)", "Cancel", "Other… (describe)"]Resume vs fresh (only if Phase 0 found a
_session.md). Read it back and summarise which stages/questions are already settled:choices: ["Resume — skip settled stages/questions (Recommended)", "Start fresh — discard the prior session", "Cancel", "Other… (describe)"]On resume, Phase 5 begins at the first unsettled stage instead of the header.
Repo refresh policy (governs Phase 4's
code-scannerdispatches):choices: ["fetch + pull default branch (Recommended)", "fetch only", "no refresh", "Other… (describe)"]fetch + pull default branchmatchescode-scanner's own default (refresh.switch_to_default_branch: true, refresh.pull: true) — grounding wants present-day code, the same rationaleepics:uses.Repos search base (
$REPOS_PATH). Read${REPOS_PATH:-/workspace}.$REPOS_PATHmay be a single directory or a colon-separated list:choices: ["Use $REPOS_PATH (default /workspace) (Recommended)", "Use a different path (you'll be prompted)", "Cancel", "Other… (describe)"]If "different path", validate that at least one directory exists under the given value before recording it.
Also display (for user context): resolved feature folder; resolved jira_export_root; resolved
jira_key (VI); resolved focus_key (Epic, or 'none — VI-level'); resolved $REPOS_PATH; resolved
$SPECS_PATH.
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 record:
Classify as SIMPLE / MODERATE / SIGNIFICANT / HIGH-RISK. Specification authoring is typically MODERATE. Resolve 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 for large/cross-cutting VIs
reason: <one-line>
current_model: <the model this orchestrator/grill 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
review_model: <§2 Opus chain> # spec-reviewer (caller-pinned; recorded)
authoring_model: <= current_model> # the interactive grill + specification.md authoring (session model, not a delegated subagent)
opus_available: <true if a §2 Opus model resolved, else false>
notes: <any §2/§2.1 fallback or degradation>
The grill + authoring run inline on current_model (interactive judgment — not a delegated subagent), consistent with the model-routing SSOT. If no Opus is available, spec-reviewer falls to the Sonnet floor — record the degradation in notes and the final report.
Phase 2 — Read Jira
Phase 2 reads Jira in two steps, cheap before expensive. Step A settles granularity — the
input's type and, for a multi-Epic VI, which Epic — with a cheap vi-plus-epics read (and, when
needed, the progress-aware picker), resolving focus_key. Only then does Step B spend the full-depth
read, now scoped to the resolved Epic. This ordering resolves a null focus_key by a cheap
enumeration before any expensive full read, so the full read never pulls a whole multi-Epic VI
subtree the grill would only discard. When focus_key is already set on entry, Step A is skipped and
Phase 2 is just the full read (Step B).
Step A — Resolve granularity + focus Epic (cheap enumeration + picker)
Skip this step entirely when focus_key is already set on entry — any two-token form
(<VI-Key> <Epic-Key>, <dir> <Epic-Key>) or a bare <Epic-Key> auto-resolved to its parent VI in
Phase 0. The Epic is already chosen, so go straight to Step B.
Otherwise (focus_key is null), dispatch jira-reader at the cheap depth: vi-plus-epics to
determine the item's type and enumerate its child Epics without reading the full Story/Sub-task
subtree:
→ task(agent_type: "dev-workflows:jira-reader", model: <detection_model — §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, read the item's type from value_increment / linked_items and enumerate its child Epics
(filter linked_items to type == Epic). Then branch — this is the reusable progress-aware
Epic-picker pattern documented in ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/jira-input-resolution.md
(§ Progress-aware Epic picker), applied here with specify:'s own done-predicate:
- Stand-alone top-level Epic (the item is itself an Epic, no parent VI) → no picker; the item
is the focus. Set
focus_key= the item (==jira_key). The feature folder stays the flatspecifications/<jira_key>-<slug>/resolved in Phase 0 — a stand-alone Epic has no distinct parent VI, so<VI>==<EPIC>and there is no self-nested subfolder (Phase 0 step 3's shared-physical-target note). Proceed to Step B. - VI with exactly 1 Epic → no picker; auto-select it. Set
focus_key= that Epic and emit a one-line notice (e.g.Single child Epic <EPIC> '<title>' — authoring its spec.). Re-point the feature folder to that Epic's per-Epic subfolder (see Re-pointing below). Proceed to Step B. - VI with ≥2 Epics → render the progress-aware picker, one row per child Epic. For each Epic,
first resolve its actual feature folder the same way Phase 0 step 3 does: look under
specifications/<VI>-<vslug>/for an existing dir matched by that Epic's key-number (tolerate a stray-/_after the key, and a pre-existing slug that doesn't exactly match a freshly-derived one), falling back to the freshly-derivedspecifications/<VI>-<vslug>/<EPIC>-<eslug>/only when no such dir exists — this keeps a human-adjusted Epic dir slug from mis-displaying as ○ not-started. Compute each Epic's status fromspecify:'s done-predicate against that resolved folder:- ○ not started — no
specification.mdand no_session.mdthere → selectable. - ◐ in progress (resume) — a
_session.mdexists there but nospecification.md→ selectable as a resume; the per-Epic stage-level resume then runs in Phase 5 from that_session.md(resume stacks on the picker, per the shared pattern). - ● done —
specification.mdexists there → shown greyed, not default-selectable; selecting it offers revise. Default cursor = the first actionable row (in-progress before not-started). Render as achoicesarray: one entry per Epic (its ○/◐/● marker + key + title), then an explicit "Author one broad VI-level spec instead" choice, then"Other… (describe)". - On selecting an Epic → set
focus_key= that Epic; re-point the feature folder to its per-Epic subfolder (see Re-pointing below). - On "Author one broad VI-level spec instead" → leave
focus_key= null; the feature folder stays the flat VI-dir pathspecifications/<VI>-<vslug>/(Phase 0 step 3'sfocus_key-null VI case). Step B then reads the whole VI subtree.
- ○ not started — no
- VI with 0 Epics → this VI hasn't been split yet. Offer the existing without-Epics choices:
choices: ["Split into Epics first with epics:, then create them in Jira and re-import (Recommended)", "Author one broad VI-level spec now", "Cancel", "Other… (describe)"]specify:does NOT create Jira Epics itself (zero external API) — on "Split…", stop and guide the user through the manual round-trip (see the Phase 7 round-trip note). On "Author one broad VI-level spec now", leavefocus_key= null and proceed to Step B.
Re-pointing the feature folder after the picker. When Step A sets focus_key to an Epic (the
single-Epic and ≥2-Epic-selection cases), the feature folder becomes that Epic's per-Epic subfolder
specifications/<VI>-<vslug>/<EPIC>-<eslug>/ (Phase 0 step 3's focus_key-set case), superseding the
provisional VI-level folder confirmed in Phase 1 — Phase 0 already marks that folder provisional until
jira-reader runs. Re-detect a prior run there (a _session.md → a resume is available for that
Epic). The stand-alone-Epic and broad-VI-spec cases leave the Phase 0 folder unchanged.
Step B — Full Epic-scoped read
With granularity settled and focus_key resolved, dispatch jira-reader at depth: full — richer
than Step A's vi-plus-epics, because specify: needs the full linked subtree (Stories/Sub-tasks) as
the raw material for user stories, acceptance criteria, and test cases; vi-plus-epics would starve
the grill of exactly the detail it needs.
→ task(agent_type: "dev-workflows:jira-reader", model: <detection_model — §2.1 detection chain>):
"Return the structured handoff for this brief:
jira_export_root: [resolved jira_export_root] jira_key: [resolved jira_key] depth: full"
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:
- Epic-scope the read.
jira-readeris dispatched withjira_key= the VI and returns the whole VI linked-item hierarchy (jira-readeritself is unchanged). Whenfocus_keyis set, scope the returned hierarchy tofocus_key's subtree — the Epic itself plus its linked Stories/Sub-tasks (linked_itemswhoseparentchain leads tofocus_key) — filtering in-orchestrator and discarding sibling Epics' subtrees before feeding the downstream phases. Whenfocus_keyis null (broad VI-level spec), use the whole VI subtree as today. Everything below — themes,idea.md, the Phase 5 raw material — derives from this scopedfocus_keysubtree. - Extract capability themes and component/product mentions from the scoped subtree — feeds
Phase 3's repo derivation and Phase 4's
code-scannerdispatches. - Write
idea.mdin the feature folder from the scoped Jira text (the focus item's summary, description, and its linked-item summaries) — pre-spec brainstorming provenance, in the same spirit as theidea.mdconventionsource-truth.mdalready treats as non-authoritative oncespecification.mdexists. - Carry the scoped linked-item tree (the Epic's Stories/Sub-tasks) forward into Phase 5 — the raw material the grill mines for user stories, acceptance criteria, and test cases.
Phase 2.5 — Resolve applicable ARD (optional)
Resolve any ARD for this item by citing ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/ard-resolution.md with <VI>, <EPIC> (focus_key), and $SPECS_PATH. On status: none, skip and proceed exactly as before. On status: unmerged, stop, naming the returned branch and any pr. On status: found, keep the spec's user stories + scope consistent with the returned invariants + guidance_summary during the Phase 5 grill; record a necessary deviation under the spec's ### Open questions (never edit the ARD). Pass the invariants to spec-reviewer in Phase 6 as applicable_ard.
Phase 3 — Derive repos + soft gate
Auto-derive candidate repos. From the Phase 2 capability themes and any linked PR URLs in the
jira-readerhandoff (pull_requests[].repo), build a candidate repo-slug list. If the list is empty, escalate per theNo 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)"]Build the slug→clone map (
epics:-style). 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 candidate against the map. One match → use it. An ambiguous slug (multiple matches) or zero matches both escalate per the
Repo 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)"]Cross-check mounted status — soft gate. A resolved repo slug that is not actually mounted under
$REPOS_PATHdoes NOT hard-blockspecify:the way an unresolved slug does above. Instead: record a feasibility- [ ]open question in_session.md(e.g. "Cannot ground —<repo-slug>is not mounted; feasibility unverified"), report the gap to the user now, and PROCEED to Phase 4 with the remaining mounted repos. Describe the missing capability and why it matters — the specification cannot name or link an unmounted repo's code, so any claim resting on it stays an open question until the repo is mounted andspecify:is re-invoked (Phase 5 keeps_session.mdcurrent, so the run is resumable).
Phase 4 — Light code scan
Spawn code-scanner instances in batches of up to 4 concurrent agents per task message, on the
mounted candidates resolved in Phase 3. Wait for each batch before spawning the next. This is
deliberately a light scan relative to epics:' — grounding for feasibility and to avoid
contradicting existing behaviour, not a full reuse audit.
For each repo in the batch:
→ task(agent_type: "dev-workflows:code-scanner", model: <detection_model — §2.1 detection chain>):
"Scan this repo for the brief:
repo_path: <resolved absolute path for this repo from Phase 3> repo_url_slug: <repo slug, e.g. "cluster"> capability_themes: [paste the themes array from jira-reader] context: | [3–5 sentences: the Jira item's goal, what the specification must ground] search_hints: symbols: [class/function names inferred from the Jira text, 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 "does this exist / where / gaps" output; this grounds Phase 5's grill (e.g. answering a question from the scan instead of asking the user).REPO_MISSING— should not happen at this stage (Phase 3 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.
Documentation grounding (optional). Run resolve-docs-grounding specify per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/docs-grounding.md. When docs_grounding: ON, dispatch-docs-grounder with feature_summary = the scoped Epic/VI goal, jira_key = the focus key, themes = the Phase 2 capability themes. Carry the digest into the Phase 5 grill with grill-rank consumption. When OFF, skip silently.
Phase 5 — Author via grill
Interview technique (grilling — embedded; no runtime dependency). Conduct each stage as a relentless interview per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/grilling-technique.md — rounds rhythm (per that file's ## Rhythm): map the stage's design tree, ask the whole settled frontier as one numbered round, recompute from the answers, repeat until that stage's frontier is empty. Recommend each answer, explore the Phase 4 code scan / Jira content to self-answer (fact-vs-decision), and clear the confirmation gate before writing that stage's section.
Walk the stages in order, authoring specification.md live against ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specification-format.md, applying the no-hard-wrap prose convention in ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/prose-formatting.md:
- Header + Problem statement
- Scope (In/Out)
- User stories (
[Uxx]) - Acceptance criteria (
[ACxx], EARS) - Test cases (
[TCxx])
As each decision settles, append it to _session.md; capture a genuinely-ambiguous term in _glossary.md. Resolve open questions to zero where possible; leave genuinely unresolvable ones as - [ ] and keep the header Open questions count in sync. A repo gap surfacing here → escalate (describe the missing capability + why) and STOP; the run is resumable from _session.md after the user remounts and re-invokes.
Phase 5.5 — Structural pre-lint
Before finalizing, run the deterministic checks in
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/pre-lint.md against the drafted specification.md: the Universal
checks plus the spec block (incl. the - **Open questions**: N header equalling the - [ ]
count). Surface every finding; inline-fix the mechanical ones (renumber a duplicate [Uxx]/[ACxx]/
[TCxx], correct the open-questions count, delete a stray placeholder token); leave content gaps for
the grill/author. Advisory — never blocks; proceed to Phase 6 once findings are surfaced.
spec-reviewer remains the gate.
Phase 6 — Finalize + review gate
Render HTML.
python3 ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/scripts/specification-to-html.py <spec path>against thespecification.mdwritten in Phase 5. On failure, report the error and proceed — the HTML mirror is a review convenience, secondary to the markdown source of record.Dispatch
spec-reviewer.
→ task(agent_type: "dev-workflows:spec-reviewer", model: <review_model — §2 Opus chain; caller-pinned; recorded>):
"Review the specification for this brief:
Specification path: [absolute path to specification.md] Detected maturity: test applicable_ard: [the ARD invariants resolved in Phase 2.5, or omit if none]"
- Act on the verdict (mirrors
epics:Phase 7):BLOCK— fix the BLOCKER findings (the orchestrator/grill editsspecification.mdinline — there is no delegated writer to re-dispatch) and re-review once. If stillBLOCK, 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:
"Defer" means appending achoices: ["Provide manual fix notes (you'll be prompted)", "Defer to a follow-up issue (record in the final report)", "Override and accept the finding", "Cancel the whole run", "Other… (describe)"]## Refinement notessection tospecification.mdwith a- [ ]item per deferred finding (mirrorsepics:' Epic-refinement note), in addition to the final report.MAJOR/MINOR/NIT(surfaced underPASS WITH RECOMMENDATIONS) — defer to the final report; no mandatory fix cycle.PASS/PASS WITH RECOMMENDATIONS— proceed to Phase 7.
Cap: one fix cycle + one re-review maximum.
Phase 7 — Handoff
Write the feature folder: specification.md (Published: no), idea.md, _session.md, _glossary.md, and the rendered .html.
Then offer (commit-when-asked — never automatic), presenting ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/phase-handoff.md §4.3's choice array verbatim:
choices: ["Branch + commit + push + open PR to main (Recommended)", "Just write the files — I'll handle git (the next phase will stop until this is on main)", "Cancel"]
On the first choice, execute handoff-to-main (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/phase-handoff.md §2) with prefix: spec; feature_folder = the Epic subfolder for a per-Epic spec (a VI + focus Epic) or a stand-alone-Epic spec (<EPIC> = focus_key, which for a stand-alone Epic equals jira_key), or the VI dir for a broad VI-level spec (focus_key null) — Epic keys are globally unique, so the per-Epic form needs no VI prefix, and both forms use hyphens; §2.2 derives spec/<EPIC>-<eslug> or spec/<VI>-<vslug> from that folder, matching today's branch names; deliverable_paths = specification.md, _session.md, _glossary.md, and the rendered .html; title: <EPIC|VI> Add specification; and body_facts = the stage/user-story/AC/TC counts, the open-question count, and the spec-reviewer verdict. Merged-to-main = ready for the dev-team handover — Devs and design: read the spec from main, never from the branch, and require-on-main now enforces that rather than merely stating it. Emit its §4.1 outcome line in the Final report.
Next Epic (after a per-Epic spec from a multi-Epic VI)
When this run authored a per-Epic spec that was selected from Step A's ≥2-Epics picker, offer — once Phase 7's write/commit completes — to continue with a sibling Epic under the same VI:
choices: ["Next Epic — re-open the picker (Recommended)", "Stop here", "Other… (describe)"]
On "Next Epic", re-render the Phase 2 Step A progress-aware picker minus the just-completed Epic — recompute each remaining Epic's ○/◐/● state from its feature folder, so the freshly-authored spec now shows ● done and drops out of the actionable set — then, on selection, set focus_key to the new Epic and loop back through Phase 2 Step B → Phases 3–7 for it. This offer does not apply to a stand-alone Epic, a single-Epic VI, or a broad VI-level spec — there is no sibling to advance to.
Jira round-trip (document to the user — they will otherwise miss it)
The end-to-end flow:
epics: <VI>drafts child Epic definitions.- You create those Epics in Jira (manual —
specify:/epics:never call Jira). - You re-import the VI to
$VAULT_PATH/jira-products/<KEY>so the new Epics appear in the export. specify: <each Epic>reads the Epic from the refreshed export and authors itsspecification.md.
Steps 2–3 are the round-trip; without them specify: cannot see the Epics.
Phase 8 — Session maintenance & feedback
Terminal phase — runs after Phase 7 and before the Final report is presented;
NEVER interrupts an earlier phase. specify: has no built-in maintenance agent,
so this phase invokes impl-maintenance on the Sonnet detection chain and then
persists the plugin-facing slice of its report as session feedback.
Capture-at-block invariant. This terminal phase captures gaps for a completed run. Separately, if an EARLIER phase halts on a plugin / skill / command / reference gap (a capability the run needed but the plugin lacked), emit-block (per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.md) at that halt before escalating — so a run abandoned at the block still records the gap. NEVER emit-block for a work-quality review BLOCK or an environment / user halt (repo/spec gate, jira-not-found, cancellation).
Session-hygiene invariant. End the report with a ### Context hygiene block per
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md — prepare-first (the
resume.md write runs later, at the end of this terminal phase, per
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md
§1 — this block prints the guidance only), then a
span suggestion (VI-level→epics: /compact; Epic-level→design: /clear) +
/rename <VI-ID>-<slug>-pe. Guidance only, never auto-run.
- Invoke
impl-maintenance(agent_type: "dev-workflows:impl-maintenance", model:<detection_model — §2.1 detection chain>):"Analyse this session and return a Lessons Learned report.
Session handoff:
- Command run: specify:
- What was done: [one-paragraph summary of the specification authored]
- Key events: [BLOCK reviews and their reason, unmounted-repo soft-gate advisories, unresolved open questions, picker / round-trip friction — or 'none']
- Workarounds used: [manual steps not automated by the workflow — or 'none']
- Review verdict: [the spec-reviewer verdict — PASS | PASS WITH RECOMMENDATIONS | BLOCK]
- Test result: N/A (no tests in specify:)
- Project root: [the resolved feature folder under $SPECS_PATH]"
- Persist plugin feedback (automatic). Project the report's plugin-facing
slice into the specs repo by citing
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.mdand calling itsemit-autoentry point (§6). Pass the Lessons Learned report,command: specify:, the run'sjira_keyandsource, andplugin_version(read from~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/.plugin/plugin.json).emit-autorenders only the report's Command workflow improvements, New agents / skills, and plugin Reference docs sections plus the Key observations that triggered them (§4) — never target-projectcopilot-instructions.md/hook advice — asorigin: autoentries, dedupes by stableid(§3), resolves the target via the §2 specs-first ladder, and writes silently. - Surface the persisted path (or "no plugin-facing signal — nothing persisted") as this phase's only output.
Write the resume pointer. Cite
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md
§1 and write/overwrite <VI-dir>/dev-workflows/resume.md now — after the
feedback and follow-up entries above, so the pointer reflects the completed run,
and before the commit step below, so it is included in it. Redact per §1.
Silent; the printed ### Context hygiene guidance already appeared in the
report.
Commit session artifacts (terminal). Cite
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md
and execute its commit-artifacts entry point (§4) inline — the LAST action of
the run. It stages ONLY the §2.1 bounded artifact paths inside $SPECS_PATH,
commits <KEY> Add dev-workflows session artifacts (specify:) with no
Co-Authored-By trailer, and pushes to the branch this run's handoff phase
created (§4.1). It NEVER touches a code repo, a docs repo, the vault, or the
current working directory; NEVER force-pushes; NEVER fails the run; and skips
entirely when the run carries specs_git: blocked (§3.3 G0), re-emitting that
notice. Hold its §6 outcome line for the Final report.
ADDITIVE — this phase NEVER fails the run, NEVER commits the deliverable (still
true — git for the deliverable is offered only in Phase 7, and this phase itself
runs no git; the terminal step above commits only the bounded session-artifact
paths in $SPECS_PATH, per
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md
§2.1), and NEVER writes into the current working directory. The specs-first
ladder writes the feedback file inside $SPECS_PATH, alongside the feature
folder — the intended home.
Final report
Report: feature-folder path; stage/user-story/AC/TC counts; open-question count; unmounted-repo advisories; the spec-reviewer verdict; the Phase handoff: outcome line from handoff-to-main (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/phase-handoff.md §4.1); the Specs repo: outcome line from commit-artifacts (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md §6), with any guard notice repeated in full; and a reminder of the round-trip described above + that Published: yes is a human-only freeze step.
Next step
End the report with a ### Next step recommendation per ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/next-phase-offer.md (guidance only — never auto-invoked): Epic-level spec (<VI> <Epic>) → hand to Dev → design: <VI> <Epic>, which will not start until this spec's pull request above is merged, and the Epic fan-out specify: <VI> <another-Epic> for a sibling Epic (breadth); VI-level spec (<VI> only) → epics: <VI> (PE), which stops rather than skipping — the spec exists but isn't yet on main — until this pull request above is merged. If the run BLOCKED or left open - [ ] items, recommend resolving those first.
Context hygiene
The resume pointer is written at the end of the terminal maintenance phase (Phase 8), per session-hygiene.md §1. Then:
- VI-level spec →
epics: <VI>(still PE)? → run/compact— context still relevant. - Epic-level spec → Dev
design: <VI> <Epic>(even yourself)? → run/clearfor a clean slate. - Consider
/rename <VI-ID>-<slug>-peto relocate this session later.
Guidance only — see ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md.