kataster 0.4.0 → 0.6.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 +4 -0
- package/.claude/agents/domain-architect.md +7 -3
- package/.claude/agents/researcher.md +77 -0
- package/.claude/hooks/validate-docs.ts +15 -0
- package/.claude/lib/architecture.ts +3 -33
- package/.claude/lib/backlog.ts +2 -0
- package/.claude/lib/config.ts +48 -0
- package/.claude/lib/discovery.ts +71 -1
- package/.claude/lib/engineering.ts +6 -0
- package/.claude/lib/gaps.ts +179 -0
- package/.claude/lib/glob.ts +39 -0
- package/.claude/lib/repo.ts +143 -19
- package/.claude/lib/research.ts +303 -0
- package/.claude/lib/slices.ts +529 -0
- package/.claude/settings.json +1 -0
- package/.claude/skills/adopt/SKILL.md +106 -31
- package/.claude/skills/adopt/scripts/gap-register.ts +61 -0
- package/.claude/skills/adopt/scripts/repo-map.ts +34 -2
- package/.claude/skills/adopt/scripts/slice-doc.ts +117 -0
- package/.claude/skills/adopt/scripts/slice.ts +163 -0
- package/.claude/skills/adopt/templates/context-map.as-is.md +22 -0
- package/.claude/skills/architect/SKILL.md +6 -1
- package/.claude/skills/domain-model/CONTEXT-FORMAT.md +1 -1
- package/.claude/skills/domain-model/SKILL.md +23 -3
- package/.claude/skills/event-storming/SKILL.md +3 -2
- package/.claude/skills/event-storming/schema/events.schema.json +2 -0
- package/.claude/skills/event-storming/templates/events.example.yaml +6 -0
- package/.claude/skills/feature/SKILL.md +8 -5
- package/.claude/skills/grilling/SKILL.md +15 -0
- package/.claude/skills/implement/SKILL.md +39 -3
- package/.claude/skills/implement/scripts/characterize.ts +252 -0
- package/.claude/skills/implement/scripts/story-context.ts +64 -0
- package/.claude/skills/implement/scripts/verify.ts +3 -0
- package/.claude/skills/improve-codebase-architecture/SKILL.md +4 -1
- package/.claude/skills/research/SKILL.md +149 -0
- package/.claude/skills/research/scripts/research-check.ts +105 -0
- package/.claude/skills/research/templates/research.md +29 -0
- package/.claude/skills/review-stories/SKILL.md +15 -5
- package/.claude/skills/shape/SKILL.md +24 -5
- package/.claude/skills/tdd/SKILL.md +10 -0
- package/.claude/skills/user-stories/SKILL.md +21 -2
- package/.claude/skills/user-stories/schema/story.schema.json +4 -0
- package/.claude/skills/user-stories/templates/story-template.md +1 -0
- package/.opencode/agents/domain-architect.md +7 -3
- package/.opencode/agents/researcher.md +91 -0
- package/.opencode/commands/adopt.md +1 -1
- package/.opencode/commands/feature.md +1 -1
- package/.opencode/commands/research.md +7 -0
- package/.opencode/commands/shape.md +1 -1
- package/AGENTS.md +14 -1
- package/CHANGELOG.md +49 -0
- package/README.md +78 -19
- package/guide/brownfield.md +41 -12
- package/guide/concepts.md +12 -1
- package/package.json +1 -1
- package/src/detect.mjs +9 -0
- package/src/install.mjs +4 -0
- package/templates/docs/domain/context-map.md +5 -1
- package/templates/docs/domain/events.yaml +3 -0
- package/templates/docs/research/README.md +70 -0
- package/templates/docs/stories/README.md +2 -0
- package/templates/docs/workflow.md +54 -13
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Grill a large idea before it becomes features – frame the problem, decide where it belongs (existing or new bounded context, shared library), map what changes vs. what is new, slice it, and produce a rough cost range with confidence. Creates no stories; ends with a go / slice / spike / discover / park / no-go recommendation.
|
|
2
|
+
description: Grill a large idea before it becomes features – frame the problem, decide where it belongs (existing or new bounded context, shared library), research external facts before placement and cost, map what changes vs. what is new, slice it, and produce a rough cost range with confidence. Creates no stories; ends with a go / slice / spike / discover / park / no-go recommendation.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
Load the `shape` skill with the `skill` tool and follow it exactly. Do not restate it.
|
package/AGENTS.md
CHANGED
|
@@ -20,7 +20,7 @@ Rules:
|
|
|
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
22
|
|
|
23
|
-
## Workflow contract (0.
|
|
23
|
+
## Workflow contract (0.5)
|
|
24
24
|
|
|
25
25
|
The workflow is spec-driven and mechanical, not a simulated organisation:
|
|
26
26
|
|
|
@@ -31,7 +31,20 @@ The workflow is spec-driven and mechanical, not a simulated organisation:
|
|
|
31
31
|
scenarios. `aggregate` and `command` are required frontmatter and are cross-checked against `docs/domain/events.yaml`.
|
|
32
32
|
- **Spec linter:** `.claude/skills/user-stories/scripts/lint-story.ts` (also `kataster lint-story`) is the gate.
|
|
33
33
|
Green → `ready-for-human-review`; the user approves `ready`. No LLM pre-implementation review.
|
|
34
|
+
- **Research is evidence, not a specification.** Only the read-only `researcher` fetches web content (`/research`,
|
|
35
|
+
`/feature --research`); findings live in `docs/research/<topic>.md` with an expiry and are cited from a story's
|
|
36
|
+
`sources:`. A gated story (`risk: high` or a configured label) needs a resolvable source before
|
|
37
|
+
`ready-for-human-review`; only a confirmed finding becomes a testable criterion.
|
|
34
38
|
- **Fast lane:** `type: chore` / `type: task`; `/implement` skips Gherkin matching and formal reviews.
|
|
39
|
+
- **Honest aggregates:** `status: target` (default when missing), `as-is` with evidence, or `unresolved` with an
|
|
40
|
+
open hotspot. A story on an `unresolved` aggregate cannot leave `review`. `/adopt` writes `as-is`/`unresolved`,
|
|
41
|
+
never an invented target.
|
|
42
|
+
- **Concept slices:** a layered repository is adopted by concept, not by package. The repo map marks generic layer
|
|
43
|
+
packages and clusters shared stems/tables; `slice.ts` resolves globs, routes, tables, events, clusters or terms.
|
|
44
|
+
- **Characterization before test-first:** in the domain lane, an untested affected path gets a characterization
|
|
45
|
+
test first, committed separately; a contradiction sends the story back to `review`.
|
|
46
|
+
- **As-is vs target:** `docs/domain/context-map.md` is the target; `/adopt` writes only
|
|
47
|
+
`docs/domain/context-map.as-is.md`; the gap register links both.
|
|
35
48
|
- **Reviewers report, never plan:** `code-reviewer` and `acceptance-tester` create no stories. Findings are fixed in
|
|
36
49
|
the story or handed back as open questions.
|
|
37
50
|
- The installer prunes the retired workflow files named in `OBSOLETE` (only manifest-tracked, unmodified ones), so a
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 – 2026-11-07
|
|
4
|
+
|
|
5
|
+
- **Research as evidence.** New read-only `researcher` agent (Claude Code and OpenCode) that searches specs,
|
|
6
|
+
standards and exact-version official documentation and returns structured findings with source, retrieval date,
|
|
7
|
+
tier and confidence – no writes, no shell, no decisions. `/research <question>` runs the workflow directly;
|
|
8
|
+
`/feature --research` forces the step when the trigger list (auth/identity, security, payment, privacy,
|
|
9
|
+
accessibility, performance, new technology) would not catch it.
|
|
10
|
+
- **Persisted research files.** Findings live in `docs/research/<topic>.md` with `topic`, `question`, `created`,
|
|
11
|
+
`retrieved`, `expires` and `stack`; the main session writes them verbatim and computes `expires` from
|
|
12
|
+
`research.expiryMonths` (default 12, month-end clamped). `research-check.ts` validates the format and expiry
|
|
13
|
+
(`--topic`, `--referenced`, `--all`, `--json`) and `verify.ts` runs the referenced check as an advisory step.
|
|
14
|
+
- **Deterministic research gate.** Stories can cite `sources:` (an `https://…` URL or a local research file). A story
|
|
15
|
+
with `risk: high` or a configured gate label (`security`, `auth`, `payment`, `privacy` by default, matched exactly
|
|
16
|
+
or by prefix) needs at least one resolvable source before `ready-for-human-review`; `lint-story` warns for
|
|
17
|
+
`draft`/`review`, `story-status.ts` and the validation hook block the transition. Existing `ready`/`done` stories
|
|
18
|
+
stay green, and expiry is a warning, never a gate error. `sources` survives the GitHub/Jira backlog round-trip and
|
|
19
|
+
appears in the implementation context pack.
|
|
20
|
+
- **Grilling integration.** `grilling`, `feature`, `shape`, `user-stories`, `review-stories` and `implement` cite
|
|
21
|
+
research findings instead of inventing "best practice"; a finding that contradicts the model is a grilling
|
|
22
|
+
question. `shape` adds `## Evidence` to the initiative and uses findings as a cost anchor, never as the estimate.
|
|
23
|
+
The payload ships `templates/docs/research/README.md`, the research skill and template, and the installer allows
|
|
24
|
+
the research scripts.
|
|
25
|
+
|
|
26
|
+
## 0.5.0 – 2026-11-07
|
|
27
|
+
|
|
28
|
+
- **Honest aggregate status.** Aggregates in `docs/domain/events.yaml` can be `target` (the default when the field
|
|
29
|
+
is missing), `as-is` (a factual brownfield boundary, with `evidence`) or `unresolved` (the boundary is unclear
|
|
30
|
+
and needs an open hotspot). The validator rejects `as-is` without evidence; the spec linter blocks a story on an
|
|
31
|
+
`unresolved` aggregate from leaving `review`. `/adopt` and `domain-model` prefer `as-is`/`unresolved` over an
|
|
32
|
+
invented aggregate.
|
|
33
|
+
- **Gap register.** `docs/domain/gap-register.md` gets one generated row per `as-is`/`unresolved` aggregate,
|
|
34
|
+
linking the aggregate and both context maps. The managed block is refreshed by
|
|
35
|
+
`node .claude/skills/adopt/scripts/gap-register.ts`; decisions live outside it.
|
|
36
|
+
- **Slices by concept, not by package.** The repository map marks generic layer packages (`services`,
|
|
37
|
+
`repositories`, `utils`) instead of proposing them as domains, and clusters files by shared concept stems and
|
|
38
|
+
tables. `/adopt` accepts a package path, `--paths`, `--route`, `--table`, `--event`, `--cluster` or a term;
|
|
39
|
+
`slice.ts` resolves the candidate files across layers and the user confirms the scope. A cross-cutting slice
|
|
40
|
+
documents its domain in `.claude/rules/<context>.md` with `paths:`; `<package>/AGENTS.md` stays for real
|
|
41
|
+
domain packages.
|
|
42
|
+
- **Characterization tests before test-first.** `characterize.ts --story ST-NNN` (or `--changed`/`--base`) names
|
|
43
|
+
the affected source files and the tests it finds. In the domain lane, an affected path with no test for the
|
|
44
|
+
behaviour about to change gets a characterization test first: current behaviour pinned, green on unchanged code,
|
|
45
|
+
committed separately, then the story tests. A discrepancy is a finding – the story goes back to `review`, never
|
|
46
|
+
the test to the expected value. The fast lane skips this except for an explicit refactoring.
|
|
47
|
+
- **As-is and target are separate.** `docs/domain/context-map.md` is the target map; `/adopt` writes only
|
|
48
|
+
`docs/domain/context-map.as-is.md` and links both through the gap register. `/shape` and
|
|
49
|
+
`/improve-codebase-architecture` write the target map; `/bootstrap`, `/feature` and `domain-architect` do the
|
|
50
|
+
same. Existing projects keep their `context-map.md` as the target – no file is moved or renamed.
|
|
51
|
+
|
|
3
52
|
## 0.4.0 – 2026-11-03
|
|
4
53
|
|
|
5
54
|
- **Spec-driven instead of corporate roleplay.** The `product-owner`, `requirements-engineer` and `lead-dev`
|
package/README.md
CHANGED
|
@@ -78,7 +78,8 @@ 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
|
-
|
|
81
|
+
skills/research/ research workflow, template and the deterministic research check
|
|
82
|
+
agents/ review agents, the read-only researcher and the on-demand UX utility (Claude Code)
|
|
82
83
|
hooks/ plain-Node guardrails and validators
|
|
83
84
|
lib/ deterministic domain/story/backlog logic
|
|
84
85
|
.opencode/
|
|
@@ -94,10 +95,13 @@ docs/
|
|
|
94
95
|
product/initiatives/ proposals for large ideas from /shape (no stories)
|
|
95
96
|
product/ux-guidelines.md the interface yardstick
|
|
96
97
|
prototypes/ throwaway prototypes on their own branch; the default branch keeps the README
|
|
98
|
+
research/ evidence for cross-cutting questions, with an expiry (format in its README)
|
|
97
99
|
domain/events.yaml the event storming model (empty is valid)
|
|
98
|
-
domain/context-map.md
|
|
100
|
+
domain/context-map.md target context map
|
|
101
|
+
domain/context-map.as-is.md as-is snapshot – created by /adopt
|
|
102
|
+
domain/gap-register.md as-is ↔ target gaps – created by /adopt
|
|
99
103
|
architecture/data-model.md
|
|
100
|
-
architecture/repo-map.* generated by /adopt: packages, edges, adoption ranking
|
|
104
|
+
architecture/repo-map.* generated by /adopt: packages, roles, edges, adoption ranking, concept slices
|
|
101
105
|
engineering/conventions.md how this repo builds code + the seam catalog
|
|
102
106
|
stories/ the backlog – or the local mirror of GitHub/Jira
|
|
103
107
|
adr/ architecture decisions
|
|
@@ -111,13 +115,14 @@ Existing `CONTEXT.md` and `docs/` are never touched.
|
|
|
111
115
|
|
|
112
116
|
| Command | What it does |
|
|
113
117
|
|---|---|
|
|
114
|
-
| `/adopt [scope] [--stories]` | Brownfield: repository map → one slice (
|
|
118
|
+
| `/adopt [scope] [--stories]` | Brownfield: repository map → one concept or package slice (+ shared library) → evidence → grilling → context docs and checks → gap register; scope is a package path, `--paths`, `--route`, `--table`, `--event`, `--cluster` or a term; stories only with `--stories`; repeat per slice |
|
|
115
119
|
| `/bootstrap` | Greenfield: vision → event storming → domain model → architecture → UX → foundation stories |
|
|
116
120
|
| `/grill-me` | Relentless interview on a plan, decision or idea |
|
|
117
121
|
| `/grill-with-docs` | The same, writing glossary and ADRs as you go |
|
|
118
122
|
| `/event-storming [process]` | Big-picture or single-process event storming |
|
|
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 |
|
|
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 |
|
|
123
|
+
| `/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; `--research` forces the research step |
|
|
124
|
+
| `/shape <idea \| ticket> [--dry-run]` | Before a large feature: frame, place (existing/new context, shared library), research external facts, impact, slices, rough cost range, recommendation; creates no stories |
|
|
125
|
+
| `/research <question>` | One cross-cutting question as evidence: check existing research and expiry, dispatch the read-only researcher, persist findings in `docs/research/<topic>.md`, cite them in grilling and stories |
|
|
121
126
|
| `/review-stories [ST-…]` | Spec linter gate → `ready-for-human-review`; the user approves `ready` |
|
|
122
127
|
| `/backlog-sync [status\|pull\|push]` | Keep `docs/stories/` in sync with GitHub Issues or Jira |
|
|
123
128
|
| `/groom-backlog [scope]` | Periodic challenge: is this backlog still worth building? |
|
|
@@ -132,6 +137,11 @@ domain, architecture, testability – and one mechanical rule: **one story = one
|
|
|
132
137
|
aggregate**, at most four Gherkin scenarios. `aggregate` and `command` are required frontmatter and are cross-checked
|
|
133
138
|
against `docs/domain/events.yaml`.
|
|
134
139
|
|
|
140
|
+
Aggregates carry a status: `target` (the default when the field is missing), `as-is` (the factual boundary
|
|
141
|
+
recovered from code, with evidence) or `unresolved` (the boundary is unclear). A story on an `unresolved`
|
|
142
|
+
aggregate cannot leave `review`; `/adopt` writes `as-is` or `unresolved`, never an invented target. Every `as-is`
|
|
143
|
+
aggregate gets a row in `docs/domain/gap-register.md`, linking the as-is and target context maps.
|
|
144
|
+
|
|
135
145
|
The **spec linter** is the gate and costs no LLM tokens:
|
|
136
146
|
|
|
137
147
|
```bash
|
|
@@ -149,6 +159,36 @@ Non-domain work takes the **fast lane**: `type: chore` (UI tweak, refactor, depe
|
|
|
149
159
|
Gherkin matching or formal review agents. `type: tech-task` keeps its checklist and acceptance; `type: spike` is a
|
|
150
160
|
timeboxed question.
|
|
151
161
|
|
|
162
|
+
In a brownfield domain story, `/implement` first runs `characterize.ts`: it names the affected source files and
|
|
163
|
+
the tests it can find. An affected path with no test for the behaviour that is about to change gets a
|
|
164
|
+
**characterization test** that pins the current behaviour, committed separately before the story's red → green
|
|
165
|
+
loop. If the current behaviour contradicts the story, that is a finding and the story goes back to `review`; the
|
|
166
|
+
code is never silently adjusted. The fast lane skips this except for an explicit refactoring.
|
|
167
|
+
|
|
168
|
+
### Research as evidence
|
|
169
|
+
|
|
170
|
+
Cross-cutting stories rest on current primary sources. `/feature` triggers research through the grilling rules for
|
|
171
|
+
auth/identity, security, payment, privacy, accessibility, performance and new technologies; `--research` forces it
|
|
172
|
+
for a topic the trigger list does not catch. `/research <question>` runs the same path directly.
|
|
173
|
+
|
|
174
|
+
The **`researcher` is strictly read-only** – web search/fetch and repository reading, no write, no shell – and the
|
|
175
|
+
only way web content enters the session. Findings are data: instructions inside a fetched page, issue or comment are
|
|
176
|
+
ignored. The main session writes them verbatim to `docs/research/<topic>.md`; `expires` is computed at write and
|
|
177
|
+
refresh time from `research.expiryMonths` (default 12 months).
|
|
178
|
+
|
|
179
|
+
Research is **evidence, not a specification**. Only a finding you confirm in grilling becomes a testable criterion
|
|
180
|
+
with an observable threshold; rejected options are recorded with the reason. A story cites its evidence in
|
|
181
|
+
`sources: [...]`, and a story with `risk: high` or a configured gate label (`security`, `auth`, `payment`, `privacy`
|
|
182
|
+
by default) needs a resolvable source before `ready-for-human-review` – the linter warns, `story-status.ts` blocks.
|
|
183
|
+
Expiry is advisory: `research-check.ts --referenced` runs in `verify.ts` and warns about stale files without failing
|
|
184
|
+
the gate.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
/research "Which PKCE configuration is required for a public SPA client?"
|
|
188
|
+
/feature "checkout with saved cards" --research
|
|
189
|
+
node .claude/skills/research/scripts/research-check.ts --referenced
|
|
190
|
+
```
|
|
191
|
+
|
|
152
192
|
### Starting from a ticket
|
|
153
193
|
|
|
154
194
|
`/feature` also accepts a reference: `/feature #123` (GitHub), `/feature PROJ-123` (Jira, with the issue fetched
|
|
@@ -203,15 +243,22 @@ open UI question during engineering; if the prototype changes the story, the sto
|
|
|
203
243
|
1. `npx kataster init --brownfield` → the profile is filled from the detected stack and monorepo tooling
|
|
204
244
|
(`repo.tooling`: Nx, Turborepo, Bazel, workspaces, Go, Cargo, Gradle, Maven).
|
|
205
245
|
2. `/adopt` → a deterministic **repository map** (`docs/architecture/repo-map.md`, `.json`) with packages,
|
|
206
|
-
dependency edges, consumers
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
246
|
+
dependency edges, consumers, an adoption ranking, **layer packages** and **concept-slice suggestions**. No
|
|
247
|
+
questions, no hand-scanning. In a layered repository (`api/`, `services/`, `repositories/`) a concept slice —
|
|
248
|
+
not a package — is the unit.
|
|
249
|
+
3. `/adopt [scope]` → **one concept or domain plus at most one shared library**. The scope can be a package path,
|
|
250
|
+
a glob set (`--paths`), an entry point (`--route`, `--table`, `--event`), a suggested cluster (`--cluster`) or
|
|
251
|
+
a term; `slice.ts` resolves the candidate files across all layers. Two or three `repo-analyst` subagents return
|
|
252
|
+
evidence (five lenses for a small single-package repository); the main session drafts `CONTEXT.md`,
|
|
253
|
+
`events.yaml`, the as-is context map, as-is data model, conventions and de-facto ADRs. A real domain package
|
|
254
|
+
gets `<package>/AGENTS.md` + `<package>/CLAUDE.md`; a cross-cutting concept slice gets
|
|
255
|
+
`.claude/rules/<context>.md` with `paths:` frontmatter. Then it grills you.
|
|
210
256
|
4. The safety net turns confirmed rules into checks (types, lint/boundary, tests, hooks) – report-only with a
|
|
211
257
|
baseline first, so a brownfield repository does not start red.
|
|
212
|
-
5. The gap analysis records **contradictions, missing behaviour and dead code** in the adoption report
|
|
213
|
-
**
|
|
214
|
-
the
|
|
258
|
+
5. The gap analysis records **contradictions, missing behaviour and dead code** in the adoption report and the
|
|
259
|
+
**gap register** (`docs/domain/gap-register.md`): one row per `as-is`/`unresolved` aggregate, linking the
|
|
260
|
+
as-is boundary to the target model. It creates **no stories by default** – what already works is documented,
|
|
261
|
+
not re-storied. `/adopt <scope> --stories` turns the selected gaps into a backlog when you want one.
|
|
215
262
|
6. `/adopt <next path>` for the next slice; `/adopt <scope> --stories`, `/review-stories`, then `/implement`.
|
|
216
263
|
|
|
217
264
|
Adopt in slices: one bounded context completely beats the whole repository shallowly. The root `AGENTS.md` stays
|
|
@@ -221,9 +268,11 @@ free of domain; the package docs are loaded only when someone works in that pack
|
|
|
221
268
|
|
|
222
269
|
The installer detects the build tool (Nx, Turborepo, Bazel, pnpm/npm/yarn workspaces, Go, Cargo, Gradle, Maven)
|
|
223
270
|
and stores it in `.claude/project.json` → `repo.tooling`. `/adopt` builds the repository map once, then adopts
|
|
224
|
-
**one domain plus at most one shared library per session**. Every adopted package gets an
|
|
225
|
-
purpose, entities or public API, interfaces and pitfalls – plus a one-line `CLAUDE.md` so
|
|
226
|
-
demand; OpenCode loads the nested `AGENTS.md` itself.
|
|
271
|
+
**one concept or domain plus at most one shared library per session**. Every adopted domain package gets an
|
|
272
|
+
`AGENTS.md` with its purpose, entities or public API, interfaces and pitfalls – plus a one-line `CLAUDE.md` so
|
|
273
|
+
Claude Code loads it on demand; OpenCode loads the nested `AGENTS.md` itself. A cross-cutting concept slice gets
|
|
274
|
+
`.claude/rules/<context>.md` with `paths:` instead, loaded by both harnesses when a matching file is touched. The
|
|
275
|
+
root `AGENTS.md` stays short and free of domain.
|
|
227
276
|
|
|
228
277
|
Commands use the detected tool instead of assuming a single package: `nx affected -t test`,
|
|
229
278
|
`turbo run test --filter=<package>`, `bazel test //<package>/...`, `pnpm --filter <package> test`. The map also
|
|
@@ -270,6 +319,10 @@ node .claude/skills/implement/scripts/affected.ts --base origin/main
|
|
|
270
319
|
"statusMap": { "draft": "To Do", "ready": "Ready", "done": "Done" },
|
|
271
320
|
"priorityMap": { "must": "Highest", "should": "High" }
|
|
272
321
|
}
|
|
322
|
+
},
|
|
323
|
+
"research": {
|
|
324
|
+
"expiryMonths": 12,
|
|
325
|
+
"gate": { "risk": ["high"], "labels": ["security", "auth", "payment", "privacy"] }
|
|
273
326
|
}
|
|
274
327
|
}
|
|
275
328
|
```
|
|
@@ -327,7 +380,7 @@ For Jira, `jira-plan.ts` prints the exact MCP calls, `jira-record.ts` writes the
|
|
|
327
380
|
node .claude/skills/adopt/scripts/boundary-check.ts --update-baseline
|
|
328
381
|
```
|
|
329
382
|
- **`verify.ts`** is the one gate: project checks, artifact validity, scenario ↔ test traceability, domain IDs in
|
|
330
|
-
the code, glossary language.
|
|
383
|
+
the code, glossary language. Referenced research files are checked for expiry as an advisory step.
|
|
331
384
|
- **Review agents** never write code or stories: `code-reviewer` and `acceptance-tester` report findings, the
|
|
332
385
|
acceptance verdict decides whether a domain story is `done`, and a finding is fixed in the story or handed back
|
|
333
386
|
as an open question. `ux-designer` is an on-demand utility (`ui: true`), never a gate.
|
|
@@ -343,6 +396,11 @@ npx kataster doctor
|
|
|
343
396
|
overwrite files you changed locally – it lists them instead. `--force` overwrites and writes a backup to
|
|
344
397
|
`.kataster/backup/`.
|
|
345
398
|
|
|
399
|
+
Project content includes `docs/workflow.md` and the context maps. An upgrade does not rewrite them; compare
|
|
400
|
+
`docs/workflow.md` with `templates/docs/workflow.md` if you want the new rules in an existing project. The schema
|
|
401
|
+
changes are additive: an aggregate without `status` is `target`, a missing `context-map.as-is.md` or gap register is
|
|
402
|
+
not an error, and the new checks are advisory until the artifacts exist.
|
|
403
|
+
|
|
346
404
|
## Design notes
|
|
347
405
|
|
|
348
406
|
- **`.claude/` is the source of truth.** OpenCode and Claude Code share skills, agents and hooks; `.opencode/` is an
|
|
@@ -372,8 +430,9 @@ Kataster stands on other people's work:
|
|
|
372
430
|
- **Matt Pocock** – [skills](https://github.com/mattpocock/skills), [aihero.dev](https://www.aihero.dev). The grilling
|
|
373
431
|
interview (`grilling`, `grill-me`, `grill-with-docs`), test-driven development (`tdd`), the deep-module vocabulary
|
|
374
432
|
(`codebase-design`), the architecture survey (`improve-codebase-architecture`), the throwaway prototype
|
|
375
|
-
(`prototype`), the
|
|
376
|
-
|
|
433
|
+
(`prototype`), the research skill (adapted: read-only researcher, source tiers, expiry, grilling integration), the
|
|
434
|
+
retro, the domain-modeling discipline and `writing-for-agents` come from his skill repository – partly adapted,
|
|
435
|
+
partly copied verbatim under MIT. The per-file mapping and the license text are in
|
|
377
436
|
[.claude/THIRD_PARTY_NOTICES.md](.claude/THIRD_PARTY_NOTICES.md).
|
|
378
437
|
- **John Ousterhout**, *A Philosophy of Software Design* – "Design It Twice" and the depth, seam and deletion-test
|
|
379
438
|
vocabulary.
|
package/guide/brownfield.md
CHANGED
|
@@ -9,6 +9,9 @@ npx kataster init --brownfield
|
|
|
9
9
|
/adopt # map the repository, then choose a slice
|
|
10
10
|
/adopt apps/billing # adopt one package
|
|
11
11
|
/adopt libs/shared-kernel # adopt a shared library
|
|
12
|
+
/adopt --cluster order # adopt a concept across api/, services/, repositories/
|
|
13
|
+
/adopt --table orders # start from a table and resolve the layers behind it
|
|
14
|
+
/adopt --route "POST /orders" # start from an entry point
|
|
12
15
|
```
|
|
13
16
|
|
|
14
17
|
## Adopt in slices, not in one pass
|
|
@@ -20,15 +23,21 @@ A monorepo with eighty packages cannot be understood in one session. `/adopt` th
|
|
|
20
23
|
2. **One slice** – one domain plus at most one shared library. Deep evidence, grilling, package docs, checks.
|
|
21
24
|
Then the next slice in a later session.
|
|
22
25
|
|
|
23
|
-
The map is generated from manifests and git history:
|
|
26
|
+
The map is generated from manifests, source files and git history:
|
|
24
27
|
|
|
25
|
-
- `docs/architecture/repo-map.json` – packages, paths, kinds, internal dependencies, consumers, adoption
|
|
28
|
+
- `docs/architecture/repo-map.json` – packages, paths, kinds, roles, internal dependencies, consumers, adoption
|
|
29
|
+
ranking, concept-slice suggestions
|
|
26
30
|
- `docs/architecture/repo-map.md` – the same as a readable map, plus dependency edges and a suggested first slice
|
|
27
31
|
- the **repository block in `AGENTS.md`** – tooling, layout, commands, adopted slices
|
|
28
32
|
- `.claude/project.json` → `repo.tooling` – Nx, Turborepo, Bazel, pnpm/npm/yarn workspaces, Go, Cargo, Gradle, Maven
|
|
29
33
|
|
|
30
34
|
The map is facts, not domain. It says where code lives, never what a word means.
|
|
31
35
|
|
|
36
|
+
In a layered repository (`api/`, `services/`, `repositories/`, `utils/`) a package is not a domain. The map marks
|
|
37
|
+
generic packages as **layer packages** and clusters files by shared concept stems and tables. A domain such as
|
|
38
|
+
“order” shows up as an `order` slice across all layers; `slice.ts` resolves the candidate files from a cluster, a
|
|
39
|
+
table, a route, an event ID, a glob or a term. The resolver is evidence – you confirm the scope.
|
|
40
|
+
|
|
32
41
|
## What `/adopt` does
|
|
33
42
|
|
|
34
43
|
### 1. Chooses the slice with you
|
|
@@ -56,18 +65,26 @@ A monorepo gets three lenses:
|
|
|
56
65
|
A small repository without monorepo tooling gets the five classic lenses: structure and stack, domain language,
|
|
57
66
|
data and integrations, behaviour and tests, history and decisions.
|
|
58
67
|
|
|
68
|
+
For a concept slice, the analysts receive the confirmed file list from `slice.ts`, not only a package path. They
|
|
69
|
+
report facts inside that scope; widening the slice is the user's decision, not theirs.
|
|
70
|
+
|
|
59
71
|
Each analyst returns facts with `path:line`, candidate vocabulary, candidate events/commands/read models,
|
|
60
72
|
contradictions, and questions with a recommended answer. Confidence is `high`, `medium` or `low`.
|
|
61
73
|
|
|
62
74
|
### 4. Drafts the slice
|
|
63
75
|
|
|
64
76
|
- `CONTEXT.md` – the slice's terms, competing spellings under `_Avoid_`
|
|
65
|
-
- `docs/domain/events.yaml` – 10–25 candidate events, commands, actors, read models, flows, hotspots
|
|
66
|
-
|
|
77
|
+
- `docs/domain/events.yaml` – 10–25 candidate events, commands, actors, read models, flows, hotspots. Each
|
|
78
|
+
aggregate is `as-is` with evidence (table, service method, path) or `unresolved` with an open hotspot – never
|
|
79
|
+
an invented `target`
|
|
80
|
+
- `docs/domain/context-map.as-is.md` (recovered boundaries, with evidence) and
|
|
81
|
+
`docs/architecture/data-model.md` (as-is). The target map `docs/domain/context-map.md` is read, never written
|
|
82
|
+
here; if it does not exist yet, the gap register says “target not decided”.
|
|
67
83
|
- `docs/engineering/conventions.md` – how the code actually works today, including the monorepo tooling
|
|
68
84
|
- `docs/adr/` – de-facto decisions worth recording (`status: proposed`)
|
|
69
|
-
- **
|
|
70
|
-
`
|
|
85
|
+
- **domain docs, by scope** – a real domain package gets `<package>/AGENTS.md` plus `<package>/CLAUDE.md` from
|
|
86
|
+
`package-doc.ts <path>`; a cross-cutting concept slice gets `.claude/rules/<context>.md` with `paths:` from
|
|
87
|
+
`slice-doc.ts <slug> --context BC-… --paths "…"`. One mechanism per scope, never both.
|
|
71
88
|
|
|
72
89
|
Everything uncertain is marked. The draft is a proposal, not a verdict.
|
|
73
90
|
|
|
@@ -92,19 +109,25 @@ baseline of existing violations; only new violations fail. A hook that is red on
|
|
|
92
109
|
`/adopt` may add characterization tests and tooling. It never changes production code, and it never writes a test
|
|
93
110
|
that fails on existing behaviour – that would be a story.
|
|
94
111
|
|
|
112
|
+
The same net carries into `/implement`: `characterize.ts --story ST-NNN` names the affected source files and the
|
|
113
|
+
tests it can find. A path with no test for the behaviour that is about to change gets a characterization test
|
|
114
|
+
first – current behaviour pinned, green on unchanged code, committed separately, then the story's red → green loop.
|
|
115
|
+
If the current behaviour contradicts the story, the story goes back to `review`; the test is not bent to fit.
|
|
116
|
+
|
|
95
117
|
### 7. Records the gap – stories only on request
|
|
96
118
|
|
|
97
119
|
| Class | Default |
|
|
98
120
|
|---|---|
|
|
99
|
-
| Exists and is intended | Documentation (data model, context map) – no action |
|
|
121
|
+
| Exists and is intended | Documentation (data model, as-is context map) – no action |
|
|
100
122
|
| Exists but contradicts the model | Candidate in the gap register |
|
|
101
123
|
| Missing | Candidate in the gap register |
|
|
102
124
|
| Dead | Candidate: removal or an explicit "leave it" |
|
|
103
125
|
|
|
104
|
-
**The first adoption pass creates no stories.** It records the gap in `docs/domain/adoption-report.md`
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
126
|
+
**The first adoption pass creates no stories.** It records the gap in `docs/domain/adoption-report.md` and
|
|
127
|
+
`docs/domain/gap-register.md` (one generated row per `as-is`/`unresolved` aggregate, with the as-is and target
|
|
128
|
+
context links), and open questions in `OPEN_QUESTIONS.md`, so the model can be reviewed before anyone commits to
|
|
129
|
+
work. Only `/adopt <scope> --stories` (or an explicit "turn these into stories") turns the selected gaps into
|
|
130
|
+
stories in the main session (spec engineer, spec linter gate).
|
|
108
131
|
|
|
109
132
|
**Behaviour that already works does not become a story.** That turns the backlog into a description of the past.
|
|
110
133
|
|
|
@@ -114,11 +137,14 @@ main session (spec engineer, spec linter gate).
|
|
|
114
137
|
and checks, gaps, what was deliberately left alone, open hotspots, next slice.
|
|
115
138
|
|
|
116
139
|
```bash
|
|
140
|
+
# a real domain package
|
|
117
141
|
node .claude/skills/adopt/scripts/repo-map.ts --adopt apps/billing
|
|
142
|
+
# a concept slice across layers
|
|
143
|
+
node .claude/skills/adopt/scripts/repo-map.ts --adopt-slice order
|
|
118
144
|
```
|
|
119
145
|
|
|
120
146
|
The next session sees the progress in `AGENTS.md` and the map, and starts the next slice with
|
|
121
|
-
`/adopt <
|
|
147
|
+
`/adopt <scope>`.
|
|
122
148
|
|
|
123
149
|
## What lives where
|
|
124
150
|
|
|
@@ -134,6 +160,9 @@ The next session sees the progress in `AGENTS.md` and the map, and starts the ne
|
|
|
134
160
|
| `docs/engineering/checks.yaml` | on check | what runs at edit time and at Stop/CI |
|
|
135
161
|
| `docs/architecture/repo-map.md` | on demand | generated map: packages, edges, consumers, ranking |
|
|
136
162
|
| `CONTEXT.md` | every session | the domain language |
|
|
163
|
+
| `docs/domain/context-map.md` | on demand | **target** contexts and relationships |
|
|
164
|
+
| `docs/domain/context-map.as-is.md` | on demand | **as-is** snapshot recovered by `/adopt`, with evidence |
|
|
165
|
+
| `docs/domain/gap-register.md` | on demand | generated as-is ↔ target rows and the user's decisions |
|
|
137
166
|
|
|
138
167
|
Nested `AGENTS.md` is loaded on demand by OpenCode; Claude Code loads the nested `CLAUDE.md` when it reads or
|
|
139
168
|
edits a file there. That is why every package gets both files.
|
package/guide/concepts.md
CHANGED
|
@@ -14,6 +14,14 @@ Two rules make it work:
|
|
|
14
14
|
user something you could find yourself.
|
|
15
15
|
- **Do not act until the frontier is empty** and the user confirms a shared understanding.
|
|
16
16
|
|
|
17
|
+
When a frontier question rests on an **external fact** – a standard, a library capability, a regulatory requirement,
|
|
18
|
+
a security or privacy rule – the agent researches it before the round. The `researcher` is read-only and returns
|
|
19
|
+
findings with source, tier, retrieval date and confidence; the main session writes them to
|
|
20
|
+
`docs/research/<topic>.md` with an expiry. The finding is evidence, not a decision: the recommendation cites it
|
|
21
|
+
(`➡️ … (RFC 9700 §2.1.1; F1 in docs/research/oauth-pkce.md)`), and only a confirmed finding becomes a testable
|
|
22
|
+
criterion. A trigger is not a mandate – if the model, an ADR or a valid research file already answers it, nothing
|
|
23
|
+
runs.
|
|
24
|
+
|
|
17
25
|
`/grill-me` is the pure form. `/grill-with-docs` adds the glossary and ADRs. Every discovery command embeds it.
|
|
18
26
|
|
|
19
27
|
## The artifacts
|
|
@@ -22,13 +30,16 @@ Two rules make it work:
|
|
|
22
30
|
|---|---|---|
|
|
23
31
|
| `CONTEXT.md` | Glossary – the ubiquitous language. One canonical word per concept, alternatives under `_Avoid_` | user, maintained by the agent |
|
|
24
32
|
| `docs/domain/events.yaml` | Event storming model: actors, contexts, aggregates, events, commands, policies, read models, hotspots, flows | user, written by the agent |
|
|
25
|
-
| `docs/domain/context-map.md` |
|
|
33
|
+
| `docs/domain/context-map.md` | **Target** bounded contexts and their relationships (DDD patterns) | domain-architect, `/bootstrap`, `/shape`, `/feature`, `/improve-codebase-architecture` |
|
|
34
|
+
| `docs/domain/context-map.as-is.md` | **As-is** snapshot recovered from code, with evidence | `/adopt` only |
|
|
35
|
+
| `docs/domain/gap-register.md` | Generated rows for every `as-is`/`unresolved` aggregate, linking as-is and target; decisions outside the block | `/adopt`, user |
|
|
26
36
|
| `docs/architecture/data-model.md` | Logical, stack-neutral model per aggregate; lifecycle and ER diagrams | domain-architect |
|
|
27
37
|
| `docs/engineering/conventions.md` | How code is built here, including the seam catalog | user |
|
|
28
38
|
| `docs/adr/` | Architecture decisions. `proposed` until the user accepts; accepted ones are superseded, never edited | user |
|
|
29
39
|
| `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
40
|
| `docs/product/vision.md` | Problem, user groups, goals, non-goals, success criteria | user |
|
|
31
41
|
| `docs/product/ux-guidelines.md` | The interface yardstick, as numbered rules with date and reason | ux-designer, approved by user |
|
|
42
|
+
| `docs/research/<topic>.md` | Evidence for a cross-cutting question: findings with source, tier, confidence and an expiry. Evidence, not a specification | researcher (read-only); main session writes; user confirms findings |
|
|
32
43
|
| `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 |
|
|
33
44
|
|
|
34
45
|
## Events, commands, aggregates
|
package/package.json
CHANGED
package/src/detect.mjs
CHANGED
|
@@ -224,6 +224,15 @@ export function buildProfile(root, { name, kind, uiLanguage, artifactLanguage, d
|
|
|
224
224
|
},
|
|
225
225
|
},
|
|
226
226
|
},
|
|
227
|
+
// Research files expire. The gate asks for `sources:` on risky work before it reaches ready-for-human-review.
|
|
228
|
+
// Keep the defaults in sync with .claude/lib/config.ts (DEFAULT_RESEARCH_CONFIG).
|
|
229
|
+
research: {
|
|
230
|
+
expiryMonths: 12,
|
|
231
|
+
gate: {
|
|
232
|
+
risk: ["high"],
|
|
233
|
+
labels: ["security", "auth", "payment", "privacy"],
|
|
234
|
+
},
|
|
235
|
+
},
|
|
227
236
|
setup: {
|
|
228
237
|
envFile: "",
|
|
229
238
|
envHint: "",
|
package/src/install.mjs
CHANGED
|
@@ -59,6 +59,7 @@ 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
61
|
"Bash(node .claude/skills/user-stories/scripts/*)",
|
|
62
|
+
"Bash(node .claude/skills/research/scripts/*)",
|
|
62
63
|
"Bash(node .claude/skills/adopt/scripts/*)",
|
|
63
64
|
"Bash(node .claude/skills/backlog/scripts/*)",
|
|
64
65
|
"Bash(node .claude/skills/implement/scripts/*)",
|
|
@@ -433,6 +434,9 @@ This repository runs the Kataster workflow. Discovery lives in \`.claude/skills/
|
|
|
433
434
|
local mirror and the tracker is the source of truth – sync with \`/backlog-sync\`; \`BACKLOG.md\` stays generated.
|
|
434
435
|
- **Map:** \`docs/workflow.md\` – sources of truth, commands, phases, rules. Read it when unsure where something
|
|
435
436
|
belongs.
|
|
437
|
+
- **Research:** cross-cutting questions go through the read-only \`researcher\` (\`/research\`,
|
|
438
|
+
\`/feature --research\`); findings live in \`docs/research/<topic>.md\` with an expiry and are cited from a story's
|
|
439
|
+
\`sources:\`. Evidence, not a specification.
|
|
436
440
|
- **Repo map (brownfield):** \`docs/architecture/repo-map.md\` – packages, dependency edges, consumers, adopted
|
|
437
441
|
slices. A package's \`AGENTS.md\` is loaded only when you work there; the root file stays free of domain.
|
|
438
442
|
- **Start:** greenfield → \`/bootstrap\`; existing code → \`/adopt\` (in slices, not the whole monorepo).
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Target context map – {{project}}
|
|
2
|
+
|
|
3
|
+
> Where the domain is going, not what the code does today. The as-is map is `context-map.as-is.md` and is
|
|
4
|
+
> written only by `/adopt`; the gap register links both sides. `/bootstrap`, `/shape`, `/feature`,
|
|
5
|
+
> `/event-storming`, `domain-architect` and `/improve-codebase-architecture` write this file.
|
|
2
6
|
|
|
3
7
|
<!--
|
|
4
8
|
One section per bounded context: purpose, core terms, owner role. Relationships as a Mermaid flowchart
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
#
|
|
7
7
|
# Written by /bootstrap, /adopt, /event-storming and /feature. Validated and rendered to
|
|
8
8
|
# docs/domain/event-storming.md after every write. An empty model is valid: it grows during discovery.
|
|
9
|
+
#
|
|
10
|
+
# Aggregates carry an optional status: target (default when missing), as-is (factual boundary, needs evidence),
|
|
11
|
+
# or unresolved (boundary unclear, needs an open hotspot and grilling; no story on it can be ready).
|
|
9
12
|
|
|
10
13
|
version: 1
|
|
11
14
|
domain: {{project}}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Research
|
|
2
|
+
|
|
3
|
+
Evidence for cross-cutting questions: authentication and identity, security, payment, privacy and data protection,
|
|
4
|
+
accessibility, performance, or a new library or technology. The files here are **evidence, not a specification** –
|
|
5
|
+
the user decides in grilling, and only a confirmed finding becomes a testable acceptance criterion.
|
|
6
|
+
|
|
7
|
+
One file per topic: `docs/research/<topic>.md`, lowercase kebab-case, no date in the file name. Refresh in place;
|
|
8
|
+
if the question changes materially, use a new topic.
|
|
9
|
+
|
|
10
|
+
## Format
|
|
11
|
+
|
|
12
|
+
```markdown
|
|
13
|
+
---
|
|
14
|
+
topic: oauth-pkce-spa
|
|
15
|
+
question: "Which PKCE configuration is required for a public SPA client?"
|
|
16
|
+
created: 2026-11-07
|
|
17
|
+
retrieved: 2026-11-07
|
|
18
|
+
expires: 2027-11-07
|
|
19
|
+
stack: ["next@15.2.0", "node@22.18.0"]
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Research: …
|
|
23
|
+
## Question
|
|
24
|
+
## Findings
|
|
25
|
+
### F1 – …
|
|
26
|
+
- **Statement:** …
|
|
27
|
+
- **Source:** <title> – <url> (<section>)
|
|
28
|
+
- **Retrieved:** YYYY-MM-DD
|
|
29
|
+
- **Tier:** 1 | 2 | 3
|
|
30
|
+
- **Confidence:** high | medium | low
|
|
31
|
+
- **Domain-model impact:** none | conflicts with `<term>` / `AGG-…` / ADR-… – what
|
|
32
|
+
## Conflicts, caveats and gaps
|
|
33
|
+
## Open questions for the grilling
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Source tiers: **1** specs, standards and authorities (RFC, W3C/WAI, OWASP, NIST, ISO, GDPR/EDPB, PCI SSC, vendor
|
|
37
|
+
security advisories); **2** official documentation or source of the exact version in the lockfile; **3** everything
|
|
38
|
+
else – a hint, never the sole basis for a criterion.
|
|
39
|
+
|
|
40
|
+
## Expiry
|
|
41
|
+
|
|
42
|
+
`expires` is computed when the file is written or refreshed: `retrieved + research.expiryMonths` from
|
|
43
|
+
`.claude/project.json` (default 12 months, month-end clamped). It is not recomputed on every read. A stale file is
|
|
44
|
+
refreshed, not silently reused.
|
|
45
|
+
|
|
46
|
+
Check a file, every referenced file, or the whole directory:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node .claude/skills/research/scripts/research-check.ts --topic <slug>
|
|
50
|
+
node .claude/skills/research/scripts/research-check.ts --referenced
|
|
51
|
+
node .claude/skills/research/scripts/research-check.ts --all
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Statuses are `VALID`, `EXPIRED`, `MISSING` and `INVALID`; exit 1 means at least one file needs a refresh or repair.
|
|
55
|
+
`verify.ts` runs the referenced check as an advisory step – an expired file warns, it never fails the gate.
|
|
56
|
+
|
|
57
|
+
## How research enters the work
|
|
58
|
+
|
|
59
|
+
- `/research <question>` runs the read-only `researcher`; the main session writes its findings verbatim into this
|
|
60
|
+
directory. `/feature --research` forces the step for a topic the trigger list does not catch.
|
|
61
|
+
- The story lists the file under `sources:`. A story with `risk: high` or one of the configured gate labels in
|
|
62
|
+
`.claude/project.json` (default `security`, `auth`, `payment`, `privacy`) needs at least one resolvable source
|
|
63
|
+
before `ready-for-human-review`; the linter warns, `story-status.ts` blocks.
|
|
64
|
+
- Adopted findings become testable criteria with an observable threshold. Rejected options are recorded with the
|
|
65
|
+
reason in the story, ADR or initiative – this file stays evidence, not a decision log.
|
|
66
|
+
- A finding that contradicts `CONTEXT.md`, `events.yaml`, an accepted ADR or the UX guidelines is a grilling
|
|
67
|
+
question, never a silent rewrite of the model.
|
|
68
|
+
|
|
69
|
+
The full workflow is `.claude/skills/research/SKILL.md`; the format template is
|
|
70
|
+
`.claude/skills/research/templates/research.md`.
|
|
@@ -11,6 +11,8 @@ Workflow: `draft → review → ready-for-human-review → ready → in-progress
|
|
|
11
11
|
Gherkin `Given/When/Then` and the scenario limit – deterministically, no LLM.
|
|
12
12
|
- Green → `ready-for-human-review`; **the user approves `ready`**. `/implement` only picks up `ready`.
|
|
13
13
|
- **1-command rule:** one `type: domain` story = one command + its events on one aggregate, at most 4 scenarios.
|
|
14
|
+
- An aggregate with `status: unresolved` blocks the story at `ready-for-human-review`; settle the boundary and
|
|
15
|
+
its hotspot in grilling first. A missing status means `target`; `as-is` is allowed.
|
|
14
16
|
- **Fast lane:** `type: chore` or `type: task` for UI tweaks, refactorings, dependencies and setup – no Gherkin
|
|
15
17
|
matching, no formal reviews. `type: tech-task` keeps its checklist; `type: spike` is a timeboxed question.
|
|
16
18
|
- `ui: true` marks a story with a frontend part; it triggers the on-demand UX utility, never a gate.
|