forgecraft-mcp 1.7.0 → 1.8.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 (52) hide show
  1. package/README.md +79 -0
  2. package/dist/registry/remote-gates.d.ts +16 -0
  3. package/dist/registry/remote-gates.d.ts.map +1 -1
  4. package/dist/registry/remote-gates.js +56 -0
  5. package/dist/registry/remote-gates.js.map +1 -1
  6. package/dist/registry/sentinel-domain-map.d.ts.map +1 -1
  7. package/dist/registry/sentinel-domain-map.js +16 -9
  8. package/dist/registry/sentinel-domain-map.js.map +1 -1
  9. package/dist/registry/sentinel-renderer.d.ts +13 -8
  10. package/dist/registry/sentinel-renderer.d.ts.map +1 -1
  11. package/dist/registry/sentinel-renderer.js +440 -162
  12. package/dist/registry/sentinel-renderer.js.map +1 -1
  13. package/dist/shared/harness-budget.d.ts +49 -0
  14. package/dist/shared/harness-budget.d.ts.map +1 -0
  15. package/dist/shared/harness-budget.js +123 -0
  16. package/dist/shared/harness-budget.js.map +1 -0
  17. package/dist/shared/hook-installer.d.ts.map +1 -1
  18. package/dist/shared/hook-installer.js +2 -1
  19. package/dist/shared/hook-installer.js.map +1 -1
  20. package/dist/tools/close-cycle-helpers.d.ts +9 -0
  21. package/dist/tools/close-cycle-helpers.d.ts.map +1 -1
  22. package/dist/tools/close-cycle-helpers.js.map +1 -1
  23. package/dist/tools/close-cycle.d.ts.map +1 -1
  24. package/dist/tools/close-cycle.js +29 -0
  25. package/dist/tools/close-cycle.js.map +1 -1
  26. package/dist/tools/contribute-gate.d.ts +30 -4
  27. package/dist/tools/contribute-gate.d.ts.map +1 -1
  28. package/dist/tools/contribute-gate.js +180 -66
  29. package/dist/tools/contribute-gate.js.map +1 -1
  30. package/dist/tools/gate-genesis.d.ts +47 -0
  31. package/dist/tools/gate-genesis.d.ts.map +1 -0
  32. package/dist/tools/gate-genesis.js +241 -0
  33. package/dist/tools/gate-genesis.js.map +1 -0
  34. package/dist/tools/learning-graph.d.ts +31 -0
  35. package/dist/tools/learning-graph.d.ts.map +1 -0
  36. package/dist/tools/learning-graph.js +266 -0
  37. package/dist/tools/learning-graph.js.map +1 -0
  38. package/dist/tools/setup-artifact-writers.d.ts +15 -3
  39. package/dist/tools/setup-artifact-writers.d.ts.map +1 -1
  40. package/dist/tools/setup-artifact-writers.js +149 -13
  41. package/dist/tools/setup-artifact-writers.js.map +1 -1
  42. package/dist/tools/setup-phase2.d.ts +9 -0
  43. package/dist/tools/setup-phase2.d.ts.map +1 -1
  44. package/dist/tools/setup-phase2.js +13 -0
  45. package/dist/tools/setup-phase2.js.map +1 -1
  46. package/dist/tools/setup-project.d.ts +6 -0
  47. package/dist/tools/setup-project.d.ts.map +1 -1
  48. package/dist/tools/setup-project.js +21 -4
  49. package/dist/tools/setup-project.js.map +1 -1
  50. package/package.json +99 -98
  51. package/templates/api/instructions.yaml +50 -188
  52. package/templates/universal/instructions.yaml +194 -1003
@@ -1,18 +1,23 @@
1
1
  /**
2
2
  * Sentinel tree renderer.
3
3
  *
4
- * Instead of one large instruction file, renders a 3-level lazy tree:
5
- * Level 0: CLAUDE.md (~50 lines) — project identity + critical rules + wayfinding
6
- * Level 1: .claude/standards/{domain}.md — full block content per domain
4
+ * Generates a multi-file Contextual Navigation Tree (CNT):
7
5
  *
8
- * The AI loads only what the current task requires.
9
- * Typical task: CLAUDE.md (~50 lines) + 1-2 domain files (50-100 lines each).
10
- * vs monolithic: 800-2000+ lines loaded regardless of task.
6
+ * CLAUDE.md — root (≤80 lines): project identity + routing only
7
+ * .claude/constitution.md non-negotiables: SOLID, invariants, prohibited ops
8
+ * .claude/lifecycle.md — GS cascade, feature estimation, tool sequencing, session loop
9
+ * .claude/routes/code.md — where code lives: folder map, naming, module protocol
10
+ * .claude/routes/docs.md — where docs live: nav mode, doc map, reading order
11
+ * .claude/corrections.md — corrections log stub (read before acting)
12
+ * .claude/standards/{domain} — full domain standards (loaded only when relevant)
11
13
  *
12
- * Only applies to the "claude" target other AI assistants receive the full file
13
- * since they do not support multi-file on-demand loading the same way.
14
+ * The root CLAUDE.md is the routing layer. It loads the always-load files and tells
15
+ * the AI exactly which branch to load for each task type. No branch is loaded unless
16
+ * relevant — this is how the CNT prevents context window degradation.
17
+ *
18
+ * Only applies to the "claude" target — other AI assistants receive the full file.
14
19
  */
15
- import { renderTemplate } from "./renderer.js";
20
+ import { renderTemplate, compactifyContent } from "./renderer.js";
16
21
  import { BLOCK_DOMAIN_MAP, DOMAIN_DESCRIPTIONS, DOMAIN_ORDER, } from "./sentinel-domain-map.js";
17
22
  // ── Public API ────────────────────────────────────────────────────────
18
23
  /**
@@ -34,6 +39,16 @@ export function renderSentinelTree(blocks, context) {
34
39
  for (const [domain, domainBlocks] of byDomain) {
35
40
  if (domainBlocks.length === 0)
36
41
  continue;
42
+ // "reference" domain: GS theory — written outside the session-loaded tree.
43
+ // Background reading for humans; the routing table never points here.
44
+ // This is the harness-budget defense: theory must not displace the task.
45
+ if (domain === "reference") {
46
+ files.push({
47
+ relativePath: ".claude/reference/gs-theory.md",
48
+ content: renderReferenceFile(domainBlocks, context),
49
+ });
50
+ continue;
51
+ }
37
52
  const content = renderDomainFile(domain, domainBlocks, context);
38
53
  files.push({ relativePath: `.claude/standards/${domain}.md`, content });
39
54
  const description = DOMAIN_DESCRIPTIONS[domain] ?? domain;
@@ -42,10 +57,31 @@ export function renderSentinelTree(blocks, context) {
42
57
  // Sort domains for consistent wayfinding table order
43
58
  domainsWithContent.sort((a, b) => (DOMAIN_ORDER.indexOf(a.domain) ?? 99) -
44
59
  (DOMAIN_ORDER.indexOf(b.domain) ?? 99));
45
- // Generate sentinel CLAUDE.md (prepend so it's first in the list)
60
+ // Generate CNT branch files
61
+ files.push({
62
+ relativePath: ".claude/constitution.md",
63
+ content: buildConstitutionFile(context),
64
+ });
65
+ files.push({
66
+ relativePath: ".claude/lifecycle.md",
67
+ content: buildLifecycleFile(context),
68
+ });
69
+ files.push({
70
+ relativePath: ".claude/routes/code.md",
71
+ content: buildCodeRoutesFile(context),
72
+ });
73
+ files.push({
74
+ relativePath: ".claude/routes/docs.md",
75
+ content: buildDocsRoutesFile(context),
76
+ });
77
+ files.push({
78
+ relativePath: ".claude/corrections.md",
79
+ content: buildCorrectionsFile(),
80
+ });
81
+ // Generate slim root CLAUDE.md (prepend so it's first in the list)
46
82
  files.unshift({
47
83
  relativePath: "CLAUDE.md",
48
- content: renderSentinelClaudeMd(domainsWithContent, context),
84
+ content: buildRootClaudeMd(domainsWithContent, context),
49
85
  });
50
86
  return files;
51
87
  }
@@ -64,6 +100,28 @@ function groupBlocksByDomain(blocks) {
64
100
  }
65
101
  return map;
66
102
  }
103
+ /**
104
+ * Render the reference file — GS theory kept OUT of session context.
105
+ * Header explicitly tells the AI not to load this during work.
106
+ */
107
+ function renderReferenceFile(blocks, context) {
108
+ const date = new Date().toISOString().split("T")[0];
109
+ const lines = [
110
+ `<!-- ForgeCraft reference: GS theory | ${date} -->`,
111
+ `<!-- DO NOT load this file during implementation sessions. -->`,
112
+ `<!-- It is background reading on the methodology. The operational rules`,
113
+ ` derived from it live in CLAUDE.md, .claude/constitution.md, and`,
114
+ ` .claude/lifecycle.md — those are the session-loaded contracts. -->`,
115
+ "",
116
+ ];
117
+ for (const block of blocks) {
118
+ const rendered = renderTemplate(block.content, context).trim();
119
+ if (rendered) {
120
+ lines.push(rendered, "");
121
+ }
122
+ }
123
+ return lines.join("\n");
124
+ }
67
125
  /**
68
126
  * Render a single domain standards file.
69
127
  * Contains full rendered block content for all blocks in that domain.
@@ -86,34 +144,56 @@ function renderDomainFile(domain, blocks, context) {
86
144
  lines.push("");
87
145
  }
88
146
  }
89
- return lines.join("\n");
147
+ // Compact by default: strip explanatory tails, dedupe bullets, compress
148
+ // blanks. Session-loaded files must be rules, not lectures — every line of
149
+ // explanation displaces task context (harness budget).
150
+ return compactifyContent(lines.join("\n"));
90
151
  }
152
+ // ── CNT root ──────────────────────────────────────────────────────────
91
153
  /**
92
- * Render the comprehensive CLAUDE.md sentinel (~130 lines).
93
- *
94
- * Contains all GS invariants, architecture, code standards, testing protocol,
95
- * commit protocol, prohibited ops, reading map, and session loop invariant.
96
- * This is the primary always-loaded file for every AI session.
97
- *
98
- * @param _domains - Domains with standards files (for wayfinding footer)
99
- * @param context - Render context
100
- * @returns Comprehensive CLAUDE.md content ready to write
154
+ * Build the slim CNT root CLAUDE.md (≤80 lines).
155
+ * Contains only: project identity, always-load list, routing table, doc obligation table.
156
+ * All content lives in branch files this is routing only.
101
157
  */
102
- function renderSentinelClaudeMd(_domains, context) {
158
+ function buildRootClaudeMd(_domains, context) {
103
159
  const date = new Date().toISOString().split("T")[0];
104
160
  const tagList = context.tags.filter((t) => t !== "UNIVERSAL").join(", ") || "UNIVERSAL";
105
- const stackLine = inferStackFromTags(context.tags);
106
- const layerDiagram = buildLayerDiagram(context.tags);
107
- const folderMap = buildFolderMap(context.tags);
161
+ const stackLine = inferStackFromTags(context.tags, context.language);
108
162
  return [
109
163
  `# ${context.projectName} — Architecture Sentinel`,
110
- `<!-- ForgeCraft sentinel | ${date} | npx forgecraft-mcp refresh . --apply to update -->`,
164
+ `<!-- ForgeCraft CNT root | ${date} | npx forgecraft-mcp refresh . --apply to regenerate -->`,
165
+ ``,
166
+ `> **CNT root** — loaded every session, routing only (≤80 lines).`,
167
+ `> Always load the files below, then navigate to the relevant branch.`,
168
+ `> If anything contradicts \`docs/PRD.md\`, PRD wins. Raise an ADR to change course.`,
169
+ ``,
170
+ `## Context Discipline (the prime directive)`,
111
171
  ``,
112
- `> Sentinel of architecture read automatically every session. Contains inviolable rules.`,
113
- `> Canonical product source: \`docs/PRD.md\``,
114
- `> If something contradicts spec, spec wins raise an ADR.`,
172
+ `**Less harness, more task.** For any roadmap item, run \`generate_session_prompt\``,
173
+ `and work from THAT bound prompt — it contains everything the step needs.`,
174
+ `Load AT MOST one branch + one standards file per task. Never graze the harness`,
175
+ `"to be thorough" — every line of methodology you load displaces the task.`,
176
+ `\`.claude/reference/\` is background reading: NEVER load it during work.`,
115
177
  ``,
116
- `---`,
178
+ `## Always Load`,
179
+ ``,
180
+ `- \`.claude/constitution.md\` — non-negotiables: SOLID, invariants, prohibited ops`,
181
+ `- \`docs/status.md\` — current project state and open items`,
182
+ `- \`.claude/corrections.md\` — past AI mistakes on this project (read before acting)`,
183
+ ``,
184
+ `## Navigate by Task`,
185
+ ``,
186
+ `| You're about to... | Load these branches |`,
187
+ `| --- | --- |`,
188
+ `| Implement a feature | \`.claude/lifecycle.md\` → \`docs/use-cases/\` → \`.claude/routes/docs.md\` |`,
189
+ `| Fix a bug | \`.claude/lifecycle.md\` → linked test → \`.claude/routes/code.md\` |`,
190
+ `| Change architecture / layers | \`.claude/constitution.md\` → \`docs/architecture/layers.md\` → \`docs/adrs/\` |`,
191
+ `| Change a module boundary | \`.claude/constitution.md\` → \`docs/architecture/modules.md\` |`,
192
+ `| Change data model / schema | \`docs/architecture/data-model.md\` → \`.claude/routes/docs.md\` |`,
193
+ `| Add / change API surface | \`.claude/standards/api.md\` → \`docs/use-cases/\` |`,
194
+ `| Write / fix tests | \`.claude/standards/testing.md\` → \`.claude/routes/code.md\` |`,
195
+ `| Review architecture | \`.claude/constitution.md\` → \`.claude/routes/code.md\` → \`docs/architecture/\` |`,
196
+ `| Start a new session | \`.claude/lifecycle.md\` → \`docs/status.md\` → relevant use case |`,
117
197
  ``,
118
198
  `## Project Identity`,
119
199
  ``,
@@ -121,164 +201,394 @@ function renderSentinelClaudeMd(_domains, context) {
121
201
  `- **Tags**: ${tagList}`,
122
202
  `- **Stack**: ${stackLine}`,
123
203
  ``,
124
- `---`,
204
+ `## Doc Obligation Table`,
205
+ ``,
206
+ `| Change type | Read first | Produce after |`,
207
+ `| --- | --- | --- |`,
208
+ `| New feature | \`docs/PRD.md\` + relevant use case | Spec decision record in \`docs/specs/\` |`,
209
+ `| Architecture change | \`docs/architecture/layers.md\` + ADR index | ADR in \`docs/adrs/active/\` |`,
210
+ `| Schema change | \`docs/architecture/data-model.md\` | Update schema + ERD |`,
211
+ `| Module boundary | \`docs/architecture/modules.md\` | Update modules.md + ADR if non-obvious |`,
212
+ `| Bug fix | Linked use case + failing test | Regression note in use case |`,
125
213
  ``,
126
- `## The 7 GS Properties (apply to every generated artifact)`,
214
+ `## @gs-links Convention`,
215
+ ``,
216
+ `\`// @gs-links: docs/use-cases/UC-NNN.md, docs/adrs/active/NNNN-slug.md\``,
217
+ `Source files that implement a decision carry this. Linked docs must be staged with code.`,
218
+ `The \`pre-commit-gs-links.sh\` hook enforces this; escape with \`docs/change-manifest.md\`.`,
219
+ ``,
220
+ ].join("\n");
221
+ }
222
+ // ── CNT branch: constitution ──────────────────────────────────────────
223
+ /**
224
+ * Build .claude/constitution.md — non-negotiables always loaded with the root.
225
+ * Contains: 7 GS properties, architecture invariants, commit protocol, prohibited ops.
226
+ */
227
+ function buildConstitutionFile(context) {
228
+ const date = new Date().toISOString().split("T")[0];
229
+ const layerDiagram = buildLayerDiagram(context.tags);
230
+ return [
231
+ `<!-- CNT branch: constitution | ${date} | always loaded alongside root -->`,
232
+ `<!-- Non-negotiables. No exceptions. Disagreement → write an ADR. -->`,
233
+ ``,
234
+ `## The 7 GS Properties`,
235
+ ``,
236
+ `Every artifact must satisfy all seven:`,
127
237
  ``,
128
238
  `1. **Self-describing** — artifacts explain themselves; no implicit human memory.`,
129
239
  `2. **Bounded** — files ≤300 lines, functions ≤50 lines, one file = one concern.`,
130
- `3. **Verifiable** — typecheck + lint + tests are the definition of "done". Never "wrote the file" = "it works".`,
131
- `4. **Defended** — destructive operations structurally blocked (see \`docs/operation-classification.md\`).`,
132
- `5. **Auditable** — Conventional Commits + ADRs for every non-trivial decision.`,
133
- `6. **Composable** — clean architecture, dependencies always inward, explicit interfaces at seams.`,
240
+ `3. **Verifiable** — typecheck + lint + tests pass = "done". "Wrote the file" done.`,
241
+ `4. **Defended** — destructive ops structurally blocked (\`docs/operation-classification.md\`).`,
242
+ `5. **Auditable** — Conventional Commits + ADRs for every non-trivial structural decision.`,
243
+ `6. **Composable** — dependencies always inward, explicit interfaces at layer seams.`,
134
244
  `7. **Executable** — tests run against real runtime, not just compilation.`,
135
245
  ``,
136
- `---`,
137
- ``,
138
- `## Architecture Layers (dependencies point INWARD ONLY)`,
246
+ `## Architecture Invariants`,
139
247
  ``,
248
+ `**Layer stack** (dependencies point INWARD ONLY):`,
140
249
  layerDiagram,
141
250
  ``,
142
- `Rule: a layer never imports from a layer above it. No lateral imports between domains.`,
143
- `Shared utilities go to a \`shared/\` module — never duplicated across domains.`,
251
+ `- A layer never imports from a layer above it. No lateral imports between domains.`,
252
+ `- Shared utilities go to \`shared/\` — never duplicated across domains.`,
253
+ ...(context.language === "python"
254
+ ? [
255
+ `- Type hints required on all public functions (mypy strict or pyright strict).`,
256
+ `- No implicit \`Any\` — use \`Union\`, \`Optional\`, or \`Protocol\` for flexible types.`,
257
+ `- Make illegal states unrepresentable: model states as types (tagged unions, \`NewType\`,`,
258
+ ` frozen dataclasses). Parse, don't validate — parse raw input into typed objects at every boundary.`,
259
+ `- No circular imports (use TYPE_CHECKING guard if needed).`,
260
+ ]
261
+ : [
262
+ `- Strict typing: no \`any\` — use \`unknown\` + narrowing.`,
263
+ `- Explicit return types on all exported functions.`,
264
+ `- Make illegal states unrepresentable: discriminated unions and \`Result<T,E>\` over`,
265
+ ` runtime checks and thrown exceptions. Parse, don't validate — at every boundary.`,
266
+ `- No circular imports (hook-enforced).`,
267
+ `- ESM imports: all local imports use \`.js\` extensions.`,
268
+ ]),
269
+ `- Functional core, imperative shell: domain logic pure; I/O and effects only in adapters.`,
270
+ `- Design by Contract: each use case's Precondition/Postcondition IS the function contract —`,
271
+ ` tests assert postconditions, types encode preconditions.`,
272
+ `- Files ≤300 lines, functions ≤50 lines. Extract when exceeded.`,
144
273
  ``,
145
- ...buildNavigationModeSection(context.tags),
274
+ `## Commit Protocol (Conventional Commits, strict)`,
146
275
  ``,
147
- `## Folder Map Where to Find Things`,
276
+ `\`type(scope): subject\`type \`feat|fix|refactor|docs|test|chore|perf|build|ci\``,
148
277
  ``,
149
- folderMap,
278
+ `- **Atomic**: one commit = one logical change. No "WIP", "fixes", "asdf".`,
279
+ `- Every commit must pass typecheck + lint + affected tests.`,
280
+ `- TDD sequence: \`test(scope): [RED]\` → \`feat(scope): [GREEN]\` → \`refactor(scope)\``,
281
+ `- A pre-commit hook enforces quality; a commit-msg hook validates format + TDD phase.`,
150
282
  ``,
151
- `---`,
283
+ `## Prohibited Operations`,
152
284
  ``,
153
- `## Tool Sequencing`,
285
+ `See \`docs/operation-classification.md\` for Tier 0–3 classification.`,
154
286
  ``,
155
- `> How to approach the most common task types in this project.`,
156
- `> Fill in the Sequence column after your first few sessions.`,
287
+ `**Blocked without \`FORGECRAFT_ALLOW_DESTRUCTIVE=1\`:**`,
288
+ `- \`DROP TABLE\`, \`TRUNCATE\`, \`DELETE\` without specific \`WHERE\``,
289
+ `- Disabling any security constraint (RLS, auth guards)`,
290
+ `- \`git push --force\` to main/master`,
291
+ `- \`rm -rf\` on src/, docs/, or database paths`,
292
+ `- Hard delete of domain entities (use soft delete + audit log instead)`,
157
293
  ``,
158
- `| Task type | Recommended tool sequence |`,
159
- `| ---------------------------- | -------------------------------------------------------------- |`,
160
- `| New feature | Read PRD → Read use-cases → Write test → Implement → Commit |`,
161
- `| Bug fix | Grep for error → Read failing test → Fix → Add regression test |`,
162
- `| Refactor | Read architecture.md Check layer diagram → Change → Test |`,
163
- `| Schema change | Read data-model.md → Write migration → Regen types → Update UC |`,
164
- `| <!-- FILL: custom task --> | <!-- FILL: tool sequence --> |`,
294
+ `**Require human confirmation (never proceed silently):**`,
295
+ `- Direct push to main (use PR)`,
296
+ `- Schema migrations on production`,
297
+ `- Adding dependencies >100 KB`,
298
+ `- Full data resync / backfill operations`,
165
299
  ``,
166
- `---`,
300
+ `## Forbidden Patterns`,
301
+ `> Failure classes that pass typecheck + unit tests yet reach production. Each was paid for once.`,
167
302
  ``,
168
- `## Corrections Log`,
303
+ `- **No duplicate business rule across handlers** — read and write share one tested helper, never parallel copies (they desync silently).`,
304
+ `- **No \`findMany\`/\`SELECT\` consumed by positional index without explicit \`ORDER BY\`** (+ \`id\` tie-breaker) — heap-scan order is luck.`,
305
+ `- **No spec-declared response field without a contract assertion** — the backend drops it silently and unit tests still pass.`,
306
+ `- **No external-render template (PDF, email, export) without a snapshot test** — review misses label drift and raw-enum leaks.`,
307
+ `- **No bug fix without a regression test that fails before the fix** — the concrete input that broke becomes a permanent fixture.`,
308
+ ...(context.tags.some((t) => ["ML", "DATA-PIPELINE", "ANALYTICS"].includes(t))
309
+ ? [
310
+ `- **No LLM/model-output-consuming test with synthetic mocks only** — record a real output as a replay fixture; production shapes differ.`,
311
+ ]
312
+ : []),
169
313
  ``,
170
- `> Past mistakes by AI assistants on this project. Read before acting to avoid repeating them.`,
171
- `> Format: \`YYYY-MM-DD | [category] what went wrong and what the correct approach is\``,
314
+ ].join("\n");
315
+ }
316
+ // ── CNT branch: lifecycle ─────────────────────────────────────────────
317
+ /**
318
+ * Build .claude/lifecycle.md — GS session lifecycle.
319
+ * Contains: cascade order, feature estimation, tool sequencing, session loop invariant.
320
+ */
321
+ function buildLifecycleFile(_context) {
322
+ const date = new Date().toISOString().split("T")[0];
323
+ return [
324
+ `<!-- CNT branch: lifecycle | ${date} | load when starting a session or implementing a change -->`,
172
325
  ``,
173
- `<!-- Log entries go here. Example:`,
174
- `2026-01-15 | [architecture] Added business logic to a route handler instead of a service — always delegate to service layer`,
175
- `2026-01-20 | [testing] Mocked the DB in an integration test — use real test DB instead (see docs/test-architecture.md)`,
176
- `-->`,
326
+ `## Memory Map What to Load and When`,
177
327
  ``,
178
- `---`,
328
+ `| Memory type | Artifact | Load when |`,
329
+ `| --- | --- | --- |`,
330
+ `| **Semantic** — architectural rules | \`CLAUDE.md\` + \`.claude/constitution.md\` | Every session (always load) |`,
331
+ `| **Procedural** — how to work | \`.claude/lifecycle.md\` + \`.claude/standards/\` | Implementing or starting a feature |`,
332
+ `| **Episodic** — decisions and state | \`docs/adrs/active/\` + \`docs/status.md\` | Starting a session, structural changes |`,
333
+ `| **Relationship** — behavioral contracts | \`docs/use-cases/\` | Before implementing any behavior |`,
334
+ `| **Working** — current task | Sub-tasks from Feature Estimation | During implementation (keep minimal) |`,
179
335
  ``,
180
- `## Code Standards`,
336
+ `Read in this order at session start: \`docs/status.md\` → relevant use case → relevant ADR → \`.claude/constitution.md\``,
181
337
  ``,
182
- `- **Strict typing**: no \`any\` — use \`unknown\` + narrowing.`,
183
- `- **Explicit return types** on all exported functions.`,
184
- `- Files ≤300 lines. Functions ≤50 lines. If exceeded, extract.`,
185
- `- Naming: files \`kebab-case\`, classes/types \`PascalCase\`, variables \`camelCase\`, DB columns \`snake_case\`.`,
186
- `- No abbreviations except universally known (id, url, http, db, api).`,
187
- `- Absolute imports with path aliases (\`@/\` → \`src/\`).`,
338
+ `## GS Initialization Cascade`,
188
339
  ``,
189
- `---`,
340
+ `Run \`check_cascade\` to verify each step before implementing anything:`,
190
341
  ``,
191
- `## Testing Protocol`,
342
+ `1. **Functional spec** — \`docs/PRD.md\` exists with real content (not stubs)`,
343
+ `2. **Architecture** — \`docs/TechSpec.md\` + \`docs/architecture/\` present`,
344
+ `3. **Constitution** — \`CLAUDE.md\` + \`.claude/constitution.md\` loaded`,
345
+ `4. **Decision records** — at least one ADR in \`docs/adrs/active/\``,
346
+ `5. **Behavioral contracts** — use cases in \`docs/use-cases/\` with acceptance criteria`,
192
347
  ``,
193
- `- **TDD mandatory** for non-trivial logic. Flow: RED GREEN REFACTOR with separate commits.`,
194
- ` - \`test(scope): [RED] description\` — failing test first`,
195
- ` - \`feat(scope): [GREEN] description\` — minimal implementation`,
196
- ` - \`refactor(scope): description\` — cleanup`,
197
- `- **Pre-commit**: run only affected tests (\`vitest run --changed --passWithNoTests\`). Set \`TDD_RED=1\` to bypass for [RED] commits.`,
198
- `- **Pre-push**: run ALL tests. No exceptions.`,
199
- `- Coverage: ≥80% global, higher for auth/security modules.`,
200
- `- Tests are adversarial: \`test_rejects_bad_input\`, \`test_denies_unauthorized\`. Not \`test_basic_flow\`.`,
201
- `- Test against interfaces, never against internal implementation.`,
348
+ `If any step fails: fix it before generating code. The cascade IS the specification.`,
202
349
  ``,
203
- `---`,
350
+ `## Feature Estimation (required before any requested change)`,
204
351
  ``,
205
- `## Commit Protocol (Conventional Commits, strict)`,
352
+ `Before writing any code:`,
353
+ `1. **Read** the relevant use case in \`docs/use-cases/\` or spec in \`docs/specs/\``,
354
+ `2. **Identify** all files that will be touched (source, tests, docs)`,
355
+ `3. **Break into sub-tasks** — each sub-task: ≤3 files, one clear acceptance criterion`,
356
+ `4. **State the scope boundary** — explicitly list what this change does NOT touch`,
357
+ `5. **Confirm** the breakdown with the user before writing any code`,
206
358
  ``,
207
- "```",
208
- `type(scope): subject`,
209
- "```",
359
+ `Sub-task granularity prevents context window degradation. Each sub-task must be`,
360
+ `completable without reloading the full spec. This is not optional ceremony.`,
210
361
  ``,
211
- `- \`type\` ∈ \`feat|fix|refactor|docs|test|chore|perf|build|ci\``,
212
- `- **Atomic**: one commit = one logical change. No "WIP", "fixes", "asdf".`,
213
- `- Every commit must pass typecheck + lint + affected tests.`,
214
- `- A pre-commit hook enforces this; a commit-msg hook validates format + TDD phase.`,
362
+ `## Tool Sequencing`,
215
363
  ``,
216
- `---`,
364
+ `| Task type | Recommended sequence |`,
365
+ `| --- | --- |`,
366
+ `| New feature | Read PRD → Read use-case → Write test ([RED]) → Implement ([GREEN]) → Commit |`,
367
+ `| Bug fix | Grep error → Read failing test → Fix → Add regression test → Commit |`,
368
+ `| Refactor | Read architecture → Check layers → Change → Run tests → Commit |`,
369
+ `| Schema change | Read data-model → Write migration → Regen types → Update UC → Commit |`,
370
+ `| <!-- FILL: custom task --> | <!-- FILL: sequence --> |`,
217
371
  ``,
218
- `## Prohibited Operations (require explicit confirmation)`,
372
+ `## Gate Awareness Detect When a Quality Gate Is Needed`,
219
373
  ``,
220
- `See \`docs/operation-classification.md\` for Tier 0–3 classification.`,
374
+ `Recognize gate-worthy moments WHILE working — don't wait for close_cycle:`,
221
375
  ``,
222
- `**Blocked without \`FORGECRAFT_ALLOW_DESTRUCTIVE=1\`:**`,
223
- `- \`DROP TABLE\`, \`TRUNCATE\`, \`DELETE\` without specific \`WHERE\``,
224
- `- Disabling any security constraint (RLS, auth guards)`,
225
- `- \`git push --force\` to main/master`,
226
- `- \`rm -rf\` on src/, docs/, or database paths`,
227
- `- Hard delete of domain entities (use soft delete / audit log)`,
376
+ `- **Same bug class fixed twice** in a session or across recent commits`,
377
+ `- **User corrects you** about something a structural check could have caught`,
378
+ `- **You repeat a manual verification** ("let me check X didn't break") more than once`,
379
+ `- **A convention exists only in prose** — if a rule lives in docs but nothing enforces it`,
228
380
  ``,
229
- `**Require human confirmation:**`,
230
- `- Direct push to main (use PR)`,
231
- `- Full data resync / backfill operations`,
232
- `- Schema migrations on production`,
233
- `- Adding dependencies >100 KB`,
381
+ `When detected, immediately create a draft gate at \`.forgecraft/gates/drafts/<id>.yaml\``,
382
+ `with \`origin: organic\` and the trigger as evidence. Also log the moment in`,
383
+ `\`.claude/corrections.md\` the close_cycle genesis scan is the safety net for`,
384
+ `moments you miss, and its drafts carry \`origin: genesis\`.`,
234
385
  ``,
235
- `---`,
386
+ `Drafts are proposals — the dev reviews and moves them to \`gates/active/\` to enforce.`,
387
+ `If a gate would help other projects, set \`generalizable: true\` so close_cycle`,
388
+ `proposes it to the community registry.`,
236
389
  ``,
237
- `## Reading Map What to Load Before Touching Code`,
390
+ `## Working Memory Protocol (mid-session context management)`,
238
391
  ``,
239
- `| When you touch... | Read first... |`,
240
- `| ---------------------- | ---------------------------------------------------- |`,
241
- `| Architecture / layers | \`docs/architecture.md\`, relevant ADR |`,
242
- `| Data model / schema | \`docs/data-model.md\`, relevant ADR |`,
243
- `| Business logic / domain| \`docs/PRD.md\` §goals, \`docs/use-cases.md\` |`,
244
- `| Any test | \`docs/test-architecture.md\` or \`docs/use-cases.md\` |`,
245
- `| Any ADR concern | \`.claude/adr/index.md\` → specific ADR |`,
246
- `| Quality gates | \`.claude/gates/index.md\` |`,
392
+ `Context windows degrade. When a session grows long:`,
247
393
  ``,
248
- `---`,
394
+ `1. **Checkpoint before continuing.** Update \`docs/status.md\` with completed sub-tasks`,
395
+ ` and the exact next step — specific enough to resume cold.`,
396
+ `2. **Don't reload what contracts already answer.** If tests pass and types compile,`,
397
+ ` trust the contract — do not re-read implementations to "refresh" your memory.`,
398
+ `3. **One sub-task at a time.** If the current sub-task's context no longer fits cleanly,`,
399
+ ` finish it, commit, checkpoint, and start the next sub-task fresh.`,
400
+ `4. **Never hold unsaved decisions in working memory.** A decision worth remembering`,
401
+ ` goes to an ADR or status.md the moment it's made — not at session end.`,
249
402
  ``,
250
403
  `## Session Loop Invariant (close-of-session gate)`,
251
404
  ``,
252
405
  `Before closing any session, verify:`,
253
406
  ``,
254
- `1. ✅ Typecheck passes (no errors)`,
255
- `2. ✅ Lint passes (no warnings promoted to errors)`,
407
+ `1. ✅ Typecheck passes no type errors`,
408
+ `2. ✅ Lint passes no promoted warnings`,
256
409
  `3. ✅ Affected tests pass`,
257
410
  `4. ✅ If schema changed: types regenerated and staged`,
258
- `5. ✅ If structural decision: ADR created in \`docs/adrs/\``,
259
- `6. ✅ Commits are Conventional Commits, atomic`,
260
- `7. ✅ No dead code, unused imports, or \`console.log\` in production code`,
261
- `8. ✅ If UC acceptance criteria changed: \`docs/use-cases.md\` updated`,
411
+ `5. ✅ If structural decision: ADR written in \`docs/adrs/active/\``,
412
+ `6. ✅ Commits are atomic Conventional Commits`,
413
+ `7. ✅ \`docs/status.md\` updated current state, open items, recent decisions`,
414
+ `8. ✅ If UC acceptance criteria changed: \`docs/use-cases/\` updated`,
415
+ ``,
416
+ `If any item is incomplete: document it in \`docs/status.md\` before stopping.`,
417
+ ``,
418
+ ].join("\n");
419
+ }
420
+ // ── CNT branch: routes/code ───────────────────────────────────────────
421
+ /**
422
+ * Build .claude/routes/code.md — where code lives.
423
+ * Contains: folder map, module addition protocol, naming conventions, code standards.
424
+ */
425
+ function buildCodeRoutesFile(context) {
426
+ const date = new Date().toISOString().split("T")[0];
427
+ const folderMap = buildFolderMap(context.tags);
428
+ return [
429
+ `<!-- CNT branch: routes/code | ${date} | load when navigating source or adding a module -->`,
430
+ ``,
431
+ `## Folder Map — Where Code Lives`,
262
432
  ``,
263
- `If any item fails: document what's open in \`docs/status.md\`.`,
433
+ `Screaming Architecture: structure states what lives where — the first search must hit.`,
434
+ `A folder named \`controllers/\` contains controllers, nothing else. Never relocate by whim;`,
435
+ `convention over configuration is what makes a stateless reader's navigation deterministic.`,
264
436
  ``,
265
- `---`,
437
+ folderMap,
438
+ ``,
439
+ `## Module Addition Protocol`,
440
+ ``,
441
+ `When adding a new module:`,
442
+ `1. Determine which layer it belongs to (see \`.claude/constitution.md\`)`,
443
+ `2. Check \`docs/architecture/modules.md\` — verify no existing module already owns this concern`,
444
+ `3. Name the file using the conventions below`,
445
+ `4. Add a \`@gs-links\` comment referencing the use case or ADR it implements`,
446
+ `5. If the addition represents a structural decision: write an ADR first`,
447
+ ``,
448
+ `## Naming Conventions`,
449
+ ``,
450
+ ...(context.language === "python"
451
+ ? [
452
+ `| Artifact | Convention | Example |`,
453
+ `| --- | --- | --- |`,
454
+ `| Files / modules | \`snake_case.py\` | \`user_service.py\` |`,
455
+ `| Classes | \`PascalCase\` | \`UserService\` |`,
456
+ `| Variables / Functions | \`snake_case\` | \`get_user_by_id\` |`,
457
+ `| Database columns / JSON keys | \`snake_case\` | \`created_at\` |`,
458
+ `| Constants | \`SCREAMING_SNAKE_CASE\` | \`MAX_RETRY_COUNT\` |`,
459
+ `| Allowed abbreviations | — | id, url, http, db, api, ctx, err |`,
460
+ ]
461
+ : [
462
+ `| Artifact | Convention | Example |`,
463
+ `| --- | --- | --- |`,
464
+ `| Files | \`kebab-case.ts\` | \`user-service.ts\` |`,
465
+ `| Classes / Types / Interfaces | \`PascalCase\` | \`UserService\` |`,
466
+ `| Variables / Functions | \`camelCase\` | \`getUserById\` |`,
467
+ `| Database columns / JSON keys | \`snake_case\` | \`created_at\` |`,
468
+ `| Constants | \`SCREAMING_SNAKE_CASE\` | \`MAX_RETRY_COUNT\` |`,
469
+ `| Allowed abbreviations | — | id, url, http, db, api, ctx, err |`,
470
+ ]),
471
+ ``,
472
+ `## Code Standards`,
266
473
  ``,
267
- `## Navigation`,
474
+ ...(context.language === "python"
475
+ ? [
476
+ `- Type hints on all public functions — mypy strict or pyright strict`,
477
+ `- No mutable default arguments; use \`None\` + guard`,
478
+ `- Files ≤300 lines, functions ≤50 lines — extract when exceeded`,
479
+ `- Absolute imports from package root; no \`sys.path\` manipulation`,
480
+ ]
481
+ : [
482
+ `- Strict typing — no \`any\`, use \`unknown\` + narrowing`,
483
+ `- Explicit return types on all exported functions`,
484
+ `- Files ≤300 lines, functions ≤50 lines — extract when exceeded`,
485
+ `- Absolute imports with path aliases (\`@/\` → \`src/\`)`,
486
+ ]),
487
+ `- No dead code, unused imports, or \`console.log\` in production files`,
268
488
  ``,
269
- `Full standards: \`.claude/index.md\` → \`.claude/core.md\` → \`.claude/standards/\``,
270
- `ADRs: \`docs/adrs/\` (indexed in \`.claude/adr/index.md\`)`,
271
- `Quality gates: \`.claude/gates/index.md\``,
489
+ ].join("\n");
490
+ }
491
+ // ── CNT branch: routes/docs ───────────────────────────────────────────
492
+ /**
493
+ * Build .claude/routes/docs.md — where documents live and how to navigate them.
494
+ * Contains: Navigation Mode, document map, reading order.
495
+ */
496
+ function buildDocsRoutesFile(context) {
497
+ const date = new Date().toISOString().split("T")[0];
498
+ const hasArchDiscipline = context.tags.some((t) => ["WEB-NEXT", "WEB-REACT", "API", "CLI", "LIBRARY"].includes(t)) || context.tags.includes("UNIVERSAL");
499
+ const navMode = hasArchDiscipline
500
+ ? [
501
+ `## Navigation Mode — How to Read This Codebase`,
502
+ ``,
503
+ `This project follows Clean Architecture with TDD. **The contracts are trustworthy.**`,
504
+ ``,
505
+ `- **Read interfaces, not implementations first.** Types and signatures tell you what`,
506
+ ` a module promises. Read those before reading the body.`,
507
+ `- **Use-cases are the spec.** Before touching business logic, read the relevant UC in`,
508
+ ` \`docs/use-cases/\`. The code is derived from the use case, not the reverse.`,
509
+ `- **ADRs explain the why.** Check \`docs/adrs/active/\` before making structural decisions.`,
510
+ ` The answer may already exist.`,
511
+ `- **Skip implementation reads when contracts are green.** If tests pass and types compile,`,
512
+ ` treat a module as a black box.`,
513
+ `- **Raise an ADR rather than deviating silently.** If the correct action contradicts the`,
514
+ ` architecture, write an ADR — do not silently break the contract.`,
515
+ ``,
516
+ ]
517
+ : [];
518
+ return [
519
+ `<!-- CNT branch: routes/docs | ${date} | load when navigating documents or before implementing -->`,
520
+ ``,
521
+ ...navMode,
522
+ `## Document Map — Where Docs Live`,
523
+ ``,
524
+ `| What you need | Where to find it |`,
525
+ `| --- | --- |`,
526
+ `| What to build | \`docs/PRD.md\` |`,
527
+ `| Architecture overview | \`docs/TechSpec.md\` |`,
528
+ `| Layer and boundary rules | \`docs/architecture/layers.md\` |`,
529
+ `| Module ownership | \`docs/architecture/modules.md\` |`,
530
+ `| Data model / schema / ERD | \`docs/architecture/data-model.md\` |`,
531
+ `| External integrations | \`docs/architecture/integrations.md\` |`,
532
+ `| Behavioral contracts | \`docs/use-cases/\` |`,
533
+ `| Why a decision was made | \`docs/adrs/active/\` |`,
534
+ `| Current project state | \`docs/status.md\` |`,
535
+ `| Non-functional requirements | \`docs/nfr-contracts.md\` |`,
536
+ `| Test architecture | \`docs/test-architecture.md\` |`,
537
+ ``,
538
+ `## Reading Order (before starting implementation)`,
539
+ ``,
540
+ `1. \`docs/status.md\` — what's done, what's in progress, recent decisions`,
541
+ `2. Relevant use case in \`docs/use-cases/\``,
542
+ `3. Relevant spec section in \`docs/specs/\` or \`docs/PRD.md\``,
543
+ `4. Relevant ADR if the area has prior decisions in \`docs/adrs/active/\``,
544
+ `5. \`.claude/constitution.md\` — verify your approach doesn't violate invariants`,
272
545
  ``,
273
546
  ].join("\n");
274
547
  }
548
+ // ── CNT branch: corrections ───────────────────────────────────────────
275
549
  /**
276
- * Infer the stack description from project tags.
550
+ * Build .claude/corrections.md corrections log stub.
551
+ * Always read before acting. Never delete entries.
552
+ */
553
+ function buildCorrectionsFile() {
554
+ const date = new Date().toISOString().split("T")[0];
555
+ return [
556
+ `<!-- CNT branch: corrections | ${date} | read before acting in every session -->`,
557
+ `<!-- Records past AI mistakes on this project. Never delete entries. Always add. -->`,
558
+ ``,
559
+ `## Corrections Log`,
560
+ ``,
561
+ `> Format: \`YYYY-MM-DD | [category] what went wrong | correct approach\``,
562
+ ``,
563
+ `<!-- Add entries when an AI assistant makes a mistake on this project. Examples:`,
564
+ `2026-01-15 | [architecture] Added business logic to a route handler — always delegate to service layer`,
565
+ `2026-01-20 | [testing] Mocked DB in integration test — use real test DB instead`,
566
+ `2026-02-10 | [scope] Changed more files than the sub-task required — one sub-task = ≤3 files`,
567
+ `-->`,
568
+ ``,
569
+ ].join("\n");
570
+ }
571
+ /**
572
+ * Infer the stack description from project tags and language.
277
573
  *
278
574
  * @param tags - Project tags
575
+ * @param language - Primary language ("typescript" default, "python")
279
576
  * @returns Human-readable stack string
280
577
  */
281
- function inferStackFromTags(tags) {
578
+ function inferStackFromTags(tags, language) {
579
+ if (language === "python") {
580
+ if (tags.includes("API"))
581
+ return "Python REST/GraphQL API (FastAPI/Django)";
582
+ if (tags.includes("CLI"))
583
+ return "Python CLI";
584
+ if (tags.includes("DATA-PIPELINE"))
585
+ return "Python data pipeline";
586
+ if (tags.includes("ML"))
587
+ return "Python ML";
588
+ if (tags.includes("LIBRARY"))
589
+ return "Python library";
590
+ return "Python";
591
+ }
282
592
  if (tags.includes("WEB-NEXT"))
283
593
  return "Next.js 14+ App Router + TypeScript";
284
594
  if (tags.includes("WEB-REACT"))
@@ -314,38 +624,6 @@ function buildLayerDiagram(tags) {
314
624
  }
315
625
  return "Entry Points → Services → Domain → Infrastructure";
316
626
  }
317
- /**
318
- * Build Navigation Mode declaration (GS WP §6.0) when applicable.
319
- * Emitted for architecturally disciplined projects where the AI should trust
320
- * contracts and read interfaces before implementations.
321
- *
322
- * @param tags - Project tags
323
- * @returns Lines to splice into the sentinel, or empty array for minimal projects
324
- */
325
- function buildNavigationModeSection(tags) {
326
- const hasArchDiscipline = tags.some((t) => ["WEB-NEXT", "WEB-REACT", "API", "CLI", "LIBRARY"].includes(t)) || tags.includes("UNIVERSAL");
327
- if (!hasArchDiscipline)
328
- return [];
329
- return [
330
- `---`,
331
- ``,
332
- `## Navigation Mode — How to Read This Codebase`,
333
- ``,
334
- `This project follows Clean Architecture with strict layer separation and TDD.`,
335
- `**The contracts are trustworthy.** Use Navigation Mode accordingly:`,
336
- ``,
337
- `- **Read interfaces, not implementations first.** Types and signatures tell you`,
338
- ` what a module promises — read those before reading the body.`,
339
- `- **Use-cases drive everything.** Before touching any business logic, read the`,
340
- ` relevant UC in \`docs/use-cases.md\`. The UC is the spec; the code is derived.`,
341
- `- **ADRs explain the why.** If you're about to make a structural decision, check`,
342
- ` \`.claude/adr/index.md\` first — the answer may already exist.`,
343
- `- **Skip implementation reads when contracts are green.** If tests pass and types`,
344
- ` compile, you can treat a module as a black box.`,
345
- `- **Raise an ADR rather than deviating.** If the correct action contradicts the`,
346
- ` architecture, write an ADR — do not silently break the contract.`,
347
- ];
348
- }
349
627
  /**
350
628
  * Build tag-specific folder map showing primary directories and their purpose.
351
629
  *