@pavp/storywright 1.11.1 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storywright",
3
- "version": "0.1.0",
3
+ "version": "1.12.0",
4
4
  "description": "PM skills for Claude Code — turn ambiguous inputs (prompts, screenshots, Figma links) into Jira-ready user stories.",
5
5
  "author": "pavp",
6
6
  "license": "MIT",
@@ -11,6 +11,7 @@
11
11
  "skills/story-refine",
12
12
  "skills/story-split",
13
13
  "skills/story-from-figma",
14
+ "skills/_components/storywright-base",
14
15
  "skills/_components/clarification-questions",
15
16
  "skills/_components/acceptance-criteria",
16
17
  "skills/_components/invest-checklist",
package/README.md CHANGED
@@ -26,7 +26,8 @@ Alternatives:
26
26
  - **Git clone + symlink** for contributors:
27
27
  ```bash
28
28
  git clone git@github.com:pavp/storywright.git
29
- ln -s "$(pwd)/storywright/skills" ~/.claude/skills/storywright
29
+ cd storywright
30
+ ln -s "$(pwd)/skills" ~/.claude/skills/storywright
30
31
  ```
31
32
  - **ZIP upload to claude.ai**:
32
33
  ```bash
@@ -15,7 +15,12 @@ Follow the skill's full procedure:
15
15
  4. Fill the CORE sections (Title, Summary, User Story, Acceptance Criteria, Definition of Done).
16
16
  5. Fill optional sections only if they have real content (drop empty ones).
17
17
  6. Run INVEST pre-split test. If count ≥2, show candidate children + ask via `AskUserQuestion` with options: "Yes, split" / "Continue without split" / "No, keep as-is". Never auto-split silently. For other verdicts (NOT A STORY / NEEDS REFINEMENT / RUN A SPIKE) — STOP and hand off accordingly.
18
- 7. Render dual outputs via `jira-wiki-formatter`. Use the `Write` tool to write `story.standard.md` and `story.jira-wiki.md` to `docs/storywright/YYYY-MM-DD-HHmm-<title-slug>/` (current local time, title in kebab-case max 5 words). Also emit both as fenced code blocks in chat. Then write `.storywright-context.json` to the same folder with all resolved answers from this session: `{"language":"...","persona":"...","naming_pattern":null,"output_folder":"...","resolved_questions":[],"sibling_refs":[]}`. Never ask — always write all three files.
18
+ 7. Render three outputs via `jira-wiki-formatter` to `docs/storywright/YYYY-MM-DD-HHmm-<title-slug>/` (current local time, title kebab-case max 5 words). Use the `Write` tool for all files never ask:
19
+ - `story.standard.md` — PM-facing CommonMark: observable behavior only, no file paths/imports/component names/CLI commands
20
+ - `story.jira-wiki.md` — PM-facing Jira wiki markup: same content as standard
21
+ - `story.dev.md` — dev-facing CommonMark: full technical detail (file paths, imports, Technical Considerations, technical edge cases, DoD with `npm run` commands)
22
+ - `.storywright-context.json` — resolved session answers: `{"language":"...","persona":"...","naming_pattern":null,"output_folder":"...","resolved_questions":[],"sibling_refs":[]}`
23
+ Emit `story.standard.md` and `story.jira-wiki.md` as fenced code blocks in chat. Do NOT emit `story.dev.md` in chat.
19
24
  8. Non-blocking assumptions remain? Mark inline with `⚠️ Assumed:`. Do NOT emit clarifications.md.
20
25
 
21
26
  Output in the input language (preserve es/en).
@@ -16,5 +16,10 @@ Follow the skill's procedure:
16
16
  4. Fill missing/weak sections via component skills. Preserve original wording where good.
17
17
  5. Append a "Refinement log" at the end listing what changed.
18
18
  6. Run INVEST pre-split test. If count ≥2, show candidate children + ask via `AskUserQuestion` with options: "Yes, split" / "Continue without split" / "No, keep as-is". Never auto-split silently.
19
- 7. Render dual outputs via `jira-wiki-formatter`. Use the `Write` tool to write `story.standard.md` and `story.jira-wiki.md` to `docs/storywright/YYYY-MM-DD-HHmm-<title-slug>/` (current local time, title in kebab-case max 5 words). Also emit both as fenced code blocks in chat. Then write `.storywright-context.json` to the same folder with all resolved answers from this session: `{"language":"...","persona":"...","naming_pattern":null,"output_folder":"...","resolved_questions":[],"sibling_refs":[]}`. Never ask — always write all three files.
19
+ 7. Render three outputs via `jira-wiki-formatter` to `docs/storywright/YYYY-MM-DD-HHmm-<title-slug>/` (current local time, title kebab-case max 5 words). Use the `Write` tool for all files never ask:
20
+ - `story.standard.md` — PM-facing CommonMark: observable behavior only, no file paths/imports/component names/CLI commands
21
+ - `story.jira-wiki.md` — PM-facing Jira wiki markup: same content as standard
22
+ - `story.dev.md` — dev-facing CommonMark: full technical detail (file paths, imports, Technical Considerations, technical edge cases, DoD with `npm run` commands)
23
+ - `.storywright-context.json` — resolved session answers: `{"language":"...","persona":"...","naming_pattern":null,"output_folder":"...","resolved_questions":[],"sibling_refs":[]}`
24
+ Emit `story.standard.md` and `story.jira-wiki.md` as fenced code blocks in chat. Do NOT emit `story.dev.md` in chat.
20
25
  8. Non-blocking assumptions remain? Mark inline with `⚠️ Assumed:`. Do NOT emit clarifications.md.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pavp/storywright",
3
- "version": "1.11.1",
3
+ "version": "1.12.1",
4
4
  "description": "PM Skills pack for Claude Code — turn ambiguous inputs (prompts, screenshots, Figma links) into Jira-ready user stories.",
5
5
  "keywords": [
6
6
  "claude",
@@ -17,6 +17,10 @@ async function installSkills() {
17
17
  }
18
18
  await mkdir(skillsTarget, { recursive: true });
19
19
  await cp(SKILLS_DIR, skillsTarget, { recursive: true });
20
+ // Verify the copy landed — cp can silently no-op on permission quirks.
21
+ if (!(await pathExists(join(skillsTarget, "_components")))) {
22
+ throw new Error(`copy verification failed: ${skillsTarget}/_components missing after install`);
23
+ }
20
24
  console.log(`✓ Installed skills to ${skillsTarget}`);
21
25
  }
22
26
 
@@ -49,7 +53,9 @@ async function ensureGlobalGitignore() {
49
53
  globalIgnorePath = join(homedir(), ".gitignore_global");
50
54
  execSync(`git config --global core.excludesFile "${globalIgnorePath}"`);
51
55
  }
52
- if (globalIgnorePath.startsWith("~")) {
56
+ if (globalIgnorePath === "~") {
57
+ globalIgnorePath = homedir();
58
+ } else if (globalIgnorePath.startsWith("~/")) {
53
59
  globalIgnorePath = join(homedir(), globalIgnorePath.slice(2));
54
60
  }
55
61
 
@@ -57,14 +57,31 @@ async function main() {
57
57
  }
58
58
  }
59
59
 
60
+ const referencedComponents = new Set();
60
61
  for (const f of files) {
61
62
  const skill = await loadSkill(f);
62
63
  const composes = Array.isArray(skill.frontmatter.composes) ? skill.frontmatter.composes : [];
63
64
  for (const dep of composes) {
64
65
  if (!componentPaths.has(dep)) {
65
66
  errors.push(`${skill.relPath}: composes references missing component '${dep}'`);
67
+ } else {
68
+ referencedComponents.add(dep);
66
69
  }
67
70
  }
71
+ // Body [[name]] links also count as a reference, so a component used only via
72
+ // prose cross-link (not composed) is not flagged as orphaned.
73
+ for (const m of skill.body.matchAll(/\[\[([a-z0-9-]+)\]\]/g)) {
74
+ referencedComponents.add(`_components/${m[1]}`);
75
+ }
76
+ }
77
+
78
+ // Orphan check: every component must be referenced by at least one skill
79
+ // (via composes or a body [[link]]). Catches dead/stale components that
80
+ // pass the existence check but are wired to nothing.
81
+ for (const comp of componentPaths) {
82
+ if (!referencedComponents.has(comp)) {
83
+ errors.push(`${comp}: orphaned component — referenced by no skill (composes or [[link]])`);
84
+ }
68
85
  }
69
86
 
70
87
  if (errors.length) {
@@ -11,16 +11,34 @@ if (!skillName) {
11
11
  process.exit(1);
12
12
  }
13
13
 
14
+ function hasZip() {
15
+ const probe = spawnSync("zip", ["-v"], { stdio: "ignore" });
16
+ return !probe.error;
17
+ }
18
+
19
+ async function resolveSourceDir() {
20
+ const topDir = join(SKILLS_DIR, skillName);
21
+ if (await pathExists(topDir)) return topDir;
22
+ const compDir = join(SKILLS_DIR, "_components", skillName);
23
+ if (await pathExists(compDir)) return compDir;
24
+ return null;
25
+ }
26
+
14
27
  async function main() {
15
- const skillDir = join(SKILLS_DIR, skillName);
16
- if (!(await pathExists(skillDir))) {
17
- const compDir = join(SKILLS_DIR, "_components", skillName);
18
- if (!(await pathExists(compDir))) {
19
- console.error(`✗ Skill not found: ${skillName}`);
20
- process.exit(1);
21
- }
28
+ const sourceDir = await resolveSourceDir();
29
+ if (!sourceDir) {
30
+ console.error(`✗ Skill not found: ${skillName}`);
31
+ process.exit(1);
22
32
  }
23
- const sourceDir = (await pathExists(skillDir)) ? skillDir : join(SKILLS_DIR, "_components", skillName);
33
+ if (!(await pathExists(join(sourceDir, "SKILL.md")))) {
34
+ console.error(`✗ ${skillName} has no SKILL.md — refusing to zip an invalid skill`);
35
+ process.exit(1);
36
+ }
37
+ if (!hasZip()) {
38
+ console.error("✗ `zip` not found on PATH. Install it (e.g. `brew install zip` / `apt-get install zip`) and retry.");
39
+ process.exit(127);
40
+ }
41
+
24
42
  const outDir = join(REPO_ROOT, "dist");
25
43
  if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
26
44
 
@@ -3,12 +3,12 @@ name: analytics-events
3
3
  description: Propose analytics/event tracking for a story. Names events, payloads, and trigger points. Returns only the analytics block, ready for ProductOps to map.
4
4
  trigger: "internal use by story-* skills"
5
5
  intent: Component skill that drafts a small, opinionated set of analytics events using a consistent naming convention.
6
- version: 1.0.0
6
+ version: 2.0.0
7
7
  inputs:
8
8
  - story-context
9
9
  - acceptance-criteria
10
10
  outputs:
11
- - analytics-events-block
11
+ - analytics-events-block (dev.md only)
12
12
  ---
13
13
 
14
14
  ## Purpose
@@ -17,7 +17,7 @@ Stories without analytics are stories without feedback. Propose the minimum set
17
17
 
18
18
  ## When to use
19
19
 
20
- After acceptance criteria are drafted; events should align to observable AC outcomes.
20
+ **Dev-file only.** Invoked while rendering `story.dev.md`, after acceptance criteria are drafted; events align to observable AC outcomes. Event names, payloads, and PII boundaries are technical detail — they belong in `story.dev.md`, never the PM-facing files (`[[storywright-base]]` rule 3).
21
21
 
22
22
  ## Inputs & interpretation
23
23
 
@@ -42,7 +42,7 @@ After acceptance criteria are drafted; events should align to observable AC outc
42
42
  - `🔧 ops` — feeds error monitoring
43
43
  - `💰 revenue` — feeds growth metrics
44
44
  5. Note retention/PII boundaries explicitly when sensitive (e.g., emails hashed).
45
- 6. Emit under `### Analytics / Eventos`.
45
+ 6. Emit under `### Analytics / Eventos` **inside `story.dev.md`**.
46
46
 
47
47
  Example block:
48
48
 
@@ -3,7 +3,7 @@ name: business-rules
3
3
  description: Extract and articulate business rules a story must honor. Distinguish rules (always true) from acceptance criteria (testable on this story). Returns only the rules block.
4
4
  trigger: "internal use by story-* skills"
5
5
  intent: Component skill that surfaces invariants, policies, and constraints that bound a story without being acceptance criteria themselves.
6
- version: 1.0.0
6
+ version: 2.0.0
7
7
  inputs:
8
8
  - story-context
9
9
  - domain-hints
@@ -17,7 +17,7 @@ Business rules are **policy invariants** the story must respect. They survive ac
17
17
 
18
18
  ## When to use
19
19
 
20
- After the story body is drafted, before ACs are finalized — so ACs can reference relevant rules.
20
+ After the story body is drafted, before ACs are finalized — so ACs can reference relevant rules. Business Rules are an **optional PM section** (see `[[jira-wiki-formatter]]` — emit in `story.standard.md` / `story.jira-wiki.md` only when non-empty) AND are mirrored in `story.dev.md`. They are policy invariants, not technical detail, so unlike edge-cases they are not dev-only.
21
21
 
22
22
  ## Inputs & interpretation
23
23
 
@@ -3,7 +3,7 @@ name: definition-of-done
3
3
  description: Produce a Definition of Done block for a user story. Covers code, tests, analytics, docs, accessibility, and release gates. Returns only the DoD block.
4
4
  trigger: "internal use by story-* skills"
5
5
  intent: Component skill that emits a baseline DoD aligned to common product/eng standards. Customizable via project-level overrides documented in the story.
6
- version: 1.0.0
6
+ version: 2.0.0
7
7
  inputs:
8
8
  - story-context
9
9
  - technical-considerations
@@ -17,7 +17,7 @@ A Definition of Done is the contract for "shippable". It must be **checkable, ob
17
17
 
18
18
  ## When to use
19
19
 
20
- Invoked by `story-generate` after acceptance criteria and technical considerations are drafted.
20
+ Invoked after acceptance criteria and technical considerations are drafted. DoD is **dual-rendered** (see `[[jira-wiki-formatter]]`): the PM-facing files (`story.standard.md` / `story.jira-wiki.md`) carry the **acceptance-only** DoD (no CLI commands, no file-level criteria); `story.dev.md` carries the **full** DoD including CLI commands (`npm run test`) and file-level lines. Produce both projections from the baseline below: PM projection = drop command/file lines; dev projection = keep everything.
21
21
 
22
22
  ## Inputs & interpretation
23
23
 
@@ -3,11 +3,11 @@ name: edge-cases
3
3
  description: Enumerate edge cases for a story. Covers boundary, concurrency, network, data, permission, and UX-state failures. Returns only the edge-cases block.
4
4
  trigger: "internal use by story-* skills"
5
5
  intent: Component skill that systematically generates edge cases across known failure axes so acceptance criteria can cover them.
6
- version: 1.0.0
6
+ version: 2.0.0
7
7
  inputs:
8
8
  - story-context
9
9
  outputs:
10
- - edge-cases-block
10
+ - edge-cases-block (dev.md only)
11
11
  ---
12
12
 
13
13
  ## Purpose
@@ -16,7 +16,7 @@ Edge cases are how engineers find latent risk. Generate them **before** acceptan
16
16
 
17
17
  ## When to use
18
18
 
19
- Invoked by `story-generate` after the story body and business rules are drafted; output feeds `[[acceptance-criteria]]`.
19
+ **Dev-file only.** Invoked while rendering `story.dev.md` (the dev-facing file), never the PM-facing `story.standard.md` / `story.jira-wiki.md`. `[[storywright-base]]` rule 3 forbids an Edge Cases section in the PM story body this output lands exclusively in `story.dev.md`. It still informs AC failure paths (`[[acceptance-criteria]]`): the AC covers the observable behavior in the PM files; the enumerated technical edge detail lives in dev.md.
20
20
 
21
21
  ## Inputs & interpretation
22
22
 
@@ -37,7 +37,7 @@ Walk these axes and pick the ones that apply:
37
37
 
38
38
  For each applicable axis, write 1–2 concrete cases. Keep each ≤1 sentence.
39
39
 
40
- Emit under `### Edge Cases`:
40
+ Emit under `### Edge Cases` **inside `story.dev.md`** (never the PM files):
41
41
 
42
42
  ```
43
43
  ### Edge Cases
@@ -1,14 +1,15 @@
1
1
  ---
2
2
  name: jira-wiki-formatter
3
- description: Render a story into both Jira wiki markup and standard CommonMark Markdown. Outputs two artifacts so the same story is copy-pasteable into Jira and into any MD-aware tool.
3
+ description: Render a story into three files: story.standard.md and story.jira-wiki.md (PM-facing, no technical detail) plus story.dev.md (dev-facing, full technical detail).
4
4
  trigger: "internal use by story-* skills"
5
- intent: Component skill that takes a structured story (all sections drafted) and produces two output files following the templates in story-generate/templates.
6
- version: 1.0.0
5
+ intent: Component skill that takes a structured story and produces three output files following the templates in story-generate/templates.
6
+ version: 2.0.0
7
7
  inputs:
8
8
  - structured-story
9
9
  outputs:
10
- - story.jira-wiki.md
11
10
  - story.standard.md
11
+ - story.jira-wiki.md
12
+ - story.dev.md
12
13
  ---
13
14
 
14
15
  ## Purpose
@@ -25,7 +26,21 @@ Final step in `story-generate` and `story-refine`. Always last.
25
26
 
26
27
  ## Application (step-by-step)
27
28
 
28
- 1. Render `story.jira-wiki.md` using Jira's wiki markup:
29
+ ## Audience separation THREE files
30
+
31
+ | File | Audience | Technical detail |
32
+ |---|---|---|
33
+ | `story.standard.md` | PM, stakeholders | ❌ None — no file paths, no imports, no component names, no `npm run X` in DoD |
34
+ | `story.jira-wiki.md` | PM → Jira paste | ❌ None — same content as standard, Jira markup |
35
+ | `story.dev.md` | Developer | ✅ Full — file paths, imports, Technical Considerations, technical edge cases, full DoD with commands |
36
+
37
+ **What is "technical":** file paths, import statements, component/hook names, API method names, CLI commands (`npm run test`), null/undefined checks, browser API constraints (HTTPS, permissions), specific library flags.
38
+
39
+ **ACs in PM files must describe observable behavior only.** "A copy icon appears next to the email field and clicking it copies the value" — not "ContentCopyOutlinedIcon is rendered next to the email Typography block and calls navigator.clipboard.writeText()".
40
+
41
+ ---
42
+
43
+ 1. Render `story.jira-wiki.md` (PM-facing) using Jira's wiki markup:
29
44
  - Headings: `h1. `, `h2. `, `h3. `
30
45
  - Bold: `*text*`
31
46
  - Italic: `_text_`
@@ -33,7 +48,8 @@ Final step in `story-generate` and `story-refine`. Always last.
33
48
  - Lists: `* item`, `# item` (numbered)
34
49
  - Tables: `||header||header||` then `|cell|cell|`
35
50
  - Panels for callouts: `{panel:title=⚠️ Assumed}…{panel}`
36
- 2. Render `story.standard.md` using CommonMark:
51
+ - Strip all technical detail (see audience table above)
52
+ 2. Render `story.standard.md` (PM-facing) using CommonMark:
37
53
  - Headings: `##`, `###`
38
54
  - Bold: `**text**`
39
55
  - Italic: `*text*`
@@ -41,29 +57,28 @@ Final step in `story-generate` and `story-refine`. Always last.
41
57
  - Lists: `- item`, `1. item`
42
58
  - Tables: standard pipe tables
43
59
  - Callouts: `> ⚠️ **Assumed:** …`
44
- 3. Section model = **core + optional**.
60
+ - Strip all technical detail (see audience table above)
61
+ 3. Render `story.dev.md` (dev-facing) using CommonMark:
62
+ - Same structure as `story.standard.md` PLUS:
63
+ - Technical Considerations section (file paths, imports, API calls)
64
+ - Edge Cases section (null checks, error states, browser constraints)
65
+ - DoD includes CLI commands and file-level criteria
66
+ - Refinement log includes technical changes
67
+ 4. Section model for PM files = **core + optional (non-technical)**.
45
68
 
46
69
  **Core (always emit, in this order):**
47
70
  1. Title
48
- 2. Summary
49
- 3. User Story (As a / I want to / so that)
50
- 4. Acceptance Criteria
51
- 5. Definition of Done
52
-
53
- **Optional (emit only if non-empty, in this order, after a separator):**
54
- 6. Contexto
55
- 7. Business Goal
56
- 8. Scope
57
- 9. Out of Scope
58
- 10. Business Rules
59
- 11. Technical Considerations
60
- 12. Dependencies
61
- 13. Risks
62
- 14. Analytics
63
- 15. Edge Cases
64
-
65
- 4. **Drop any section with no real content.** An empty heading is noise. A story with only the 5 core sections is a valid output.
66
- 5. Emit both as fenced code blocks in the chat so the user can copy them. File persistence is handled by the calling skill via the `Write` tool.
71
+ 2. User Story (As a / I want to / so that)
72
+ 3. Acceptance Criteria (observable behavior only)
73
+ 4. Definition of Done (acceptance criteria only, no commands)
74
+
75
+ **Optional PM sections (emit only if non-empty):**
76
+ 5. Business Goal
77
+ 6. Scope / Out of Scope
78
+ 7. Business Rules
79
+
80
+ 5. **Drop any section with no real content.** An empty heading is noise.
81
+ 6. Emit `story.standard.md` and `story.jira-wiki.md` as fenced code blocks in chat (PM-facing). Do NOT emit `story.dev.md` in chat — write to disk only. File persistence is handled by the calling skill via the `Write` tool.
67
82
 
68
83
  ## Examples
69
84
 
@@ -3,13 +3,13 @@ name: risks-and-dependencies
3
3
  description: Surface technical, product, and organizational risks plus blocking dependencies for a story. Each item has owner, likelihood, mitigation. Returns only the risks+deps block.
4
4
  trigger: "internal use by story-* skills"
5
5
  intent: Component skill that turns hidden assumptions into tracked risks and dependencies so PMs and tech leads can act on them.
6
- version: 1.0.0
6
+ version: 2.0.0
7
7
  inputs:
8
8
  - story-context
9
9
  - business-rules
10
10
  - technical-considerations
11
11
  outputs:
12
- - risks-and-dependencies-block
12
+ - risks-and-dependencies-block (dev.md only)
13
13
  ---
14
14
 
15
15
  ## Purpose
@@ -18,7 +18,7 @@ Risks and dependencies that aren't written down end up as outages or missed laun
18
18
 
19
19
  ## When to use
20
20
 
21
- Late in `story-generate`, after business rules and technical considerations are drafted — those inform what's risky.
21
+ **Dev-file only.** Invoked while rendering `story.dev.md`, after business rules and technical considerations are drafted — those inform what's risky. Risks and dependencies reference infra, SDKs, env vars, and ownership — technical/delivery detail that belongs in `story.dev.md`, not the PM-facing files (`[[storywright-base]]` rule 3 bans Dependencies-as-prose in the PM body; PM files link Jira tickets only).
22
22
 
23
23
  ## Inputs & interpretation
24
24
 
@@ -41,7 +41,7 @@ Late in `story-generate`, after business rules and technical considerations are
41
41
  - **Operational** (oncall toil, monitoring gap)
42
42
  4. For each risk: `<risk> · likelihood (L/M/H) · impact (L/M/H) · mitigation`
43
43
  5. If a risk is high-impact AND high-likelihood, flag it `🚨` so it gets attention in review.
44
- 6. Emit under two subheadings: `### Dependencias` and `### Riesgos` (or English).
44
+ 6. Emit under two subheadings: `### Dependencias` and `### Riesgos` (or English) **inside `story.dev.md`**.
45
45
 
46
46
  Example:
47
47
 
@@ -3,7 +3,7 @@ name: storywright-base
3
3
  description: Shared base behavior for all storywright top-level skills. Hard rules, canonical output, terminal-only Q, context schema, mechanical deps, V audit, language detect.
4
4
  trigger: "internal use by story-* skills"
5
5
  intent: Component skill that holds the v2.2 baseline. Top-level skills (story-generate, story-refine, story-split, story-from-figma) compose this and add only their source-specific behavior on top.
6
- version: 2.2.0
6
+ version: 2.3.0
7
7
  inputs:
8
8
  - none
9
9
  outputs:
@@ -31,13 +31,15 @@ If you are reading this through a top-level skill, treat every rule below as non
31
31
  - ONE AC Scenario (one Given chain + one `When` + one `Then`).
32
32
  If the input naturally needs >1 `When`/`Then`, the skill MUST stop the single-story path and route to `[[story-split]]`.
33
33
 
34
- 3. **No mini-PRDs.** PROHIBITED sections in any story output:
34
+ 3. **No mini-PRDs in the PM story body.** PROHIBITED in `story.standard.md` / `story.jira-wiki.md`:
35
35
  - Non-Functional Requirements blocks (a11y/i18n/perf/tokens) — DoD only.
36
36
  - Edge Cases enumerated as their own section — fold into AC failure paths.
37
37
  - Dependencies as prose — Jira ticket links only.
38
38
  - Per-claim visual specs (pixel measurements, hex inferences) inline — use single banner (rule 5).
39
39
  - Logs >3 lines (>5 if SPLIT verdict).
40
40
 
41
+ 3a. **Technical detail lives in `story.dev.md`.** The content rule 3 bans from the PM body is NOT discarded — it is rendered in the dev-facing file. Edge cases, analytics events, risks/dependencies, technical considerations, and the command-level DoD belong in `story.dev.md`, populated by the enrichment components (Application step 8b). The PM↔dev split is the home for this content; rule 3 governs the PM files, `story.dev.md` carries the technical detail. See `[[jira-wiki-formatter]]` for the audience table.
42
+
41
43
  4. **Output language matches the user's chat language**, not the input's. Auto-detect first via rule 4a; only ask via `AskUserQuestion` if signals split.
42
44
 
43
45
  5. **Visual inference confidence — single banner only.** Do NOT tag every visual claim. ONE banner at the top of the Design Reference block declares source type; all claims under it inherit:
@@ -218,7 +220,15 @@ NOTHING else. No NFR block. No Edge Cases enumeration. No Dependencies prose. No
218
220
  - Count ≤1 → continue to step 8 (single-story path).
219
221
  - Count ≥2 → execute the **host skill's split behavior** (see Source-specific differential in each top-level skill).
220
222
 
221
- 8. **Fill the canonical block** (Use Case + AC + Design Ref + INVEST). Preserve original wording where it was already good. NEVER invent NFR/edge-case/deps sections.
223
+ 8. **Fill the canonical block** (Use Case + AC + Design Ref + INVEST). Preserve original wording where it was already good. NEVER invent NFR/edge-case/deps sections **in the PM story body** — rule 3 still holds for `story.standard.md` / `story.jira-wiki.md`.
224
+
225
+ 8b. **Gather dev-file enrichment** (feeds `story.dev.md` only — see rule 3a). Invoke the enrichment components to populate the technical sections of the dev file:
226
+ - `[[edge-cases]]` → `### Edge Cases` (technical failure axes)
227
+ - `[[risks-and-dependencies]]` → `### Dependencias` + `### Riesgos`
228
+ - `[[analytics-events]]` → `### Analytics / Eventos`
229
+ - `[[definition-of-done]]` → full DoD with CLI commands (PM files get the acceptance-only projection)
230
+ - `[[business-rules]]` → policy invariants (also an *optional* PM section per `[[jira-wiki-formatter]]` when non-empty)
231
+ None of these may appear in the PM story body except the optional Business Rules section. Skip any component whose output is empty (drop empty sections — rule 3 / jira-wiki-formatter).
222
232
 
223
233
  9. **Run INVEST** via `[[invest-checklist]]`.
224
234
  - `READY` → render.
@@ -228,10 +238,13 @@ NOTHING else. No NFR block. No Edge Cases enumeration. No Dependencies prose. No
228
238
 
229
239
  10. **Render** via `[[jira-wiki-formatter]]`.
230
240
  - Derive the output folder: `docs/storywright/YYYY-MM-DD-HHmm-<title-slug>/` where `YYYY-MM-DD-HHmm` is the current local date+time and `<title-slug>` is the story title in kebab-case (max 5 words, drop articles/prepositions).
231
- - Use the `Write` tool to persist `story.standard.md` and `story.jira-wiki.md` to that folder (create it if it does not exist).
232
- - Also emit both as fenced code blocks in chat.
241
+ - Use the `Write` tool to persist three files to that folder (create it if it does not exist):
242
+ - `story.standard.md` PM-facing CommonMark, no technical detail
243
+ - `story.jira-wiki.md` — PM-facing Jira wiki markup, no technical detail
244
+ - `story.dev.md` — dev-facing CommonMark, full technical detail (file paths, imports, technical edge cases, full DoD with commands)
245
+ - Emit `story.standard.md` and `story.jira-wiki.md` as fenced code blocks in chat. Do NOT emit `story.dev.md` in chat.
233
246
  - Write `.storywright-context.json` to the same folder.
234
- - No other files. Never ask whether to save — always write.
247
+ - Never ask whether to save — always write all four files.
235
248
 
236
249
  11. **Log** ≤3 bullets (≤5 if SPLIT) appended at story end. Log type label is host-specific (Generation / Refinement / Split).
237
250
 
@@ -9,12 +9,18 @@ inputs:
9
9
  outputs:
10
10
  - story-1.standard.md
11
11
  - story-1.jira-wiki.md
12
+ - story-1.dev.md
12
13
  - flow-summary.md
13
14
  - .storywright-context.json
14
15
  composes:
15
16
  - _components/storywright-base
16
17
  - _components/clarification-questions
18
+ - _components/business-rules
17
19
  - _components/acceptance-criteria
20
+ - _components/edge-cases
21
+ - _components/analytics-events
22
+ - _components/risks-and-dependencies
23
+ - _components/definition-of-done
18
24
  - _components/invest-checklist
19
25
  - _components/jira-wiki-formatter
20
26
  ---
@@ -85,15 +91,15 @@ Use the base canonical output shape. Design Reference banner per source-specific
85
91
 
86
92
  ### Phase 5 — Output
87
93
 
88
- Per drafted flow:
89
- - `story-<N>.standard.md` + `story-<N>.jira-wiki.md`.
94
+ Per drafted flow, render the full trio via `[[jira-wiki-formatter]]` (same 3-file contract as `story-generate` / `story-refine`):
95
+ - `story-<N>.standard.md` + `story-<N>.jira-wiki.md` (PM-facing) + `story-<N>.dev.md` (dev-facing).
90
96
 
91
97
  If N>1 OR any flow was routed to split:
92
98
  - `flow-summary.md` with the matrix, V audit, build order, and SPLIT-RECOMMENDED markers.
93
99
 
94
100
  Plus `.storywright-context.json` updated (`extra.figma_url`, `extra.figma_scope`, `extra.mcp_available`).
95
101
 
96
- NO `clarifications.md`. NO Edge Cases sections. NO NFR blocks. NO per-claim visual tags.
102
+ NO `clarifications.md`. NO Edge Cases / NFR sections **in the PM files** (they live in `story-<N>.dev.md` per base rule 3a). NO per-claim visual tags.
97
103
 
98
104
  ## Examples
99
105
 
@@ -124,7 +130,7 @@ Skipping the mechanical matrix in `flow-summary.md` when N>1.
124
130
 
125
131
  - Treating each frame as a story.
126
132
  - Skipping prototype-link analysis — without flow structure, user goals are guesses.
127
- - Ignoring empty/error/loading states. Fold into AC failure paths, not edge-case sections.
133
+ - Ignoring empty/error/loading states. In the PM files fold them into AC failure paths (no edge-case section); the technical detail goes to `story-<N>.dev.md`.
128
134
  - Trusting MEDIUM/LOW inferences silently — mark `⚠️ Assumed`.
129
135
  - Skipping per-story V audit when N>1 (figma flows over-split easily).
130
136
  - All other pitfalls in `[[storywright-base]]` apply equally.
@@ -11,11 +11,17 @@ inputs:
11
11
  outputs:
12
12
  - story.standard.md
13
13
  - story.jira-wiki.md
14
+ - story.dev.md
14
15
  - .storywright-context.json
15
16
  composes:
16
17
  - _components/storywright-base
17
18
  - _components/clarification-questions
19
+ - _components/business-rules
18
20
  - _components/acceptance-criteria
21
+ - _components/edge-cases
22
+ - _components/analytics-events
23
+ - _components/risks-and-dependencies
24
+ - _components/definition-of-done
19
25
  - _components/invest-checklist
20
26
  - _components/jira-wiki-formatter
21
27
  ---
@@ -0,0 +1,27 @@
1
+ # {{Title}} — Dev Notes
2
+
3
+ > This file is the developer supplement to `story.standard.md`.
4
+ > It contains all technical detail stripped from the PM-facing outputs.
5
+
6
+ ## Technical Considerations
7
+
8
+ - {{file path or component name}} — {{what changes}}
9
+ - {{import to add/remove}}
10
+ - {{API call / SDK / feature flag / data model note}}
11
+
12
+ ## Edge Cases & Error States
13
+
14
+ - **{{axis}}:** {{technical behavior — null checks, error states, race conditions, HTTPS requirements}}
15
+
16
+ ## Definition of Done
17
+
18
+ - [ ] {{business criterion}}
19
+ - [ ] {{test command: npm run test / npm run lint}}
20
+ - [ ] {{file-level criterion: file X updated, import Y removed}}
21
+
22
+ ---
23
+
24
+ <!-- Refinement Log — full version including technical changes -->
25
+
26
+ *Refinement log*
27
+ - {{change}} — {{reason}}
@@ -20,6 +20,10 @@ h3. Definition of Done
20
20
 
21
21
  ----
22
22
 
23
+ {panel:title=PM-facing — no technical detail}
24
+ Technical Considerations, Edge Cases, Analytics, Risks & Dependencies live in story.dev.md (rule 3). Optional sections below — keep only those with content.
25
+ {panel}
26
+
23
27
  h3. Contexto
24
28
  {{trigger: feedback / OKR / incident / competitor}}
25
29
 
@@ -34,21 +38,3 @@ h3. Out of Scope
34
38
 
35
39
  h3. Business Rules
36
40
  # {{rule 1}}
37
-
38
- h3. Technical Considerations
39
- * {{api / sdk / flag / data model}}
40
-
41
- h3. Dependencies
42
- ||What||Owner||Status||Blocks?||
43
- |{{dep}}|{{owner}}|{{READY/IN-PROGRESS}}|{{Yes/No}}|
44
-
45
- h3. Risks
46
- ||Risk||L||I||Mitigation||
47
- |{{risk}}|{{L/M/H}}|{{L/M/H}}|{{action}}|
48
-
49
- h3. Analytics
50
- ||Event||Trigger||Payload||
51
- |{{event_name}}|{{when}}|{{fields}}|
52
-
53
- h3. Edge Cases
54
- * *{{axis}}:* {{behavior}}
@@ -20,7 +20,12 @@
20
20
 
21
21
  ---
22
22
 
23
- <!-- Optional sections — keep only those with content. Delete the rest. -->
23
+ <!--
24
+ PM-facing file. NO technical detail (rule 3): no file paths, imports, commands,
25
+ edge-case sections, NFR blocks, or dependency prose. Technical Considerations,
26
+ Edge Cases, Analytics, Risks & Dependencies live in story.dev.md.
27
+ Optional sections below — keep only those with content. Delete the rest.
28
+ -->
24
29
 
25
30
  ## Contexto
26
31
  {{trigger: feedback / OKR / incident / competitor}}
@@ -36,24 +41,3 @@
36
41
 
37
42
  ## Business Rules
38
43
  1. {{rule 1}}
39
-
40
- ## Technical Considerations
41
- - {{api / sdk / flag / data model}}
42
-
43
- ## Dependencies
44
- | What | Owner | Status | Blocks? |
45
- |---|---|---|---|
46
- | {{dep}} | {{owner}} | {{READY/IN-PROGRESS}} | {{Yes/No}} |
47
-
48
- ## Risks
49
- | Risk | L | I | Mitigation |
50
- |---|---|---|---|
51
- | {{risk}} | {{L/M/H}} | {{L/M/H}} | {{action}} |
52
-
53
- ## Analytics
54
- | Event | Trigger | Payload |
55
- |---|---|---|
56
- | `{{event_name}}` | {{when}} | {{fields}} |
57
-
58
- ## Edge Cases
59
- - **{{axis}}:** {{behavior}}
@@ -11,11 +11,17 @@ inputs:
11
11
  outputs:
12
12
  - story.standard.md
13
13
  - story.jira-wiki.md
14
+ - story.dev.md
14
15
  - .storywright-context.json
15
16
  composes:
16
17
  - _components/storywright-base
17
18
  - _components/clarification-questions
19
+ - _components/business-rules
18
20
  - _components/acceptance-criteria
21
+ - _components/edge-cases
22
+ - _components/analytics-events
23
+ - _components/risks-and-dependencies
24
+ - _components/definition-of-done
19
25
  - _components/invest-checklist
20
26
  - _components/jira-wiki-formatter
21
27
  ---
@@ -10,14 +10,23 @@ inputs:
10
10
  - figma-link
11
11
  outputs:
12
12
  - epic.md
13
- - story-1.md
14
- - story-2.md
13
+ - story-1.standard.md
14
+ - story-1.jira-wiki.md
15
+ - story-1.dev.md
16
+ - story-2.standard.md
17
+ - story-2.jira-wiki.md
18
+ - story-2.dev.md
15
19
  - .storywright-context.json
16
20
  composes:
17
21
  - _components/storywright-base
18
22
  - _components/invest-checklist
19
23
  - _components/clarification-questions
24
+ - _components/business-rules
20
25
  - _components/acceptance-criteria
26
+ - _components/edge-cases
27
+ - _components/analytics-events
28
+ - _components/risks-and-dependencies
29
+ - _components/definition-of-done
21
30
  - _components/jira-wiki-formatter
22
31
  ---
23
32
 
@@ -35,8 +44,8 @@ When a story is an epic in disguise, splitting badly is worse than not splitting
35
44
  ## Split behavior differential
36
45
 
37
46
  This skill IS the split behavior. It always emits multiple files:
38
- - `epic.md` — title, why-split, INVEST failure reasons, mechanical NxN matrix, build order, V audit per child, list of children.
39
- - `story-1.md`, `story-2.md`, one canonical story per child (per base shape).
47
+ - `epic.md` — title, why-split, INVEST failure reasons, mechanical NxN matrix, build order, V audit per child, list of children. Single file (epic metadata, not a user story).
48
+ - Per child: the full 3-file trio `story-<N>.standard.md` + `story-<N>.jira-wiki.md` + `story-<N>.dev.md`, rendered via `[[jira-wiki-formatter]]` same contract as every other story-producing skill. Each child is a canonical user story (per base shape).
40
49
  - `.storywright-context.json` — persisted answers.
41
50
 
42
51
  NO `split-plan.md`. The plan lives inside `epic.md`.
@@ -107,7 +116,7 @@ Follow the **base Application** skeleton for the front-end behaviors (context lo
107
116
 
108
117
  5. **STOP and ask the user to approve via `AskUserQuestion`.**
109
118
 
110
- 6. **For each approved child, write the base canonical block.** Each child is its own file (`story-<N>.md`).
119
+ 6. **For each approved child, write the base canonical block, then render via `[[jira-wiki-formatter]]` to the 3-file trio** (`story-<N>.standard.md` + `story-<N>.jira-wiki.md` + `story-<N>.dev.md`). The child's enrichment (edge cases, risks, analytics) populates its `story-<N>.dev.md` per base step 8b.
111
120
 
112
121
  7. **Build dependency matrix mechanically (base rule 10).** Render in `epic.md`.
113
122