kataster 0.3.0 → 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/THIRD_PARTY_NOTICES.md +69 -0
- package/.claude/agents/acceptance-tester.md +7 -2
- package/.claude/agents/code-reviewer.md +7 -2
- package/.claude/agents/ux-designer.md +43 -38
- 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 +37 -11
- package/.claude/skills/feature/scripts/intake.ts +1 -1
- package/.claude/skills/groom-backlog/SKILL.md +19 -16
- package/.claude/skills/implement/SKILL.md +169 -63
- 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/LOGIC.md +101 -0
- package/.claude/skills/prototype/SKILL.md +85 -0
- package/.claude/skills/prototype/UI.md +130 -0
- 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 +30 -5
- package/.opencode/agents/acceptance-tester.md +8 -3
- package/.opencode/agents/code-reviewer.md +8 -3
- package/.opencode/agents/ux-designer.md +44 -39
- 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 +38 -0
- package/README.md +64 -7
- package/guide/brownfield.md +2 -2
- package/guide/concepts.md +26 -5
- package/guide/greenfield.md +4 -3
- package/guide/release.md +1 -1
- package/package.json +1 -1
- package/src/cli.mjs +42 -4
- package/src/install.mjs +62 -6
- package/templates/docs/product/ux-guidelines.md +2 -0
- package/templates/docs/prototypes/README.md +9 -0
- package/templates/docs/stories/README.md +10 -3
- package/templates/docs/workflow.md +38 -13
- package/.claude/agents/lead-dev.md +0 -50
- package/.claude/agents/product-owner.md +0 -39
- package/.claude/agents/requirements-engineer.md +0 -44
- package/.opencode/agents/lead-dev.md +0 -67
- package/.opencode/agents/product-owner.md +0 -59
- package/.opencode/agents/requirements-engineer.md +0 -58
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Runs the deterministic spec linter on finished stories, fixes mechanical gaps, moves green stories to ready-for-human-review and guides the user to approval (status ready). No subagent review pass.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Load the `review-stories` skill with the `skill` tool and follow it exactly. Do not restate it.
|
package/AGENTS.md
CHANGED
|
@@ -19,3 +19,20 @@ Rules:
|
|
|
19
19
|
- A file the installer manages is tracked in `.claude/install.json`; project content (`CONTEXT.md`, `docs/`,
|
|
20
20
|
`project.json`, `AGENTS.md` block) is not. Never make an upgrade overwrite user content.
|
|
21
21
|
- Run `npm test` and `npm run typecheck --prefix .claude` before committing.
|
|
22
|
+
|
|
23
|
+
## Workflow contract (0.4)
|
|
24
|
+
|
|
25
|
+
The workflow is spec-driven and mechanical, not a simulated organisation:
|
|
26
|
+
|
|
27
|
+
- **No product-owner, requirements-engineer or lead-dev subagents.** The main session writes stories as a spec
|
|
28
|
+
engineer with three lenses (domain, architecture, testability). Only the `ux-designer` remains on demand
|
|
29
|
+
(`ui: true` / prototyping), and it never gates.
|
|
30
|
+
- **1-command rule:** one `type: domain` story = one command + its events on one aggregate, at most 4 Gherkin
|
|
31
|
+
scenarios. `aggregate` and `command` are required frontmatter and are cross-checked against `docs/domain/events.yaml`.
|
|
32
|
+
- **Spec linter:** `.claude/skills/user-stories/scripts/lint-story.ts` (also `kataster lint-story`) is the gate.
|
|
33
|
+
Green → `ready-for-human-review`; the user approves `ready`. No LLM pre-implementation review.
|
|
34
|
+
- **Fast lane:** `type: chore` / `type: task`; `/implement` skips Gherkin matching and formal reviews.
|
|
35
|
+
- **Reviewers report, never plan:** `code-reviewer` and `acceptance-tester` create no stories. Findings are fixed in
|
|
36
|
+
the story or handed back as open questions.
|
|
37
|
+
- The installer prunes the retired workflow files named in `OBSOLETE` (only manifest-tracked, unmodified ones), so a
|
|
38
|
+
removed agent disappears on upgrade without touching optional extras or user files.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 – 2026-11-03
|
|
4
|
+
|
|
5
|
+
- **Spec-driven instead of corporate roleplay.** The `product-owner`, `requirements-engineer` and `lead-dev`
|
|
6
|
+
subagents are gone (Claude Code and OpenCode). The main session writes stories as a spec engineer with three
|
|
7
|
+
lenses – domain, architecture, testability – instead of handing them to simulated roles. The `ux-designer` stays
|
|
8
|
+
as an on-demand utility for `ui: true` stories and the prototyping phase; it never gates.
|
|
9
|
+
- **1-command rule.** One `type: domain` story = one command + its events on one aggregate, at most 4 Gherkin
|
|
10
|
+
scenarios. `aggregate` and `command` are required frontmatter and are cross-checked against
|
|
11
|
+
`docs/domain/events.yaml`; the events must be exactly what the command produces. `type: story` remains valid as a
|
|
12
|
+
legacy alias and is reported as a warning.
|
|
13
|
+
- **Deterministic spec linter.** `node .claude/skills/user-stories/scripts/lint-story.ts [ST-NNN|file]` and
|
|
14
|
+
`kataster lint-story` check frontmatter, required fields, referential integrity, `Given/When/Then`, the scenario
|
|
15
|
+
limit and unique titles – no LLM, no tokens. The same rules run in the PostToolUse hook, `story-status.ts` and
|
|
16
|
+
`verify.ts`. Green → `ready-for-human-review`; only the user approves `ready`.
|
|
17
|
+
- **Fast lane.** `type: chore` and `type: task` for UI tweaks, refactorings, dependencies and setup.
|
|
18
|
+
`/implement --fast` (or automatic detection) does branch → implement → lint/typecheck/unit tests → pull request,
|
|
19
|
+
without Gherkin matching or formal subagent reviews. `type: tech-task` and `type: spike` keep their behaviour.
|
|
20
|
+
- **Reviews report, they do not plan.** `code-reviewer` and `acceptance-tester` no longer create, split or revise
|
|
21
|
+
stories; a finding is fixed in the story or handed back as an open question. Review effort follows the diff, not a
|
|
22
|
+
T-shirt size. `size` is no longer a gate.
|
|
23
|
+
- **Installer prunes retired workflow files.** `upgrade` deletes the manifest-tracked files named in `OBSOLETE`
|
|
24
|
+
(the removed agents). Locally modified files are kept and reported; `--force` backs them up first. Optional
|
|
25
|
+
extras and user-added agents are never pruned.
|
|
26
|
+
|
|
27
|
+
## 0.3.1 – 2026-11-02
|
|
28
|
+
|
|
29
|
+
- **Optional prototyping, owned by the UX designer.** New `prototype` skill (adapted from Matt Pocock's, MIT) builds
|
|
30
|
+
a throwaway self-contained HTML prototype for one design question: several structurally different UI variants
|
|
31
|
+
(`ui`) or a clickable state model (`logic`). `/feature --prototype[=ui|logic]` – or a proposal from the UX frontier
|
|
32
|
+
during grilling – runs it between grilling and the stories; `/implement --prototype` settles an open UI question
|
|
33
|
+
before the test plan. The verdict goes into the story (`Prototype: …`) and, when it is a recurring rule, into
|
|
34
|
+
`docs/product/ux-guidelines.md` as a G-number. The prototype lives under `docs/prototypes/<slug>/`, is captured on
|
|
35
|
+
a throwaway branch `prototype/<slug>` and is never merged.
|
|
36
|
+
- **Credit where the workflow comes from.** `.claude/THIRD_PARTY_NOTICES.md` lists which skills are derived from
|
|
37
|
+
[Matt Pocock's skills](https://github.com/mattpocock/skills) – some adapted, some copied verbatim – and carries his
|
|
38
|
+
MIT license text. The file ships with the payload and lands in every installation; the README has a Credits
|
|
39
|
+
section.
|
|
40
|
+
|
|
3
41
|
## 0.3.0 – 2026-10-31
|
|
4
42
|
|
|
5
43
|
- **Removed the optional extras and the vendored `shadcn` skill.** `--with` is gone; the CLI fails with a clear
|
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ npx kataster init . --yes --name "Acme" --ui-language de --artifacts en
|
|
|
78
78
|
skills/ the workflow skills (grilling, event-storming, domain-model, architect, backlog, …)
|
|
79
79
|
skills/adopt/scripts/ repository map and per-package docs for brownfield adoption
|
|
80
80
|
skills/feature/scripts/ read-only intake: story, GitHub/Jira ticket or URL → route
|
|
81
|
-
agents/ review agents
|
|
81
|
+
agents/ review agents and the on-demand UX utility (Claude Code)
|
|
82
82
|
hooks/ plain-Node guardrails and validators
|
|
83
83
|
lib/ deterministic domain/story/backlog logic
|
|
84
84
|
.opencode/
|
|
@@ -92,6 +92,8 @@ docs/
|
|
|
92
92
|
workflow.md the map: sources of truth, commands, phases, rules
|
|
93
93
|
product/vision.md the vision, grilled with you
|
|
94
94
|
product/initiatives/ proposals for large ideas from /shape (no stories)
|
|
95
|
+
product/ux-guidelines.md the interface yardstick
|
|
96
|
+
prototypes/ throwaway prototypes on their own branch; the default branch keeps the README
|
|
95
97
|
domain/events.yaml the event storming model (empty is valid)
|
|
96
98
|
domain/context-map.md
|
|
97
99
|
architecture/data-model.md
|
|
@@ -114,15 +116,39 @@ Existing `CONTEXT.md` and `docs/` are never touched.
|
|
|
114
116
|
| `/grill-me` | Relentless interview on a plan, decision or idea |
|
|
115
117
|
| `/grill-with-docs` | The same, writing glossary and ADRs as you go |
|
|
116
118
|
| `/event-storming [process]` | Big-picture or single-process event storming |
|
|
117
|
-
| `/feature <idea \| ST-NNN \| #123 \| PROJ-123>` | New feature from an idea, an existing story or a ticket: intake and routing, grilling, focused storming, model, stories, review; bugs become a regression story |
|
|
119
|
+
| `/feature <idea \| ST-NNN \| #123 \| PROJ-123>` | New feature from an idea, an existing story or a ticket: intake and routing, grilling, focused storming, model, stories, review; bugs become a regression story; `--prototype` adds a throwaway prototype before the stories |
|
|
118
120
|
| `/shape <idea \| ticket> [--dry-run]` | Before a large feature: frame, place (existing/new context, shared library), impact, slices, rough cost range, recommendation; creates no stories |
|
|
119
|
-
| `/review-stories [ST-…]` |
|
|
121
|
+
| `/review-stories [ST-…]` | Spec linter gate → `ready-for-human-review`; the user approves `ready` |
|
|
120
122
|
| `/backlog-sync [status\|pull\|push]` | Keep `docs/stories/` in sync with GitHub Issues or Jira |
|
|
121
123
|
| `/groom-backlog [scope]` | Periodic challenge: is this backlog still worth building? |
|
|
122
|
-
| `/implement [ST-NNN]` |
|
|
124
|
+
| `/implement [ST-NNN] [--fast]` | One story on its branch: domain = test-first, diff-scaled review, acceptance; `chore`/`task` or `--fast` = fast lane without Gherkin matching or formal reviews; `--prototype` settles an open UI question first |
|
|
123
125
|
| `/improve-codebase-architecture` | Scan for deepening opportunities, present them, grill one |
|
|
124
126
|
| `/retro` | Retrospective on a session, proposing rule changes |
|
|
125
127
|
|
|
128
|
+
### Spec-driven stories, fast lane
|
|
129
|
+
|
|
130
|
+
Stories are written by the main session as a **spec engineer**, not by simulated roles. Three lenses at once –
|
|
131
|
+
domain, architecture, testability – and one mechanical rule: **one story = one command + its events on one
|
|
132
|
+
aggregate**, at most four Gherkin scenarios. `aggregate` and `command` are required frontmatter and are cross-checked
|
|
133
|
+
against `docs/domain/events.yaml`.
|
|
134
|
+
|
|
135
|
+
The **spec linter** is the gate and costs no LLM tokens:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
kataster lint-story # all stories
|
|
139
|
+
kataster lint-story ST-012 # one story
|
|
140
|
+
node .claude/skills/user-stories/scripts/lint-story.ts docs/stories/ST-012-*.md
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Frontmatter and required fields, aggregate/command/event references, Gherkin `Given/When/Then`, the scenario limit
|
|
144
|
+
and unique titles. Green → `ready-for-human-review`; only you approve `ready`. The same rules run in the PostToolUse
|
|
145
|
+
hook and in `verify.ts`.
|
|
146
|
+
|
|
147
|
+
Non-domain work takes the **fast lane**: `type: chore` (UI tweak, refactor, dependency) or `type: task` (setup).
|
|
148
|
+
`/implement` detects it (or takes `--fast`) and does branch → implement → lint/typecheck/unit tests → PR, without
|
|
149
|
+
Gherkin matching or formal review agents. `type: tech-task` keeps its checklist and acceptance; `type: spike` is a
|
|
150
|
+
timeboxed question.
|
|
151
|
+
|
|
126
152
|
### Starting from a ticket
|
|
127
153
|
|
|
128
154
|
`/feature` also accepts a reference: `/feature #123` (GitHub), `/feature PROJ-123` (Jira, with the issue fetched
|
|
@@ -149,11 +175,26 @@ The brief lands in `docs/product/initiatives/<slug>.md` (`proposed` until you ac
|
|
|
149
175
|
existing monorepo is treated as a new context in an existing landscape, not as a greenfield project; a similar
|
|
150
176
|
service is used as evidence and as the cost anchor, never as a template.
|
|
151
177
|
|
|
178
|
+
### Prototyping an open question
|
|
179
|
+
|
|
180
|
+
When a UI, flow or state question cannot be settled on paper, `/feature --prototype` (or a proposal from the UX
|
|
181
|
+
lens during grilling) runs a throwaway prototype before the stories are written. The `ux-designer` builds one
|
|
182
|
+
self-contained HTML file under `docs/prototypes/<slug>/` – several structurally different UI variants or a
|
|
183
|
+
clickable state model. The verdict goes into the story and, when it is a recurring rule, into the UX guidelines;
|
|
184
|
+
the prototype is captured on a throwaway branch and never merged. `/implement --prototype` does the same for an
|
|
185
|
+
open UI question during engineering; if the prototype changes the story, the story goes back to `review`.
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
/feature "checkout with saved cards" --prototype=ui
|
|
189
|
+
/feature PROJ-123 --prototype=logic
|
|
190
|
+
/implement ST-042 --prototype
|
|
191
|
+
```
|
|
192
|
+
|
|
152
193
|
## Greenfield, end to end
|
|
153
194
|
|
|
154
195
|
1. `npx kataster init --greenfield` → review `.claude/project.json`.
|
|
155
196
|
2. `/bootstrap` → vision grilled, event storming, contexts/aggregates/data model, tech-stack ADR, UX guidelines.
|
|
156
|
-
3. `/review-stories` → the
|
|
197
|
+
3. `/review-stories` → the spec linter turns finished stories into `ready-for-human-review`; you approve `ready`.
|
|
157
198
|
4. `/implement` → one story at a time, test-first, reviewed, merged by you.
|
|
158
199
|
5. `/feature <idea>` for everything after that.
|
|
159
200
|
|
|
@@ -287,8 +328,9 @@ For Jira, `jira-plan.ts` prints the exact MCP calls, `jira-record.ts` writes the
|
|
|
287
328
|
```
|
|
288
329
|
- **`verify.ts`** is the one gate: project checks, artifact validity, scenario ↔ test traceability, domain IDs in
|
|
289
330
|
the code, glossary language.
|
|
290
|
-
- **Review agents** never write code: `code-reviewer` and `acceptance-tester` report, the
|
|
291
|
-
whether a story is `done
|
|
331
|
+
- **Review agents** never write code or stories: `code-reviewer` and `acceptance-tester` report findings, the
|
|
332
|
+
acceptance verdict decides whether a domain story is `done`, and a finding is fixed in the story or handed back
|
|
333
|
+
as an open question. `ux-designer` is an on-demand utility (`ui: true`), never a gate.
|
|
292
334
|
|
|
293
335
|
## Upgrading
|
|
294
336
|
|
|
@@ -323,6 +365,21 @@ The toolkit is maintained in the open: bug reports, a skill that fills a real ga
|
|
|
323
365
|
[SECURITY.md](SECURITY.md) is the way to report a vulnerability privately. Participation is covered by the
|
|
324
366
|
[Code of Conduct](CODE_OF_CONDUCT.md).
|
|
325
367
|
|
|
368
|
+
## Credits
|
|
369
|
+
|
|
370
|
+
Kataster stands on other people's work:
|
|
371
|
+
|
|
372
|
+
- **Matt Pocock** – [skills](https://github.com/mattpocock/skills), [aihero.dev](https://www.aihero.dev). The grilling
|
|
373
|
+
interview (`grilling`, `grill-me`, `grill-with-docs`), test-driven development (`tdd`), the deep-module vocabulary
|
|
374
|
+
(`codebase-design`), the architecture survey (`improve-codebase-architecture`), the throwaway prototype
|
|
375
|
+
(`prototype`), the retro, the domain-modeling discipline and `writing-for-agents` come from his skill repository –
|
|
376
|
+
partly adapted, partly copied verbatim under MIT. The per-file mapping and the license text are in
|
|
377
|
+
[.claude/THIRD_PARTY_NOTICES.md](.claude/THIRD_PARTY_NOTICES.md).
|
|
378
|
+
- **John Ousterhout**, *A Philosophy of Software Design* – "Design It Twice" and the depth, seam and deletion-test
|
|
379
|
+
vocabulary.
|
|
380
|
+
- **Eric Evans**, *Domain-Driven Design* – ubiquitous language, bounded contexts, aggregates.
|
|
381
|
+
- **Martin Fowler** – the smell baseline the review agents work from.
|
|
382
|
+
|
|
326
383
|
## License
|
|
327
384
|
|
|
328
385
|
MIT
|
package/guide/brownfield.md
CHANGED
|
@@ -103,8 +103,8 @@ that fails on existing behaviour – that would be a story.
|
|
|
103
103
|
|
|
104
104
|
**The first adoption pass creates no stories.** It records the gap in `docs/domain/adoption-report.md` (and open
|
|
105
105
|
questions in `OPEN_QUESTIONS.md`), so the model can be reviewed before anyone commits to work. Only
|
|
106
|
-
`/adopt <scope> --stories` (or an explicit "turn these into stories")
|
|
107
|
-
|
|
106
|
+
`/adopt <scope> --stories` (or an explicit "turn these into stories") turns the selected gaps into stories in the
|
|
107
|
+
main session (spec engineer, spec linter gate).
|
|
108
108
|
|
|
109
109
|
**Behaviour that already works does not become a story.** That turns the backlog into a description of the past.
|
|
110
110
|
|
package/guide/concepts.md
CHANGED
|
@@ -26,9 +26,10 @@ Two rules make it work:
|
|
|
26
26
|
| `docs/architecture/data-model.md` | Logical, stack-neutral model per aggregate; lifecycle and ER diagrams | domain-architect |
|
|
27
27
|
| `docs/engineering/conventions.md` | How code is built here, including the seam catalog | user |
|
|
28
28
|
| `docs/adr/` | Architecture decisions. `proposed` until the user accepts; accepted ones are superseded, never edited | user |
|
|
29
|
-
| `docs/stories/` | The backlog. One Markdown file per story; `BACKLOG.md` is generated. With a tracker, this is the local mirror |
|
|
29
|
+
| `docs/stories/` | The backlog. One Markdown file per story; `BACKLOG.md` is generated. With a tracker, this is the local mirror | main session as spec engineer; spec linter; `/backlog-sync` with a tracker |
|
|
30
30
|
| `docs/product/vision.md` | Problem, user groups, goals, non-goals, success criteria | user |
|
|
31
31
|
| `docs/product/ux-guidelines.md` | The interface yardstick, as numbered rules with date and reason | ux-designer, approved by user |
|
|
32
|
+
| `docs/prototypes/<slug>/` | Throwaway prototypes on their own branch; only the README stays on the default branch | ux-designer; verdict in the story and the guidelines |
|
|
32
33
|
|
|
33
34
|
## Events, commands, aggregates
|
|
34
35
|
|
|
@@ -45,15 +46,21 @@ The code carries the same IDs, which is what makes traceability checkable.
|
|
|
45
46
|
|
|
46
47
|
## Stories
|
|
47
48
|
|
|
48
|
-
A story is a vertical slice of observable behaviour: `draft → review → ready →
|
|
49
|
-
`superseded`).
|
|
49
|
+
A story is a vertical slice of observable behaviour: `draft → review → ready-for-human-review → ready →
|
|
50
|
+
in-progress → done` (plus `superseded`).
|
|
50
51
|
|
|
52
|
+
- **The linter is the gate.** `lint-story.ts` checks the spec deterministically. Green → `ready-for-human-review`;
|
|
53
|
+
the user approves `ready`.
|
|
51
54
|
- **Discovery ends at `ready`.** Engineering moves `ready → in-progress → done`.
|
|
55
|
+
- **1-command rule.** One domain story = one command + its events on one aggregate, at most 4 scenarios. A second
|
|
56
|
+
command is a second story.
|
|
57
|
+
- **Fast lane.** `type: chore`/`task` for UI tweaks, refactors, dependencies and setup – no Gherkin matching, no
|
|
58
|
+
formal reviews.
|
|
52
59
|
- **A story that turns out wrong goes back to `review`** with an `[OPEN]` and a row in `OPEN_QUESTIONS.md` – never
|
|
53
60
|
guessed into shape during implementation.
|
|
54
61
|
- **`done` is final.** A change to finished behaviour is a new story.
|
|
55
|
-
- **
|
|
56
|
-
|
|
62
|
+
- **A scenario title becomes a test title**: `ST-NNN: <scenario title>`. `verify.ts` checks the link for domain
|
|
63
|
+
stories.
|
|
57
64
|
|
|
58
65
|
### Stories from tickets
|
|
59
66
|
|
|
@@ -75,6 +82,20 @@ An initiative is **not** a work item: no `ready`/`done`, no stories, no second b
|
|
|
75
82
|
with a basis and a confidence – an analogue service is evidence, not a template. Each accepted slice then goes
|
|
76
83
|
through `/feature`, which creates the stories and runs the review.
|
|
77
84
|
|
|
85
|
+
## Prototypes
|
|
86
|
+
|
|
87
|
+
A **prototype** is throwaway code that answers one design question. It is not a first draft: no tests, no
|
|
88
|
+
persistence, no production path. The question decides the branch – `ui` (what should it look like) or `logic`
|
|
89
|
+
(does the state model feel right). In discovery it is one self-contained HTML file under
|
|
90
|
+
`docs/prototypes/<slug>/`, built by the `ux-designer`; a question that needs the real application page is built
|
|
91
|
+
by the main session during `/implement`.
|
|
92
|
+
|
|
93
|
+
`/feature --prototype` (or a proposal from the UX frontier during grilling) adds the phase between grilling and
|
|
94
|
+
the stories. The verdict goes into the story (`Prototype: prototype/<slug> – <question> – <verdict>`) and, when
|
|
95
|
+
it is a recurring rule, into `ux-guidelines.md` as a G-number. The code is captured on a throwaway branch
|
|
96
|
+
`prototype/<slug>` and never merged. `/implement --prototype` does the same for an open UI question during
|
|
97
|
+
engineering; if it changes the story, the story goes back to `review`.
|
|
98
|
+
|
|
78
99
|
## The seam catalog
|
|
79
100
|
|
|
80
101
|
A **seam** is where a test attaches. Testing everything everywhere is not affordable, so the project agrees up front
|
package/guide/greenfield.md
CHANGED
|
@@ -62,12 +62,13 @@ Two kinds of work, kept apart:
|
|
|
62
62
|
- **The first vertical slice** – the smallest set of stories that delivers one real end-to-end path from the
|
|
63
63
|
vision, each with Gherkin scenarios.
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
One story = one command on one aggregate, at most 4 scenarios; no implementation plan inside a domain story; every domain story links `aggregate`, `command` and its `events`.
|
|
66
66
|
|
|
67
67
|
## Phase 6 – Review
|
|
68
68
|
|
|
69
|
-
`/review-stories` –
|
|
70
|
-
pull before the review and push the
|
|
69
|
+
`/review-stories` – the spec linter checks frontmatter, aggregate/command/events, Gherkin and the scenario limit.
|
|
70
|
+
Green → `ready-for-human-review`; you approve every `ready`. With a tracker, pull before the review and push the
|
|
71
|
+
approved stories afterwards (`/backlog-sync`).
|
|
71
72
|
|
|
72
73
|
## Phase 7 – Build
|
|
73
74
|
|
package/guide/release.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
npm install --prefix .claude --no-audit --no-fund
|
|
12
12
|
npm run typecheck --prefix .claude
|
|
13
13
|
npm test
|
|
14
|
-
npm pack --dry-run #
|
|
14
|
+
npm pack --dry-run # 148 files, 218 kB – no examples/, no node_modules, no state/
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
4. Install the tarball once and start a throwaway project with it – a tarball that installs is not the same as a
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
-
import { basename, join, resolve } from "node:path";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
5
|
import { stdin, stdout } from "node:process";
|
|
6
6
|
import { Installer, VERSION } from "./install.mjs";
|
|
@@ -12,6 +12,8 @@ const HELP = `Kataster ${VERSION} – agent workflow for domain-driven discovery
|
|
|
12
12
|
Usage:
|
|
13
13
|
kataster init [dir] Install the workflow into a repository (default: .)
|
|
14
14
|
kataster upgrade [dir] Update the workflow, keep project content and local changes
|
|
15
|
+
kataster lint-story [ST-NNN|file]
|
|
16
|
+
Deterministic spec linter for stories (no LLM); empty = all stories
|
|
15
17
|
kataster doctor [dir] Check the installation
|
|
16
18
|
kataster --version
|
|
17
19
|
kataster --help
|
|
@@ -99,8 +101,8 @@ Useful commands afterwards:
|
|
|
99
101
|
/grill-me /grill-with-docs sharpen a plan and write the docs as you go
|
|
100
102
|
/event-storming explore a process or the whole domain
|
|
101
103
|
/feature <idea> add a feature through grilling, storming, stories
|
|
102
|
-
/review-stories
|
|
103
|
-
/implement [ST-NNN] test-first implementation of one story
|
|
104
|
+
/review-stories linter gate + human approval before a story is ready
|
|
105
|
+
/implement [ST-NNN] test-first implementation of one story (--fast for chore/task)
|
|
104
106
|
/backlog-sync pull/push the backlog mirror (Jira or GitHub Issues)
|
|
105
107
|
/retro retrospective on a session
|
|
106
108
|
`);
|
|
@@ -219,6 +221,36 @@ async function upgrade(options) {
|
|
|
219
221
|
console.log("\nUpgrade complete. Project content (CONTEXT.md, docs/domain, docs/stories, ADRs) was not touched.");
|
|
220
222
|
}
|
|
221
223
|
|
|
224
|
+
/** Nearest directory that has the story linter installed (the repository of the given file, or an ancestor). */
|
|
225
|
+
function findInstallRoot(start) {
|
|
226
|
+
let dir = resolve(start);
|
|
227
|
+
if (dir.endsWith(".md")) dir = dirname(dir);
|
|
228
|
+
for (;;) {
|
|
229
|
+
if (existsSync(join(dir, ".claude", "skills", "user-stories", "scripts", "lint-story.ts"))) return dir;
|
|
230
|
+
const parent = dirname(dir);
|
|
231
|
+
if (parent === dir) return null;
|
|
232
|
+
dir = parent;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* `kataster lint-story [ST-NNN|file]` – delegates to the installed spec linter. Deterministic: the same checks
|
|
238
|
+
* the hook, `/review-stories` and `verify.ts` run, without an LLM.
|
|
239
|
+
*/
|
|
240
|
+
function lintStory(options) {
|
|
241
|
+
const arg = options._[1];
|
|
242
|
+
const root = findInstallRoot(arg && arg.endsWith(".md") ? arg : (arg && /^ST-/i.test(arg) ? process.cwd() : (arg || process.cwd())));
|
|
243
|
+
if (!root) {
|
|
244
|
+
throw new Error("No Kataster installation found (missing .claude/skills/user-stories/scripts/lint-story.ts) – run `kataster init` first.");
|
|
245
|
+
}
|
|
246
|
+
const script = join(root, ".claude", "skills", "user-stories", "scripts", "lint-story.ts");
|
|
247
|
+
const args = [script];
|
|
248
|
+
if (arg) args.push(arg.endsWith(".md") ? resolve(arg) : arg);
|
|
249
|
+
if (options.json) args.push("--json");
|
|
250
|
+
const r = spawnSync(process.execPath, args, { cwd: root, stdio: "inherit" });
|
|
251
|
+
process.exitCode = r.status ?? 1;
|
|
252
|
+
}
|
|
253
|
+
|
|
222
254
|
function doctor(options) {
|
|
223
255
|
const root = resolve(options._[1] ?? ".");
|
|
224
256
|
const checks = [];
|
|
@@ -230,6 +262,11 @@ function doctor(options) {
|
|
|
230
262
|
add("Install manifest", Boolean(manifest), manifest ? `version ${manifest.version}` : "missing – run init");
|
|
231
263
|
const leftovers = existsSync(join(root, ".laguardia")) || existsSync(join(root, ".opencode", "plugins", "laguardia"));
|
|
232
264
|
add("No leftovers from the old name", !leftovers, leftovers ? "run upgrade to migrate them" : "");
|
|
265
|
+
const retired = [
|
|
266
|
+
".claude/agents/product-owner.md", ".claude/agents/requirements-engineer.md", ".claude/agents/lead-dev.md",
|
|
267
|
+
".opencode/agents/product-owner.md", ".opencode/agents/requirements-engineer.md", ".opencode/agents/lead-dev.md",
|
|
268
|
+
].filter((file) => existsSync(join(root, file)));
|
|
269
|
+
add("No retired role-play agents", retired.length === 0, retired.join(", ") || "clean");
|
|
233
270
|
const profile = readJson(join(root, ".claude", "project.json"));
|
|
234
271
|
add("Project profile", Boolean(profile?.name), profile?.name ?? "missing");
|
|
235
272
|
|
|
@@ -238,7 +275,7 @@ function doctor(options) {
|
|
|
238
275
|
add("Backlog provider", ["local", "github", "jira"].includes(provider), provider);
|
|
239
276
|
if (provider === "jira") {
|
|
240
277
|
add("Backlog: Jira project", Boolean(backlog.jira?.project), backlog.jira?.project || "backlog.jira.project is missing");
|
|
241
|
-
const statuses = ["draft", "review", "ready", "in-progress", "done", "superseded"];
|
|
278
|
+
const statuses = ["draft", "review", "ready-for-human-review", "ready", "in-progress", "done", "superseded"];
|
|
242
279
|
const missingStatuses = statuses.filter((status) => !backlog.jira?.statusMap?.[status]);
|
|
243
280
|
add("Backlog: Jira status map", missingStatuses.length === 0, missingStatuses.join(", ") || "all statuses mapped");
|
|
244
281
|
const priorities = ["must", "should", "could", "wont"];
|
|
@@ -296,6 +333,7 @@ export async function main(argv) {
|
|
|
296
333
|
const command = options._[0];
|
|
297
334
|
if (command === "init") return init(options);
|
|
298
335
|
if (command === "upgrade") return upgrade(options);
|
|
336
|
+
if (command === "lint-story") return lintStory(options);
|
|
299
337
|
if (command === "doctor") return doctor(options);
|
|
300
338
|
throw new Error(`Unknown command '${command}'. Try --help.`);
|
|
301
339
|
}
|
package/src/install.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { existsSync, mkdirSync, readdirSync, renameSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "node:fs";
|
|
3
3
|
import { dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import {
|
|
@@ -58,8 +58,7 @@ const HOOK_EVENTS = {
|
|
|
58
58
|
const ALLOW = [
|
|
59
59
|
"Bash(node .claude/skills/event-storming/scripts/validate-events.ts)",
|
|
60
60
|
"Bash(node .claude/skills/event-storming/scripts/render-event-storming.ts)",
|
|
61
|
-
"Bash(node .claude/skills/user-stories/scripts
|
|
62
|
-
"Bash(node .claude/skills/user-stories/scripts/render-backlog.ts)",
|
|
61
|
+
"Bash(node .claude/skills/user-stories/scripts/*)",
|
|
63
62
|
"Bash(node .claude/skills/adopt/scripts/*)",
|
|
64
63
|
"Bash(node .claude/skills/backlog/scripts/*)",
|
|
65
64
|
"Bash(node .claude/skills/implement/scripts/*)",
|
|
@@ -70,6 +69,21 @@ const ALLOW = [
|
|
|
70
69
|
"Bash(git log *)",
|
|
71
70
|
];
|
|
72
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Files earlier versions shipped and 0.4 removed. `upgrade` deletes them from an existing installation – but only
|
|
74
|
+
* when the manifest tracks them and the local copy is unmodified, so a project that customised one keeps it.
|
|
75
|
+
* Add a path here whenever a workflow file is retired; never prune by "not in the payload", because files from
|
|
76
|
+
* optional extras and user-added agents are not the installer's to delete.
|
|
77
|
+
*/
|
|
78
|
+
const OBSOLETE = [
|
|
79
|
+
".claude/agents/product-owner.md",
|
|
80
|
+
".claude/agents/requirements-engineer.md",
|
|
81
|
+
".claude/agents/lead-dev.md",
|
|
82
|
+
".opencode/agents/product-owner.md",
|
|
83
|
+
".opencode/agents/requirements-engineer.md",
|
|
84
|
+
".opencode/agents/lead-dev.md",
|
|
85
|
+
];
|
|
86
|
+
|
|
73
87
|
export class Installer {
|
|
74
88
|
constructor(root, { dryRun = false, force = false, log = () => {} } = {}) {
|
|
75
89
|
this.root = resolve(root);
|
|
@@ -165,17 +179,52 @@ export class Installer {
|
|
|
165
179
|
}
|
|
166
180
|
|
|
167
181
|
copyWorkflowDirs() {
|
|
182
|
+
const present = new Set();
|
|
168
183
|
for (const dir of WORKFLOW_DIRS) {
|
|
169
184
|
const source = join(PKG, dir);
|
|
170
185
|
if (!existsSync(source)) continue;
|
|
171
186
|
for (const file of walk(source)) {
|
|
172
187
|
const name = toPosix(relative(source, file));
|
|
173
188
|
if (name.split("/").some((part) => SKIP.has(part))) continue;
|
|
174
|
-
const
|
|
189
|
+
const key = relPosix(this.root, join(this.root, dir, name));
|
|
190
|
+
present.add(key);
|
|
175
191
|
// settings.json and opencode.jsonc are merged, not replaced
|
|
176
192
|
if (file === join(source, "settings.json") || file === join(source, "opencode.jsonc")) continue;
|
|
177
|
-
this.put(join(this.root, dir, name),
|
|
193
|
+
this.put(join(this.root, dir, name), read(file));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
this.pruneObsolete(present);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Removes the retired workflow files listed in OBSOLETE (e.g. the deleted corporate-roleplay agents).
|
|
201
|
+
*
|
|
202
|
+
* Only files recorded in the manifest are candidates, so project content and files from other tools are never
|
|
203
|
+
* touched. A file the user edited is kept and reported as a conflict – unless `--force` is given, which backs it
|
|
204
|
+
* up first. This is what makes a removed agent actually disappear from an existing installation on upgrade.
|
|
205
|
+
*/
|
|
206
|
+
pruneObsolete(present) {
|
|
207
|
+
for (const key of OBSOLETE) {
|
|
208
|
+
if (present.has(key)) continue;
|
|
209
|
+
if (!(key in (this.manifest?.files ?? {}))) continue;
|
|
210
|
+
|
|
211
|
+
const path = join(this.root, key);
|
|
212
|
+
if (!existsSync(path)) {
|
|
213
|
+
delete this.files[key];
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const known = this.manifest.files[key];
|
|
218
|
+
const local = sha(read(path));
|
|
219
|
+
if (local !== known && !this.force) {
|
|
220
|
+
this.conflicts.push(key);
|
|
221
|
+
this.record("conflict", path, "retired, but locally modified – kept");
|
|
222
|
+
continue;
|
|
178
223
|
}
|
|
224
|
+
if (this.force) this.backup(path);
|
|
225
|
+
if (!this.dryRun) rmSync(path, { force: true });
|
|
226
|
+
delete this.files[key];
|
|
227
|
+
this.record("remove", path, "retired workflow file");
|
|
179
228
|
}
|
|
180
229
|
}
|
|
181
230
|
|
|
@@ -391,9 +440,16 @@ This repository runs the Kataster workflow. Discovery lives in \`.claude/skills/
|
|
|
391
440
|
- **Project checks:** \`docs/engineering/checks.yaml\` – what runs at edit time and Stop/CI; architecture boundaries
|
|
392
441
|
in \`docs/architecture/boundaries.yaml\` with existing debt in the baseline (only new violations fail).
|
|
393
442
|
- **Language:** domain terms exactly as in \`CONTEXT.md\`; UI words from its \`_UI (<lang>)_\` lines.
|
|
394
|
-
- **
|
|
443
|
+
- **1-command rule:** one story = one command + its events on one aggregate, at most 4 Gherkin scenarios. Full
|
|
444
|
+
domain stories are \`type: domain\`; UI tweaks, refactors, dependencies and setup use the fast lane
|
|
445
|
+
(\`type: chore\` or \`type: task\`).
|
|
446
|
+
- **Spec gate:** \`node .claude/skills/user-stories/scripts/lint-story.ts <file>\` must be green. A story the linter
|
|
447
|
+
accepts becomes \`ready-for-human-review\`; only the user approves \`ready\`.
|
|
448
|
+
- **Traceability:** every domain scenario has a test titled \`ST-NNN: <scenario title>\`; domain IDs come from
|
|
395
449
|
\`docs/domain/events.yaml\`.
|
|
396
450
|
- **ADRs:** new ones are \`proposed\`; only the user sets \`accepted\`. A \`done\` story is never reopened.
|
|
451
|
+
- **Reviews:** \`/implement\` scales review to the diff. \`code-reviewer\` and \`acceptance-tester\` report findings and
|
|
452
|
+
never create stories; fast-lane stories skip the formal review pass.
|
|
397
453
|
- **Gate:** \`node .claude/skills/implement/scripts/verify.ts\`.
|
|
398
454
|
|
|
399
455
|
Keep this block short: it is loaded into every session. Put rules into the skill that owns them, not here.
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
The yardstick, not the method. The method is `.claude/skills/ux-design/SKILL.md`.
|
|
5
5
|
Every guideline is a rule someone can point at, with the date and the reason it was decided.
|
|
6
6
|
`ux-designer` maintains this file; the user approves a guideline before it is written here.
|
|
7
|
+
A prototype verdict that becomes a recurring rule lands here as a G-number; the prototype itself stays on
|
|
8
|
+
its throwaway branch (`docs/prototypes/<slug>/`).
|
|
7
9
|
|
|
8
10
|
Format:
|
|
9
11
|
## G1 – <short rule>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Prototypes
|
|
2
|
+
|
|
3
|
+
Throwaway code that answers one design question. The method is `.claude/skills/prototype/SKILL.md`.
|
|
4
|
+
|
|
5
|
+
- A prototype lives in `docs/prototypes/<slug>/` on a throwaway branch `prototype/<slug>`; it is never merged.
|
|
6
|
+
- The default branch keeps this README only. The prototype itself is a primary source on its branch.
|
|
7
|
+
- The decision it settled goes into the story (`Prototype: prototype/<slug> – <question> – <verdict>` in
|
|
8
|
+
`## Context`) and, when it is a recurring rule, into `docs/product/ux-guidelines.md` as a G-number.
|
|
9
|
+
- One question, one self-contained HTML file, one timebox. No tests, no persistence, no production code.
|
|
@@ -4,9 +4,16 @@ One Markdown file per story: `ST-NNN-short-title.md`. `BACKLOG.md` is generated
|
|
|
4
4
|
Rules, format and splitting: `.claude/skills/user-stories/SKILL.md`.
|
|
5
5
|
Template: `.claude/skills/user-stories/templates/story-template.md`.
|
|
6
6
|
|
|
7
|
-
Workflow: `draft → review → ready → in-progress → done` (plus `superseded`).
|
|
8
|
-
|
|
9
|
-
-
|
|
7
|
+
Workflow: `draft → review → ready-for-human-review → ready → in-progress → done` (plus `superseded`).
|
|
8
|
+
|
|
9
|
+
- The **spec linter** is the gate: `node .claude/skills/user-stories/scripts/lint-story.ts <file>` (or
|
|
10
|
+
`kataster lint-story`). It checks frontmatter, `aggregate`/`command`/events against `docs/domain/events.yaml`,
|
|
11
|
+
Gherkin `Given/When/Then` and the scenario limit – deterministically, no LLM.
|
|
12
|
+
- Green → `ready-for-human-review`; **the user approves `ready`**. `/implement` only picks up `ready`.
|
|
13
|
+
- **1-command rule:** one `type: domain` story = one command + its events on one aggregate, at most 4 scenarios.
|
|
14
|
+
- **Fast lane:** `type: chore` or `type: task` for UI tweaks, refactorings, dependencies and setup – no Gherkin
|
|
15
|
+
matching, no formal reviews. `type: tech-task` keeps its checklist; `type: spike` is a timeboxed question.
|
|
16
|
+
- `ui: true` marks a story with a frontend part; it triggers the on-demand UX utility, never a gate.
|
|
10
17
|
- A story that turns out wrong goes back to `review` with an `[OPEN]` and a row in `OPEN_QUESTIONS.md`.
|
|
11
18
|
- `done` is final: a change to finished behaviour is a new story.
|
|
12
19
|
|