kataster 0.0.0-stage → 0.2.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.
Files changed (162) hide show
  1. package/.claude/agents/acceptance-tester.md +53 -0
  2. package/.claude/agents/code-reviewer.md +56 -0
  3. package/.claude/agents/domain-architect.md +40 -0
  4. package/.claude/agents/lead-dev.md +50 -0
  5. package/.claude/agents/product-owner.md +39 -0
  6. package/.claude/agents/repo-analyst.md +78 -0
  7. package/.claude/agents/requirements-engineer.md +44 -0
  8. package/.claude/agents/ux-designer.md +64 -0
  9. package/.claude/hooks/bash-guard.ts +92 -0
  10. package/.claude/hooks/code-check.ts +37 -0
  11. package/.claude/hooks/path-guard.ts +34 -0
  12. package/.claude/hooks/path-rules.ts +66 -0
  13. package/.claude/hooks/project-check.ts +108 -0
  14. package/.claude/hooks/protect-files.ts +55 -0
  15. package/.claude/hooks/session-start.ts +213 -0
  16. package/.claude/hooks/stop-gate.ts +56 -0
  17. package/.claude/hooks/validate-docs.ts +58 -0
  18. package/.claude/lib/architecture.ts +736 -0
  19. package/.claude/lib/backlog-github.ts +454 -0
  20. package/.claude/lib/backlog-jira.ts +347 -0
  21. package/.claude/lib/backlog-sync.ts +42 -0
  22. package/.claude/lib/backlog.ts +396 -0
  23. package/.claude/lib/bazel.ts +212 -0
  24. package/.claude/lib/config.ts +122 -0
  25. package/.claude/lib/discovery.ts +821 -0
  26. package/.claude/lib/engineering.ts +406 -0
  27. package/.claude/lib/nx.ts +129 -0
  28. package/.claude/lib/repo.ts +1194 -0
  29. package/.claude/lib/toolgraph.ts +74 -0
  30. package/.claude/lib/turbo.ts +166 -0
  31. package/.claude/package-lock.json +427 -0
  32. package/.claude/package.json +21 -0
  33. package/.claude/settings.json +82 -0
  34. package/.claude/skills/adopt/SKILL.md +283 -0
  35. package/.claude/skills/adopt/scripts/boundary-check.ts +156 -0
  36. package/.claude/skills/adopt/scripts/package-doc.ts +71 -0
  37. package/.claude/skills/adopt/scripts/repo-map.ts +123 -0
  38. package/.claude/skills/adopt/scripts/rule-doc.ts +80 -0
  39. package/.claude/skills/architect/ADR-FORMAT.md +97 -0
  40. package/.claude/skills/architect/SKILL.md +64 -0
  41. package/.claude/skills/architect/TECH-STACK.md +21 -0
  42. package/.claude/skills/backlog/SKILL.md +198 -0
  43. package/.claude/skills/backlog/scripts/backlog-pull.ts +45 -0
  44. package/.claude/skills/backlog/scripts/backlog-push.ts +38 -0
  45. package/.claude/skills/backlog/scripts/backlog-status.ts +32 -0
  46. package/.claude/skills/backlog/scripts/jira-import.ts +40 -0
  47. package/.claude/skills/backlog/scripts/jira-plan.ts +26 -0
  48. package/.claude/skills/backlog/scripts/jira-record.ts +41 -0
  49. package/.claude/skills/bootstrap/SKILL.md +119 -0
  50. package/.claude/skills/codebase-design/DEEPENING.md +37 -0
  51. package/.claude/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  52. package/.claude/skills/codebase-design/SKILL.md +114 -0
  53. package/.claude/skills/domain-model/CONTEXT-FORMAT.md +47 -0
  54. package/.claude/skills/domain-model/SKILL.md +64 -0
  55. package/.claude/skills/domain-model/templates/data-model.md +29 -0
  56. package/.claude/skills/engineering-conventions/SKILL.md +31 -0
  57. package/.claude/skills/event-storming/SKILL.md +44 -0
  58. package/.claude/skills/event-storming/schema/events.schema.json +124 -0
  59. package/.claude/skills/event-storming/scripts/render-event-storming.ts +11 -0
  60. package/.claude/skills/event-storming/scripts/validate-events.ts +11 -0
  61. package/.claude/skills/event-storming/templates/events.example.yaml +91 -0
  62. package/.claude/skills/feature/SKILL.md +86 -0
  63. package/.claude/skills/feature/scripts/intake.ts +356 -0
  64. package/.claude/skills/grill-me/SKILL.md +7 -0
  65. package/.claude/skills/grill-with-docs/SKILL.md +7 -0
  66. package/.claude/skills/grilling/SKILL.md +30 -0
  67. package/.claude/skills/groom-backlog/SKILL.md +93 -0
  68. package/.claude/skills/groom-backlog/scripts/backlog-health.ts +238 -0
  69. package/.claude/skills/implement/SKILL.md +129 -0
  70. package/.claude/skills/implement/scripts/affected.ts +245 -0
  71. package/.claude/skills/implement/scripts/check-commands.ts +37 -0
  72. package/.claude/skills/implement/scripts/check-language.ts +15 -0
  73. package/.claude/skills/implement/scripts/check-scenarios.ts +59 -0
  74. package/.claude/skills/implement/scripts/next-story.ts +23 -0
  75. package/.claude/skills/implement/scripts/story-context.ts +135 -0
  76. package/.claude/skills/implement/scripts/story-status.ts +47 -0
  77. package/.claude/skills/implement/scripts/verify.ts +92 -0
  78. package/.claude/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  79. package/.claude/skills/improve-codebase-architecture/SKILL.md +71 -0
  80. package/.claude/skills/retro/SKILL.md +53 -0
  81. package/.claude/skills/review-stories/SKILL.md +31 -0
  82. package/.claude/skills/shape/SKILL.md +193 -0
  83. package/.claude/skills/tdd/SKILL.md +38 -0
  84. package/.claude/skills/tdd/mocking.md +59 -0
  85. package/.claude/skills/tdd/tests.md +77 -0
  86. package/.claude/skills/user-stories/SKILL.md +138 -0
  87. package/.claude/skills/user-stories/schema/story.schema.json +39 -0
  88. package/.claude/skills/user-stories/scripts/render-backlog.ts +4 -0
  89. package/.claude/skills/user-stories/scripts/validate-stories.ts +13 -0
  90. package/.claude/skills/user-stories/templates/story-template.md +38 -0
  91. package/.claude/skills/ux-design/SKILL.md +107 -0
  92. package/.claude/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  93. package/.claude/skills/writing-for-agents/SKILL.md +81 -0
  94. package/.claude/tsconfig.json +15 -0
  95. package/.opencode/agents/acceptance-tester.md +64 -0
  96. package/.opencode/agents/code-reviewer.md +69 -0
  97. package/.opencode/agents/domain-architect.md +59 -0
  98. package/.opencode/agents/lead-dev.md +67 -0
  99. package/.opencode/agents/product-owner.md +59 -0
  100. package/.opencode/agents/repo-analyst.md +86 -0
  101. package/.opencode/agents/requirements-engineer.md +58 -0
  102. package/.opencode/agents/ux-designer.md +83 -0
  103. package/.opencode/commands/adopt.md +7 -0
  104. package/.opencode/commands/backlog-sync.md +7 -0
  105. package/.opencode/commands/bootstrap.md +7 -0
  106. package/.opencode/commands/event-storming.md +7 -0
  107. package/.opencode/commands/feature.md +7 -0
  108. package/.opencode/commands/grill-me.md +7 -0
  109. package/.opencode/commands/grill-with-docs.md +7 -0
  110. package/.opencode/commands/groom-backlog.md +7 -0
  111. package/.opencode/commands/implement.md +7 -0
  112. package/.opencode/commands/improve-codebase-architecture.md +7 -0
  113. package/.opencode/commands/retro.md +7 -0
  114. package/.opencode/commands/review-stories.md +7 -0
  115. package/.opencode/commands/shape.md +7 -0
  116. package/.opencode/opencode.jsonc +15 -0
  117. package/.opencode/plugins/kataster/index.ts +283 -0
  118. package/AGENTS.md +21 -0
  119. package/CHANGELOG.md +82 -0
  120. package/LICENSE +21 -0
  121. package/README.md +324 -2
  122. package/bin/kataster.mjs +7 -0
  123. package/extras/skills/shadcn/SKILL.md +277 -0
  124. package/extras/skills/shadcn/agents/openai.yml +5 -0
  125. package/extras/skills/shadcn/assets/shadcn-small.png +0 -0
  126. package/extras/skills/shadcn/assets/shadcn.png +0 -0
  127. package/extras/skills/shadcn/cli.md +290 -0
  128. package/extras/skills/shadcn/customization.md +209 -0
  129. package/extras/skills/shadcn/evals/evals.json +77 -0
  130. package/extras/skills/shadcn/mcp.md +105 -0
  131. package/extras/skills/shadcn/registry.md +277 -0
  132. package/extras/skills/shadcn/rules/base-vs-radix.md +306 -0
  133. package/extras/skills/shadcn/rules/chat.md +250 -0
  134. package/extras/skills/shadcn/rules/composition.md +213 -0
  135. package/extras/skills/shadcn/rules/forms.md +192 -0
  136. package/extras/skills/shadcn/rules/icons.md +101 -0
  137. package/extras/skills/shadcn/rules/styling.md +185 -0
  138. package/guide/README.md +9 -0
  139. package/guide/brownfield.md +242 -0
  140. package/guide/concepts.md +109 -0
  141. package/guide/greenfield.md +84 -0
  142. package/guide/install.md +144 -0
  143. package/guide/release.md +62 -0
  144. package/package.json +56 -4
  145. package/src/cli.mjs +302 -0
  146. package/src/detect.mjs +237 -0
  147. package/src/install.mjs +427 -0
  148. package/src/repo.mjs +129 -0
  149. package/src/util.mjs +110 -0
  150. package/templates/CONTEXT.md +21 -0
  151. package/templates/conventions.md +63 -0
  152. package/templates/docs/adr/README.md +7 -0
  153. package/templates/docs/architecture/data-model.md +31 -0
  154. package/templates/docs/domain/context-map.md +21 -0
  155. package/templates/docs/domain/events.yaml +23 -0
  156. package/templates/docs/product/initiatives/README.md +41 -0
  157. package/templates/docs/product/ux-guidelines.md +27 -0
  158. package/templates/docs/product/vision.md +36 -0
  159. package/templates/docs/reviews/.gitkeep +0 -0
  160. package/templates/docs/stories/OPEN_QUESTIONS.md +8 -0
  161. package/templates/docs/stories/README.md +26 -0
  162. package/templates/docs/workflow.md +135 -0
@@ -0,0 +1,82 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "permissions": {
4
+ "allow": [
5
+ "Bash(node .claude/skills/adopt/scripts/*)",
6
+ "Bash(node .claude/skills/event-storming/scripts/validate-events.ts)",
7
+ "Bash(node .claude/skills/event-storming/scripts/render-event-storming.ts)",
8
+ "Bash(node .claude/skills/user-stories/scripts/validate-stories.ts)",
9
+ "Bash(node .claude/skills/user-stories/scripts/render-backlog.ts)",
10
+ "Bash(node .claude/skills/implement/scripts/*)",
11
+ "Bash(git status *)",
12
+ "Bash(git diff *)",
13
+ "Bash(git log *)"
14
+ ],
15
+ "deny": [],
16
+ "ask": []
17
+ },
18
+ "hooks": {
19
+ "SessionStart": [
20
+ {
21
+ "hooks": [
22
+ {
23
+ "type": "command",
24
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.ts\""
25
+ }
26
+ ]
27
+ }
28
+ ],
29
+ "PreToolUse": [
30
+ {
31
+ "matcher": "Write|Edit|MultiEdit",
32
+ "hooks": [
33
+ {
34
+ "type": "command",
35
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.ts\""
36
+ }
37
+ ]
38
+ },
39
+ {
40
+ "matcher": "Bash",
41
+ "hooks": [
42
+ {
43
+ "type": "command",
44
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/bash-guard.ts\""
45
+ }
46
+ ]
47
+ }
48
+ ],
49
+ "PostToolUse": [
50
+ {
51
+ "matcher": "Write|Edit|MultiEdit",
52
+ "hooks": [
53
+ {
54
+ "type": "command",
55
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/validate-docs.ts\""
56
+ },
57
+ {
58
+ "type": "command",
59
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/code-check.ts\"",
60
+ "timeout": 90
61
+ },
62
+ {
63
+ "type": "command",
64
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/project-check.ts\"",
65
+ "timeout": 60
66
+ }
67
+ ]
68
+ }
69
+ ],
70
+ "Stop": [
71
+ {
72
+ "hooks": [
73
+ {
74
+ "type": "command",
75
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/stop-gate.ts\"",
76
+ "timeout": 600
77
+ }
78
+ ]
79
+ }
80
+ ]
81
+ }
82
+ }
@@ -0,0 +1,283 @@
1
+ ---
2
+ name: adopt
3
+ description: Brownfield entry point – maps the repository, adopts it in slices (one domain plus at most one shared library), drafts the domain model with evidence, grills the user, documents each package where it lives and records the gap; it derives stories only when asked (--stories). Use when the workflow is dropped into a repository that already has code.
4
+ disable-model-invocation: true
5
+ argument-hint: "[scope, e.g. 'apps/billing' or 'the order process' – empty = map the repository and choose a slice; add --stories to derive stories now]"
6
+ ---
7
+
8
+ # Adopt an Existing Repository
9
+
10
+ The repository already works. Your job is to **recover the domain it encodes** – in slices, not by rewriting it
11
+ and not by documenting the whole monorepo in one pass. Code is evidence of decisions someone already made; the
12
+ user is the only one who can say which of the readings is the intended domain.
13
+
14
+ Scope: the arguments from the invocation (empty = map the repository and choose a slice). `--stories` is an
15
+ explicit opt-in for Phase 6; without it the adoption records the gap but creates no stories. Pick a short
16
+ kebab-case slug for the adoption (`adoption-<scope>`) for the report file.
17
+
18
+ ## Preconditions
19
+
20
+ 1. Read `.claude/project.json`. If it is missing, tell the user to run `npx kataster init` first and stop.
21
+ 2. If the repository has no code yet, this is the wrong command: use `/bootstrap`.
22
+ 3. Read what already exists, before analysing anything: `CONTEXT.md`, `docs/product/vision.md`,
23
+ `docs/domain/events.yaml`, `docs/domain/context-map.md`, `docs/architecture/data-model.md`,
24
+ `docs/architecture/repo-map.md`, `docs/engineering/conventions.md`, `docs/adr/`, `README*`, existing `docs/`
25
+ and any `AGENTS.md`/`CLAUDE.md`. Existing documentation is **primary evidence** – it outranks your inference
26
+ from code. Contradictions between docs and code are findings, not something to resolve silently.
27
+
28
+ ## Phase 0 – Repository map (deterministic, no questions)
29
+
30
+ Run:
31
+
32
+ ```bash
33
+ node .claude/skills/adopt/scripts/repo-map.ts
34
+ ```
35
+
36
+ It scans manifests and git history and writes:
37
+
38
+ - `docs/architecture/repo-map.json` – packages, paths, kinds, internal dependencies, consumers, adoption ranking,
39
+ and the build tool's own graph when it answers (Turbo, Nx, Bazel)
40
+ - `docs/architecture/repo-map.md` – the same as a readable map (never edit it by hand)
41
+ - the generated repository block in `AGENTS.md` – tooling, layout, commands, adopted slices
42
+ - `.claude/project.json` → `repo.tooling` – Nx, Turborepo, Bazel, pnpm/npm/yarn workspaces, Go, Cargo, Gradle, Maven
43
+
44
+ Read the map yourself. **Do not hand-scan the repository for packages**; if the map is stale, run it again.
45
+ The map is facts, not domain: it says where code lives and what depends on what, never what a word means.
46
+
47
+ ## Phase 1 – Choose the slice (one round, at most three questions)
48
+
49
+ The map suggests a first slice. Ask, each with a recommended answer:
50
+
51
+ 1. **Slice**: the suggested domain plus its most-used shared library, or a different one? Recommended: the
52
+ suggestion from `repo-map.md` – it weighs recent churn, fan-in and kind, not size.
53
+ 2. **Intent**: a domain model for future work, a map for onboarding, or a backlog for a rewrite? Recommended:
54
+ the domain model first; the other two follow from it.
55
+ 3. **Language**: confirm `languages.ui` and `languages.artifacts` from the profile. Recommended: what the code
56
+ and UI already use.
57
+
58
+ Hard rule: **one domain plus at most one shared library per session.** A simple repository without monorepo
59
+ tooling is one slice – then the whole repository is in scope. Never "the whole monorepo"; a shallow map of 80
60
+ packages is worse than a confirmed model of two.
61
+
62
+ Create `docs/domain/adoption-report.md` with the answers under `## Scope`; fill the rest as you go. If earlier
63
+ slices are already adopted, name the next one and what changed since it was adopted (`git log --since=<date>`).
64
+
65
+ ## Phase 2 – Evidence for the slice
66
+
67
+ Call the `skill` tool for `grilling`, `domain-model` and `architect` first: grilling sets how you ask,
68
+ domain-model sets what you are looking for, architect decides what becomes an ADR.
69
+
70
+ Dispatch `repo-analyst` subagents **in one message**, each with the slice path, the repository map path and one
71
+ lens. They are read-only.
72
+
73
+ - **Monorepo / several packages**: three analysts.
74
+ | Lens | What it looks for |
75
+ |---|---|
76
+ | Structure, data and entry points | Manifests, entry points, schema, migrations, enums, state columns, external services, jobs, the slice's internal dependencies and consumers |
77
+ | Language, behaviour and tests | Nouns and verbs in types, routes, UI texts, errors; handlers, validations, permissions; tests as executable specifications; candidate events/commands/read models |
78
+ | Architecture, dependencies and history | Layering and import direction from `repo-map.md`; build tooling and its graph; de-facto decisions in config; `git log` hotspots, reverted changes, TODOs |
79
+ - **Simple repository / no monorepo tooling**: the five lenses from the old adoption (structure and stack,
80
+ domain language, data and integrations, behaviour and tests, history and decisions) – the slice is the whole
81
+ repository.
82
+
83
+ While they run, read the repository's own documentation yourself. Do not block the round on the analysts.
84
+
85
+ ## Phase 3 – Draft the slice
86
+
87
+ Merge the reports into one picture. Write the artifacts **as a draft**, every uncertain statement marked.
88
+
89
+ - **`CONTEXT.md`** – only the slice's terms, grouped by guessed bounded context, competing spellings under
90
+ `_Avoid_`, `[OPEN]` where the meaning is unclear. Do not touch terms of other slices.
91
+ - **`docs/domain/events.yaml`** – 10–25 candidate events/commands/actors/read models/policies/flows for this
92
+ slice. Every uncertainty becomes a hotspot (`HS-n`, `status: open`).
93
+ - **`docs/domain/context-map.md`** – the boundaries the module structure suggests, marked as a proposal.
94
+ - **`docs/architecture/data-model.md`** – the **as-is** model for the slice, derived from schema and code.
95
+ - **`docs/engineering/conventions.md`** – fill what the slice actually does: module layout, how a command runs,
96
+ read models, "now", texts, test data, seam catalog. Include how the monorepo tooling is used.
97
+ - **`docs/product/vision.md`** – only if missing or empty, reconstruct and mark `[OPEN]`.
98
+ - **`docs/adr/`** – de-facto decisions worth recording, `status: proposed`. Only the user accepts.
99
+ - **Package docs** – for the domain and the shared library (in a monorepo):
100
+ ```bash
101
+ node .claude/skills/adopt/scripts/package-doc.ts apps/billing
102
+ node .claude/skills/adopt/scripts/package-doc.ts libs/shared-kernel
103
+ ```
104
+ A single-package repository has no package file: its root `AGENTS.md` is the package doc (`package-doc.ts .`
105
+ deliberately refuses). The script writes `<package>/AGENTS.md` (source of truth) and `<package>/CLAUDE.md`
106
+ (`@AGENTS.md`, for Claude Code's on-demand nested loading). It generates the facts block; **you** fill the prose
107
+ during the grilling:
108
+ - domain/service: Purpose, Key entities, External interfaces, Typical pitfalls, Boundaries
109
+ - shared library: Purpose, Public API, Consumers, Compatibility rules, Typical pitfalls, Boundaries
110
+ Keep each file under ~80 lines. This file is loaded only when someone works in that package.
111
+ - **Root `AGENTS.md`** – the generated block comes from the map. Below it, add only structure, commands, hard
112
+ conventions and links. Keep at most ten bullets under `## Hard conventions`, each naming where it is enforced
113
+ (`lint`, a test, `.claude/rules/<file>.md`, `docs/engineering/checks.yaml`) – a rule without an enforcement
114
+ point is a wish. **No domain rules, no entities, no business vocabulary** – those belong in `CONTEXT.md` and
115
+ the package docs.
116
+ - **`.claude/rules/`** – only for path-scoped rules that cannot be a directory document (e.g. `**/*.sql`,
117
+ `**/migrations/**`), with `paths:` frontmatter. Directory-scoped rules belong in `<dir>/AGENTS.md` because that
118
+ is the mechanism both harnesses load on demand. A rule for a whole group gets `<group>/AGENTS.md` plus a
119
+ one-line `<group>/CLAUDE.md` (`@AGENTS.md`) – e.g. `libs/AGENTS.md` for "everything under `libs/**`". Never
120
+ duplicate the same rule in both mechanisms.
121
+
122
+ After every write of `events.yaml`, the hook validates and renders it. Fix errors immediately.
123
+
124
+ ### Rules for the draft
125
+
126
+ - A code name is a *spelling*, never automatically the domain term. `OrderService.place()` is evidence for
127
+ "Order placed", not proof of the word "order".
128
+ - One concept with three spellings → one candidate term and two `_Avoid_` entries, or a hotspot.
129
+ - Never invent a business rule. If the code enforces something, report it as "the code enforces X (path)"; the
130
+ user decides whether that is a rule or an accident.
131
+ - If the repository contradicts itself, that is a hotspot, not a choice you make.
132
+
133
+ ## Phase 4 – Grill the user against the draft
134
+
135
+ This is the core of the adoption. Present the draft, then work the frontier in rounds exactly as the `grilling`
136
+ skill says: numbered questions, each with a recommended answer, whole frontier per round.
137
+
138
+ Questions brownfield needs, roughly in this order:
139
+
140
+ 1. **Terms** – one question per cluster of competing spellings, worst first.
141
+ 2. **Boundaries** – which package owns which state; where a shared library ends and a domain begins.
142
+ 3. **Lifecycle** – states the schema allows, transitions it does not block.
143
+ 4. **Invariants** – what the code checks only in the UI; what must always hold.
144
+ 5. **Missing behaviour** – what has no trace: never needed, or a gap?
145
+ 6. **Architecture** – layering, CQRS/read models, dependency direction, cross-context communication. Which are
146
+ real decisions and which are accidents? Record the real ones as ADRs.
147
+ 7. **Build tooling** – how packages are built, tested and filtered; whether affected tests are trustworthy.
148
+ 8. **Shared libraries** – public API, consumers, what may not break without a migration.
149
+ 9. **Intent** – which of this is deliberate, and which is legacy you want to leave behind.
150
+
151
+ Every answer updates the draft **immediately**: `CONTEXT.md`, `events.yaml`, the package's `AGENTS.md`, the ADR.
152
+ Resolved hotspots get `status: resolved` + `resolution`. New uncertainty becomes a new hotspot. Do not move on
153
+ until the frontier is empty and the user confirms a shared understanding.
154
+
155
+ ## Phase 5 – Safety net: make the confirmed rules checkable
156
+
157
+ For every confirmed hard rule or invariant, choose the cheapest deterministic enforcement – in this order:
158
+
159
+ 1. **Type system** (a state that cannot be represented cannot be written)
160
+ 2. **Lint / boundary check** (import direction, layer, package visibility – dependency-cruiser, Nx module
161
+ boundaries, Bazel visibility, ArchUnit, import-linter)
162
+ 3. **Architecture or characterization test** (a test pins the rule or the existing behaviour)
163
+ 4. **Hook** (only for fast, edit-time checks; full checks belong in Stop/CI)
164
+ 5. **Documentation only** (when nothing can check it)
165
+
166
+ What you may create here:
167
+
168
+ - 3–5 **characterization tests** for the slice's most important existing behaviour – they pin what is, they do
169
+ not assert what should be.
170
+ - The architecture boundaries and checks:
171
+ ```bash
172
+ node .claude/skills/adopt/scripts/boundary-check.ts --init
173
+ # edit docs/architecture/boundaries.yaml with the rules the user confirmed, then
174
+ node .claude/skills/adopt/scripts/boundary-check.ts --update-baseline
175
+ ```
176
+ Run `--init` on the first slice only; later slices extend the existing `boundaries.yaml`. It writes a proposal
177
+ for `docs/architecture/boundaries.yaml`, the default `docs/engineering/checks.yaml` and an empty baseline.
178
+ Rules are evaluated in order; the first matching `from` → `to` pair decides (no match = allow). The engine is
179
+ `scan` for JS/TS imports, or `command` for the project's own tool (dependency-cruiser, Nx module boundaries,
180
+ Bazel, ArchUnit, import-linter).
181
+ - `.claude/rules/` entries for confirmed rules that a directory cannot express:
182
+ ```bash
183
+ node .claude/skills/adopt/scripts/rule-doc.ts libs-shared --paths "libs/**" --title "Shared libraries"
184
+ ```
185
+ A rule for a whole directory belongs in `<dir>/AGENTS.md` instead; do not duplicate it in both mechanisms.
186
+ - `docs/engineering/checks.yaml` entries with `phase: edit` (fast, changed file only) or `phase: stop` (full set).
187
+
188
+ What you may **not** do: change production code, or write a test that fails on existing behaviour. On a
189
+ brownfield repository the checks are **report-only first**: record existing violations in a baseline, then let
190
+ only new violations fail (ratchet). A hook that is red on day one gets switched off.
191
+
192
+ Hooks are wired once, through the `project-check.ts` dispatcher reading `docs/engineering/checks.yaml`, not by
193
+ adding per-package hook entries to `.claude/settings.json`. Keep edit-time checks fast; the full set runs at
194
+ Stop/CI. If a rule needs new behaviour, it becomes a story – not a failing test.
195
+
196
+ ## Phase 6 – The gap register (stories only on request)
197
+
198
+ Compare the confirmed model with the code. Classify, and show the table to the user:
199
+
200
+ | Class | Meaning | Default |
201
+ |---|---|---|
202
+ | **Exists and is intended** | Code matches the confirmed model | Documented in the data model/context map. No action. |
203
+ | **Exists but contradicts the model** | Code does something the user says is wrong | Candidate in the gap register |
204
+ | **Missing** | The model needs it, the code has no trace | Candidate in the gap register |
205
+ | **Dead** | Code has no place in the model | Candidate: removal or an explicit "leave it" |
206
+
207
+ **The default is no stories.** The first adoption pass is about understanding the repo, not about filling a
208
+ backlog. Write the table into `docs/domain/adoption-report.md`; open questions go into
209
+ `docs/stories/OPEN_QUESTIONS.md` or a hotspot. This keeps the model reviewable without committing to work the
210
+ user has not prioritised.
211
+
212
+ Only when the invocation contains `--stories`, or the user explicitly asks after seeing the table:
213
+
214
+ - delegate to `requirements-engineer` with the **selected** gaps only, the confirmed IDs from `events.yaml`, the
215
+ label `adoption:<slug>`, and `ui` for stories with a frontend part;
216
+ - new stories start as `status: draft`; the ones the user wants first go through `/review-stories`.
217
+
218
+ **Do not write stories for behaviour that already works** – that turns the backlog into a description of the
219
+ past. Existing behaviour is covered by its tests, and the domain model is the map. If an earlier run created
220
+ stories the user does not want, do not delete them silently: ask whether to `supersede` them or keep them.
221
+
222
+ ## Phase 7 – Report and the next slice
223
+
224
+ Write `docs/domain/adoption-report.md`:
225
+
226
+ ```md
227
+ # Adoption – <scope>
228
+ Date: YYYY-MM-DD · Commit: <sha> · Slice: <paths> · Analysts: <n> lenses
229
+
230
+ ## Scope and intent
231
+ ## Repository map (tooling, packages, why this slice)
232
+ ## What the repository is (facts)
233
+ ## Confirmed domain model
234
+ - contexts, aggregates, glossary changes
235
+ ## Package documentation written
236
+ - <path>/AGENTS.md + CLAUDE.md – what was confirmed and what stays [OPEN]
237
+ ## Contradictions found and how they were resolved
238
+ ## Rules and checks
239
+ - rule → enforcement (type / lint / test / hook / doc) → baseline or green
240
+ ## Gap register (candidates – stories only with --stories)
241
+ ## Deliberately left alone
242
+ ## Open hotspots
243
+ ## Next slice
244
+ ```
245
+
246
+ Mark the slice adopted so the next session sees the progress:
247
+
248
+ ```bash
249
+ node .claude/skills/adopt/scripts/repo-map.ts --adopt apps/billing
250
+ ```
251
+
252
+ Then run `node .claude/skills/event-storming/scripts/validate-events.ts` and
253
+ `node .claude/skills/user-stories/scripts/validate-stories.ts`, and show the result.
254
+
255
+ ## Wrap-up
256
+
257
+ Summarize in a few lines: terms added, contexts/aggregates proposed, hotspots open, package docs written,
258
+ checks created, gap candidates (and stories only if requested), ADRs proposed. Then name the next step:
259
+
260
+ - `git diff` is the review: no production code changed, only docs, package docs and tooling.
261
+ - `/adopt <next path>` for the next slice.
262
+ - `/feature <idea>` for the next piece of work, now that the domain has a language.
263
+ - `/adopt <scope> --stories` (or `/review-stories` if stories already exist) when the user wants the gap turned
264
+ into a backlog.
265
+ - `/implement` once a story is `ready`.
266
+
267
+ ## Rules
268
+
269
+ - **Never change production code in `/adopt`.** Tests and tooling are allowed only as the safety net above.
270
+ - **Never present an inference as a fact.** Confidence and evidence, or a hotspot.
271
+ - **The user owns the language.** You may propose a better word; you may not rename the domain on your own.
272
+ - **Adopt in slices.** One domain plus at most one shared library. Never the whole monorepo in one pass.
273
+ - **The root `AGENTS.md` stays free of domain.** Structure, commands, hard conventions and links only.
274
+ - **Package docs are short and on demand.** `<package>/AGENTS.md` + `<package>/CLAUDE.md`, under ~80 lines.
275
+ - **Directory docs before glob rules.** `.claude/rules/` is for patterns a directory cannot express. Both
276
+ harnesses see the same file: Claude Code scopes it natively by `paths:`, OpenCode's plugin attaches it when a
277
+ matching file is read or written. Directory-scoped rules still belong in `<dir>/AGENTS.md`.
278
+ - **No backlog by default.** Adoption produces the model and a gap register; stories are an explicit second step
279
+ (`--stories`) after the user has prioritised.
280
+ - **Checks are green on day one.** Baseline existing violations, ratchet new ones; no red hook.
281
+ - **The map is generated.** Never hand-edit `repo-map.json`/`repo-map.md` or the generated blocks.
282
+ - **Stop when the frontier is empty.** A model that is 80% confirmed and 20% hotspot is more useful than one
283
+ that is 100% invented.
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Architecture boundary check with baseline/ratchet.
3
+ *
4
+ * node .claude/skills/adopt/scripts/boundary-check.ts --init
5
+ * node .claude/skills/adopt/scripts/boundary-check.ts
6
+ * node .claude/skills/adopt/scripts/boundary-check.ts --changed [file]
7
+ * node .claude/skills/adopt/scripts/boundary-check.ts --update-baseline
8
+ * node .claude/skills/adopt/scripts/boundary-check.ts --json
9
+ *
10
+ * `--init` writes a proposal for `docs/architecture/boundaries.yaml`, the default `docs/engineering/checks.yaml`
11
+ * and an empty baseline. The user confirms the rules during /adopt; `--update-baseline` freezes violations that
12
+ * already exist, so only new ones fail.
13
+ */
14
+ import { existsSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ import {
17
+ BOUNDARIES_FILE, BASELINE_FILE, CHECKS_FILE, adapterHints, baselineFrom, checkBoundaries, defaultChecks, defaultRules,
18
+ emptyBaseline, evaluateBaseline, formatViolation, loadBaseline, loadBoundaries, relPath, rootMap,
19
+ writeBaseline, writeBoundaries, writeChecks,
20
+ } from "../../../lib/architecture.ts";
21
+ import { ROOT } from "../../../lib/repo.ts";
22
+
23
+ const args = process.argv.slice(2);
24
+ const help = args.includes("--help") || args.includes("-h");
25
+ const init = args.includes("--init");
26
+ const update = args.includes("--update-baseline");
27
+ const json = args.includes("--json");
28
+
29
+ function usage(): void {
30
+ console.log(
31
+ [
32
+ "Usage: node .claude/skills/adopt/scripts/boundary-check.ts [options]",
33
+ "",
34
+ " --init write a boundaries.yaml proposal, checks.yaml and an empty baseline",
35
+ " --force with --init: overwrite existing files",
36
+ " --changed [file] check only this file (or $CHANGED_FILE, used by the edit hook)",
37
+ " --update-baseline freeze current violations so only new ones fail",
38
+ " --json machine-readable result",
39
+ ].join("\n"),
40
+ );
41
+ }
42
+
43
+ if (help) {
44
+ usage();
45
+ process.exit(0);
46
+ }
47
+
48
+ try {
49
+ if (init) {
50
+ const map = rootMap(ROOT);
51
+ const force = args.includes("--force");
52
+ if (!force) {
53
+ for (const file of [BOUNDARIES_FILE, CHECKS_FILE, BASELINE_FILE]) {
54
+ if (existsSync(join(ROOT, file))) throw new Error(`${file} already exists – edit it, or pass --force`);
55
+ }
56
+ }
57
+ const boundaries = { version: 1 as const, engine: "auto" as const, command: "", rules: defaultRules(map) };
58
+ const boundariesPath = writeBoundaries(ROOT, boundaries, force);
59
+ const checksPath = writeChecks(ROOT, { version: 1, checks: defaultChecks() }, force);
60
+ const baselinePath = writeBaseline(ROOT, emptyBaseline());
61
+ console.log(`Wrote ${relPath(ROOT, boundariesPath)} with ${boundaries.rules.length} proposed rule(s).`);
62
+ console.log(`Wrote ${relPath(ROOT, checksPath)} and ${relPath(ROOT, baselinePath)}.`);
63
+ if (!boundaries.rules.length) {
64
+ console.log("No apps/, services/, libs/ or packages/ directories were found – add the rules by hand.");
65
+ }
66
+ for (const hint of adapterHints(map)) console.log(`Hint: ${hint}`);
67
+ console.log("Review and confirm the rules with the user, then freeze existing violations:");
68
+ console.log(" node .claude/skills/adopt/scripts/boundary-check.ts --update-baseline");
69
+ process.exit(0);
70
+ }
71
+
72
+ const changedIndex = args.indexOf("--changed");
73
+ const changedArg = changedIndex === -1 ? undefined : args[changedIndex + 1];
74
+ const changed = changedIndex === -1
75
+ ? undefined
76
+ : changedArg && !changedArg.startsWith("--")
77
+ ? relPath(ROOT, changedArg)
78
+ : process.env.CHANGED_FILE
79
+ ? relPath(ROOT, process.env.CHANGED_FILE)
80
+ : undefined;
81
+
82
+ if (update && changed) {
83
+ console.error("--update-baseline must run without --changed – freezing a single file would drop the rest.");
84
+ process.exit(1);
85
+ }
86
+
87
+ const boundaries = loadBoundaries(ROOT);
88
+ if (!boundaries) {
89
+ console.log(`No ${BOUNDARIES_FILE} – architecture boundaries are not configured yet.`);
90
+ console.log("Run `node .claude/skills/adopt/scripts/boundary-check.ts --init` during /adopt.");
91
+ process.exit(0);
92
+ }
93
+
94
+ if (!boundaries.rules.length && boundaries.engine !== "command") {
95
+ console.log("No boundary rules configured – nothing to check.");
96
+ process.exit(0);
97
+ }
98
+
99
+ const map = rootMap(ROOT);
100
+ const result = checkBoundaries(ROOT, boundaries, map, changed);
101
+
102
+ if (update) {
103
+ const path = writeBaseline(ROOT, baselineFrom(result));
104
+ const command = result.command ? ` and the command failure` : "";
105
+ console.log(`Baseline written to ${relPath(ROOT, path)}: ${result.violations.length} violation(s)${command} frozen.`);
106
+ process.exit(0);
107
+ }
108
+
109
+ const report = evaluateBaseline(result, loadBaseline(ROOT));
110
+
111
+ if (json) {
112
+ console.log(JSON.stringify({
113
+ ok: report.ok,
114
+ engine: report.engine,
115
+ checked: report.checked,
116
+ violations: report.violations.length,
117
+ new: report.newViolations,
118
+ stale: report.stale,
119
+ command: report.command ? { name: report.command.name, baselined: report.commandBaselined, output: report.command.output } : undefined,
120
+ note: report.note,
121
+ }, null, 2));
122
+ process.exit(report.ok ? 0 : 1);
123
+ }
124
+
125
+ if (report.note) console.log(report.note);
126
+ const unit = report.engine === "scan" ? "import edge(s)" : "check(s)";
127
+ console.log(`Architecture boundaries (${report.engine}): ${report.checked} ${unit}, ${report.violations.length} violation(s).`);
128
+
129
+ if (report.command && !report.commandBaselined) {
130
+ console.error(`\nThe architecture command failed (not baselined):\n${report.command.output}`);
131
+ process.exit(1);
132
+ }
133
+
134
+ if (report.newViolations.length) {
135
+ const shown = report.newViolations.slice(0, 50);
136
+ console.error(`\nNew boundary violations – fix them or, if they are existing debt, freeze them with --update-baseline:\n${shown.map(formatViolation).join("\n")}`);
137
+ if (report.newViolations.length > shown.length) {
138
+ console.error(`… and ${report.newViolations.length - shown.length} more (see --json).`);
139
+ }
140
+ process.exit(1);
141
+ }
142
+
143
+ if (report.violations.length) {
144
+ console.log(`${report.violations.length} baselined violation(s) – existing debt, not failing.`);
145
+ }
146
+ if (report.stale.length) {
147
+ console.log(`${report.stale.length} baseline entr${report.stale.length === 1 ? "y" : "ies"} no longer occur – update the baseline to tighten the ratchet.`);
148
+ }
149
+ if (report.command && report.commandBaselined) {
150
+ console.log("The architecture command failure is baselined.");
151
+ }
152
+ console.log("OK – no new boundary violations.");
153
+ } catch (error) {
154
+ console.error(error instanceof Error ? error.message : String(error));
155
+ process.exit(1);
156
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Writes or refreshes the per-package documentation that is loaded only when an agent works in that package.
3
+ *
4
+ * node .claude/skills/adopt/scripts/package-doc.ts apps/billing
5
+ * node .claude/skills/adopt/scripts/package-doc.ts apps/billing --adopt
6
+ *
7
+ * It creates `<package>/AGENTS.md` (source of truth) and `<package>/CLAUDE.md` (`@AGENTS.md` for Claude Code).
8
+ * The generated Facts block is refreshed on every run; the prose sections (Purpose, Key entities, External
9
+ * interfaces, Typical pitfalls, Boundaries) are never touched. If an existing AGENTS.md has no generated
10
+ * markers, the script leaves it alone and says so.
11
+ */
12
+ import {
13
+ ROOT, findPackage, markAdopted, readRepoMap, scanRepo, updateProjectTooling, writePackageDoc, writeRepoMap, writeRootBlock,
14
+ } from "../../../lib/repo.ts";
15
+
16
+ const args = process.argv.slice(2).filter((arg) => !arg.startsWith("--"));
17
+ const adopt = process.argv.includes("--adopt");
18
+ const path = args[0];
19
+
20
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
21
+ console.log("Usage: node .claude/skills/adopt/scripts/package-doc.ts <package-path> [--adopt]");
22
+ process.exit(0);
23
+ }
24
+ if (!path) {
25
+ console.error("Usage: node .claude/skills/adopt/scripts/package-doc.ts <package-path> [--adopt]");
26
+ process.exit(1);
27
+ }
28
+
29
+ try {
30
+ if (path === "." || path === "./" || path === "") {
31
+ console.error("The root package is documented in AGENTS.md, not in a package file.");
32
+ process.exit(1);
33
+ }
34
+
35
+ let map = readRepoMap(ROOT);
36
+ if (!map) {
37
+ map = scanRepo(ROOT);
38
+ writeRepoMap(ROOT, map);
39
+ updateProjectTooling(ROOT, map.tooling);
40
+ writeRootBlock(ROOT, map);
41
+ console.log("Wrote docs/architecture/repo-map.json and the root AGENTS.md block first (they were missing).");
42
+ }
43
+
44
+ const pkg = findPackage(map, path);
45
+ if (!pkg) {
46
+ const available = map.packages.map((p) => p.path).slice(0, 25).join(", ");
47
+ console.error(`Package '${path}' is not in the repository map. Known packages: ${available}${map.packages.length > 25 ? ", …" : ""}`);
48
+ process.exit(1);
49
+ }
50
+
51
+ const result = writePackageDoc(ROOT, map, pkg);
52
+ const agentsRel = result.agents.replace(`${ROOT}/`, "");
53
+ const claudeRel = result.claude.replace(`${ROOT}/`, "");
54
+
55
+ if (result.status === "created") {
56
+ console.log(`Created ${agentsRel} and ${claudeRel}`);
57
+ console.log("Fill the [OPEN] sections in AGENTS.md during the grilling – do not invent domain meaning.");
58
+ } else if (result.status === "refreshed") {
59
+ console.log(`Refreshed the generated block in ${agentsRel}`);
60
+ } else {
61
+ console.log(`Kept ${agentsRel}: it has no generated markers, so it is treated as hand-written.`);
62
+ }
63
+
64
+ if (adopt) {
65
+ markAdopted(ROOT, pkg.path);
66
+ console.log(`Marked adopted: ${pkg.path}`);
67
+ }
68
+ } catch (error) {
69
+ console.error(error instanceof Error ? error.message : String(error));
70
+ process.exit(1);
71
+ }