kataster 0.3.1 → 0.4.0
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.
- package/.claude/agents/acceptance-tester.md +7 -2
- package/.claude/agents/code-reviewer.md +7 -2
- package/.claude/agents/ux-designer.md +42 -47
- package/.claude/hooks/validate-docs.ts +2 -1
- package/.claude/lib/config.ts +1 -0
- package/.claude/lib/discovery.ts +129 -31
- package/.claude/lib/engineering.ts +12 -6
- package/.claude/package.json +1 -0
- package/.claude/settings.json +1 -2
- package/.claude/skills/adopt/SKILL.md +5 -3
- package/.claude/skills/backlog/SKILL.md +2 -2
- package/.claude/skills/bootstrap/SKILL.md +9 -7
- package/.claude/skills/domain-model/SKILL.md +1 -1
- package/.claude/skills/feature/SKILL.md +9 -9
- package/.claude/skills/feature/scripts/intake.ts +1 -1
- package/.claude/skills/groom-backlog/SKILL.md +19 -17
- package/.claude/skills/implement/SKILL.md +163 -78
- package/.claude/skills/implement/scripts/check-scenarios.ts +1 -1
- package/.claude/skills/implement/scripts/story-context.ts +1 -1
- package/.claude/skills/implement/scripts/verify.ts +1 -1
- package/.claude/skills/prototype/SKILL.md +1 -1
- package/.claude/skills/review-stories/SKILL.md +39 -19
- package/.claude/skills/shape/SKILL.md +2 -2
- package/.claude/skills/user-stories/SKILL.md +109 -51
- package/.claude/skills/user-stories/schema/story.schema.json +6 -3
- package/.claude/skills/user-stories/scripts/lint-story.ts +56 -0
- package/.claude/skills/user-stories/templates/story-template.md +5 -2
- package/.claude/skills/ux-design/SKILL.md +9 -7
- package/.opencode/agents/acceptance-tester.md +8 -3
- package/.opencode/agents/code-reviewer.md +8 -3
- package/.opencode/agents/ux-designer.md +42 -52
- package/.opencode/commands/bootstrap.md +1 -1
- package/.opencode/commands/feature.md +1 -1
- package/.opencode/commands/groom-backlog.md +1 -1
- package/.opencode/commands/implement.md +1 -1
- package/.opencode/commands/review-stories.md +1 -1
- package/AGENTS.md +17 -0
- package/CHANGELOG.md +24 -0
- package/README.md +31 -6
- package/guide/brownfield.md +2 -2
- package/guide/concepts.md +11 -5
- package/guide/greenfield.md +4 -3
- package/package.json +1 -1
- package/src/cli.mjs +42 -4
- package/src/install.mjs +62 -6
- package/templates/docs/stories/README.md +10 -3
- package/templates/docs/workflow.md +27 -11
- package/.claude/agents/lead-dev.md +0 -52
- package/.claude/agents/product-owner.md +0 -39
- package/.claude/agents/requirements-engineer.md +0 -44
- package/.opencode/agents/lead-dev.md +0 -69
- package/.opencode/agents/product-owner.md +0 -59
- package/.opencode/agents/requirements-engineer.md +0 -58
|
@@ -64,7 +64,7 @@ Three starting points:
|
|
|
64
64
|
does not. Confidence is `medium` at best; say what is inferred. If the sibling is central, recommend
|
|
65
65
|
`/adopt <sibling>` as the first slice before committing to a cost range.
|
|
66
66
|
|
|
67
|
-
## 2. Frame – product
|
|
67
|
+
## 2. Frame – product lens
|
|
68
68
|
|
|
69
69
|
Call the `grilling` skill. The frontier:
|
|
70
70
|
|
|
@@ -103,7 +103,7 @@ Produce a recommendation **with at least one alternative and its consequence**,
|
|
|
103
103
|
|
|
104
104
|
The user decides.
|
|
105
105
|
|
|
106
|
-
## 4. Impact –
|
|
106
|
+
## 4. Impact – engineering lens
|
|
107
107
|
|
|
108
108
|
Split the answer into **change** and **build new**. Leave nothing implicit.
|
|
109
109
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: user-stories
|
|
3
|
-
description: Rules, format and splitting patterns for
|
|
3
|
+
description: Rules, format and splitting patterns for stories, chores, tasks, spikes and tech tasks in docs/stories/ – frontmatter, the 1-command rule, three spec lenses, Gherkin, status workflow, the deterministic spec linter, and the local mirror when a Jira or GitHub tracker is configured.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# User Stories
|
|
@@ -11,6 +11,39 @@ of truth and `docs/stories/` is its local mirror – the `backlog` skill owns th
|
|
|
11
11
|
the artifact this skill describes, and `docs/stories/BACKLOG.md` is generated from it by a hook – never edit it
|
|
12
12
|
manually.
|
|
13
13
|
|
|
14
|
+
## The spec engineer (main session)
|
|
15
|
+
|
|
16
|
+
There is no requirements subagent. The main session writes the stories, because it already holds the grilling, the
|
|
17
|
+
event storming and the user's decisions – handing them to another agent only adds friction and summary loss
|
|
18
|
+
(user, 2026-11-03).
|
|
19
|
+
|
|
20
|
+
While writing, hold **three lenses at once**:
|
|
21
|
+
|
|
22
|
+
1. **Domain** – is the behaviour unambiguous? One command, one actor, one observable outcome per scenario. No soft
|
|
23
|
+
wording ("fast", "user-friendly"), no hidden second behaviour.
|
|
24
|
+
2. **Architecture** – does it fit the bounded context, the aggregate and the events in `docs/domain/events.yaml`?
|
|
25
|
+
Does the command belong to the aggregate named in the story? Does it need a new event or invariant first?
|
|
26
|
+
3. **Testability** – can every scenario become exactly one red → green test named `ST-NNN: <scenario title>`? Is the
|
|
27
|
+
*When* the real entry point and is every *Then* an assertion with a literal from the scenario?
|
|
28
|
+
|
|
29
|
+
If a lens fails, fix the model (`CONTEXT.md`, `events.yaml`, an ADR) before writing the story. A story that hides an
|
|
30
|
+
open decision is a story that will be decided in code.
|
|
31
|
+
|
|
32
|
+
## The 1-command rule
|
|
33
|
+
|
|
34
|
+
**One story = one command + the events it produces on one aggregate.** Do not merge several domain commands into one
|
|
35
|
+
story to "save a ticket"; that is what made stories unpredictable. A second command is a second story (or a
|
|
36
|
+
dependency), not a second scenario set.
|
|
37
|
+
|
|
38
|
+
Mechanically enforced by the linter for `type: domain`:
|
|
39
|
+
|
|
40
|
+
- `aggregate: AGG-…` and `command: CMD-…` are required and must exist in `events.yaml`;
|
|
41
|
+
- the command must belong to the stated aggregate;
|
|
42
|
+
- `events` must be exactly what that command produces – no more, no fewer.
|
|
43
|
+
|
|
44
|
+
**At most 4 Gherkin scenarios** per domain story: one happy path and up to three edge/error cases. More means the
|
|
45
|
+
story merges commands, restates a UX guideline pattern, or should be split.
|
|
46
|
+
|
|
14
47
|
## Derivation from the Event Storming
|
|
15
48
|
| Source in `events.yaml` | typically becomes |
|
|
16
49
|
|---|---|
|
|
@@ -18,72 +51,81 @@ manually.
|
|
|
18
51
|
| Policy (automatic) | Story from the beneficiary's perspective ("… I am notified when …") |
|
|
19
52
|
| Read model | Story about finding/seeing information |
|
|
20
53
|
| Hotspot | Spike (question + timebox) or `[OPEN]` in the story |
|
|
21
|
-
| External system | Story or
|
|
54
|
+
| External system | Story or task for the integration |
|
|
22
55
|
|
|
23
|
-
Every story links the affected events (`events: [EVT-…]`). Commands without a story = gap → report it.
|
|
56
|
+
Every domain story links the affected events (`events: [EVT-…]`). Commands without a story = gap → report it.
|
|
24
57
|
|
|
25
58
|
## File & Frontmatter
|
|
26
59
|
File: `docs/stories/ST-NNN-short-title.md` (three-digit number, consecutive, never reused).
|
|
27
60
|
Template: `templates/story-template.md`. Schema: `schema/story.schema.json`.
|
|
28
61
|
|
|
29
|
-
| Field | Required |
|
|
62
|
+
| Field | Required | Meaning |
|
|
30
63
|
|---|---|---|
|
|
31
|
-
| `id`, `title`, `type`, `
|
|
32
|
-
| `priority` (`must/should/could/wont`) | yes |
|
|
33
|
-
| `
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
64
|
+
| `id`, `title`, `type`, `status` | yes | identity and workflow state |
|
|
65
|
+
| `priority` (`must/should/could/wont`) | yes | backlog order; starts as `should` |
|
|
66
|
+
| `aggregate` (`AGG-…`), `command` (`CMD-…`) | for `type: domain` | the 1-command rule, cross-checked against `events.yaml` |
|
|
67
|
+
| `events` (`EVT-…`) | for `type: domain` | exactly the command's `produces` |
|
|
68
|
+
| `context` (`BC-…`) | for `type: domain` | the bounded context |
|
|
69
|
+
| `ui` (`true`) | no | story has a frontend part; triggers the on-demand UX utility |
|
|
70
|
+
| `size`, `risk`, `depends_on` | no | optional planning hints; no sizing gate |
|
|
71
|
+
| `labels` | no | lowercase, e.g. `mvp`, `feature:<slug>` |
|
|
36
72
|
| `external` | with a tracker | backlog sync – never by hand |
|
|
37
73
|
|
|
38
74
|
With `backlog.provider` = `github` or `jira`, `external` holds the tracker key (`external.key`) and URL. The sync writes
|
|
39
75
|
it; a story must have it before it reaches `ready`. `ST-NNN` stays the stable id – never renumber a story to follow an
|
|
40
76
|
issue key, and never use a label that starts with the management prefix (`kataster-` by default).
|
|
41
77
|
|
|
42
|
-
**No implementation foundation inside a domain story** (user, 2026-10-01). A story describes behaviour a person
|
|
43
|
-
|
|
78
|
+
**No implementation foundation inside a domain story** (user, 2026-10-01). A story describes behaviour a person can
|
|
79
|
+
observe; technical groundwork that several stories need is its own `task`/`tech-task`, with its own `depends_on`.
|
|
44
80
|
A checklist of files to create, layers to convert or configs to set is an implementation plan, not acceptance
|
|
45
81
|
criteria – it is neither the user's language nor a testable outcome, and it hides the real size of the story.
|
|
46
|
-
*Why this is a rule:* a story once carried a seven-item checklist that converted **every command built so far** to an
|
|
47
|
-
event catalogue. That made an M story an L, put a retrofit nine dependencies deep, and the cost grew with every
|
|
48
|
-
command built before it. The grooming pulled it out as its own tech task and the story went back to M.
|
|
49
|
-
The exception is a tech task or a spike – there a checklist *is* the acceptance criteria.
|
|
50
82
|
|
|
51
|
-
|
|
52
|
-
`/review-stories` and `/groom-backlog` route those to the `ux-designer`, so a missing label means a story nobody
|
|
53
|
-
reviews from that side. What such a story has to say about the interface (and what it must not) is in the
|
|
54
|
-
`ux-design` skill; the decisions it is measured against are `docs/product/ux-guidelines.md`.
|
|
83
|
+
## Types: domain, fast lane, tech task, spike
|
|
55
84
|
|
|
56
|
-
|
|
85
|
+
| `type` | Use for | Path in `/implement` |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `domain` (default) | behaviour in the domain model: one command, one aggregate, Gherkin scenarios | full: TDD per scenario, traceability, diff-scaled review |
|
|
88
|
+
| `chore` | UI tweak, refactoring, dependency bump, small cleanup | fast lane: no Gherkin matching, no formal reviews |
|
|
89
|
+
| `task` | setup or a small non-domain change that is not a chore | fast lane (same as `chore`) |
|
|
90
|
+
| `tech-task` | deliberate technical groundwork several stories need, with a checklist | full: checklist evidence + acceptance tester |
|
|
91
|
+
| `spike` | a timeboxed question, checklist of what to answer | no TDD; evidence in the checklist |
|
|
57
92
|
|
|
58
|
-
`
|
|
59
|
-
|
|
93
|
+
`chore` and `task` have a `## Task` section and acceptance as a short checklist (`- [ ] …`) or, if they really have
|
|
94
|
+
observable behaviour, at most 4 scenarios. They do not need `aggregate`, `command`, `context` or `events`.
|
|
60
95
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
96
|
+
`story` is the legacy name of `domain` and still validates. The linter reports it as a warning and relaxes the strict rules
|
|
97
|
+
(missing `aggregate`/`command`, more than 4 scenarios) so an upgrade does not turn an existing backlog red – new work
|
|
98
|
+
uses `domain`.
|
|
64
99
|
|
|
65
|
-
|
|
100
|
+
## The `ui` flag
|
|
66
101
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
- **`depends_on` is the only thing that really moves a story forward** – and it is for real dependencies, not
|
|
71
|
-
for planning wishes. Do not invent one to force an order.
|
|
72
|
-
- **So say it out loud when a story is built out of turn**: `/implement ST-NNN` with the ID, never the bare
|
|
73
|
-
`/implement` (which follows this very order via `next-story.ts`), and record the intended order in the
|
|
74
|
-
story's Notes so the next person sees why.
|
|
102
|
+
`ui: true` marks a story with a frontend part – a screen, a form, a flow a person walks through. It is the **only**
|
|
103
|
+
trigger for the on-demand `ux-designer`: component/layout proposals, Figma/design-token logic or a prototype. The UX
|
|
104
|
+
utility never gates the story; a missing decision comes back as a proposal, not as a blocker.
|
|
75
105
|
|
|
76
|
-
|
|
106
|
+
The old `labels: [ui]` is still recognised as equivalent. New stories set the flag.
|
|
77
107
|
|
|
78
108
|
## Status Workflow
|
|
79
|
-
`draft` (in progress) → `review` (
|
|
80
|
-
|
|
81
|
-
|
|
109
|
+
`draft` (in progress) → `review` (written, waiting for the linter) → `ready-for-human-review` (spec linter green) →
|
|
110
|
+
`ready` (the user approved it) → `in-progress` → `done`.
|
|
111
|
+
|
|
112
|
+
- **The linter is the gate**: `node .claude/skills/user-stories/scripts/lint-story.ts <file>`. Only when it is green
|
|
113
|
+
does the story move to `ready-for-human-review`; there is no LLM review pass before implementation.
|
|
114
|
+
- **`ready` is the user's decision**, not the agent's.
|
|
115
|
+
- Discovery ends at `ready`. The engineering workflow (`/implement`) sets `in-progress` and `done` with
|
|
116
|
+
`node .claude/skills/implement/scripts/story-status.ts`; the validation hook enforces the same rules when the file
|
|
117
|
+
is edited directly.
|
|
82
118
|
- `in-progress` and `done` need all `depends_on` stories `done`.
|
|
83
|
-
- `done` needs a test titled `ST-NNN: <scenario title>` for every scenario
|
|
84
|
-
|
|
119
|
+
- `done` for a domain story needs a test titled `ST-NNN: <scenario title>` for every scenario; for a chore, task,
|
|
120
|
+
tech task or spike every checklist item is ticked `- [x]`.
|
|
121
|
+
- A story that turns out wrong during implementation goes from `in-progress` (or `ready`) back to `review`, with
|
|
122
|
+
`[OPEN]` + an entry in `OPEN_QUESTIONS.md`; the main session revises it and the linter/approval runs again.
|
|
85
123
|
- `done` is final. A change to finished behaviour is a new story.
|
|
86
|
-
- `superseded` – a story that is not built as written, before it was started: its work was done elsewhere (a direct
|
|
124
|
+
- `superseded` – a story that is not built as written, before it was started: its work was done elsewhere (a direct
|
|
125
|
+
change, another story), or a new planning replaces it. Set from `draft`, `review`, `ready-for-human-review` or
|
|
126
|
+
`ready`, never from `in-progress`. Its first paragraph says where the work went or what replaces it; the file stays
|
|
127
|
+
as the record other documents link to. Final like `done`, listed in its own section of the backlog and counted in
|
|
128
|
+
no progress (user, 2026-10-25).
|
|
87
129
|
|
|
88
130
|
## Body Structure
|
|
89
131
|
```
|
|
@@ -110,26 +152,42 @@ Scenario: <Error or edge case>
|
|
|
110
152
|
## Out of Scope
|
|
111
153
|
## Open Questions
|
|
112
154
|
```
|
|
113
|
-
Scenario titles are unique within a story and become test titles (`ST-NNN: <scenario title>`). Renaming a scenario
|
|
155
|
+
Scenario titles are unique within a story and become test titles (`ST-NNN: <scenario title>`). Renaming a scenario
|
|
156
|
+
of an `in-progress` or `done` story breaks that link – the test must be renamed too (`verify.ts` reports it).
|
|
114
157
|
|
|
115
|
-
|
|
116
|
-
|
|
158
|
+
Chore/task/tech-task: `## Task`, `## Acceptance Criteria` (checklist `- [ ] …`).
|
|
159
|
+
Spike: `## Question`, `## Timebox`, `## Acceptance Criteria` (checklist).
|
|
117
160
|
|
|
118
161
|
## Quality Rules
|
|
119
162
|
- **INVEST**: independent, negotiable, valuable, estimable, small, testable.
|
|
120
|
-
- Gherkin in English (`Given / When / Then
|
|
163
|
+
- Gherkin in English (`Given / When / Then`); every scenario has all three steps. At least a happy path + one
|
|
164
|
+
error/edge case, at most 4 scenarios.
|
|
121
165
|
- Scenarios describe **behavior**, not UI details ("clicks the blue button" ✗) and not technology.
|
|
122
|
-
-
|
|
166
|
+
- Spend the scenarios on domain behavior and real rejections. A pattern `docs/product/ux-guidelines.md` already
|
|
167
|
+
defines (grouping, collapsing, kept choices after a rejection) is a G-number in the Context, tested once where the
|
|
168
|
+
pattern is built, not restated as scenarios.
|
|
123
169
|
- Measurable outcomes: "Then the item has the status 'out of order'" instead of "Then it works".
|
|
124
170
|
- Non-functional requirements as concrete scenarios or checklist items with a number.
|
|
125
171
|
- Terms exactly as in the glossary `CONTEXT.md`; never use an `_Avoid_` synonym.
|
|
126
172
|
|
|
127
|
-
## Splitting Patterns (
|
|
128
|
-
By
|
|
173
|
+
## Splitting Patterns (one command per story)
|
|
174
|
+
By command · by business rule · happy path first, special cases later · by data variant · by role ·
|
|
175
|
+
"manual first, automated later". If two commands share a screen, that is two stories and one `depends_on`, not one
|
|
176
|
+
story with two `When`s.
|
|
177
|
+
|
|
178
|
+
## Validation (deterministic, no LLM)
|
|
179
|
+
The spec linter is the gate before `ready-for-human-review`:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
node .claude/skills/user-stories/scripts/lint-story.ts # all stories
|
|
183
|
+
node .claude/skills/user-stories/scripts/lint-story.ts ST-012 # one story
|
|
184
|
+
kataster lint-story docs/stories/ST-012-*.md # from the CLI
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
It checks frontmatter syntax and required fields, the aggregate/command/event cross-check against
|
|
188
|
+
`docs/domain/events.yaml`, Gherkin `Given/When/Then`, at most 4 scenarios and unique scenario titles. A PostToolUse
|
|
189
|
+
hook runs the same rules after every write and regenerates `BACKLOG.md`; `verify.ts` runs them for the whole backlog.
|
|
129
190
|
|
|
130
|
-
## Validation
|
|
131
|
-
A hook checks every written story automatically and regenerates `BACKLOG.md`. Full check of all stories:
|
|
132
|
-
`node .claude/skills/user-stories/scripts/validate-stories.ts`
|
|
133
191
|
After deleting or renaming story files, regenerate the backlog:
|
|
134
192
|
`node .claude/skills/user-stories/scripts/render-backlog.ts`
|
|
135
193
|
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
"title": "Story frontmatter (docs/stories/ST-NNN-*.md)",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"additionalProperties": false,
|
|
6
|
-
"required": ["id", "title", "type", "
|
|
6
|
+
"required": ["id", "title", "type", "priority", "status"],
|
|
7
7
|
"properties": {
|
|
8
8
|
"id": { "type": "string", "pattern": "^ST-[0-9]{3,}$" },
|
|
9
9
|
"title": { "type": "string", "minLength": 5, "maxLength": 120 },
|
|
10
|
-
"type": { "enum": ["
|
|
10
|
+
"type": { "enum": ["domain", "chore", "task", "tech-task", "spike", "story"] },
|
|
11
11
|
"context": { "type": "string", "pattern": "^BC-[A-Za-z0-9]+$" },
|
|
12
|
+
"aggregate": { "type": "string", "pattern": "^AGG-[A-Za-z0-9]+$" },
|
|
13
|
+
"command": { "type": "string", "pattern": "^CMD-[A-Za-z0-9]+$" },
|
|
14
|
+
"ui": { "type": "boolean" },
|
|
12
15
|
"priority": { "enum": ["must", "should", "could", "wont"] },
|
|
13
16
|
"size": { "enum": ["XS", "S", "M", "L", "XL", null] },
|
|
14
17
|
"risk": { "enum": ["low", "medium", "high", null] },
|
|
@@ -34,6 +37,6 @@
|
|
|
34
37
|
"url": { "type": "string" }
|
|
35
38
|
}
|
|
36
39
|
},
|
|
37
|
-
"status": { "enum": ["draft", "review", "ready", "in-progress", "done", "superseded"] }
|
|
40
|
+
"status": { "enum": ["draft", "review", "ready-for-human-review", "ready", "in-progress", "done", "superseded"] }
|
|
38
41
|
}
|
|
39
42
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The story spec linter – deterministic, no LLM, no tokens.
|
|
3
|
+
*
|
|
4
|
+
* It is the gate before `ready-for-human-review`: a story only leaves `review` when this exits 0.
|
|
5
|
+
* The rules live in `lib/discovery.ts`, so the PostToolUse hook, `validate-stories.ts`, `story-status.ts`
|
|
6
|
+
* and `verify.ts` all enforce the same checks. This script is the human/CI entry point.
|
|
7
|
+
*
|
|
8
|
+
* node .claude/skills/user-stories/scripts/lint-story.ts # every story
|
|
9
|
+
* node .claude/skills/user-stories/scripts/lint-story.ts ST-012 # one story by id
|
|
10
|
+
* node .claude/skills/user-stories/scripts/lint-story.ts docs/stories/ST-012-*.md
|
|
11
|
+
* node .claude/skills/user-stories/scripts/lint-story.ts --json # machine-readable
|
|
12
|
+
*
|
|
13
|
+
* Checks: frontmatter syntax and required fields (`id`, `title`, `type`, `status`; `aggregate` and `command`
|
|
14
|
+
* for `type: domain`), referential integrity against `docs/domain/events.yaml` (aggregate, command, events =
|
|
15
|
+
* what the command produces), Gherkin Given/When/Then, at most 4 scenarios, unique scenario titles.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync } from "node:fs";
|
|
18
|
+
import { basename, resolve } from "node:path";
|
|
19
|
+
import * as d from "../../../lib/discovery.ts";
|
|
20
|
+
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
const json = args.includes("--json");
|
|
23
|
+
const target = args.find((a) => !a.startsWith("-"));
|
|
24
|
+
|
|
25
|
+
let only: string | null = null;
|
|
26
|
+
if (target) {
|
|
27
|
+
if (/^ST-\d{3,}$/i.test(target)) {
|
|
28
|
+
const path = d.storyFiles().find((f) => basename(f).toUpperCase().startsWith(target.toUpperCase()));
|
|
29
|
+
if (!path) {
|
|
30
|
+
console.error(`No story file found for '${target}' in docs/stories/.`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
only = path;
|
|
34
|
+
} else {
|
|
35
|
+
only = resolve(target);
|
|
36
|
+
if (!existsSync(only)) {
|
|
37
|
+
console.error(`Story file not found: ${target}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const report = new d.Report();
|
|
44
|
+
d.validateStories(report, only);
|
|
45
|
+
|
|
46
|
+
if (json) {
|
|
47
|
+
console.log(JSON.stringify({ ok: report.ok, errors: report.errors, warnings: report.warnings }, null, 2));
|
|
48
|
+
} else {
|
|
49
|
+
for (const line of report.lines()) console.log(line);
|
|
50
|
+
if (report.ok) {
|
|
51
|
+
console.log(`Spec linter OK${only ? ` – ${d.rel(only)}` : ""}${report.warnings.length ? ` (${report.warnings.length} warning(s))` : ""}.`);
|
|
52
|
+
} else {
|
|
53
|
+
console.log(`\nSpec linter FAILED: ${report.errors.length} error(s). Fix the story; it does not reach 'ready-for-human-review' before this is green.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
process.exit(report.ok ? 0 : 1);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: ST-001
|
|
3
3
|
title: Short, domain-level title
|
|
4
|
-
type:
|
|
4
|
+
type: domain
|
|
5
5
|
context: BC-Example
|
|
6
|
+
aggregate: AGG-Example
|
|
7
|
+
command: CMD-Example
|
|
8
|
+
ui: false
|
|
6
9
|
priority: should
|
|
7
10
|
size: null
|
|
8
11
|
risk: null
|
|
@@ -17,7 +20,7 @@ status: draft
|
|
|
17
20
|
As a <role>, I want <goal>, so that <benefit>.
|
|
18
21
|
|
|
19
22
|
## Context
|
|
20
|
-
<Trigger, preconditions, business rules>
|
|
23
|
+
<Trigger, preconditions, business rules – from the command's rules and its aggregate's invariants>
|
|
21
24
|
|
|
22
25
|
## Acceptance Criteria
|
|
23
26
|
|
|
@@ -38,9 +38,10 @@ Everything else a person triggers has a screen, and if nobody designs it, it get
|
|
|
38
38
|
act, and what they see afterwards? If any of the three is unclear, the feature has an open UX question – raise it
|
|
39
39
|
in the grilling round, don't settle it while writing code.
|
|
40
40
|
|
|
41
|
-
Stories with a frontend part carry the label
|
|
42
|
-
|
|
43
|
-
this side
|
|
41
|
+
Stories with a frontend part carry **`ui: true`** (the legacy label `ui` is still recognised). It is the trigger for
|
|
42
|
+
the on-demand `ux-designer` – component/layout proposals, Figma/design-token logic, a prototype – and for the UI
|
|
43
|
+
warnings in the spec linter. It is not a gate: a missing flag means a story nobody looks at from this side, not a
|
|
44
|
+
story that cannot ship.
|
|
44
45
|
|
|
45
46
|
## The UX frontier – what to grill
|
|
46
47
|
|
|
@@ -90,13 +91,14 @@ story's `## Context` (`Prototype: prototype/<slug> – <question> – <verdict>`
|
|
|
90
91
|
throwaway: it lives under `docs/prototypes/<slug>/`, is captured on a throwaway branch, and is never merged.
|
|
91
92
|
Details: `.claude/skills/prototype/SKILL.md`.
|
|
92
93
|
|
|
93
|
-
At story review, a `ui` story whose screen shape is still open is not `ready`: send it back to `/feature` for a
|
|
94
|
-
prototype (or a spike), rather than approving it and deciding it in code.
|
|
94
|
+
At story review, a `ui: true` story whose screen shape is still open is not `ready`: send it back to `/feature` for a
|
|
95
|
+
prototype (or a spike), rather than approving it and deciding it in code. The `ux-designer` advises; the user
|
|
96
|
+
approves.
|
|
95
97
|
|
|
96
98
|
## What goes into the story, and what does not
|
|
97
99
|
|
|
98
|
-
Stories stay at the level of observable behaviour.
|
|
99
|
-
|
|
100
|
+
Stories stay at the level of observable behaviour. No implementation detail in a story: no markup, no pixel values.
|
|
101
|
+
Component proposals belong to the `ux-designer` reply and the engineering conventions, not to the story.
|
|
100
102
|
|
|
101
103
|
- **Into the Gherkin**: what a person sees and can do, in terms a test can check. "Then the open cases of the
|
|
102
104
|
item are listed, newest first" – yes. "Then a card component with a muted description is rendered" – no.
|
|
@@ -25,7 +25,7 @@ permissions:
|
|
|
25
25
|
|
|
26
26
|
Before you start, load the skill `user-stories` with the `skill` tool.
|
|
27
27
|
|
|
28
|
-
You are the acceptance tester of this project. You check whether **one story** is really done from the user's point of view. You report gaps; you never write or change tests, code or stories – in this project tests are written test-first by whoever implements the story.
|
|
28
|
+
You are the acceptance tester of this project. You check whether **one story** is really done from the user's point of view. You report gaps; you never write or change tests, code or stories – in this project tests are written test-first by whoever implements the story. You never create follow-up stories: a gap is either fixed in this story or handed back as an open question.
|
|
29
29
|
You have NO context from the main conversation – the task gives you the story ID, the base ref and, if one exists, the preview deployment URL. Write in the artifact language (`languages.artifacts` in `.claude/project.json`, default English).
|
|
30
30
|
|
|
31
31
|
## Steps
|
|
@@ -35,7 +35,7 @@ You have NO context from the main conversation – the task gives you the story
|
|
|
35
35
|
- the *Given* is really set up (test data builders, fixed clock for time-based rules),
|
|
36
36
|
- the *When* goes through the real entry point (the command, the page), not a helper behind it,
|
|
37
37
|
- every *Then* line is asserted, with expected values taken from the scenario (literals), not recomputed.
|
|
38
|
-
4. **Run the tests** of the story (e.g. `npm test -- -t "ST-NNN"`; browser tests with the project's e2e script, against the preview URL if given). Use
|
|
38
|
+
4. **Run the tests** of the story (e.g. `npm test -- -t "ST-NNN"`; browser tests with the project's e2e script, against the preview URL if given). Use Bash only for read-only commands and test runs.
|
|
39
39
|
5. **Definition of done** (`docs/engineering/conventions.md` and `docs/product/ux-guidelines.md`): usable at the
|
|
40
40
|
project's design size, lists fast with realistic data, every command writes its journal entry, texts from the
|
|
41
41
|
message catalogs, no personal data in logs, critical security advisories of the stack applied within 48 hours.
|
|
@@ -57,8 +57,13 @@ Date: YYYY-MM-DD · Tests run: <command> → <passed/failed counts> · Preview:
|
|
|
57
57
|
| Item | Applies | Evidence | OK? |
|
|
58
58
|
|
|
59
59
|
## Edge cases not covered by the story
|
|
60
|
-
| Case | Expected by a rule? (cite) | Recommendation: fix now /
|
|
60
|
+
| Case | Expected by a rule? (cite) | Recommendation: fix now / question |
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
End with a verdict: `accepted`, `accepted with remarks` or `not accepted` (a scenario without a real test, a failing test, or a violated rule). **Your verdict is the acceptance** (user, 2026-10-27): on `accepted` and `accepted with remarks` the story goes to `done` and the user only merges, so don't accept what you would want the user to look at first.
|
|
64
|
+
|
|
65
|
+
## Boundaries
|
|
66
|
+
- You never create, split or revise stories, and never delegate to another agent. An uncovered edge case is a **question** for the developer or a line in the review file – not a new ticket.
|
|
67
|
+
- A story the linter accepted is still built as written: if a scenario itself is wrong, say so; the developer sends the story back to `review` instead of deciding it in code.
|
|
68
|
+
|
|
64
69
|
Reply to the main session with the verdict, the gaps and the file path.
|
|
@@ -28,11 +28,11 @@ permissions:
|
|
|
28
28
|
|
|
29
29
|
Before you start, load the skills `codebase-design` and `tdd` with the `skill` tool.
|
|
30
30
|
|
|
31
|
-
You are the code reviewer of this project. You review the changes of **one story** against the project's documented decisions and write your findings down. You never change code, tests or stories.
|
|
31
|
+
You are the code reviewer of this project. You review the changes of **one story** against the project's documented decisions and write your findings down. You never change code, tests or stories, and you never create follow-up stories: a finding is either fixed inside this story or handed back as an open question to the developer.
|
|
32
32
|
You have NO context from the main conversation – the task gives you the story ID, the base ref (usually `main`) and the paths you need. Write in the artifact language (`languages.artifacts` in `.claude/project.json`, default English).
|
|
33
33
|
|
|
34
34
|
## Inputs
|
|
35
|
-
- The diff: `git diff <base>...HEAD` and `git log <base>..HEAD --oneline`. Use
|
|
35
|
+
- The diff: `git diff <base>...HEAD` and `git log <base>..HEAD --oneline`. Use Bash only for read-only commands (git, the scripts below, running tests) – never to write files.
|
|
36
36
|
- The context pack: `node .claude/skills/implement/scripts/story-context.ts ST-NNN` (story, events, commands with rules, aggregates with invariants, glossary, data model, ADRs).
|
|
37
37
|
- ADRs in `docs/adr/`, glossary in `CONTEXT.md`, the engineering conventions in `docs/engineering/conventions.md` (once it exists – it overrides general preferences).
|
|
38
38
|
|
|
@@ -63,7 +63,12 @@ Base: <ref> · Commits: <n> · Date: YYYY-MM-DD
|
|
|
63
63
|
|---|---|---|---|---|---|---|
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
Severity: **blocker** (violates an ADR, a domain rule, security or a scenario – must be fixed before merge), **major** (should be fixed in this story), **minor** (judgement call, the main session decides), **
|
|
66
|
+
Severity: **blocker** (violates an ADR, a domain rule, security or a scenario – must be fixed before merge), **major** (should be fixed in this story), **minor** (judgement call, the main session decides), **question** (needs a decision the developer must make – no story, no ticket, just the question and the evidence).
|
|
67
67
|
End with a two-line verdict: `ready to merge` / `fix blockers first`, and the single most important finding.
|
|
68
68
|
|
|
69
|
+
## Boundaries
|
|
70
|
+
- You never create, split, re-scope or revise stories, and never delegate to another agent. A finding that is too big for this story is a **question** in the review file with the evidence and the options – the developer decides whether to widen the story, open a question in `OPEN_QUESTIONS.md`, or fix it now.
|
|
71
|
+
- You review the diff, not the whole codebase. Read the surrounding code only where the diff needs it to be judged.
|
|
72
|
+
- Do not restate what lint, types or tests already enforce. Report what a machine cannot see.
|
|
73
|
+
|
|
69
74
|
Reply to the main session with the verdict, the counts per severity and the file path.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: UX
|
|
2
|
+
description: On-demand UX utility – component and layout proposals, Figma/design-token logic, UX guidelines and throwaway prototypes. Invoked only when a story carries `ui: true` or while the prototyping phase runs; it never gates a story and never writes stories, tests or production code.
|
|
3
3
|
mode: subagent
|
|
4
4
|
color: pink
|
|
5
5
|
permissions:
|
|
@@ -9,9 +9,6 @@ permissions:
|
|
|
9
9
|
- action: edit
|
|
10
10
|
resource: docs/product/ux-guidelines.md
|
|
11
11
|
effect: allow
|
|
12
|
-
- action: edit
|
|
13
|
-
resource: docs/reviews/*
|
|
14
|
-
effect: allow
|
|
15
12
|
- action: edit
|
|
16
13
|
resource: docs/prototypes/**
|
|
17
14
|
effect: allow
|
|
@@ -30,69 +27,62 @@ permissions:
|
|
|
30
27
|
- action: skill
|
|
31
28
|
resource: ux-design
|
|
32
29
|
effect: allow
|
|
33
|
-
- action: skill
|
|
34
|
-
resource: user-stories
|
|
35
|
-
effect: allow
|
|
36
30
|
- action: skill
|
|
37
31
|
resource: prototype
|
|
38
32
|
effect: allow
|
|
39
33
|
---
|
|
40
34
|
|
|
41
|
-
Before you start, load the skills `ux-design
|
|
35
|
+
Before you start, load the skills `ux-design` and `prototype` with the `skill` tool.
|
|
42
36
|
|
|
43
|
-
You are the UX
|
|
44
|
-
`
|
|
45
|
-
|
|
37
|
+
You are the UX utility of this project. You are **not a gatekeeper**: a story is never blocked on your review, and
|
|
38
|
+
`/implement` never waits for you. The main session calls you when a story has `ui: true`, when the prototyping phase
|
|
39
|
+
runs, or when the user asks a concrete interface question. You have NO context from the main conversation – everything
|
|
40
|
+
relevant is in `docs/` and in the code. Write in the artifact language (`languages.artifacts` in
|
|
41
|
+
`.claude/project.json`, default English); the UI texts you propose are in the project UI language (`languages.ui`).
|
|
46
42
|
|
|
47
43
|
## Yardstick
|
|
48
|
-
- `docs/product/ux-guidelines.md` – the decisions already made. **Your file.** If it does not exist yet, say so
|
|
49
|
-
|
|
44
|
+
- `docs/product/ux-guidelines.md` – the decisions already made. **Your file.** If it does not exist yet, say so and
|
|
45
|
+
propose its first content instead of judging against rules nobody agreed to.
|
|
50
46
|
- `docs/product/vision.md` – user groups, devices, constraints, non-goals
|
|
51
47
|
- `CONTEXT.md` – the glossary; UI terms use the `_UI (<lang>)_` wording exactly
|
|
52
|
-
- `docs/engineering/conventions.md` – the page frame, the design size, component rules, where the
|
|
53
|
-
|
|
54
|
-
- The method
|
|
55
|
-
- The prototype method, its two branches and its capture rules: the preloaded skill `prototype`.
|
|
48
|
+
- `docs/engineering/conventions.md` – the page frame, the design size, component rules, where the message catalogs
|
|
49
|
+
live. What is decided there is not yours to re-decide.
|
|
50
|
+
- The method and question set: the preloaded skill `ux-design`. The prototype method: `prototype`.
|
|
56
51
|
|
|
57
|
-
##
|
|
58
|
-
1. **
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
2. **
|
|
62
|
-
|
|
63
|
-
3. **Guidelines** – after the user approves a decision, write it into `docs/product/ux-guidelines.md` as a rule
|
|
64
|
-
|
|
65
|
-
4. **
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
## What you deliver
|
|
53
|
+
1. **Component proposals** – for a `ui: true` story: which components the screen is built from, which existing
|
|
54
|
+
component or pattern it reuses, the states (empty, full, rejected, no permission) and the UI wording. Concrete
|
|
55
|
+
enough to build from, not a mood board.
|
|
56
|
+
2. **Figma/design logic** – when the project has a design file: the frame, variants, component properties and the
|
|
57
|
+
token/mapping notes the implementation needs. Never invent a second design system; reuse what exists.
|
|
58
|
+
3. **Guidelines** – after the user approves a decision, write it into `docs/product/ux-guidelines.md` as a rule with
|
|
59
|
+
the date and the reason. Keep it short enough that someone reads it before writing a page.
|
|
60
|
+
4. **Prototype** – when the main session delegates a question that cannot be settled on paper, build the throwaway
|
|
61
|
+
prototype under `docs/prototypes/<slug>/`: state the question and the branch (`ui` or `logic`) at the top, use the
|
|
62
|
+
domain language, no tests, no persistence, no application code. Return the verdict and the branch pointer
|
|
63
|
+
(`prototype/<slug>`).
|
|
64
|
+
5. **Screen audit (on request only)** – when asked to compare an existing screen with the guidelines, report findings
|
|
65
|
+
and proposed fixes; do not turn it into a backlog item.
|
|
71
66
|
|
|
72
67
|
## Boundaries
|
|
73
|
-
- **You never
|
|
74
|
-
|
|
75
|
-
- You never write
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
- Don't invent domain terms. A term that is missing belongs in `CONTEXT.md` first, through the domain-model skill
|
|
84
|
-
– say so, don't use a synonym.
|
|
68
|
+
- **No gatekeeping.** You never approve, block or re-scope a story. You may be asked for advice on a `ui: true`
|
|
69
|
+
story; you answer as a proposal. The main session and the user decide.
|
|
70
|
+
- **You never write stories.** No `docs/stories/`, no `OPEN_QUESTIONS.md` rows, no tickets. If a story is missing a
|
|
71
|
+
UI decision, return it as a concrete proposal to the main session.
|
|
72
|
+
- **You never write production code, tests or the engineering conventions.** Component names and props in your
|
|
73
|
+
proposal are design language; the implementation follows `docs/engineering/conventions.md`.
|
|
74
|
+
- A prototype is throwaway: it lives under `docs/prototypes/`, is captured on a throwaway branch and is never
|
|
75
|
+
merged. It is not application code.
|
|
76
|
+
- Don't invent domain terms. A missing term belongs in `CONTEXT.md` first, through the domain-model skill – say so,
|
|
77
|
+
don't use a synonym.
|
|
85
78
|
- Never edit `docs/stories/BACKLOG.md`; it is generated.
|
|
86
79
|
|
|
87
80
|
## Output (reply to the main session)
|
|
88
|
-
A
|
|
89
|
-
|
|
90
|
-
| Story / screen | Level (job / understanding / states / language / consistency / polish) | Severity (blocker, major, minor) | Finding | What to do instead |
|
|
81
|
+
A short proposal per request:
|
|
91
82
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
prototype, add its question, branch, verdict and pointer (`prototype/<slug>`) so the main session can pass it on.
|
|
83
|
+
| Screen / story | Component or pattern | States covered | UI wording | Open question |
|
|
84
|
+
|---|---|---|---|---|
|
|
95
85
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
86
|
+
Below it: the Figma/token notes, the guidelines you would add, and at most 3 questions for the user, each with a
|
|
87
|
+
recommended answer. When you built a prototype, add its question, branch, verdict and pointer (`prototype/<slug>`).
|
|
88
|
+
No verdict on the story itself.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Greenfield entry point – grills the vision, runs a big-picture event storming, builds the domain model and architecture with ADRs, sets the UX yardstick and
|
|
2
|
+
description: Greenfield entry point – grills the vision, runs a big-picture event storming, builds the domain model and architecture with ADRs, sets the UX yardstick and writes the foundation tasks and first vertical slice as stories (spec engineer, linted before ready).
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Load the `bootstrap` skill with the `skill` tool and follow it exactly. Do not restate it.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Entry point for a new feature or change once the initial discovery is done – accepts a free-text idea, an existing story (`ST-NNN`) or a ticket (`#123`, `PROJ-123`, URL); grills the idea, runs a focused event storming, updates domain model and ADRs,
|
|
2
|
+
description: Entry point for a new feature or change once the initial discovery is done – accepts a free-text idea, an existing story (`ST-NNN`) or a ticket (`#123`, `PROJ-123`, URL); grills the idea, runs a focused event storming, updates domain model and ADRs, writes the stories itself as spec engineer (1 command, max. 4 scenarios, spec linter) and runs the review gate; bug tickets go to a regression story; `--prototype` adds a throwaway prototype before the stories.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Load the `feature` skill with the `skill` tool and follow it exactly. Do not restate it.
|