--- name: parley-tracker description: "Author epics, user stories, and technical subtasks as canonical markdown files that read well for business people, technical people, AND the AI agents that implement them — then mirror them into any tracker (Jira, Linear, GitHub Issues, GitLab, Trello, a kanban board). Use when a Parley Deck idea or any backlog needs vendor-neutral, no-assumption, AI-implementable tickets with hybrid acceptance criteria and a tool-enforced gap-scan before work starts." --- # parley-tracker An opt-in Parley Deck addon skill for authoring epics, stories, and technical subtasks that are simultaneously readable by a **business** reader, a **technical** reader, and an **AI agent** that implements them. The skill is vendor-, tracker-, and runtime-agnostic. It defines a neutral markdown contract and a neutral field schema; mapping to a concrete tracker (Jira, Linear, GitHub Issues, GitLab, Trello, a plain kanban board) happens at the edge, with graceful degradation. The skill itself authors text and emits a payload — it never holds tracker credentials. ## Core Rule **The tracker is a mirror. The markdown ticket files are canonical.** A ticket lives as a markdown file in the repo. Its YAML frontmatter is the machine contract; its body is the human contract. A tracker (Jira, Linear, GitHub Issues, GitLab, Trello, …) is a downstream *projection* of that file, never a source of truth. - Sync is **one-way (file → tracker)** by default. - A `--pull` reconcile writes tracker-side edits back into the file **only** for fields the file flags `mirror-owned` (default `[status, assignee]`). Any field not listed is never written back; divergence on a non-mirror-owned field surfaces as a conflict, not a silent overwrite. - **Graceful degradation:** a field the target tracker lacks is dropped from the *mirror*, never from the *file*. The file stays whole; only the projection loses fidelity. A tracker comment, status flip, or hand-edited acceptance criterion can never silently change a requirement. Requirement changes discovered in a tracker return to Parley through a new round, an inbox escalation, or an `IMPLEMENTATION.md` update — see "Relationship to Parley Deck core" below. ## When to use this skill Use it when: - A Parley Deck idea (`parley-deck/ideas//FINAL.md`) must become a backlog of work items. - A backlog must be readable by non-technical stakeholders *and* drive AI implementers without hidden assumptions. - Tickets must survive a tracker migration (the canonical file is the asset; the tracker is replaceable). - Multiple implementers will pick up work in parallel and you need each item's scope (its `files` set) to be explicit so work can be split without collisions. Skip it for throwaway notes, or when the team's tracker is genuinely the system of record and there is no canonical-file requirement. ## File layout Tickets live under a `tickets/` tree whose path mirrors the epic hierarchy: ```text tickets//epic.md tickets///story.md tickets////subtask.md ``` The canonical design they trace back to stays in Parley: ```text parley-deck/ideas//00-prompt.md # problem + participants (epic seed) parley-deck/ideas//FINAL.md # authoritative design / spec parley-deck/ideas//IMPLEMENTATION.md # implementation state + validation ``` The three canonical skeletons authors copy, and the readiness tooling, live next to this file: ```text skills/parley-tracker/templates/epic.md # filled, self-passing exemplars skills/parley-tracker/templates/story.md skills/parley-tracker/templates/subtask.md skills/parley-tracker/bin/validate.js # readiness gap-scan / lint skills/parley-tracker/bin/claim.js # gap-scan-gated claim ``` Each template is a **filled, self-passing example** (`validate` exits 0 on it): copy the matching one, then replace every value — `id`, `title`, the `SLUG`/`REVISION`/`AGENT-ID`/`COMMIT-SHA` markers, and the prose — with your own. Never delete a required slot — mark it `n/a (reason)` instead. Because `validate` fails on any leftover `<...>` placeholder, a half-filled copy cannot be marked ready by mistake. ## One file, three audiences Every ticket is **one** file with an audience-tagged body and a YAML frontmatter metadata block. The audience tags are sections of that one file, not separate documents: - **`## At a glance`** — MANDATORY 2–4 lines, written for all three audiences: one-sentence outcome · one-sentence scope · one-sentence done-when. It must surface any constraint that materially alters the outcome, because a stakeholder may read only this block. It is the only mandatory cross-audience block, and it is what makes a busy reader willing to open the file at all. - **`## [B] Business`** — value, who benefits, why now, the success indicator. - **`## [T] Technical`** — systems touched, interfaces, constraints, NFRs. - **`## [A] Agent directives`** — self-contained scope, explicit `Do` / `Do not`, and the assumption policy. Must be non-empty and contain at least one `Do not` constraint (it forces explicit negative scope). A human reader skims their own tag. An AI agent reads **all three sections plus the frontmatter**. Tooling MAY render a per-reader filtered view by tag, but the file is never split. ### Frontmatter metadata schema This is the neutral machine contract. Fields are mapped to a concrete tracker at the edge (see "Generic field schema → tracker mapping"). ```yaml --- id: E-001 | S-001 | T-001 # immutable, never reused; tracker-stable type: epic | story | subtask title: parent: # epic has none; story -> epic; subtask -> story status: draft | ready | in-progress | review | done | blocked | paused | dropped assignee: | n/a> priority: p0 | p1 | p2 | p3 labels: [domain:, nfr:] # free-form tags; map to tracker labels/components estimate: # optional files: [] # the parallelism boundary; AI scopes its reads to these apis: [ | n/a] # interface contracts the work must honor arch: [ | n/a] # architecture references worktree: n/a | { path, branch, base } # set when this item is built in an isolated worktree dod: [AC-1, AC-2] # Definition of Done = checklist of AC ids (not prose) mirror-owned: [status, assignee] # only these fields may be written back on --pull canonical_source: parley-deck/ideas//FINAL.md@ # design source + revision tracker: { provider: generic, external_id: , url: } --- ``` Rules: - `id` is immutable and never reused, even after a ticket is `dropped`. - `validate` requires the full canonical frontmatter the templates prescribe — `id`, `type`, `title`, `status`, `parent`, `assignee`, `priority`, `labels`, `files`, `apis`, `arch`, `worktree`, `dod`, `mirror-owned`, and `canonical_source` — each present and either populated or an explicit `n/a (reason)`. `canonical_source` must be **populated** (not `n/a`) on a story/subtask. Prefer an explicit `n/a (reason)` over silently omitting a slot. - Do not add fields not in this schema. Tracker-specific extras live in an optional projection plugin (see vendor-neutrality), never in the canonical file. - `parent` must resolve to an existing ticket file (or `n/a` for an epic). ### Body skeleton ```markdown # ## At a glance # MANDATORY 2-4 lines, all audiences: outcome · scope · done-when ## [B] Business # value, who benefits, why now, success indicator ## [T] Technical # systems, interfaces, constraints, NFRs ## [A] Agent directives # self-contained scope, explicit Do / Do not, assumption policy ## Acceptance criteria # AC-1..AC-N, audience-tagged; Gherkin or measurable + Verify ## Definition of Done / Verification # one checkbox per AC: - [ ] AC-1 (Verify: <cmd>) — <commit-sha> ## Non-goals # explicit out-of-scope (prevents AI scope creep) ## Dependencies / blocks # ticket ids and reasons ## Open questions # each tagged [needs:business|technical|decision] ``` ## Acceptance criteria (hybrid, audience-tagged, id'd) Every criterion is named `AC-N` and carries an audience tag (`[B]`, `[T]`, `[A]`, or a combination). The format depends on the kind of criterion: - **Behavioural → Gherkin.** One `Given / When / Then` scenario per `AC-N`. Keep the `Given` free of implementation detail a business reader cannot parse; push implementation detail into the `[T]` section and reference it. - **Non-functional (perf, security, availability, reliability) → measurable bullet + mandatory `Verify:` command.** Shape: `<measurable statement with a number>. Verify: <single command>`. The `Verify:` clause is mandatory: it is what makes the AC AI-checkable and reviewer-checkable with one paste. **No `Verify:` command ⇒ the AC is not measurable ⇒ rewrite it.** Tag a non-functional AC `[NFR]` (in addition to its audience tag). `validate` **enforces** the split lightly: an `[NFR]`-tagged AC **must** carry a non-empty `Verify:` command, and any AC with a `Verify:` line must supply a real command (an empty `Verify:` fails). Behavioural ACs carry the Gherkin `Given / When / Then`. Required categories for any story or subtask: - At least one **happy-path** behavioural AC. - At least one **edge / error / offline** AC — or an explicit `n/a (reason)`. - **NFR ACs are required** where the item touches perf, security, or availability, and are **forbidden from being implied** — write them as measurable bullets with `Verify:`. Audience tags let a reviewer spot a story with only `[T]` ACs (a sign the business value was never stated) or a story with no `[A]` AC (a sign it is not actually AI-ready). Example (lifted shape — see the templates for full instances): ```markdown ## Acceptance criteria - AC-1 [A][T] Given <initial state>, When <action>, Then <observable result>. - AC-2 [A][T] Given <error/edge state>, When <failure action>, Then <observable fallback>. - AC-3 [T] Measurable: <statement with a number>. Verify: `<single command>`. ``` ## No-assumption gap-scan (tool-enforced) Before an agent claims any ticket it MUST run the gap-scan. `validate` runs **every** check and **reports all errors** (it does not stop at the first one), so a single run shows the whole gap list. The checks it enforces: 1. **Frontmatter present and parseable;** `validate` exits 0 only when all of the below hold. 2. **Required fields non-empty** (`id`, `type`, `title`, `status`, `parent`); `parent` is non-empty or `n/a` (an epic must be `n/a`); every `dod` entry references an existing `AC-N` id. 3. **Full canonical schema present and populated-or-`n/a`:** `assignee`, `priority`, `labels`, `worktree`, `mirror-owned`. `canonical_source` is **required and populated** for a story/subtask (present-or-`n/a` for an epic). 4. **Enums valid** (`type`, `status`, and `priority` when set). 5. **`files` / `apis` / `arch` each populated or explicitly `n/a`.** 6. **No unreplaced `<...>` placeholder** remains in any required field, in the `At a glance` / `[B]` / `[T]` sections, or in any acceptance criterion — a slot may instead be an explicit `n/a (reason)`. (This is what makes a half-filled copy of a template fail until it is actually filled in.) 7. **`At a glance`, `[B] Business`, `[T] Technical` sections non-empty** (`n/a (reason)` accepted — typically a subtask's `[B]`). 8. **`[A] Agent directives` non-empty** with at least one `Do not` constraint. 9. **Every AC has an audience tag** and is either a Gherkin scenario or a measurable bullet with a **non-empty** `Verify:` command; an `[NFR]`-tagged AC **must** carry a `Verify:` command. 10. **At least one happy-path (non-edge) AC** AND **at least one edge / error / offline AC** (or an explicit `n/a (reason)`). Any failure → the agent returns `BLOCKED: <failing check>` referencing the check, or opens an `Open questions` entry tagged `[needs:business|technical|decision]`. **It never proceeds by guessing.** Enforcement is in the tool, not just the doc: - The **`claim` command RUNS the gap-scan and refuses to set `status: in-progress` on failure** (`bin/claim.js`; on a failed scan it prints `BLOCKED:` and exits non-zero without writing the file). A template alone cannot guarantee the agent stops; running the scan as part of `claim` does. This is the single highest-leverage rule for AI output quality. - **Parent resolution** is only cross-checked when `validate` can see the sibling tickets, i.e. in directory mode: run `validate --strict --dir <tickets-dir>` (or `--strict <glob>`) for the whole-tree gap-scan that resolves every `parent:` against the other files. Single-file mode (`validate <ticket.md>`) checks one file in isolation and treats any non-empty, non-`n/a` `parent` as a syntactic reference (it cannot confirm the parent file exists). Use `--strict --dir` for the readiness gate over a backlog. `bin/validate.js` and `bin/claim.js` are dependency-free and run on any modern Node (`node bin/validate.js <ticket>`, `node bin/claim.js --assignee <who> <ticket>`). ## Definition of Done = AC-id checklist DoD is a checklist of **AC ids**, never prose, so it is mechanically verifiable. The `dod` frontmatter field lists the AC ids that must pass. Per ticket type: - **Epic DoD:** all child stories are `done`; all epic ACs pass their `Verify:`; non-goals respected (no scope-creep commits in the diff). - **Story DoD:** all ACs pass `Verify:`; `validate` exits 0; the claim is released (`status: review`); linked subtasks are `done`. - **Subtask DoD:** all ACs pass `Verify:`; `validate` exits 0; tests are green on the integration branch; every `dod` checkbox is ticked with a commit ref. ### The `## Definition of Done / Verification` checklist (recordable completion) Beyond the `dod` frontmatter ids, every ticket body carries a `## Definition of Done / Verification` section: one checkbox per AC, each naming its `Verify:` command and the commit that proved it, e.g. ```markdown ## Definition of Done / Verification - [ ] AC-1 (Verify: <cmd>) — <commit-sha> - [ ] AC-2 (Verify: <cmd>) — <commit-sha> ``` Ticking a box with its commit sha is how "this AC passed, here is the proof" is recorded in the canonical file — the boxes are filled as the work lands, never up front. All three shipped templates include this section pre-wired to their ACs; copy it and fill `<cmd>`/`<commit-sha>` as each AC verifies. ## Quality and decomposition - **INVEST governs stories.** Independent (so they are parallel-safe), Negotiable, Valuable, Estimable, Small (so a story fits an agent's context), Testable (clear assertions — the ACs). - **Stories are vertical end-to-end slices; subtasks are technical units.** A **story** is split from an epic as a *vertical*, end-to-end slice that delivers one observable, independently valuable behaviour (INVEST). A **subtask** is a *technical unit* of one story — it is **not** independently end-to-end valuable (its parent story is); it exists to make execution and review tractable. Split a story into subtasks with **disjoint `files` sets**. Disjoint `files` sets are what make parallel implementation safe by construction: two subtasks that never touch the same file can be built concurrently with zero merge conflict. The `files` field is the boundary; an isolation layer (e.g. a per-subtask worktree) enforces it. - **Readiness lint (`validate`)** rejects vague tickets — anything that only says "improve", "support", "handle", or "integrate" with no observable criteria — and AI-unready tickets (no `[A]` directives, no `Verify:` on NFR ACs, blank required slots). Rewrite, do not mark such a ticket `ready`. Decomposition discipline: - One **epic** per coherent business outcome — never one epic per technical layer. - One **story** per independently valuable, user-visible behaviour — a vertical, end-to-end slice (INVEST). - **Subtasks** are technical units of one story, with disjoint file scope; they are not independently end-to-end valuable but make execution and review tractable. - Every AI-assigned ticket carries `canonical_source` (path + revision), `files`, `apis`/`arch` (or `n/a`), test expectations, and the assumption policy. ## FINAL.md → tracker mapping `FINAL.md` is canonical for **design**; tickets are canonical for **work state**. Two different canonical artifacts, no overlap. ```text idea 00-prompt problem + non-goals -> epic [B] Business + Non-goals FINAL.md design / value streams -> stories (one per observable behaviour) FINAL.md observable acceptance criteria -> story acceptance criteria FINAL.md context / orientation -> [T] Technical + AI references (files/apis/arch) FINAL.md known risks / de-risking -> story risks, ask-before rules, NFR ACs IMPLEMENTATION.md plan / checklist -> subtasks review-consensus deferred follow-ups -> follow-up tickets FINAL.md open questions -> Open questions [needs:...] (promoted to tickets only when a decision unblocks work) ``` Minimum created set for one idea: ```text 1 epic : the idea's outcome N stories : one per observable behaviour / acceptance-criterion cluster M subtasks : one per implementation boundary, migration, test suite, or docs task ``` ## Generic field schema → tracker mapping (with graceful degradation) The mirror contract — the minimum-viable fields **every** tracker supports — is: ```text id, type, title, status, assignee, parent, labels, priority ``` Extended fields (`files`, `apis`, `arch`, `nfr`, `dod`, `worktree`, `canonical_source`) live in the file and are mirrored **only where the tracker allows**. Map the neutral schema to the target tracker at the edge — for example: ```text neutral -> typical tracker concept ----------------- ---------------------------------- type -> issue type (epic / story / sub-task / task) status -> workflow status / state column assignee -> assignee / owner parent -> epic link / parent issue / parent card labels -> labels / components / tags priority -> priority field title/body -> summary + description (audience sections concatenated) acceptance crit. -> description block or a checklist field dod -> checklist (project AC titles, not opaque ids, for tracker UIs) files/apis/arch -> custom field if supported, else folded into description ``` Graceful degradation: if the tracker has no field for `files`/`apis`/`worktree`, those are appended to the description (or dropped from the mirror) — but they **stay in the canonical file**. A degraded mirror is acceptable; a corrupted file is not. ## Vendor-neutrality and the opt-in connector - The core skill **authors text and emits a payload** (the markdown file plus a neutral JSON/YAML representation of the frontmatter). It defines payloads and decision rules first. - Actual create/update against a live tracker (MCP, REST, CLI) is an **opt-in connector add-on**. **No authentication or credentials live in the core skill** — the connector is a separate, separately-enabled component. - A per-tracker **projection plugin** MAY add native fields (e.g. sprint or cycle fields) to the *mirror* without polluting the canonical file. Tracker-specific features stay below the neutral schema, never inside it. ## Relationship to Parley Deck core This skill stays thin where Parley Deck core is thin. The only seam the core protocol needs is a thin note (a separate meta-protocol change, not this skill): > External trackers are mirrors. A tracker ticket cannot override `FINAL.md`. > Requirement changes discovered in a tracker return through a Parley round, an > inbox escalation, or a new idea. This skill carries all the ticketing mechanics: the three-audience template, the field schema, the hybrid AC rules, the gap-scan, the DoD model, the FINAL.md mapping, the tracker field mapping, and the connector boundary. ## Pitfalls - **Tracker becomes a second source of truth.** If comments or status flips drift back into the file un-gated, the canonical model is broken. Keep `--pull` restricted to `mirror-owned` fields; surface any other divergence as a conflict. - **Three-audience bloat → everyone skim-reads.** Mitigate with the mandatory `At a glance` block that surfaces outcome-altering constraints, and audience tags for filtered views. - **AI fills gaps anyway.** Only enforcement stops this — run the gap-scan inside `claim` and refuse `in-progress` on failure. - **Gherkin-for-NFRs theatre.** Forcing perf/security into Gherkin to feel "complete" yields unmeasurable criteria. Keep NFRs as measurable bullets with a `Verify:` command; a Gherkin `Then` with no machine-checkable assertion is a lint warning. - **Over-fitting to implementation hints.** Distinguish "allowed / likely files" from "must modify exactly these files" in `[A]`, so a ticket does not suppress a better design. - **Lowest-common-denominator genericity.** The right generic layer is a stable neutral schema with per-tracker projections below it — not the absence of structure.