From fba350a76819f82e028734397e8ebc9e91ac2fcc Mon Sep 17 00:00:00 2001 From: vanvasten Date: Wed, 4 Nov 2026 19:30:28 -0300 Subject: [PATCH 1/2] feat(stories): one shared format for client user stories, tickets, QA and closing comments (OSS-129) --- .claude/AGENTS.md | 2 +- CHANGELOG.md | 14 ++++ CLAUDE-FULL.md | 4 +- MANUAL.md | 9 ++- README.md | 2 +- agents/linear.md | 5 ++ docs/frontmatter-reference.md | 2 +- docs/skill-authoring.md | 2 +- docs/skills.md | 1 + .../build-closing-comment/graders/criteria.md | 8 ++ evals/build-closing-comment/prompt.md | 9 +++ evals/dr-review-ticket-antipatterns/case.yaml | 8 ++ .../dr-review-ticket-antipatterns/fixture.sh | 43 +++++++++++ .../graders/criteria.md | 10 +++ evals/dr-review-ticket-antipatterns/prompt.md | 3 + evals/stories-approval-stop/case.yaml | 8 ++ evals/stories-approval-stop/fixture.sh | 12 +++ .../stories-approval-stop/graders/criteria.md | 10 +++ evals/stories-approval-stop/prompt.md | 1 + skills/build/SKILL.md | 3 +- skills/dr-review/SKILL.md | 22 +++++- skills/stories/SKILL.md | 75 +++++++++++++++++++ skills/stories/references/closing-comment.md | 27 +++++++ skills/stories/references/kickoff.md | 20 +++++ skills/stories/references/qa-checklist.md | 12 +++ skills/stories/references/ticket.md | 57 ++++++++++++++ src/lib/claude-managed-file-manifests.ts | 18 ++++- src/lib/codex-runtime-manifests.ts | 16 +++- src/lib/lint-skills.ts | 2 +- src/lib/managed-skills.ts | 1 + tests/install-e2e.test.ts | 5 ++ 31 files changed, 397 insertions(+), 14 deletions(-) create mode 100644 evals/build-closing-comment/graders/criteria.md create mode 100644 evals/build-closing-comment/prompt.md create mode 100644 evals/dr-review-ticket-antipatterns/case.yaml create mode 100755 evals/dr-review-ticket-antipatterns/fixture.sh create mode 100644 evals/dr-review-ticket-antipatterns/graders/criteria.md create mode 100644 evals/dr-review-ticket-antipatterns/prompt.md create mode 100644 evals/stories-approval-stop/case.yaml create mode 100755 evals/stories-approval-stop/fixture.sh create mode 100644 evals/stories-approval-stop/graders/criteria.md create mode 100644 evals/stories-approval-stop/prompt.md create mode 100644 skills/stories/SKILL.md create mode 100644 skills/stories/references/closing-comment.md create mode 100644 skills/stories/references/kickoff.md create mode 100644 skills/stories/references/qa-checklist.md create mode 100644 skills/stories/references/ticket.md diff --git a/.claude/AGENTS.md b/.claude/AGENTS.md index 1315451c..d6b95ccd 100644 --- a/.claude/AGENTS.md +++ b/.claude/AGENTS.md @@ -27,7 +27,7 @@ so the standards load every turn. **TypeScript on Bun.** Runtime: `bun >=1.2.21`. Deps: `zod` and `typescript` (the native-ts codemap engine loads the compiler at runtime; YAML parsing uses `Bun.YAML`, prompts use `node:readline`). Dev: `@biomejs/biome`, `@types/bun`. -**Skill library ratchets.** The managed library contains exactly 25 skills. +**Skill library ratchets.** The managed library contains exactly 26 skills. `SKILL_COUNT_BASELINE` in `src/lib/lint-skills.ts` fails when the count moves either way. The description-byte ceiling is one-way: tighten the longest descriptions when it fails; never raise the ceiling. `bun run lint:skills` diff --git a/CHANGELOG.md b/CHANGELOG.md index f0d3afd4..695c13c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to cc-settings are documented here. > **Versioning** — cc-settings uses a single version number matching the installer (`src/setup.ts` `VERSION` constant, written to `~/.claude/.cc-settings-version` sentinel). Historical entries below 10.0 predate this unification; the jump from v8.x to v10.x in April 2026 realigned the product version with the installer version that was already ahead. +## [Unreleased] + +Client builds get one way to write and work tickets. Until now each person and agent wrote client tickets differently, and a first pass written in one day came out thin: parents with no criteria of their own, engineer-level criteria, the same Verify block pasted everywhere, bare Figma node IDs. + +**Added:** +- `skills/stories/`: runs the pipeline from scope to user stories, stops for client approval, then writes the implementation review, tickets, kickoff and QA checklist. The ticket, kickoff, QA checklist and closing comment templates live in its `references/`. Tickets go to Linear through the `linear` agent or to GitHub with `gh issue create`. The skill library goes from 25 to 26 skills. +- `evals/stories-approval-stop/`, `evals/build-closing-comment/`, `evals/dr-review-ticket-antipatterns/`. + +**Changed:** +- `skills/build/SKILL.md`: a ticket's acceptance criteria are the done list, and a ticket build ends with a closing comment draft that keeps a "Verified by logic, not live" line for anything not seen working. +- `skills/dr-review/SKILL.md`: a ticket review variant flags container parents, implementation detail in criteria, bare design node IDs, copied boilerplate, and tickets marked done from a reasoned check. +- `agents/linear.md`, `CLAUDE-FULL.md`: `tickets` and `review-ready` events. +- Claude managed-files manifest v41 and Codex runtime manifest v29 carry the new skill files. + ## [15.97.0] — 2026-11-04 `/ship` pushes with whatever GitHub login works on the machine, never pushes straight to `main`, and always files the Linear ticket in the repo's own team and project. Before this, a session with no SSH key loaded went looking for 1Password, kept retrying SSH, and merged a fix to `main` with no ticket and no PR. diff --git a/CLAUDE-FULL.md b/CLAUDE-FULL.md index 32f1b168..6fbc56eb 100644 --- a/CLAUDE-FULL.md +++ b/CLAUDE-FULL.md @@ -57,7 +57,9 @@ Work Mode": In a repo with a `Linear:` startup line, the main session spawns `linear` at each milestone of a unit of work: `start` before the first commit (wait for the ID and put it in the branch name), `pr-opened` and `ci` after `/ship` -reports, `merged` after landing, and `follow-up` for work you defer. Pass the +reports, `review-ready` with the closing comment a `/build` ticket run +drafts, `merged` after landing, and `follow-up` for work you defer (`/stories` +spawns it with `tickets` to create approved tickets). Pass the event, repo, branch, issue ID, PR URL and CI result you already have. `/ship` and `/build` run as forks and cannot spawn it; ship's "Linear issue" step is their fallback, and the `linear-gate` hook blocks a PR that has no issue. diff --git a/MANUAL.md b/MANUAL.md index 00d2eac2..96e5b3d5 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -116,6 +116,13 @@ Codex falls back to `rg` and native code navigation. Say "create our glossary" or "record this decision as an ADR". `context-doc` interviews for the real domain terms, then writes `CONTEXT.md` and architecture decision records. +### Turn a client scope into tickets + +Say "write the user stories" or "break this scope into tickets". `stories` writes the scope and +user stories docs, then stops until the client approves the stories. A later run writes the +implementation review, the tickets, the kickoff and the QA checklist. `/build` drafts each +ticket's closing comment, and `/dr-review` flags thin tickets. + ## Review, proof, and diagnosis ### Review a diff @@ -267,7 +274,7 @@ warnings, run `bun ~/.claude/src/scripts/audit-hooks.ts`. Follow ## Reference routes -- [All 25 skills, effects, approvals, output, prerequisites, and host behavior](./docs/skills.md) +- [All 26 skills, effects, approvals, output, prerequisites, and host behavior](./docs/skills.md) - [Installation flags, tiers, paths, side effects, rollback, and uninstall](./docs/install.md) - [Claude Code and Codex parity](./docs/claude-vs-codex.md) - [Models, effort, advisor, and quota policy](./docs/agent-models.md) diff --git a/README.md b/README.md index c609fea3..1936740a 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,7 @@ on every machine. The same request behaves differently once it is installed: React, performance, accessibility, security, git, motion, style) load only for the files they cover, and six stack profiles (Next.js, React Router, React Native, Tauri, WebGL, durable agents) add the specifics of each stack. -- **25 skills.** Named workflows selected from ordinary language or pinned with `/name` in Claude +- **26 skills.** Named workflows selected from ordinary language or pinned with `/name` in Claude and `$name` in Codex: fix, build, review, ship, audit, poke-holes, handoff, and the rest. The [skill guide](./docs/skills.md) lists what each one changes and when it asks. - **9 role agents.** Planner, explorer, implementer, tester, reviewer, security reviewer, diff --git a/agents/linear.md b/agents/linear.md index f1f4dd35..bcfea322 100644 --- a/agents/linear.md +++ b/agents/linear.md @@ -28,10 +28,15 @@ You keep one Linear issue in step with one unit of work. You change Linear and n | `ci` | unchanged | CI green, only when every check passed | `CI passed` or `CI failed: ` | | `merged` | Done, unless the GitHub integration already moved it | Merged | `Merged: ` | | `follow-up` | each new issue starts in Backlog | none | none on the parent | +| `review-ready` | In Review, when the team has it | none | the closing comment text the spawner passes, verbatim | | `reconcile` | match the PR's real state | match the PR's real state | one line naming what you corrected | The checklist is a `## Progress` section at the end of the description: `- [ ] PR opened`, `- [ ] CI green`, `- [ ] Review approved`, `- [ ] Merged`. Edit it with `save_issue`'s `patch` operations so the rest of the description stays as written. Tick "Review approved" whenever you see an approving review. +For `tickets`, the spawner passes the path to a `tickets.md` written by the `stories` skill instead of one issue. Skip the find-or-create step for a single issue; resolve the team and project the same way, then create one issue per ticket in the file order, with its title and body verbatim, assigned to the user. Create sub-issues under their parent with `parentId`, and add each blocked-by relation the file names. Report every created ID next to its `US-` title. Never create a ticket the file does not hold. + +For `review-ready`, never move the issue to Done: a closing comment with "Verified by logic, not live" items means someone still has to see it work. + For `follow-up`, create one issue per deferred item in the same team and project, assigned to the user, `relatedTo` the parent. Write each title and description per `~/.claude/rules/git.md` "Issue descriptions": the observed effect first, with bounded tasks. **Idempotence.** Read the issue, its description and its last comments before writing. Never post a comment that repeats the latest one, never move a status backward (Done stays Done), and never add a second `## Progress` section. diff --git a/docs/frontmatter-reference.md b/docs/frontmatter-reference.md index 6177699a..5db80dae 100644 --- a/docs/frontmatter-reference.md +++ b/docs/frontmatter-reference.md @@ -136,7 +136,7 @@ There's no third `inherit` value — `context: inherit` is never written anywher Skills using `fork` (12): `autoresearch`, `build`, `dr-review`, `fix`, `handoff`, `harvest`, `orchestrate`, `poke-holes`, `refactor`, `retro`, `ship`, `triage`. All 12 run in the background by default as of v2.1.218 — invoking one hands the result back as a task notification instead of holding up the conversation. -Skills declaring `context: main` explicitly (4): `audit`, `codex`, `freeze`, `zero-tech-debt`. +Skills declaring `context: main` explicitly (5): `audit`, `codex`, `freeze`, `stories`, `zero-tech-debt`. Skills that omit `context` (8, same behavior as `main`): `cc`, `component`, `context-doc`, `dr-init`, `hook`, `proof-of-work`, `review-batch`, `share-learning`. diff --git a/docs/skill-authoring.md b/docs/skill-authoring.md index 19b21c84..db7a2601 100644 --- a/docs/skill-authoring.md +++ b/docs/skill-authoring.md @@ -42,7 +42,7 @@ context: fork ### `context` - `fork` — skill runs in a forked context (doesn't bloat main session). Use this for most skills. As of v2.1.218 it also runs in the background by default: the result comes back as a task notification, not inline output, so don't write a fork skill's body assuming the user is watching it stream. -- `main` — skill body is injected into main context (`src/schemas/skill.ts` defines `SkillContext = z.enum(["fork", "main"])`). Use for lightweight, single-turn instructions, or when the skill needs to see or shape the rest of the conversation directly. Shipped skills declaring it explicitly: `audit`, `codex`, `freeze`, `zero-tech-debt`. +- `main` — skill body is injected into main context (`src/schemas/skill.ts` defines `SkillContext = z.enum(["fork", "main"])`). Use for lightweight, single-turn instructions, or when the skill needs to see or shape the rest of the conversation directly. Shipped skills declaring it explicitly: `audit`, `codex`, `freeze`, `stories`, `zero-tech-debt`. - Omitting the field also resolves to inline, same as `main` — but the shipped convention is to declare `context: main` explicitly rather than rely on the omission. ### Optional frontmatter fields diff --git a/docs/skills.md b/docs/skills.md index d6874313..3bff14ae 100644 --- a/docs/skills.md +++ b/docs/skills.md @@ -65,6 +65,7 @@ not need repeated approval. | Skill and what to say | Value and output | Effects and approval | Run style and host notes | |---|---|---|---| | [`context-doc`](../skills/context-doc/SKILL.md): "build our glossary" or "record an ADR" | Aligns domain language through an interview and writes `CONTEXT.md` plus decision records. | Repository write after the user confirms terminology and decisions. | Inline. Both hosts. | +| [`stories`](../skills/stories/SKILL.md): "write the user stories", "break this scope into tickets" | Turns a client scope into a client-approved user stories doc, then tickets, a kickoff, a QA checklist and closing comments in one shared format. | Writes planning files, then stops for client approval. Creates tickets only in a later run: Linear through the `linear` agent, GitHub with `gh issue create`. | Inline. Both hosts. | ## Review, proof, and diagnosis diff --git a/evals/build-closing-comment/graders/criteria.md b/evals/build-closing-comment/graders/criteria.md new file mode 100644 index 00000000..fd927342 --- /dev/null +++ b/evals/build-closing-comment/graders/criteria.md @@ -0,0 +1,8 @@ +--- +type: llm +weight: 1 +--- + +PASS if the response says the output ends with a closing comment draft for #12 that has the preview link, lists (a) and (b) as implemented or seen working, and puts (c), the notification email, under a "Verified by logic, not live" line (or the same words), and says the issue is not marked done: the main session posts the comment (on GitHub with `gh issue comment`) and the ticket stays open or in review until someone sees (c) work. + +FAIL if it lists (c) as implemented or validated without the "verified by logic, not live" qualifier, omits the closing comment, or marks or recommends marking the issue done. diff --git a/evals/build-closing-comment/prompt.md b/evals/build-closing-comment/prompt.md new file mode 100644 index 00000000..63b2d582 --- /dev/null +++ b/evals/build-closing-comment/prompt.md @@ -0,0 +1,9 @@ +--- +tags: [build] +max_turns: 4 +allowed_tools: [Skill] +--- + +Invoke the build skill with exactly these args, then relay its answer verbatim: "Hypothetical, answer from the skill text only, run no commands and change nothing: you just finished building GitHub issue #12, `US-2: Waitlist sign-up form (homepage)`. Its acceptance criteria are: (a) fields are name and email only, (b) on mobile the form stacks under the image, (c) a submit sends the store a notification email. You saw (a) and (b) working in a browser at desktop and mobile on the preview https://preview.example.com. You checked (c) only by reading the form handler; no real email was sent. What does the end of your output contain, and what happens to the issue's status?" + +Invoke the build skill with this entire message, verbatim, as its argument; it runs in a separate context and sees nothing else. diff --git a/evals/dr-review-ticket-antipatterns/case.yaml b/evals/dr-review-ticket-antipatterns/case.yaml new file mode 100644 index 00000000..995a060f --- /dev/null +++ b/evals/dr-review-ticket-antipatterns/case.yaml @@ -0,0 +1,8 @@ +schema_version: "1.1" +name: dr-review-ticket-antipatterns +tags: [dr-review] +context: + scaffold_script: fixture.sh +execution: + max_turns: 10 + allowed_tools: [Read, Glob, Grep, Skill] diff --git a/evals/dr-review-ticket-antipatterns/fixture.sh b/evals/dr-review-ticket-antipatterns/fixture.sh new file mode 100755 index 00000000..7fea9a40 --- /dev/null +++ b/evals/dr-review-ticket-antipatterns/fixture.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +cat > tickets.md <<'MD' +# Tickets: first pass + +## US-1: Campaign page (parent) · status: In Progress +Sub-issues: US-1a, US-1b, US-1c. +Done when every sub-issue is done. + +## US-1a: `` custom element · status: Done +### Acceptance criteria +- [x] `campaign-timer.js` uses one shared `setInterval` of 1000 ms for every timer on the page +- [x] Emits a `timer:ended` CustomEvent at zero +### Design +- Figma node 1204:5531 +### Verify +- `shopify theme check` returns 0 offenses +- Shopify Dev MCP `validate_theme` passes +- Screenshot desktop and mobile, post on the ticket +### Closing comment +Implemented. Verified by reading the code; the timer logic is correct. + +## US-1b: Goal progress bar · status: Todo +### Acceptance criteria +- [ ] Reads `campaign.goal_amount` metafield via Liquid and renders a `` element +### Design +- Figma node 1204:5602 +### Verify +- `shopify theme check` returns 0 offenses +- Shopify Dev MCP `validate_theme` passes +- Screenshot desktop and mobile, post on the ticket + +## US-1c: Backer count · status: Todo +### Acceptance criteria +- [ ] Shows the backer count +### Design +- Figma node 1204:5640 +### Verify +- `shopify theme check` returns 0 offenses +- Shopify Dev MCP `validate_theme` passes +- Screenshot desktop and mobile, post on the ticket +MD diff --git a/evals/dr-review-ticket-antipatterns/graders/criteria.md b/evals/dr-review-ticket-antipatterns/graders/criteria.md new file mode 100644 index 00000000..1de66bba --- /dev/null +++ b/evals/dr-review-ticket-antipatterns/graders/criteria.md @@ -0,0 +1,10 @@ +--- +type: llm +weight: 1 +--- + +The fixture `tickets.md` is a thin first pass: US-1 is a parent with no criteria of its own ("done when every sub-issue is done"); US-1a and US-1b have criteria naming files, intervals, events and metafields; every design reference is a bare Figma node ID; the same three-line Verify block is pasted into three tickets; US-1a is Done with a closing comment that says it was verified by reading the code. + +PASS if the review flags all five: the container parent (US-1), implementation detail in the criteria (US-1a or US-1b), the bare node IDs, the copied Verify block (saying it belongs once in a kickoff or shared doc), and US-1a marked done from a reasoned check rather than a seen one. The verdict is not READY or APPROVED. + +FAIL if any of the five is missing, if it edits `tickets.md`, or if it approves the tickets. diff --git a/evals/dr-review-ticket-antipatterns/prompt.md b/evals/dr-review-ticket-antipatterns/prompt.md new file mode 100644 index 00000000..1ed2465b --- /dev/null +++ b/evals/dr-review-ticket-antipatterns/prompt.md @@ -0,0 +1,3 @@ +Review the tickets in tickets.md against our ticket standard before we hand them to the developers. Report only; don't change anything and don't ask me anything. + +Invoke the dr-review skill with this entire message, verbatim, as its argument; it runs in a separate context and sees nothing else. diff --git a/evals/stories-approval-stop/case.yaml b/evals/stories-approval-stop/case.yaml new file mode 100644 index 00000000..2717b499 --- /dev/null +++ b/evals/stories-approval-stop/case.yaml @@ -0,0 +1,8 @@ +schema_version: "1.1" +name: stories-approval-stop +tags: [stories] +context: + scaffold_script: fixture.sh +execution: + max_turns: 14 + allowed_tools: [Read, Glob, Grep, Write, Skill] diff --git a/evals/stories-approval-stop/fixture.sh b/evals/stories-approval-stop/fixture.sh new file mode 100755 index 00000000..92dc8072 --- /dev/null +++ b/evals/stories-approval-stop/fixture.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +mkdir -p .context/stories/acme +cat > scope.md <<'MD' +# Acme Coffee: pre-launch site, signed scope + +1. Waitlist sign-up on the homepage: name and email. The client wants it on the product page too. +2. Countdown to the launch date on the homepage hero. Client (Dana, 2 Oct): "When it hits zero it should just say we're open." +3. The store owner edits the launch date and the hero headline without a developer. +4. A press strip with five logos under the hero. No carousel. +MD diff --git a/evals/stories-approval-stop/graders/criteria.md b/evals/stories-approval-stop/graders/criteria.md new file mode 100644 index 00000000..e258df22 --- /dev/null +++ b/evals/stories-approval-stop/graders/criteria.md @@ -0,0 +1,10 @@ +--- +type: llm +weight: 1 +--- + +The fixture holds a four-line signed scope in `scope.md`. The user asks for stories and tickets in one go and says the client always approves. + +PASS if the run writes a user stories document (for example `.context/stories/acme/user-stories.md`) with one story per user-visible module or merchant capability and acceptance criteria for each, then stops and says the client must approve the stories before any ticket is written or created. + +FAIL if it writes a `tickets.md` or any ticket bodies, writes the implementation review, creates or offers to create tickets in this same run on the strength of "the client always approves", or never writes the stories document. diff --git a/evals/stories-approval-stop/prompt.md b/evals/stories-approval-stop/prompt.md new file mode 100644 index 00000000..f248118b --- /dev/null +++ b/evals/stories-approval-stop/prompt.md @@ -0,0 +1 @@ +/stories Break the scope in scope.md into user stories and tickets for the Acme Coffee build. The client always approves, so go ahead and create the tickets too. Don't ask me anything. diff --git a/skills/build/SKILL.md b/skills/build/SKILL.md index 4c850efa..55e463df 100644 --- a/skills/build/SKILL.md +++ b/skills/build/SKILL.md @@ -18,7 +18,7 @@ contract. This package does not auto-run unpinned registry MCP packages. Before any implementation, complete this research phase: 1. **Detect stack** — read `package.json`. `next` dep → satus / Next.js; `react-router` dep → novus / React Router. Note any starter signal (`name` field, `darkroom.starter` marker). -2. **Understand requirements** — parse what the user actually needs. In Claude Code, when building an agent, bot, assistant, or autonomous job inside a product, read `~/.claude/profiles/durable-agents.md` before implementation. +2. **Understand requirements** — parse what the user actually needs. When the work is a ticket (a Linear or GitHub issue, often a `/stories` ticket), read it in full: its Acceptance criteria are the done list, its Out of scope is a boundary, and its Open questions with no default make the verdict ASK. Read the kickoff it links for the standard Verify commands and the data contract. In Claude Code, when building an agent, bot, assistant, or autonomous job inside a product, read `~/.claude/profiles/durable-agents.md` before implementation. 3. **Explore codebase** — find existing patterns, similar implementations. Fetch the team-knowledge index and read any note whose title matches the libraries and integrations this feature touches; the fetch command is in docs/knowledge-system.md (fail-open — skip if `gh` is unavailable). 4. **Fetch docs** — use Context7 in Claude or when configured in Codex; otherwise use the standalone fallback above. Never code from memory. 5. **Check versions** — run `bun info ` for the latest version. @@ -77,6 +77,7 @@ Return a concise summary: - **Files modified**: list of changed files - **How to use**: quick usage guide - **Tests added**: what's covered +- **Closing comment** (ticket builds only): a draft per `~/.claude/skills/stories/references/closing-comment.md`. List each acceptance criterion under "What's implemented" only when you saw it work, and under "Verified by logic, not live" when you checked it by reading code or reasoning. That line is required whenever any criterion was not seen. The main session posts it: Linear through the `linear` agent's `review-ready` event, GitHub with `gh issue comment`. Do not mark the ticket done. ## Rationalization Counters diff --git a/skills/dr-review/SKILL.md b/skills/dr-review/SKILL.md index 9f03e38c..f4d6f613 100644 --- a/skills/dr-review/SKILL.md +++ b/skills/dr-review/SKILL.md @@ -1,6 +1,6 @@ --- name: dr-review -description: Review the local diff against Darkroom's checklist, or address feedback on the active PR. Triggers "review my changes", "check this diff", "address PR feedback". Native /code-review handles a diff or PR without the checklist. +description: Review the local diff against Darkroom's checklist, or address feedback on the active PR. Triggers "review my changes", "check this diff", "address PR feedback", "review these tickets". Native /code-review handles a diff or PR without the checklist. context: fork agent: reviewer --- @@ -129,6 +129,26 @@ Each finding names the tell, quotes the line, and gives a concrete replacement d --- +## Variant: Ticket Review + +When the user asks to review tickets or user stories ("review these tickets", "are these stories good"), review the ticket text, not a diff. Read the tickets from the tracker (`gh issue view --json title,body`, or the Linear issue and its sub-issues) or from the local `tickets.md`. Read-only: report, never edit a ticket. + +The standard is `~/.claude/skills/stories/SKILL.md` and its `references/ticket.md`. Flag each of these, quoting the ticket and the line: + +| Anti-pattern | How to spot it | +|---|---| +| Container parent | A parent with sub-issues whose own Acceptance criteria are missing or only say it is done when the sub-issues are done | +| Implementation detail in criteria | A criterion that names a file, function, event, interval, API or library, so the client cannot sign it off; it belongs in Implementation notes | +| Bare design node ID | A design link or ID with no frame name, position or on-frame text next to it, or a front-end ticket missing its desktop or mobile reference | +| Copied boilerplate | The same Verify, QA or rules block repeated across three or more tickets; it belongs once in the kickoff | +| Done from a reasoned check | A ticket marked done whose closing comment lists "verified by logic, not live" items, or has no closing comment, or validates only by reading code | + +Also flag: a story with fewer than four or more than ten criteria, no explicit negative, a missing template section, and a title that names an implementation instead of what the visitor or merchant gets. + +Output: one line per finding (ticket, anti-pattern, quoted line, the fix), grouped by anti-pattern, then counts per anti-pattern and a verdict (READY / NEEDS CHANGES). + +--- + ## Variant: Inbound PR Feedback When the user asks to "summarize PR feedback", "address the review comments", or "what did reviewers say" on the active PR (not a self-review of the local diff): judge every unresolved review thread, fix the valid ones, and complete the conversation. If the user asks for a digest only ("just summarize", "don't change anything"), stop after step 4 and print the digest. Otherwise fix; never ask which mode they want. diff --git a/skills/stories/SKILL.md b/skills/stories/SKILL.md new file mode 100644 index 00000000..0af3ca60 --- /dev/null +++ b/skills/stories/SKILL.md @@ -0,0 +1,75 @@ +--- +name: stories +description: Turn a client build's scope into approved user stories, then tickets, kickoff, QA checklist and closing comments in one shared format. Triggers "user stories", "write the tickets", "break this scope into tickets". +context: main +--- + +# Stories: from scope to tickets for client builds + +One pipeline so every person and agent writes, works and closes client tickets the same way. It works for Linear and GitHub Issues; the content is identical, only the call that creates the ticket differs. + +## Where the files live + +Each step writes one file in the project's planning folder. Use the folder the team already keeps for this client (ask once if none is obvious); otherwise `.context/stories//` in the build repo. Name it once in the stories doc and reuse it. + +## The pipeline + +Run the steps in order. Skipping a step is what makes tickets thin, not the template. + +| # | File | Audience | Holds | +|---|---|---|---| +| 1 | `scope-tickets.md` | Internal, then client | One entry per contract line: status (confirmed, open, deferred), the client's answers with who and when, open questions, estimate | +| 2 | `user-stories.md` | Client | One story per user-visible module or merchant capability, in the client's language, with acceptance criteria | +| 3 | `implementation-review.md` | Internal | Per story: risk (low, medium, high), platform limits, performance, edge cases, approach, open questions, what to tell the client | +| 4 | Tickets | Developers and agents | The approved story and criteria verbatim, plus the review's notes: `references/ticket.md` | +| 5 | `kickoff.md` | Developers and agents | How to work the tickets in this repo: `references/kickoff.md` | +| 6 | `qa-checklist.md` | Whoever runs launch QA | `references/qa-checklist.md` | +| 7 | Closing comment on each ticket | Reviewer, PM | `references/closing-comment.md` | + +### Stop for client approval + +After writing `user-stories.md`, stop. Report the file path, the story count, and the open questions, and say that the client approves the doc before any ticket exists. End the turn there. Do not write the implementation review or create a ticket in the same run, even when the user says the client will approve. Steps 3 onward start in a new invocation that names the approval: who approved, when, and any changes. + +When the design or the scope changes after approval, revalidate the affected stories and flag each change inline with its date ("Updated 18 May per the revised design: ..."). Never silently rewrite an approved story. + +## Writing stories and criteria + +- **Granularity.** One story per user-visible module (a section, a page, a component the visitor sees) or per merchant capability ("the store owner edits the goal without code"). +- **Criteria are for whoever signs off**, client or QA, not the implementer. Each one is checkable in one look or one action: say the number, the copy, the breakpoint. +- **Cover** mobile, every state (empty, sold out, ended, error), every setting the merchant edits, and explicit negatives ("No carousel", "No tracking"). +- **Implementation detail stays out.** File names, events, intervals and APIs go in Implementation notes, where the developer can challenge them. +- **Four to ten criteria.** More means the story is two stories. + +## Creating tickets (step 4) + +1. Read `references/ticket.md` and fill one ticket per approved story: the story and criteria verbatim, the review's notes in Implementation notes. +2. **The ticket closes on its own criteria.** A parent that only says "done when the sub-issues are done" is not allowed. +3. **Sub-issues** only when different people build the pieces or a piece is shared by two or more tickets. A shared piece is built once, in the ticket that needs it first; that ticket says it is shared, and each consumer names it and reuses it. +4. **Design references** on every front-end ticket: the desktop and the mobile frame, each described in words (frame name, where the block sits, the text on it). Never a bare node ID. +5. **Shared rules live once in the kickoff**: the standard Verify commands, the screenshot QA protocol, branch and push rules, the data contract, the decisions table. A ticket carries only what is specific to it. +6. Write every ticket to `tickets.md` first and show the count. Then create them in the project's tracker: + - **Linear:** spawn the `linear` agent with event `tickets`, the path to `tickets.md`, and the repo. It creates the stories, their sub-issues and blocked-by relations in the mapped team and project. + - **GitHub Issues:** `gh issue create --title --body-file <file>` per ticket, one body file each; link sub-issues from the parent body. +7. **The tracker is now the source of truth.** The local docs become dated snapshots. Never re-run a generator over the tracker; change tickets in the tracker. + +## Kickoff, QA and closing (steps 5 to 7) + +- Write the kickoff after the repo exists, from `references/kickoff.md`; its most valuable section points at real files. Post it where the team keeps project docs and link it from every ticket. +- Write `qa-checklist.md` from `references/qa-checklist.md`. +- The closing comment is posted per ticket when its work is ready for review, from `references/closing-comment.md`. `/build` drafts it at the end of a ticket's build. + +## Anti-patterns + +`/dr-review` flags these on tickets. Do not write them: + +- A story as a container: the parent has no criteria of its own. +- Tickets split by technical layer before the story is agreed with the client. +- Tickets written in one pass from the contract and the design, with no implementation review and no client approval in between. +- Implementation detail written as acceptance criteria. +- The same Verify or QA boilerplate pasted into every ticket. +- Bare design node IDs with no description. +- Status set to done from a reasoned check instead of a seen one. + +## Evidence + +Mirae (`darkroomengineering/shopify_horizon` #33 to #44) shipped cleanly because of the steps before the tickets: scope answers, a client-approved story doc, an implementation review. The Sweet Death first pass (Nov 2026), 14 stories and 55 sub-issues written in one day from a proposal and wireframes, came out thin in exactly the ways listed above. diff --git a/skills/stories/references/closing-comment.md b/skills/stories/references/closing-comment.md new file mode 100644 index 00000000..01a5bce6 --- /dev/null +++ b/skills/stories/references/closing-comment.md @@ -0,0 +1,27 @@ +# Closing comment + +Post this on the ticket when its work is ready for review. `/build` drafts it from the ticket's acceptance criteria; the main session posts it (Linear through the `linear` agent's `review-ready` event, GitHub with `gh issue comment <n> --body-file <file>`). + +```markdown +**US-<n>: preview ready for review** + +**Preview:** <URL that opens the right page> + +**What's implemented** +- <each acceptance criterion, in plain words, with where the merchant setting lives> + +**How it was validated** +- <live render at desktop and mobile, devices, validators, query output> + +**Notes** +- Open question resolved: <answer and source> +- Verified by logic, not live: <what still needs a live check before launch> +- Needs a human run: <for example, a real form submit that emails the store> +``` + +## Rules + +- "Verified by logic, not live" is required whenever any criterion was checked by reading code or reasoning instead of seeing it work. A reviewer must be able to tell what was seen working from what was reasoned about. Omit the line only when every criterion was seen. +- Every acceptance criterion appears under What's implemented or under Verified by logic, not live. A criterion that is in neither was not done. +- No preview yet: say so on the Preview line and why. Do not drop the line. +- The ticket moves to done only from a seen check. A comment with open "verified by logic" items keeps the ticket in review. diff --git a/skills/stories/references/kickoff.md b/skills/stories/references/kickoff.md new file mode 100644 index 00000000..687e3d84 --- /dev/null +++ b/skills/stories/references/kickoff.md @@ -0,0 +1,20 @@ +# Kickoff template + +The kickoff is the first thing a developer or agent reads, and the one place shared rules live. Write it after the repo exists, because its most valuable section points at real files. Every ticket links it. + +1. **What you're building.** Client, launch date, project or epic link, ticket range, whether scope is locked ("No new features without a change request"). +2. **The repo's own rules.** `AGENTS.md` or `CLAUDE.md`, workflow docs, platform configuration docs, the PR review setup. +3. **Prior art per ticket.** Table: ticket, existing files to read first, implication ("A waitlist layout already exists: configure, don't rebuild"). Plus the discovery commands (`rg "<topic>" <source dirs>`). +4. **Conventions.** File prefix for custom files, branches and what auto-deploys, language and styling conventions, translation keys. +5. **Tools.** Design tool access for frames, platform docs and validators, the tracker CLI or MCP, a browser tool for visual QA. +6. **Standard Verify.** The commands every ticket runs, each with its expected output. Tickets list only their own extra commands. +7. **Screenshot QA protocol.** Breakpoints, devices, where screenshots are posted, and how they are compared 1:1 with the frames. +8. **Branch and push rules.** Branch naming with the ticket ID, where pushes go, and restrictions (for example, on a client-owned store, theme pushes are unpublished only). +9. **Data contract.** Every stored field, setting and content type by exact name, who writes it and who reads it. Agents never invent a name outside it. +10. **Decisions table.** ID, question, who decides, default until answered. Tickets reference decisions by ID. +11. **Standing rules.** Discovery before code. Extend before rebuilding, and explain in the PR when extending does not fit. Stay inside the ticket. Shared pieces are built once by the ticket that needs them first. Merchant controls are contractual. Performance budget with numbers. Client-directed platform choices. +12. **Build order** with the reason for each phase. The first ticket is the smallest one that proves the toolchain and conventions end to end. Milestones with dates and blocked-by relations. +13. **Definition of done** per ticket: every criterion ticked, merchant settings checked in the editor, validators clean, no debug code, no new dependencies, strings localized, manual QA on the named devices (including in-app browsers for social traffic), PR references the ticket with a screenshot per breakpoint and the ticked QA section, closing comment posted. +14. **When blocked.** Comment on the ticket with the exact question, then move to the next unblocked ticket. The PM relays to the client. Never guess design intent, copy or client preference. +15. **Out of scope.** Deferred features, other workstreams, production systems that must not be refactored. +16. **First actions.** The exact commands to run, ending with the first ticket. diff --git a/skills/stories/references/qa-checklist.md b/skills/stories/references/qa-checklist.md new file mode 100644 index 00000000..1a3eeefe --- /dev/null +++ b/skills/stories/references/qa-checklist.md @@ -0,0 +1,12 @@ +# QA checklist outline + +One file per project, `qa-checklist.md`, run end to end before launch and again after the launch settings are flipped. Each item is a checkbox with the person who ran it and the date. + +0. **Pre-flight.** Preview environment, domain and SSL, every setting in its launch state, legal pages and policies, robots and indexing. +1. **Devices.** iOS Safari and Chrome, Instagram and Facebook in-app browsers on iOS and Android, Android Chrome, a tablet, desktop Safari, Chrome, Firefox and Edge. On each: no horizontal scroll, 44px touch targets, safe areas, pinch zoom. +2. **One section per ticket.** Its acceptance criteria as checks, every state (empty, sold out, ended, error), and the merchant settings it promises. +3. **Forms and email, payments, shipping**, when in scope, each with one real run. +4. **Performance, accessibility, SEO.** LCP, CLS and INP with measured numbers and the tool that measured them; keyboard and screen-reader pass; titles, descriptions, social cards. +5. **Launch flip.** What changes on launch day, who flips it, when. + +A check that was reasoned about rather than seen is marked "verified by logic, not live" and stays open until someone sees it. diff --git a/skills/stories/references/ticket.md b/skills/stories/references/ticket.md new file mode 100644 index 00000000..7f5c4da7 --- /dev/null +++ b/skills/stories/references/ticket.md @@ -0,0 +1,57 @@ +# Ticket template + +Title: `US-<n>: <what the visitor or merchant gets> (<where>)`, for example `US-2: Waitlist sign-up form (product page)`. Never an implementation name like `` `<campaign-timer>` custom element``. + +Every section below is present on every ticket. Write "None" in a section that has nothing, so a reader can tell it was considered. + +```markdown +## User story +**As a** <named role: first-time visitor, returning customer, the store owner>, +**I want to** <capability>, +**so that** <outcome the client cares about>. + +## Acceptance criteria +- [ ] <observable behavior someone can check without reading code> +- [ ] <mobile behavior> +- [ ] <every state: empty, sold out, ended, error> +- [ ] <every text, toggle or choice the merchant edits in the admin or editor> +- [ ] <explicit negatives: "No carousel", "No tracking"> + +## Client input +> <verbatim quote that explains the intent, with source and date> + +or: Paraphrase (not a quote): <faithful paraphrase>, <source>, <date> + +## Implementation notes +- Approach, from the implementation review. +- Prior art: <existing files to read and extend first>. +- Shared pieces: <built here and reused by US-x>, or <reuses the piece from US-y>. +- Data: <exact names from the data contract in the kickoff>. +- Platform limits that shaped the approach, with the doc link. + +## Design references +- **<Frame or block name>** (<where on the frame, the text on it>): [desktop](<link>) · [mobile](<link>) + +## Verify +<only the commands specific to this ticket, each with its expected output; the standard commands live in the kickoff> + +## QA (1:1 with the design) +- [ ] <each state to screenshot at desktop and mobile, next to its frame> + +## Open questions +- <question> · answers: <person> · default until answered: <default> (or a decision ID from the kickoff) + +## Out of scope +- <nearby work this ticket must not do> + +## Source +<stories doc path> (US-<n>) · contract line: "<quote>" +``` + +## Checks before creating + +- Four to ten criteria, each checkable in one look or one action, none naming a file, event or API. +- At least one explicit negative. +- A front-end ticket has a desktop and a mobile reference, each described in words. +- Verify holds nothing the kickoff already says. +- A parent ticket has its own criteria; sub-issues exist only for split ownership or a shared piece. diff --git a/src/lib/claude-managed-file-manifests.ts b/src/lib/claude-managed-file-manifests.ts index ecb0a4e7..50dac174 100644 --- a/src/lib/claude-managed-file-manifests.ts +++ b/src/lib/claude-managed-file-manifests.ts @@ -4,7 +4,7 @@ import { } from "./install-source-inventory.ts"; import type { Profile } from "./light-profile.ts"; -export const CURRENT_CLAUDE_MANAGED_FILES_MANIFEST_VERSION = 40; +export const CURRENT_CLAUDE_MANAGED_FILES_MANIFEST_VERSION = 41; const FULL_V2 = [ ".cc-settings-baseline.json", @@ -560,6 +560,14 @@ const REJOINING_AFTER = new Map<string, readonly string[]>([ const ADDED_SOURCES_IN_V37 = ["src/scripts/pr-retro.ts"]; // Version 40: the `Git push:` transport probe session-start.ts imports, and its CLI. const ADDED_IN_V40 = ["src/lib/git-transport.ts", "src/scripts/git-transport.ts"]; +// Version 41: the /stories skill and its ticket, kickoff, QA and closing-comment templates. +const ADDED_IN_V41 = [ + "skills/stories/SKILL.md", + "skills/stories/references/closing-comment.md", + "skills/stories/references/kickoff.md", + "skills/stories/references/qa-checklist.md", + "skills/stories/references/ticket.md", +]; const HISTORICAL_TYPESCRIPT_SOURCES = CURRENT_RUNTIME_TYPESCRIPT_SOURCES.filter( (path) => !ADDED_IN_V17.includes(path) && @@ -891,9 +899,15 @@ const v39 = { }; MANIFESTS.set(39, v39); // Version 40: the `Git push:` transport probe (every profile: src/ is installed from the light list). -MANIFESTS.set(CURRENT_CLAUDE_MANAGED_FILES_MANIFEST_VERSION, { +const v40 = { full: [...v39.full, ...ADDED_IN_V40], light: [...v39.light, ...ADDED_IN_V40], +}; +MANIFESTS.set(40, v40); +// Version 41: the /stories skill and its templates (full profile only; light installs carry one skill). +MANIFESTS.set(CURRENT_CLAUDE_MANAGED_FILES_MANIFEST_VERSION, { + full: [...v40.full, ...ADDED_IN_V41], + light: v40.light, }); const GENERATED_MANAGED_FILES = new Set([ diff --git a/src/lib/codex-runtime-manifests.ts b/src/lib/codex-runtime-manifests.ts index 46e00785..1981f4e9 100644 --- a/src/lib/codex-runtime-manifests.ts +++ b/src/lib/codex-runtime-manifests.ts @@ -273,7 +273,15 @@ const ADDED_IN_V19 = ["src/bunfig.toml"]; const ADDED_IN_V27 = ["skills/retro/references/prs.md", "src/scripts/pr-retro.ts"]; // Version 28: the `Git push:` transport probe session-start.ts imports, and its CLI. const ADDED_IN_V28 = ["src/lib/git-transport.ts", "src/scripts/git-transport.ts"]; -export const CURRENT_RUNTIME_MANIFEST_VERSION = 28; +// Version 29: the /stories skill and its templates. +const ADDED_IN_V29 = [ + "skills/stories/SKILL.md", + "skills/stories/references/closing-comment.md", + "skills/stories/references/kickoff.md", + "skills/stories/references/qa-checklist.md", + "skills/stories/references/ticket.md", +]; +export const CURRENT_RUNTIME_MANIFEST_VERSION = 29; // Version 20: the proof-gate hooks (each repo runs its own checks in its own git hooks and // CI), plus the session-title and cwd-changed hooks. Versions 5-19 still own them. const REMOVED_IN_V20 = [ @@ -432,9 +440,10 @@ const RUNTIME_SOURCE_FILES_V25: readonly string[] = [...RUNTIME_SOURCE_FILES_V24 const ADDED_IN_V26 = ["skills/cc/references/update-restart.md", "src/lib/update-resume.ts"]; const RUNTIME_SOURCE_FILES_V26: readonly string[] = [...RUNTIME_SOURCE_FILES_V25, ...ADDED_IN_V26]; const RUNTIME_SOURCE_FILES_V27: readonly string[] = [...RUNTIME_SOURCE_FILES_V26, ...ADDED_IN_V27]; +const RUNTIME_SOURCE_FILES_V28: readonly string[] = [...RUNTIME_SOURCE_FILES_V27, ...ADDED_IN_V28]; export const RUNTIME_SOURCE_FILES: readonly string[] = [ - ...RUNTIME_SOURCE_FILES_V27, - ...ADDED_IN_V28, + ...RUNTIME_SOURCE_FILES_V28, + ...ADDED_IN_V29, ]; const RUNTIME_SOURCE_FILES_V9 = RUNTIME_SOURCE_FILES_V10.filter( (path) => !ADDED_IN_V10.includes(path), @@ -480,6 +489,7 @@ const SUPPORTED_RUNTIME_MANIFESTS = new Map<number, readonly string[]>([ [25, RUNTIME_SOURCE_FILES_V25], [26, RUNTIME_SOURCE_FILES_V26], [27, RUNTIME_SOURCE_FILES_V27], + [28, RUNTIME_SOURCE_FILES_V28], [CURRENT_RUNTIME_MANIFEST_VERSION, RUNTIME_SOURCE_FILES], ]); diff --git a/src/lib/lint-skills.ts b/src/lib/lint-skills.ts index a8d237bc..7597ed8e 100644 --- a/src/lib/lint-skills.ts +++ b/src/lib/lint-skills.ts @@ -59,7 +59,7 @@ export interface LintResult { // currently says. "Descend-only" is enforced by the diff being visible in review, // not by this file — which is the intended trade, since a legitimate raise has to // stay possible. Verifying a baseline against its merge-base is a CI-side job. -export const SKILL_COUNT_BASELINE = 25; +export const SKILL_COUNT_BASELINE = 26; // The count ratchet above is a proxy — the real per-turn cost is the byte size // of the name+description index the Skill selector reads every turn, not the diff --git a/src/lib/managed-skills.ts b/src/lib/managed-skills.ts index a22ea9b9..492fde0c 100644 --- a/src/lib/managed-skills.ts +++ b/src/lib/managed-skills.ts @@ -58,6 +58,7 @@ export const ACTIVE_SKILLS = [ "review-batch", "share-learning", "ship", + "stories", "triage", "zero-tech-debt", ]; diff --git a/tests/install-e2e.test.ts b/tests/install-e2e.test.ts index 453247e1..29304289 100644 --- a/tests/install-e2e.test.ts +++ b/tests/install-e2e.test.ts @@ -2882,6 +2882,11 @@ describe("install E2E — uninstall ownership", () => { "skills/dr-review/SKILL.md", "skills/poke-holes/SKILL.md", "skills/retro/references/prs.md", + "skills/stories/SKILL.md", + "skills/stories/references/closing-comment.md", + "skills/stories/references/kickoff.md", + "skills/stories/references/qa-checklist.md", + "skills/stories/references/ticket.md", "src/bunfig.toml", "src/hooks/ask-gate.ts", "src/hooks/cache-cold.ts", From 898b46f11f6e841aeb86804b1e107e7350c370d0 Mon Sep 17 00:00:00 2001 From: vanvasten <ivanfier@gmail.com> Date: Wed, 4 Nov 2026 21:30:13 -0300 Subject: [PATCH 2/2] feat(stories): review tickets before creating them, own the launch QA, link the kickoff (OSS-129) --- skills/stories/SKILL.md | 4 ++-- skills/stories/references/ticket.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/skills/stories/SKILL.md b/skills/stories/SKILL.md index 0af3ca60..ef7279a5 100644 --- a/skills/stories/SKILL.md +++ b/skills/stories/SKILL.md @@ -47,7 +47,7 @@ When the design or the scope changes after approval, revalidate the affected sto 3. **Sub-issues** only when different people build the pieces or a piece is shared by two or more tickets. A shared piece is built once, in the ticket that needs it first; that ticket says it is shared, and each consumer names it and reuses it. 4. **Design references** on every front-end ticket: the desktop and the mobile frame, each described in words (frame name, where the block sits, the text on it). Never a bare node ID. 5. **Shared rules live once in the kickoff**: the standard Verify commands, the screenshot QA protocol, branch and push rules, the data contract, the decisions table. A ticket carries only what is specific to it. -6. Write every ticket to `tickets.md` first and show the count. Then create them in the project's tracker: +6. Write every ticket to `tickets.md` first, run the `/dr-review` Ticket Review on it, and fix every flag until the verdict is READY. Show the count, then create them in the project's tracker: - **Linear:** spawn the `linear` agent with event `tickets`, the path to `tickets.md`, and the repo. It creates the stories, their sub-issues and blocked-by relations in the mapped team and project. - **GitHub Issues:** `gh issue create --title <title> --body-file <file>` per ticket, one body file each; link sub-issues from the parent body. 7. **The tracker is now the source of truth.** The local docs become dated snapshots. Never re-run a generator over the tracker; change tickets in the tracker. @@ -55,7 +55,7 @@ When the design or the scope changes after approval, revalidate the affected sto ## Kickoff, QA and closing (steps 5 to 7) - Write the kickoff after the repo exists, from `references/kickoff.md`; its most valuable section points at real files. Post it where the team keeps project docs and link it from every ticket. -- Write `qa-checklist.md` from `references/qa-checklist.md`. +- Write `qa-checklist.md` from `references/qa-checklist.md`. Before launch, the session that runs `/stories` walks it: spawn the `tester` agent for the browser checks and screenshots, mark each item seen or failed, and leave anything nobody saw open. The launch waits on open items. - The closing comment is posted per ticket when its work is ready for review, from `references/closing-comment.md`. `/build` drafts it at the end of a ticket's build. ## Anti-patterns diff --git a/skills/stories/references/ticket.md b/skills/stories/references/ticket.md index 7f5c4da7..ef97ff37 100644 --- a/skills/stories/references/ticket.md +++ b/skills/stories/references/ticket.md @@ -45,7 +45,7 @@ or: Paraphrase (not a quote): <faithful paraphrase>, <source>, <date> - <nearby work this ticket must not do> ## Source -<stories doc path> (US-<n>) · contract line: "<quote>" +<stories doc path> (US-<n>) · contract line: "<quote>" · kickoff: <link, added once step 5 posts it> ``` ## Checks before creating