@codewithjuber/forgekit 0.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 (140) hide show
  1. package/.claude-plugin/marketplace.json +12 -0
  2. package/.claude-plugin/plugin.json +20 -0
  3. package/.codex-plugin/plugin.json +29 -0
  4. package/.mcp.json +8 -0
  5. package/ARCHITECTURE.md +314 -0
  6. package/CHANGELOG.md +467 -0
  7. package/LICENSE +21 -0
  8. package/ONBOARDING.md +180 -0
  9. package/README.md +286 -0
  10. package/bin/claude-init.sh +90 -0
  11. package/bin/claude-taste.sh +33 -0
  12. package/bin/learn-consolidate.sh +51 -0
  13. package/brand.json +15 -0
  14. package/global/CLAUDE.md +31 -0
  15. package/global/crew/frontend-verifier.md +36 -0
  16. package/global/crew/independent-reviewer.md +29 -0
  17. package/global/crew/scout.md +24 -0
  18. package/global/crew/verifier.md +28 -0
  19. package/global/guards/_guardlib.sh +36 -0
  20. package/global/guards/cortex.sh +14 -0
  21. package/global/guards/cost-budget.sh +41 -0
  22. package/global/guards/doom-loop.sh +25 -0
  23. package/global/guards/format-on-edit.sh +32 -0
  24. package/global/guards/lean-guard.sh +20 -0
  25. package/global/guards/protect-paths.sh +45 -0
  26. package/global/guards/recall-load.sh +22 -0
  27. package/global/guards/secret-redact.sh +18 -0
  28. package/global/guards/session-learner.sh +72 -0
  29. package/global/recall/MEMORY.md +7 -0
  30. package/global/rules/self-correction.md +17 -0
  31. package/global/rules/stack-notes.md +24 -0
  32. package/global/rules/tech-currency.md +19 -0
  33. package/global/settings.template.json +183 -0
  34. package/global/statusline.sh +51 -0
  35. package/global/taste/brutalist.json +9 -0
  36. package/global/taste/brutalist.md +19 -0
  37. package/global/taste/corporate.json +9 -0
  38. package/global/taste/corporate.md +19 -0
  39. package/global/taste/editorial.json +9 -0
  40. package/global/taste/editorial.md +19 -0
  41. package/global/taste/minimalist.json +9 -0
  42. package/global/taste/minimalist.md +20 -0
  43. package/global/taste/playful.json +9 -0
  44. package/global/taste/playful.md +19 -0
  45. package/global/tools/atlas/SKILL.md +27 -0
  46. package/global/tools/code-modernization/SKILL.md +275 -0
  47. package/global/tools/code-modernization/references/cost-impact-preflight.md +54 -0
  48. package/global/tools/code-modernization/references/design-patterns-cheatsheet.md +24 -0
  49. package/global/tools/code-modernization/references/research-protocol.md +42 -0
  50. package/global/tools/code-modernization/scripts/preflight_scan.py +190 -0
  51. package/global/tools/cognitive-substrate/SKILL.md +56 -0
  52. package/global/tools/cognitive-substrate/references/capability-map.md +17 -0
  53. package/global/tools/cost-guard/SKILL.md +50 -0
  54. package/global/tools/design-md/SKILL.md +54 -0
  55. package/global/tools/dev-radar/SKILL.md +56 -0
  56. package/global/tools/explore-plan-code/SKILL.md +24 -0
  57. package/global/tools/lean/SKILL.md +41 -0
  58. package/global/tools/recall/SKILL.md +31 -0
  59. package/global/tools/reuse-first/SKILL.md +64 -0
  60. package/global/tools/self-improve/SKILL.md +44 -0
  61. package/global/tools/taste/SKILL.md +26 -0
  62. package/global/tools/tech-selector/SKILL.md +35 -0
  63. package/global/tools/ui-workflow/SKILL.md +44 -0
  64. package/hooks/hooks.json +107 -0
  65. package/install.sh +88 -0
  66. package/package.json +93 -0
  67. package/public/index.html +45 -0
  68. package/scripts/build-pages.mjs +180 -0
  69. package/scripts/bump.mjs +322 -0
  70. package/skills/cognitive-substrate/SKILL.md +56 -0
  71. package/skills/cognitive-substrate/references/capability-map.md +17 -0
  72. package/source/mcp.json +10 -0
  73. package/source/rules.json +106 -0
  74. package/source/substrate.json +41 -0
  75. package/src/adjudicate.js +84 -0
  76. package/src/anchor.js +210 -0
  77. package/src/atlas.js +487 -0
  78. package/src/brain.js +84 -0
  79. package/src/brand.js +25 -0
  80. package/src/cli.js +1509 -0
  81. package/src/context.js +273 -0
  82. package/src/cortex.js +251 -0
  83. package/src/cortex_distill.js +55 -0
  84. package/src/cortex_features.js +81 -0
  85. package/src/cortex_hook.js +197 -0
  86. package/src/cortex_hook_main.js +139 -0
  87. package/src/cortex_mcp.js +352 -0
  88. package/src/cost_report.js +271 -0
  89. package/src/dash.html +396 -0
  90. package/src/dash.js +220 -0
  91. package/src/diagnose.js +0 -0
  92. package/src/doctor.js +315 -0
  93. package/src/embed.js +244 -0
  94. package/src/emit/_shared.js +39 -0
  95. package/src/emit/aider.js +22 -0
  96. package/src/emit/claude.js +44 -0
  97. package/src/emit/codex.js +17 -0
  98. package/src/emit/continue.js +28 -0
  99. package/src/emit/copilot.js +12 -0
  100. package/src/emit/cursor.js +23 -0
  101. package/src/emit/gemini.js +40 -0
  102. package/src/emit/mcp.js +94 -0
  103. package/src/emit/windsurf.js +22 -0
  104. package/src/emit/zed.js +34 -0
  105. package/src/eval.js +47 -0
  106. package/src/extract.js +82 -0
  107. package/src/harden.js +44 -0
  108. package/src/imagine.js +301 -0
  109. package/src/init.js +178 -0
  110. package/src/lean.js +149 -0
  111. package/src/ledger.js +475 -0
  112. package/src/ledger_bridge.js +279 -0
  113. package/src/ledger_read.js +152 -0
  114. package/src/ledger_store.js +360 -0
  115. package/src/lessons.js +185 -0
  116. package/src/lessons_store.js +137 -0
  117. package/src/metrics.js +54 -0
  118. package/src/model_tiers.js +17 -0
  119. package/src/model_tiers.json +39 -0
  120. package/src/predictor.js +143 -0
  121. package/src/preflight.js +410 -0
  122. package/src/providers.js +320 -0
  123. package/src/recall.js +103 -0
  124. package/src/reuse.js +0 -0
  125. package/src/route.js +323 -0
  126. package/src/scope.js +122 -0
  127. package/src/skillgate.js +89 -0
  128. package/src/speclock.js +64 -0
  129. package/src/substrate.js +492 -0
  130. package/src/sync.js +132 -0
  131. package/src/taste.js +55 -0
  132. package/src/uicheck.js +96 -0
  133. package/src/uifingerprint.js +861 -0
  134. package/src/uivisual.js +334 -0
  135. package/src/util.js +71 -0
  136. package/src/verify.js +117 -0
  137. package/templates/project-layer/.claude/settings.json +22 -0
  138. package/templates/project-layer/.claude/skills/hostlelo-deploy/SKILL.md +38 -0
  139. package/templates/project-layer/AGENTS.md +28 -0
  140. package/templates/project-layer/CLAUDE.md +40 -0
@@ -0,0 +1,275 @@
1
+ ---
2
+ name: code-modernizer
3
+ description: >-
4
+ Modernize or refactor a legacy codebase incrementally while preserving business
5
+ logic. Replaces hand-rolled logic with the standard library, a native feature,
6
+ an already-installed dependency, or (only after live research) a well-vetted new
7
+ package, then applies minimal design patterns to whatever custom code remains.
8
+ Confirms scope first (full-codebase, one module/partial, or only the exact lines
9
+ named) and flags file count, line count, and breaking-change risk before
10
+ generating a large diff, asking instead of assuming when scope, a library choice,
11
+ or a behavior change is unclear.
12
+ Use for migrations (framework/language/version upgrades), killing tech debt,
13
+ refactoring an old project, or "bring this up to date". Use whenever the user
14
+ asks to refactor, modernize, de-bloat, clean up, simplify, upgrade, or audit
15
+ code; asks "is there a library for this", "don't reinvent the wheel", "replace
16
+ with a framework", "reduce boilerplate", or "apply proper design patterns"; wants
17
+ a root-cause fix over a quick patch; says "full upgrade" vs "partial upgrade" vs
18
+ "just fix this one thing"; or wants a legacy-code/tech-debt audit or a
19
+ dependency-choice recommendation.
20
+ license: MIT
21
+ attribution: >-
22
+ This skill's ladder is adapted from DietrichGebert/ponytail (MIT licensed).
23
+ See "Relationship to ponytail" below.
24
+ ---
25
+
26
+ # Code Modernizer
27
+
28
+ ## Philosophy
29
+
30
+ A senior engineer isn't measured by how much code they wrote today, but by how
31
+ little the system needs. Before touching anything, decide whether the code should
32
+ be replaced with something already established. If custom code is genuinely
33
+ necessary, write the least of it that solves the real problem without dropping
34
+ behavior anyone relies on.
35
+
36
+ This skill's core decision procedure is adapted from Dietrich Gebert's `ponytail`
37
+ project (MIT licensed, github.com/DietrichGebert/ponytail). It extends ponytail
38
+ two ways: it applies the same ladder retroactively to audit code that already
39
+ exists, not just to gate new code being written, and it adds scope control, a
40
+ pre-flight cost/impact gate, and a mandatory live-research step for whenever a
41
+ genuinely new dependency is on the table. See "Relationship to ponytail" at the
42
+ end.
43
+
44
+ ## The ladder
45
+
46
+ Before writing, keeping, or replacing any piece of logic, stop at the first rung
47
+ that holds:
48
+
49
+ 1. **Does this need to exist at all?** (YAGNI). If a feature isn't used, delete it
50
+ instead of modernizing it.
51
+ 2. **Already solved elsewhere in this codebase?** Reuse it, don't rewrite it.
52
+ 3. **Standard library does it?** Use it.
53
+ 4. **Native platform feature does it?** Use it. The browser already has
54
+ `<input type="date">`, so don't reach for a date-picker library.
55
+ 5. **Already-installed dependency does it?** Use it. Zero new install cost.
56
+ 6. **Is a new dependency genuinely justified?** Only after the research pass in
57
+ Step 3 below. Never skip straight here.
58
+ 7. **Can what's left be one line?** Make it one line.
59
+ 8. **Only then:** write the minimum code that works, shaped by whichever design
60
+ pattern (if any) removes real duplication. See
61
+ `references/design-patterns-cheatsheet.md`.
62
+
63
+ The ladder runs after understanding the problem, not instead of it. Read the code
64
+ and its tests before picking a rung (Step 2).
65
+
66
+ ## Two modes, same ladder
67
+
68
+ - **Forward** (writing new code): apply the ladder before writing anything.
69
+ - **Audit** (existing code): apply the same ladder retroactively. For every
70
+ hand-rolled block in scope, ask: "would rung 3, 4, 5, or a researched rung 6
71
+ now produce less code, or safer code, than what's already here?" If yes, and the
72
+ check in Step 4 clears it, propose the swap. This audit mode is the part
73
+ `ponytail` doesn't cover. It governs new code; this skill governs the code
74
+ that's already sitting in the repo.
75
+
76
+ ## Step 0: Scope handshake (every time, before any real work)
77
+
78
+ Refactoring has a blast radius. Before generating anything beyond a one-file,
79
+ one-function fix, pin down which of these three the user wants:
80
+
81
+ - **Full**: a comprehensive pass across the named codebase or repo. Expect
82
+ multiple files and possibly breaking changes; produce a migration note.
83
+ - **Partial**: bounded to one named module, directory, or feature area. No
84
+ drive-by edits outside that boundary, even if something nearby looks equally
85
+ outdated.
86
+ - **Targeted**: only the exact file, function, or lines named. Nothing else
87
+ changes.
88
+
89
+ If the request already states scope clearly ("just fix this function", "modernize
90
+ the whole `utils/` folder"), proceed without asking. If it's ambiguous ("clean up
91
+ this codebase", "make this better"), ask one direct question offering these three
92
+ options before reading any more files than needed to ask it well. Don't default to
93
+ Full because it seems more thorough. Full is the most expensive and highest-risk
94
+ option, not the safe default.
95
+
96
+ ## Step 1: Pre-flight scan and cost/impact flag (Full/Partial only, skip for Targeted)
97
+
98
+ Ground the estimate in real numbers instead of a guess. Run:
99
+
100
+ ```
101
+ python3 scripts/preflight_scan.py <path>
102
+ ```
103
+
104
+ It's stdlib-only Python, nothing to install. Report back to the user in a short
105
+ block before generating anything:
106
+
107
+ ```
108
+ Scope: <Full|Partial> on <path>
109
+ ~<N> files, ~<X> lines in range
110
+ Dependencies already available: <short list from the manifest>
111
+ Flagged high-cost: <any file over ~800 lines, or the pass touching 15-20+ files, name them>
112
+ Estimated: <rough tool-call / diff count>, <low|medium|high> breaking-change risk
113
+ Proceed as scoped, narrow it, or switch to Targeted?
114
+ ```
115
+
116
+ Treat anything the scan flags as high-cost as its own decision point. Offer full
117
+ detail there or a summarized diff, rather than silently generating all of it. Full
118
+ rubric, including the flexibility trade-off, in `references/cost-impact-preflight.md`.
119
+
120
+ ## Step 2: Read before you touch (root cause, not a patch)
121
+
122
+ Before proposing any swap, read what's actually there: the function, its tests,
123
+ nearby comments, and the commit that introduced the "ugly" version if it's
124
+ available. Hand-rolled code is sometimes just unmaintained. Sometimes it's
125
+ load-bearing for an edge case the clean replacement doesn't handle. Confirm which
126
+ one is in front of you before replacing it. If the tests don't cover a case the
127
+ old code was clearly written for, say so instead of silently dropping it.
128
+
129
+ ## Step 3: Research before recommending a new dependency (mandatory, live)
130
+
131
+ Rungs 1 through 5 need no research; they're free and already known to be safe.
132
+ Rung 6, a genuinely new dependency, is the one place memory goes stale fast: a
133
+ library that was the obvious choice eighteen months ago can be unmaintained,
134
+ superseded, or carrying an open CVE today. Never recommend a package from memory
135
+ alone. Check its current state first, live, with search. Checklist,
136
+ current-as-of-lookup sources, and red/green flags are in
137
+ `references/research-protocol.md`. Summarize the choice in one or two sentences
138
+ per swap in the final answer; this step is not the place to write an essay.
139
+
140
+ ## Step 4: Impact vs. flexibility, before writing the change
141
+
142
+ Before writing the replacement, work out:
143
+
144
+ - who else calls this (the blast radius may be bigger than the one call site that
145
+ prompted the change),
146
+ - what flexibility the current code buys and whether anyone actually uses it (grep
147
+ before removing), and
148
+ - whether the migration cost (call-site updates, type changes, test churn) is
149
+ worth what's gained.
150
+
151
+ If the trade isn't clearly worth it, say what was found and ask. The user knows
152
+ release timing and risk appetite that the code alone doesn't reveal. Full rubric
153
+ in `references/cost-impact-preflight.md`.
154
+
155
+ ## Step 5: Output discipline
156
+
157
+ - Show the diff or the changed function, not the whole file, unless the whole file
158
+ is asked for.
159
+ - One consolidated summary per batch of related changes, not a running commentary
160
+ per file.
161
+ - Batch logically related edits together instead of narrating each one separately.
162
+ - Don't restate the ladder or the research trail in the final answer. The user
163
+ needs the change and a one-line reason, not the process that produced it.
164
+
165
+ ## Incremental modernization methodology (Full/Partial scope)
166
+
167
+ For legacy/dated codebases, modernize in safe, verifiable increments — never a
168
+ big-bang rewrite. Keep a human in the loop at each gate.
169
+
170
+ ### Assess (read-only first)
171
+ - Map dependencies and the module graph; identify dead code and the highest-churn,
172
+ highest-complexity, highest-business-value hotspots.
173
+ - Use the `serena` LSP + `scout` subagent so this exploration doesn't fill main
174
+ context. Write findings to `MODERNIZATION.md`.
175
+ - Verify target frameworks/versions with `tech-selector` (current best, not
176
+ training-data defaults).
177
+
178
+ ### Safety net before changing anything
179
+ - Characterize current behavior with tests. If coverage is thin on the code you'll
180
+ touch, add regression tests that pin the *existing* output first — so a refactor
181
+ that changes behavior fails loudly.
182
+
183
+ ### Transform incrementally
184
+ - One bounded slice at a time (a module, a route, a component). Preserve business
185
+ logic exactly; modernize the form around it.
186
+ - After each slice: run tests + build + lint, and for UI use `ui-workflow`'s
187
+ screenshot check. Commit per slice with a conventional message so each step is
188
+ revertible.
189
+
190
+ ### Verify each slice
191
+ - Tests green, build passes, behavior unchanged (diff against the pinned regression
192
+ output). Use the `verifier` subagent on non-trivial slices.
193
+ - Patch security issues surfaced along the way (semgrep is installed) but keep them
194
+ as separate commits.
195
+
196
+ ### Document
197
+ - Update `MODERNIZATION.md` with what changed and why; capture any institutional
198
+ knowledge recovered from the old code before it's lost.
199
+
200
+ ### Guardrails
201
+ - Business continuity first: if a slice can't be proven behavior-preserving, stop
202
+ and surface it rather than guessing.
203
+ - No scope creep — modernize what the slice covers, not everything you notice.
204
+
205
+ ## Never lazy about (unchanged from ponytail)
206
+
207
+ Input validation at trust boundaries, error handling that prevents data loss,
208
+ security, accessibility, and anything the user explicitly asked for. These are
209
+ never traded away for a smaller diff, no matter which rung of the ladder applies.
210
+
211
+ ## Marking deferred opportunities
212
+
213
+ When a swap is correct in principle but out of scope for a Targeted request, don't
214
+ make it. Leave a one-line marker instead, mirroring ponytail's `ponytail:` comment:
215
+
216
+ ```js
217
+ // modernize: could use structuredClone() (Node 17+) instead of this deep-clone helper
218
+ ```
219
+
220
+ At the end of a session, list any `modernize:` markers left behind, so "later"
221
+ leaves a paper trail instead of quietly becoming "never."
222
+
223
+ ## Ask, don't assume
224
+
225
+ Stop and ask one direct question, don't proceed on a guess, when:
226
+
227
+ - Scope isn't stated and can't be inferred confidently (Step 0).
228
+ - Two well-maintained libraries are both reasonable and the right one depends on a
229
+ constraint the user hasn't stated (bundle size vs. features, already using a
230
+ sibling package from one ecosystem, etc.).
231
+ - The swap is a breaking change to a public API or an exported function.
232
+ - The "clean" replacement doesn't obviously cover an edge case the current code
233
+ handles.
234
+
235
+ ## Example
236
+
237
+ **Request:** "This `debounce` function in `hooks/useDebounce.ts` looks
238
+ hand-rolled, can you clean it up?"
239
+
240
+ This names an exact file and function, so it's **Targeted**; skip Step 1. Step 2:
241
+ read it and its tests; it correctly cancels on unmount, which a naive replacement
242
+ might miss. Step 3: `lodash` is already an installed dependency (rung 5) with a
243
+ well-tested `debounce`, so no new dependency and no research pass are needed.
244
+ Step 4: one call site, low risk, no flexibility lost. Result: a 3-line wrapper
245
+ around `lodash.debounce` that preserves the unmount-cancel behavior, with a
246
+ one-line note on why. Not a rewrite, not an essay, not a new package.
247
+
248
+ ## Relationship to ponytail
249
+
250
+ This skill deliberately does not re-implement ponytail's own commands
251
+ (`/ponytail-review`, `/ponytail-audit`, `/ponytail-debt`, its lite/full/ultra
252
+ intensity dial). That would be exactly the kind of reinventing this skill exists
253
+ to prevent. For governing new code as it's written, install ponytail itself in
254
+ Claude Code: it's free, MIT-licensed, actively maintained, and benchmarked at
255
+ roughly half the code and 20% lower cost against a no-skill baseline.
256
+
257
+ ```
258
+ /plugin marketplace add DietrichGebert/ponytail
259
+ /plugin install ponytail@ponytail
260
+ ```
261
+
262
+ The two compose cleanly. Ponytail keeps new code minimal as it's written; this
263
+ skill audits and modernizes what's already in the repo, with the scope control,
264
+ cost/impact gate, and live research discipline the ladder alone doesn't cover.
265
+
266
+ ## Reference files (load only when the step above points here)
267
+
268
+ - `references/research-protocol.md`: vetting a candidate library, current sources
269
+ to check, red/green flags, decision template.
270
+ - `references/design-patterns-cheatsheet.md`: smell → pattern → when to skip it,
271
+ compact table.
272
+ - `references/cost-impact-preflight.md`: full pre-flight output template and the
273
+ impact/flexibility rubric.
274
+ - `scripts/preflight_scan.py`: stdlib-only scanner for file count, LOC, and
275
+ dependency manifests.
@@ -0,0 +1,54 @@
1
+ # Cost / impact pre-flight and flexibility rubric
2
+
3
+ ## Pre-flight output template (Step 1)
4
+
5
+ Run `python3 scripts/preflight_scan.py <path>` and report:
6
+
7
+ ```
8
+ Scope: <Full|Partial> on <path>
9
+ ~<N> files, ~<X> lines in range
10
+ Dependencies already available: <short list from the manifest>
11
+ Flagged high-cost: <any file over ~800 lines, or the pass touching 15-20+ files, name them>
12
+ Estimated: <rough tool-call / diff count>, <low|medium|high> breaking-change risk
13
+ Proceed as scoped, narrow it, or switch to Targeted?
14
+ ```
15
+
16
+ ### Breaking-change risk levels
17
+
18
+ | Level | Criteria |
19
+ |---|---|
20
+ | **Low** | Internal/private functions only; no exported API changes; no type signature changes |
21
+ | **Medium** | Exported functions change signature but callers are all in-repo; or a dependency is swapped that has a slightly different API |
22
+ | **High** | Public API / SDK changes; cross-repo consumers possible; type changes that propagate through generics; removal of a feature flag or config option |
23
+
24
+ ### High-cost file handling
25
+
26
+ When a file exceeds ~800 lines or the total pass touches 15–20+ files:
27
+
28
+ 1. Name the files explicitly in the pre-flight report.
29
+ 2. Offer the user a choice: full detailed diff, summarized diff (key changes
30
+ only), or skip that file for now.
31
+ 3. Don't silently generate a massive diff — the user may want to split the work
32
+ across PRs.
33
+
34
+ ## Impact vs. flexibility rubric (Step 4)
35
+
36
+ Before writing each swap, evaluate:
37
+
38
+ | Question | If yes → | If no → |
39
+ |---|---|---|
40
+ | Does anyone else call this? | Check all call sites; mention them in the summary | Safe to change in isolation |
41
+ | Does the current code handle edge cases the replacement doesn't? | Keep the edge-case handling; wrap the replacement if needed | Straight swap |
42
+ | Does the current API surface offer flexibility someone might rely on? | Grep for usage of that flexibility; if unused, remove | Keep the simpler replacement |
43
+ | Is the migration cost (call-site updates, type changes, test churn) < the maintenance cost of keeping the old code? | Proceed | Defer — leave a `// modernize:` marker |
44
+ | Does the swap change observable behavior (return types, error messages, side effects)? | Treat as a breaking change; flag in the pre-flight report | Transparent swap |
45
+
46
+ ### When to defer instead of swap
47
+
48
+ - The swap is correct but the module is in active development (merge conflicts).
49
+ - The user said "Targeted" and the swap is outside the named scope.
50
+ - The migration cost is high and the old code works fine — it's debt, not a bug.
51
+ - Two equally good replacements exist and the choice depends on constraints the
52
+ user hasn't stated.
53
+
54
+ In all these cases, leave a `// modernize:` marker and list it at session end.
@@ -0,0 +1,24 @@
1
+ # Design patterns cheatsheet
2
+
3
+ Apply a pattern only when it removes real duplication or coupling. If the code is
4
+ already clear and short, a pattern adds ceremony for no gain — skip it.
5
+
6
+ | Smell | Pattern | When to skip |
7
+ |---|---|---|
8
+ | Copy-pasted logic with minor variations | **Strategy** — extract the varying part into a function/object, pass it in | Fewer than 3 copies, or the variations are trivial one-liners |
9
+ | Long `if/else` or `switch` choosing behavior by type/string | **Strategy** or **Map lookup** — a plain `Record<string, handler>` is usually enough | Only 2–3 branches and unlikely to grow |
10
+ | Object construction with many optional params | **Builder** or plain options object | A single config object with defaults already reads well |
11
+ | Multiple callers need the same setup/teardown around a core operation | **Template Method** (or just a higher-order function) | Only one caller — inline the setup |
12
+ | Need to react to state changes across unrelated modules | **Observer / Event emitter** | Two modules — a direct callback is simpler |
13
+ | Expensive object creation, same inputs → same output | **Flyweight / Cache / Memoize** | Object is cheap, or inputs rarely repeat |
14
+ | Access to a resource that needs lifecycle management | **Dispose / using / context manager** | Resource is process-scoped (no cleanup needed) |
15
+ | External API that doesn't match your domain model | **Adapter** | You control both sides — just change the source |
16
+ | Deep nesting of decorators or wrappers | **Middleware / Pipeline** — compose a flat list | Two wrappers max — nesting is still readable |
17
+ | Repeated null-checks or fallback chains | **Null Object** or optional chaining (`?.`) | Language already has `??` / `?.` — use it (rung 3/4) |
18
+
19
+ ## Anti-patterns to avoid
20
+
21
+ - **Singleton for testability**: makes mocking hard. Prefer dependency injection.
22
+ - **Factory for one type**: a constructor call is simpler.
23
+ - **Abstract base class with one subclass**: remove the abstraction.
24
+ - **Pattern just to match a textbook**: the code is the product, not the diagram.
@@ -0,0 +1,42 @@
1
+ # Research protocol — vetting a candidate library (rung 6)
2
+
3
+ Only reach this file when rungs 1–5 failed and a new dependency is genuinely on
4
+ the table. Never skip straight here.
5
+
6
+ ## Mandatory live checks
7
+
8
+ Run these before recommending. Stale memory is the failure mode this protocol
9
+ exists to prevent.
10
+
11
+ | Check | Source | Red flag |
12
+ |---|---|---|
13
+ | Last commit / release | GitHub releases or npm/PyPI page | > 12 months with open issues |
14
+ | Open CVEs | `npm audit` / `pip-audit` / Snyk DB / GitHub advisories | Any unpatched critical/high |
15
+ | Maintenance signal | Issue tracker, PR merge cadence | Dozens of unanswered issues, no maintainer response in months |
16
+ | Download trend | npm trends, PyPI stats | Steep decline or flatline vs. competitors |
17
+ | License compatibility | `package.json` / `setup.cfg` license field | Copyleft (GPL) in an MIT project, or no license |
18
+ | Bundle size (frontend) | bundlephobia.com or `import-cost` | > 50 kB gzipped for a single utility |
19
+ | Peer / transitive deps | `npm ls` / `pip show` | Pulls in a heavy tree for a small task |
20
+
21
+ ## Green flags (not required, but strengthen the case)
22
+
23
+ - Active maintainer with a history of responding to security reports.
24
+ - TypeScript types shipped (not DefinitelyTyped-only).
25
+ - Used by well-known projects (check dependents on GitHub).
26
+ - Clear migration path if abandoned (small API surface, stdlib fallback exists).
27
+
28
+ ## Decision template (one per candidate)
29
+
30
+ ```
31
+ Library: <name@version>
32
+ Rung: 6 (new dependency)
33
+ Replaces: <what hand-rolled code or older dep>
34
+ Last release: <date> | Weekly downloads: <N> | License: <X>
35
+ CVEs: <none | list>
36
+ Bundle impact: <+N kB gzipped> (frontend only)
37
+ Verdict: adopt / skip / ask user
38
+ Reason (1–2 sentences): ...
39
+ ```
40
+
41
+ Include this block in the final answer when recommending a new dependency. Keep it
42
+ short — the user needs the decision, not the research log.
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env python3
2
+ """Pre-flight scanner for code-modernizer skill.
3
+
4
+ Stdlib-only — nothing to install.
5
+
6
+ Usage:
7
+ python3 scripts/preflight_scan.py <path> [--json]
8
+
9
+ Reports file count, total lines of code, detected dependency manifests,
10
+ and flags high-cost files (> 800 lines).
11
+ """
12
+
13
+ import json
14
+ import os
15
+ import sys
16
+ from pathlib import Path
17
+
18
+ SKIP_DIRS = {
19
+ "node_modules", ".git", "__pycache__", ".venv", "venv",
20
+ "dist", "build", ".next", ".nuxt", "coverage", ".tox",
21
+ "vendor", "target", "out", ".cache", ".turbo",
22
+ }
23
+
24
+ CODE_EXTENSIONS = {
25
+ ".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs",
26
+ ".py", ".pyx",
27
+ ".rs", ".go", ".java", ".kt", ".kts",
28
+ ".c", ".cpp", ".cc", ".h", ".hpp",
29
+ ".rb", ".php", ".swift", ".scala",
30
+ ".vue", ".svelte", ".astro",
31
+ ".css", ".scss", ".less",
32
+ ".sql", ".sh", ".bash", ".zsh",
33
+ ".lua", ".zig", ".nim", ".ex", ".exs",
34
+ ".cs", ".fs",
35
+ }
36
+
37
+ MANIFEST_FILES = {
38
+ "package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml",
39
+ "requirements.txt", "pyproject.toml", "setup.py", "setup.cfg", "Pipfile",
40
+ "Cargo.toml", "go.mod", "Gemfile", "composer.json",
41
+ "build.gradle", "build.gradle.kts", "pom.xml",
42
+ "pubspec.yaml", "mix.exs",
43
+ }
44
+
45
+ HIGH_COST_THRESHOLD = 800
46
+
47
+
48
+ def count_lines(path: Path) -> int:
49
+ try:
50
+ with open(path, "r", encoding="utf-8", errors="replace") as f:
51
+ return sum(1 for _ in f)
52
+ except (OSError, UnicodeDecodeError):
53
+ return 0
54
+
55
+
56
+ def parse_dependencies(root: Path) -> list[str]:
57
+ deps = []
58
+ pkg = root / "package.json"
59
+ if pkg.is_file():
60
+ try:
61
+ data = json.loads(pkg.read_text(encoding="utf-8"))
62
+ for key in ("dependencies", "devDependencies"):
63
+ if key in data:
64
+ deps.extend(data[key].keys())
65
+ except (json.JSONDecodeError, OSError):
66
+ pass
67
+
68
+ req = root / "requirements.txt"
69
+ if req.is_file():
70
+ try:
71
+ for line in req.read_text(encoding="utf-8").splitlines():
72
+ line = line.strip()
73
+ if line and not line.startswith("#") and not line.startswith("-"):
74
+ name = line.split("==")[0].split(">=")[0].split("<=")[0].split("[")[0].strip()
75
+ if name:
76
+ deps.append(name)
77
+ except OSError:
78
+ pass
79
+
80
+ pyproject = root / "pyproject.toml"
81
+ if pyproject.is_file():
82
+ try:
83
+ content = pyproject.read_text(encoding="utf-8")
84
+ in_deps = False
85
+ for line in content.splitlines():
86
+ if line.strip().startswith("dependencies"):
87
+ in_deps = True
88
+ continue
89
+ if in_deps:
90
+ if line.strip() == "]":
91
+ in_deps = False
92
+ continue
93
+ dep = line.strip().strip('",').split(">=")[0].split("==")[0].split("<")[0].strip()
94
+ if dep:
95
+ deps.append(dep)
96
+ except OSError:
97
+ pass
98
+
99
+ return sorted(set(deps))
100
+
101
+
102
+ def scan(root: Path) -> dict:
103
+ file_count = 0
104
+ total_lines = 0
105
+ high_cost_files = []
106
+ manifests_found = []
107
+
108
+ for dirpath, dirnames, filenames in os.walk(root):
109
+ dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS]
110
+
111
+ for fname in filenames:
112
+ fpath = Path(dirpath) / fname
113
+
114
+ if fname in MANIFEST_FILES:
115
+ manifests_found.append(str(fpath.relative_to(root)))
116
+
117
+ if fpath.suffix.lower() in CODE_EXTENSIONS:
118
+ file_count += 1
119
+ lines = count_lines(fpath)
120
+ total_lines += lines
121
+ if lines > HIGH_COST_THRESHOLD:
122
+ high_cost_files.append({
123
+ "file": str(fpath.relative_to(root)),
124
+ "lines": lines,
125
+ })
126
+
127
+ deps = parse_dependencies(root)
128
+
129
+ return {
130
+ "root": str(root),
131
+ "file_count": file_count,
132
+ "total_lines": total_lines,
133
+ "manifests": manifests_found,
134
+ "dependencies": deps,
135
+ "high_cost_files": sorted(high_cost_files, key=lambda x: -x["lines"]),
136
+ }
137
+
138
+
139
+ def format_report(result: dict) -> str:
140
+ lines = [
141
+ f"Scope: scan on {result['root']}",
142
+ f"~{result['file_count']} files, ~{result['total_lines']} lines of code",
143
+ ]
144
+
145
+ if result["dependencies"]:
146
+ dep_preview = result["dependencies"][:20]
147
+ dep_str = ", ".join(dep_preview)
148
+ if len(result["dependencies"]) > 20:
149
+ dep_str += f" (+{len(result['dependencies']) - 20} more)"
150
+ lines.append(f"Dependencies already available: {dep_str}")
151
+ else:
152
+ lines.append("Dependencies already available: (none detected)")
153
+
154
+ if result["high_cost_files"]:
155
+ hc = "; ".join(f"{f['file']} ({f['lines']} lines)" for f in result["high_cost_files"][:10])
156
+ lines.append(f"Flagged high-cost (>{HIGH_COST_THRESHOLD} lines): {hc}")
157
+ else:
158
+ lines.append(f"Flagged high-cost: none (all files <{HIGH_COST_THRESHOLD} lines)")
159
+
160
+ risk = "low"
161
+ if result["file_count"] > 20:
162
+ risk = "medium"
163
+ if result["file_count"] > 50 or result["total_lines"] > 20000:
164
+ risk = "high"
165
+
166
+ lines.append(f"Estimated breaking-change risk: {risk}")
167
+
168
+ return "\n".join(lines)
169
+
170
+
171
+ def main():
172
+ if len(sys.argv) < 2:
173
+ print(f"Usage: {sys.argv[0]} <path> [--json]", file=sys.stderr)
174
+ sys.exit(1)
175
+
176
+ target = Path(sys.argv[1]).resolve()
177
+ if not target.is_dir():
178
+ print(f"Error: {target} is not a directory", file=sys.stderr)
179
+ sys.exit(1)
180
+
181
+ result = scan(target)
182
+
183
+ if "--json" in sys.argv:
184
+ print(json.dumps(result, indent=2))
185
+ else:
186
+ print(format_report(result))
187
+
188
+
189
+ if __name__ == "__main__":
190
+ main()
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: cognitive-substrate
3
+ description: >-
4
+ Use before ambiguous, expensive, multi-file, or mutating coding work to run
5
+ Forge's cognitive substrate: assumption gate, model routing, impact
6
+ prediction, scope decomposition, memory/lesson lookup, minimality check, and
7
+ verification planning. Trigger when a user asks to edit/refactor/fix/design
8
+ production code, integrate features, choose model effort, inspect blast
9
+ radius, or avoid agent assumptions.
10
+ ---
11
+
12
+ # Cognitive Substrate
13
+
14
+ Wrap the frozen model in a pre-action check: gate assumptions, route model effort, predict
15
+ blast radius, decompose scope, surface past lessons, and plan verification — **before** editing.
16
+
17
+ ## When to run it
18
+
19
+ Any ambiguous, expensive, multi-file, or mutating task. Skip one-line, well-specified fixes.
20
+ In Claude Code it fires automatically on every prompt (UserPromptSubmit hook); in other
21
+ agents run the CLI yourself, or call the MCP tool `substrate_check`.
22
+
23
+ ## Run
24
+
25
+ ```bash
26
+ forge substrate "<task>" --json # full contract; use the fields below
27
+ ```
28
+
29
+ ## Act on the result
30
+
31
+ 1. **`okToProceed: false`** → ask the returned `assumption.questions` before editing. Do not guess.
32
+ 2. **`route.tier`** → start at that model tier (cheapest capable); escalate only after an external verifier fails.
33
+ 3. **`impact.impactedFiles`** → read these before editing a named symbol/file (the blast radius).
34
+ 4. **`scope.clusters`** → split independent groups into separate sessions; note coupled files you didn't name.
35
+ 5. **`memory.advisory`** → context, not law; tests and human corrections override it.
36
+ 6. **`verification.checklist`** → run it and show output before claiming done.
37
+
38
+ ## Worked example
39
+
40
+ `forge substrate "make the auth better"` → `proceed: ASK FIRST` + clarify
41
+ questions: ask them instead of editing. A clear task returns `proceed: yes` plus
42
+ the impacted files — including importers you didn't name.
43
+
44
+ ## Deeper single checks
45
+
46
+ `forge preflight "<task>"` (assumptions) · `forge route "<task>"` (model tier) ·
47
+ `forge impact <symbol|file>` (blast radius) · `forge scope <file…>` (decomposition) ·
48
+ `forge context "<task>"` (budgeted context assembly; *computes* what's missing) ·
49
+ `forge imagine "<task>" [--run]` (predicted breaks + minimal covering test suite;
50
+ `--run` dry-runs it in a sandboxed worktree) ·
51
+ `forge diagnose "<error>"` (doom-loop: 3× the same failure signature = stop retrying,
52
+ escalate one tier with the minted diagnosis claim at the head of the prompt).
53
+ MCP equivalents: `assumption_gate`, `route_task`, `predict_impact`, `scope_files`.
54
+
55
+ For the full guide (how it works, extending it, the honesty boundary) and the white paper,
56
+ see `docs/cognitive-substrate/README.md`. `references/capability-map.md` maps faculties to commands.
@@ -0,0 +1,17 @@
1
+ # Cognitive substrate capability map
2
+
3
+ | Paper capability | Forge surface | Guarantee |
4
+ | --- | --- | --- |
5
+ | Memory | `forge recall`, `forge cortex`, `forge ledger` | Facts/lessons persist as content-addressed ledger claims; `forge ledger blame` shows provenance. |
6
+ | Learning | `forge cortex`, ledger oracles | External outcomes (tests, CI, human accept/revert) move claim confidence; model weights do not change. |
7
+ | Imagination | `forge imagine [--run]`, `forge impact` | Predicted breaks + minimal covering test suite; `--run` dry-runs it in a sandboxed worktree. |
8
+ | Self-correction | `forge verify`, `forge diagnose` | Tests/builds beat model claims; 3× the same failure signature mints a diagnosis + escalation. |
9
+ | Impact-awareness | `forge atlas`, `forge impact` | Known symbols/files and likely dependents are surfaced. |
10
+ | M1 routing | `forge route` | Transparent model-tier recommendation. |
11
+ | M2 assumption gate | `forge preflight`, `forge context` | Under-specified tasks return *computed* missing-set questions. |
12
+ | M3 decomposition | `forge scope` | Import clusters show independent vs coupled files. |
13
+ | M4 goal anchoring | `forge anchor`, `forge substrate` | Changed files are checked against the stated goal. |
14
+ | M5 anti-over-engineering | `forge lean`, `forge uicheck design` | Footprint vs ask; UI slop-distance + fingerprint conformance gate. |
15
+ | M6 inline verification | `forge verify` | External checks are required before done. |
16
+
17
+ Limits: static graph edges are conservative; memory relevance and model routing are advisory; non-hook tools cannot be forcibly blocked.