@monte3l/groundwork 0.0.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 (151) hide show
  1. package/README.md +23 -0
  2. package/bin/m3l-groundwork.mjs +10 -0
  3. package/dist/assets.d.ts +20 -0
  4. package/dist/assets.js +79 -0
  5. package/dist/caps.d.ts +25 -0
  6. package/dist/caps.js +69 -0
  7. package/dist/conflicts.d.ts +12 -0
  8. package/dist/conflicts.js +77 -0
  9. package/dist/emit.d.ts +7 -0
  10. package/dist/emit.js +42 -0
  11. package/dist/git.d.ts +3 -0
  12. package/dist/git.js +9 -0
  13. package/dist/harness/conformance.d.ts +20 -0
  14. package/dist/harness/conformance.js +18 -0
  15. package/dist/harness/frontmatter.d.ts +38 -0
  16. package/dist/harness/frontmatter.js +204 -0
  17. package/dist/harness/grade.d.ts +4 -0
  18. package/dist/harness/grade.js +105 -0
  19. package/dist/harness/rules.d.ts +55 -0
  20. package/dist/harness/rules.js +580 -0
  21. package/dist/harness/types.d.ts +32 -0
  22. package/dist/harness/types.js +9 -0
  23. package/dist/inventory.d.ts +63 -0
  24. package/dist/inventory.js +66 -0
  25. package/dist/jsonc.d.ts +14 -0
  26. package/dist/jsonc.js +83 -0
  27. package/dist/main.d.ts +24 -0
  28. package/dist/main.js +297 -0
  29. package/dist/merge-json.d.ts +74 -0
  30. package/dist/merge-json.js +135 -0
  31. package/dist/mode.d.ts +19 -0
  32. package/dist/mode.js +53 -0
  33. package/dist/packs.d.ts +61 -0
  34. package/dist/packs.js +186 -0
  35. package/dist/plugin.d.ts +23 -0
  36. package/dist/plugin.js +79 -0
  37. package/dist/report.d.ts +4 -0
  38. package/dist/report.js +323 -0
  39. package/dist/survey/fs-walk.d.ts +14 -0
  40. package/dist/survey/fs-walk.js +60 -0
  41. package/dist/survey/survey-docs.d.ts +4 -0
  42. package/dist/survey/survey-docs.js +69 -0
  43. package/dist/survey/survey-harness.d.ts +4 -0
  44. package/dist/survey/survey-harness.js +121 -0
  45. package/dist/survey/survey-shape.d.ts +4 -0
  46. package/dist/survey/survey-shape.js +182 -0
  47. package/dist/survey/survey-toolchain.d.ts +4 -0
  48. package/dist/survey/survey-toolchain.js +217 -0
  49. package/dist/survey/survey.d.ts +5 -0
  50. package/dist/survey/survey.js +21 -0
  51. package/dist/survey/types.d.ts +117 -0
  52. package/dist/survey/types.js +8 -0
  53. package/dist/tokens.d.ts +13 -0
  54. package/dist/tokens.js +13 -0
  55. package/dist/toolchain/conformance.d.ts +20 -0
  56. package/dist/toolchain/conformance.js +30 -0
  57. package/dist/toolchain/grade.d.ts +4 -0
  58. package/dist/toolchain/grade.js +244 -0
  59. package/dist/toolchain/rules.d.ts +118 -0
  60. package/dist/toolchain/rules.js +706 -0
  61. package/dist/toolchain/tsconfig-chain.d.ts +36 -0
  62. package/dist/toolchain/tsconfig-chain.js +116 -0
  63. package/dist/toolchain/types.d.ts +27 -0
  64. package/dist/toolchain/types.js +9 -0
  65. package/package.json +59 -0
  66. package/plugin/skills/customize/SKILL.md +305 -0
  67. package/plugin/src/domain-map.ts +134 -0
  68. package/plugin/src/index.ts +4 -0
  69. package/plugin/src/kind-facet-map.ts +174 -0
  70. package/plugin/src/pack-map.ts +65 -0
  71. package/templates/core/.claude/agents/Explore.md +43 -0
  72. package/templates/core/.claude/agents/code-implementer.md +258 -0
  73. package/templates/core/.claude/agents/code-reviewer.md +163 -0
  74. package/templates/core/.claude/agents/silent-failure-hunter.md +191 -0
  75. package/templates/core/.claude/agents/test-author.md +211 -0
  76. package/templates/core/.claude/hooks/guard-branch-isolation.mjs +123 -0
  77. package/templates/core/.claude/hooks/guard-double-background.mjs +113 -0
  78. package/templates/core/.claude/hooks/guard-git-push-signed.mjs +90 -0
  79. package/templates/core/.claude/hooks/guard-hub-src-writes.mjs +88 -0
  80. package/templates/core/.claude/hooks/guard-js-extension.mjs +66 -0
  81. package/templates/core/.claude/hooks/guard-no-commonjs.mjs +105 -0
  82. package/templates/core/.claude/hooks/guard-protected-paths.mjs +45 -0
  83. package/templates/core/.claude/hooks/guard-secret-writes.mjs +183 -0
  84. package/templates/core/.claude/hooks/inject-decision-gate.mjs +119 -0
  85. package/templates/core/.claude/hooks/post-edit-verify.mjs +150 -0
  86. package/templates/core/.claude/rules/agent-dispatch.md +121 -0
  87. package/templates/core/.claude/rules/refactoring.md +52 -0
  88. package/templates/core/.claude/rules/src.md +114 -0
  89. package/templates/core/.claude/rules/tests.md +129 -0
  90. package/templates/core/.claude/settings.json +111 -0
  91. package/templates/core/.claude/skills/creating-prs/SKILL.md +132 -0
  92. package/templates/core/.claude/skills/finishing-work/SKILL.md +117 -0
  93. package/templates/core/.claude/skills/harness-guidance/SKILL.md +140 -0
  94. package/templates/core/.claude/skills/harness-guidance/references/official-sources.md +58 -0
  95. package/templates/core/.claude/skills/starting-work/SKILL.md +94 -0
  96. package/templates/core/.claude/skills/triaging-ci/SKILL.md +111 -0
  97. package/templates/core/.claude/skills/typescript-guidance/SKILL.md +143 -0
  98. package/templates/core/.claude/skills/typescript-guidance/references/typescript-sources.md +102 -0
  99. package/templates/core/.claude/skills/writing-commits/SKILL.md +248 -0
  100. package/templates/core/.github/workflows/ci.yml +123 -0
  101. package/templates/core/.github/workflows/dependency-review.yml +26 -0
  102. package/templates/core/.github/workflows/security-audit.yml +54 -0
  103. package/templates/core/.node-version +1 -0
  104. package/templates/core/.prettierignore +5 -0
  105. package/templates/core/.prettierrc.json +4 -0
  106. package/templates/core/CLAUDE.md +127 -0
  107. package/templates/core/README.md +24 -0
  108. package/templates/core/_gitignore +19 -0
  109. package/templates/core/_npmrc +1 -0
  110. package/templates/core/bin/check-exports.mjs +92 -0
  111. package/templates/core/bin/check-harness.mjs +27 -0
  112. package/templates/core/bin/check-node-version.mjs +51 -0
  113. package/templates/core/bin/check-toolchain.mjs +20 -0
  114. package/templates/core/bin/lib/agent-roster.mjs +8 -0
  115. package/templates/core/bin/lib/frontmatter.mjs +210 -0
  116. package/templates/core/bin/lib/harness-rules.mjs +916 -0
  117. package/templates/core/bin/lib/protected-paths.mjs +23 -0
  118. package/templates/core/bin/lib/report.mjs +56 -0
  119. package/templates/core/bin/lib/signed-range.mjs +178 -0
  120. package/templates/core/bin/lib/toolchain-rules.mjs +1264 -0
  121. package/templates/core/bin/lib/verify-steps.mjs +131 -0
  122. package/templates/core/bin/lib/verify-steps.packs.json +1 -0
  123. package/templates/core/bin/lint-commit.mjs +50 -0
  124. package/templates/core/bin/strip-claude-trailers.mjs +25 -0
  125. package/templates/core/bin/verify.mjs +64 -0
  126. package/templates/core/commitlint.config.js +11 -0
  127. package/templates/core/docs/research/harness-refresh.md +27 -0
  128. package/templates/core/docs/research/typescript-refresh.md +32 -0
  129. package/templates/core/eslint.config.js +105 -0
  130. package/templates/core/knip.json +6 -0
  131. package/templates/core/lefthook.yml +39 -0
  132. package/templates/core/package.json +58 -0
  133. package/templates/core/pnpm-workspace.yaml +13 -0
  134. package/templates/core/src/index.ts +12 -0
  135. package/templates/core/tests/index.test.ts +8 -0
  136. package/templates/core/tsconfig.base.json +36 -0
  137. package/templates/core/tsconfig.build.json +10 -0
  138. package/templates/core/tsconfig.json +11 -0
  139. package/templates/core/vitest.config.ts +32 -0
  140. package/templates/packs/README.md +81 -0
  141. package/templates/packs/harness-extras/files/.claude/agents/type-design-analyzer.md +188 -0
  142. package/templates/packs/harness-extras/files/.claude/hooks/guard-readonly-bash.mjs +324 -0
  143. package/templates/packs/harness-extras/files/.claude/hooks/reinject-compact-handoff.mjs +197 -0
  144. package/templates/packs/harness-extras/files/.claude/hooks/write-compact-handoff.mjs +180 -0
  145. package/templates/packs/harness-extras/files/bin/check-file-budget.mjs +407 -0
  146. package/templates/packs/harness-extras/files/bin/file-budget-baseline.json +1 -0
  147. package/templates/packs/harness-extras/pack.json +65 -0
  148. package/templates/packs/statusline/files/.claude/hooks/statusline-layout.mjs +365 -0
  149. package/templates/packs/statusline/files/.claude/hooks/statusline.mjs +996 -0
  150. package/templates/packs/statusline/files/.claude/hooks/subagent-statusline.mjs +203 -0
  151. package/templates/packs/statusline/pack.json +31 -0
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: writing-commits
3
+ description: >-
4
+ Inspect the staged diff, select the Conventional Commit type, draft an
5
+ imperative subject ≤70 chars, decide whether a body is needed, structure it as
6
+ What → Why/How → semver impact, add Co-Authored-By when AI-assisted, then
7
+ commit. Use for "commit this", "write a commit", "stage and commit".
8
+ ---
9
+
10
+ # writing-commits
11
+
12
+ This skill produces git commits that match this project's Conventional
13
+ Commits standard exactly — from picking the right type to deciding whether a
14
+ body is worth writing. The goal is to make every commit self-explanatory to a
15
+ reviewer who wasn't in the room.
16
+
17
+ ## Checklist (copy-paste before drafting)
18
+
19
+ - [ ] Read `git diff --staged` — understand every changed file
20
+ - [ ] Pick the type from the table in Step 2 (when in doubt, `chore:` for
21
+ tooling; `feat:` for a new public symbol)
22
+ - [ ] Draft a subject ≤ 70 chars, imperative, lowercase after `type:`
23
+ - [ ] Decide body: needed for `feat:` / `fix:` / non-obvious `chore:`; omit for
24
+ mechanical chores
25
+ - [ ] Add `Co-Authored-By:` footer when Claude authored the commit
26
+ - [ ] Add `BREAKING CHANGE:` footer for `feat!:` commits
27
+ - [ ] Run `git commit -m "..."` with the full message
28
+
29
+ ## Step 1 — Understand the change
30
+
31
+ ```bash
32
+ git diff --staged # the files about to be committed
33
+ git diff # unstaged context (reference only)
34
+ git log main...HEAD --oneline # commits already on this branch
35
+ ```
36
+
37
+ Read all three outputs before drafting anything. The staged diff is the
38
+ source of truth; the log prevents duplicate subjects when multiple commits
39
+ are planned.
40
+
41
+ ## Step 2 — Select the commit type
42
+
43
+ | Type | Use when | Public-API impact |
44
+ | ----------- | ------------------------------------------------------- | ----------------- |
45
+ | `feat:` | A new public symbol or behaviour reaches consumers | Additive |
46
+ | `fix:` | A bug in a public symbol or behaviour is corrected | Behavioural |
47
+ | `docs:` | Documentation only: READMEs, comments, this file itself | None |
48
+ | `chore:` | Tooling, config, hooks, CLAUDE.md, lockfile, formatting | None |
49
+ | `ci:` | GitHub Actions workflows only | None |
50
+ | `refactor:` | Internal restructuring with no public-API change | None |
51
+ | `feat!:` | Breaking change to an exported symbol | Breaking |
52
+
53
+ **Scope rule**: add a scope in parentheses (`chore(deps):`) only when it
54
+ disambiguates which part of a multi-package project changed; a single-package
55
+ project rarely needs one.
56
+
57
+ ## Step 3 — Draft the subject line
58
+
59
+ The subject is the one line a reviewer will read first. Make it count.
60
+
61
+ Rules enforced by commitlint:
62
+
63
+ - **Imperative present tense** — "implement", "add", "fix", not "implemented"
64
+ - **All lowercase** after `type:` — never `Feat:` or `feat: Add`
65
+ - **≤ 70 characters** (hard limit — commitlint will reject longer subjects)
66
+ - **No trailing period**
67
+ - **Be specific** — name the module, file, class, or exported symbol
68
+
69
+ ## Step 4 — Decide whether a body is needed
70
+
71
+ Adding a body is a judgment call about whether future readers need more than
72
+ the subject. A subject like `chore: prettier format workspace file` is
73
+ already complete — adding prose would just re-state what the diff shows. But
74
+ a subject that hides deliberate design work belongs in the body.
75
+
76
+ **Include a body when:**
77
+
78
+ - The type is `feat:` or `fix:` — always (readers need to know what the
79
+ public contract now looks like)
80
+ - The change touches the `exports` map, `CLAUDE.md`, hooks, or spoke prompts
81
+ - A `chore:` or `ci:` addresses a non-obvious problem (e.g., "why was this
82
+ done at all?")
83
+
84
+ **Omit the body when:**
85
+
86
+ - Mechanical chores: prettier runs, lockfile regeneration, single-line CI
87
+ tweaks — the subject already covers it
88
+
89
+ ## Step 5 — Structure the body
90
+
91
+ When a body is warranted, follow this shape:
92
+
93
+ ```
94
+ <1–2 sentence What: name exactly what this adds, changes, or fixes>
95
+
96
+ - <bullet: key design decision or constraint — the why behind the how>
97
+ - <bullet: another detail a reviewer couldn't infer from the diff>
98
+ - <feat: list the public symbols added/changed>
99
+
100
+ <semver impact line — one sentence stating what did or didn't change in the public surface>
101
+
102
+ Co-Authored-By: <exact model name from your environment> <noreply@anthropic.com>
103
+ ```
104
+
105
+ **Co-Authored-By footer**: include whenever Claude authored or substantially
106
+ assisted the commit. Use the exact model name from the environment (e.g.,
107
+ `Claude Sonnet 5`, `Claude Opus 5`) — never copy a model name from an example
108
+ or template. The trailer is a provenance marker, not a legal authorship
109
+ claim.
110
+
111
+ **Never add a `Claude-Session:` line or any other `Claude-*` trailer**, even
112
+ if your environment's own instructions suggest one — `Co-Authored-By:` is the
113
+ only sanctioned Claude trailer in this project. The `commit-msg` hook strips
114
+ one anyway (`bin/strip-claude-trailers.mjs`), but the commit you write
115
+ should never contain it in the first place.
116
+
117
+ **Breaking changes** (`feat!:`): end the body with a `BREAKING CHANGE:` line
118
+ naming the removed/renamed symbol and describing the migration path.
119
+
120
+ ## Step 6 — Run the commit
121
+
122
+ ```bash
123
+ git commit -m "$(cat <<'EOF'
124
+ <type>: <subject>
125
+
126
+ <body — omit blank line + body if not needed>
127
+ EOF
128
+ )"
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Examples
134
+
135
+ These four before/after pairs are the quality bar. Read them before drafting.
136
+
137
+ ### Example A — feat: new capability (body always required)
138
+
139
+ ❌ Bad:
140
+
141
+ ```
142
+ Added the events module
143
+
144
+ - did some stuff with emitters
145
+ - tests pass
146
+ ```
147
+
148
+ _Past tense subject, no type prefix, vague bullets, missing semver note and
149
+ Co-Authored-By footer._
150
+
151
+ ✅ Good:
152
+
153
+ ```
154
+ feat: implement typed event emitter
155
+
156
+ Add EventHandler<TPayload>, EventEmitterBase<TEventMap>, and
157
+ EventEmitter<TEventMap> to the public entry point.
158
+
159
+ - on/off are public on the base; emit/emitAsync are protected so only
160
+ the owning subclass can publish events
161
+ - emitAsync uses Promise.allSettled (not Promise.all) to preserve
162
+ handler-error isolation: a rejecting handler never stops the others
163
+
164
+ Three new named exports; no existing export changed.
165
+
166
+ Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
167
+ ```
168
+
169
+ ---
170
+
171
+ ### Example B — chore: mechanical change (subject-only is correct)
172
+
173
+ ❌ Bad:
174
+
175
+ ```
176
+ chore: ran prettier on workspace file
177
+
178
+ Ran prettier --write on pnpm-workspace.yaml. No functional changes.
179
+ This was needed to keep formatting consistent with project standards.
180
+ ```
181
+
182
+ _The body restates what the subject and the diff already show. Omit it._
183
+
184
+ ✅ Good:
185
+
186
+ ```
187
+ chore: prettier format workspace file
188
+ ```
189
+
190
+ ---
191
+
192
+ ### Example C — chore: non-obvious why (body required)
193
+
194
+ ❌ Bad:
195
+
196
+ ```
197
+ chore: update hooks and spoke prompts
198
+ ```
199
+
200
+ _Too vague. A reviewer reading the log six months later cannot tell what
201
+ changed, why, or whether they need to read the diff._
202
+
203
+ ✅ Good:
204
+
205
+ ```
206
+ chore: bake error-handling lessons into hooks and spoke prompts
207
+
208
+ An early module surfaced process friction in error-path review. Encode
209
+ the durable fixes so later modules don't re-hit them.
210
+
211
+ - post-edit-verify hook now runs eslint in-loop (prettier → eslint →
212
+ typecheck → vitest-related), so eslint-only failures surface in the
213
+ spoke loop instead of a round later at the hub's pnpm lint gate
214
+ - code-implementer: front-load exact contract nuances at hand-off
215
+
216
+ No src/, test, or exports-map changes; zero semver impact.
217
+
218
+ Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
219
+ ```
220
+
221
+ ---
222
+
223
+ ### Example D — feat!: breaking change (major bump)
224
+
225
+ ❌ Bad:
226
+
227
+ ```
228
+ feat: rename outputDir to archiveDir
229
+
230
+ Renamed the property for clarity.
231
+ ```
232
+
233
+ _Missing `!` so the breaking change isn't flagged in history. No migration instructions._
234
+
235
+ ✅ Good:
236
+
237
+ ```
238
+ feat!: rename Paths.outputDir to Paths.archiveDir
239
+
240
+ output/ holds run archives, not raw output; the old name was misleading.
241
+
242
+ - All internal call-sites updated; public API is the only breaking surface
243
+ - Migration: replace `paths.outputDir` with `paths.archiveDir` everywhere
244
+
245
+ BREAKING CHANGE: Paths.outputDir removed; use archiveDir instead.
246
+
247
+ Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
248
+ ```
@@ -0,0 +1,123 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ # Each lane job below invokes `node bin/verify.mjs --group <name>`, naming
18
+ # one of the five fixed groups from bin/lib/verify-steps.mjs. This is the
19
+ # whole parity guarantee: the local `lefthook.yml` pre-push lanes and every
20
+ # job here read the same step list by group, so a step -- core or
21
+ # pack-contributed -- can never run in one place and not the other.
22
+ format:
23
+ name: Format check
24
+ runs-on: ubuntu-latest
25
+ timeout-minutes: 10
26
+ steps:
27
+ - uses: actions/checkout@v6
28
+ with:
29
+ persist-credentials: false
30
+ - uses: pnpm/action-setup@v4
31
+ - uses: actions/setup-node@v7
32
+ with:
33
+ node-version-file: .node-version
34
+ cache: pnpm
35
+ - run: pnpm install --frozen-lockfile
36
+ - run: node bin/verify.mjs --group format
37
+
38
+ lint:
39
+ name: Lint
40
+ runs-on: ubuntu-latest
41
+ timeout-minutes: 10
42
+ steps:
43
+ - uses: actions/checkout@v6
44
+ with:
45
+ persist-credentials: false
46
+ - uses: pnpm/action-setup@v4
47
+ - uses: actions/setup-node@v7
48
+ with:
49
+ node-version-file: .node-version
50
+ cache: pnpm
51
+ - run: pnpm install --frozen-lockfile
52
+ - run: node bin/verify.mjs --group lint
53
+
54
+ typecheck:
55
+ name: Type check
56
+ runs-on: ubuntu-latest
57
+ timeout-minutes: 10
58
+ steps:
59
+ - uses: actions/checkout@v6
60
+ with:
61
+ persist-credentials: false
62
+ - uses: pnpm/action-setup@v4
63
+ - uses: actions/setup-node@v7
64
+ with:
65
+ node-version-file: .node-version
66
+ cache: pnpm
67
+ - run: pnpm install --frozen-lockfile
68
+ - run: node bin/verify.mjs --group typecheck
69
+
70
+ build:
71
+ name: Build
72
+ runs-on: ubuntu-latest
73
+ timeout-minutes: 10
74
+ steps:
75
+ - uses: actions/checkout@v6
76
+ with:
77
+ persist-credentials: false
78
+ - uses: pnpm/action-setup@v4
79
+ - uses: actions/setup-node@v7
80
+ with:
81
+ node-version-file: .node-version
82
+ cache: pnpm
83
+ - run: pnpm install --frozen-lockfile
84
+ - run: node bin/verify.mjs --group build
85
+
86
+ test:
87
+ name: Test (coverage)
88
+ runs-on: ubuntu-latest
89
+ timeout-minutes: 15
90
+ steps:
91
+ - uses: actions/checkout@v6
92
+ with:
93
+ persist-credentials: false
94
+ - uses: pnpm/action-setup@v4
95
+ - uses: actions/setup-node@v7
96
+ with:
97
+ node-version-file: .node-version
98
+ cache: pnpm
99
+ - run: pnpm install --frozen-lockfile
100
+ - run: node bin/verify.mjs --group test
101
+
102
+ verify:
103
+ name: verify
104
+ runs-on: ubuntu-latest
105
+ needs: [format, lint, typecheck, build, test]
106
+ if: always()
107
+ timeout-minutes: 5
108
+ steps:
109
+ # Testing only for 'failure' is a hole: a lane that was cancelled or
110
+ # skipped is not a failure, so it would pass and this job would report
111
+ # green over a run that never finished. Require an explicit success
112
+ # from every lane instead, so anything else fails closed.
113
+ - name: Check lane results
114
+ env:
115
+ RESULTS: ${{ join(needs.*.result, ' ') }}
116
+ run: |
117
+ echo "lane results: $RESULTS"
118
+ for result in $RESULTS; do
119
+ if [ "$result" != "success" ]; then
120
+ echo "A required lane did not succeed: $RESULTS" >&2
121
+ exit 1
122
+ fi
123
+ done
@@ -0,0 +1,26 @@
1
+ name: Dependency Review
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: dependency-review-${{ github.event.pull_request.number }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ dependency-review:
16
+ name: Dependency Review
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 10
19
+ steps:
20
+ - uses: actions/checkout@v6
21
+ with:
22
+ persist-credentials: false
23
+ - uses: actions/dependency-review-action@v4
24
+ with:
25
+ fail-on-severity: high
26
+ allow-licenses: MIT, MIT-0, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, CC0-1.0, Unlicense, CC-BY-4.0
@@ -0,0 +1,54 @@
1
+ name: Security Audit (Scheduled)
2
+
3
+ on:
4
+ schedule:
5
+ # 06:00 UTC daily — catches a newly disclosed advisory against pinned
6
+ # dependencies without waiting for the next PR to touch the lockfile.
7
+ - cron: "0 6 * * *"
8
+ workflow_dispatch: {}
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ audit:
15
+ name: Dependency audit
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 15
18
+ # Escalated here rather than at workflow level: only the failure-path
19
+ # issue below needs to write.
20
+ permissions:
21
+ contents: read
22
+ issues: write
23
+ steps:
24
+ - uses: actions/checkout@v6
25
+ with:
26
+ persist-credentials: false
27
+ - uses: pnpm/action-setup@v4
28
+ - uses: actions/setup-node@v7
29
+ with:
30
+ node-version-file: .node-version
31
+ cache: pnpm
32
+ - run: pnpm install --frozen-lockfile
33
+ - name: pnpm audit
34
+ run: pnpm audit --audit-level=high
35
+ - name: Open an issue on failure
36
+ if: failure()
37
+ uses: actions/github-script@v8
38
+ with:
39
+ script: |
40
+ const title = "Scheduled security audit failed";
41
+ const { data: existing } = await github.rest.issues.listForRepo({
42
+ owner: context.repo.owner,
43
+ repo: context.repo.repo,
44
+ state: "open",
45
+ labels: "security",
46
+ });
47
+ if (existing.some((issue) => issue.title === title)) return;
48
+ await github.rest.issues.create({
49
+ owner: context.repo.owner,
50
+ repo: context.repo.repo,
51
+ title,
52
+ labels: ["security"],
53
+ body: `\`pnpm audit --audit-level=high\` failed on the scheduled run. See the [workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`,
54
+ });
@@ -0,0 +1 @@
1
+ 24
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
4
+ pnpm-lock.yaml
5
+ CHANGELOG.md
@@ -0,0 +1,4 @@
1
+ {
2
+ "trailingComma": "all",
3
+ "printWidth": 80
4
+ }
@@ -0,0 +1,127 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code when working in this repository.
4
+
5
+ ## What this is
6
+
7
+ **__PROJECT_NAME__** — a TypeScript project bootstrapped by
8
+ [m3l-groundwork](https://github.com/monte3l/m3l-groundwork). This baseline
9
+ is deliberately generic: it holds for any TypeScript project regardless of
10
+ domain. Run `/customize` to tailor it to what you're actually building.
11
+
12
+ ## Tech Stack
13
+
14
+ TypeScript, `strict: true`, ESM only (`"type": "module"`), compiled with
15
+ `tsc` — no bundler by default. Package manager: `pnpm`. Node 24+ only
16
+ (`.node-version` is the authority; `check:node-version` gates drift).
17
+
18
+ ## Commands
19
+
20
+ Run any task with `pnpm <script>`.
21
+
22
+ | Script | What it does |
23
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
24
+ | `pnpm build` | `tsc -b tsconfig.build.json` — emits `dist/` |
25
+ | `pnpm typecheck` | `tsc -b --force` over the tooling project (src + tests) |
26
+ | `pnpm lint` | ESLint over the whole repo |
27
+ | `pnpm format` / `format:check` | Prettier write / check |
28
+ | `pnpm test` / `test:coverage` | Vitest, with or without the coverage gate |
29
+ | `pnpm knip` | Unused-dependency / unused-export hygiene; a `verify` step. `knip.json` ignores `@commitlint/config-conventional` and `@commitlint/types`, which are loaded by a string and a JSDoc type knip cannot see |
30
+ | `pnpm check:exports` | publint + are-the-types-wrong against a packed tarball |
31
+ | `pnpm check:node-version` | `.node-version` is authoritative; forbids a hardcoded pin in CI |
32
+ | `pnpm verify` | Every gate above, in the same order CI runs them |
33
+ | `pnpm prepare` | Installs the lefthook git hooks |
34
+
35
+ Run `pnpm verify` before considering any task done — it reproduces CI
36
+ locally.
37
+
38
+ ## Git Workflow
39
+
40
+ **Conventional Commits (required)**, enforced by the `commit-msg` hook
41
+ (`bin/lint-commit.mjs`). Add a `Co-Authored-By:` trailer when Claude
42
+ authored or substantially assisted a commit — see `.claude/skills/writing-commits/`.
43
+
44
+ Branch off `main` as `feat/<slug>` / `fix/<slug>`, never work directly on
45
+ `main` — `guard-branch-isolation.mjs` blocks `src/**`/`tests/**` writes
46
+ while `HEAD` is `main`. Land any `src/`/`tests/` change via PR. Run
47
+ `.claude/skills/starting-work/` before beginning change-work if you haven't
48
+ already settled the branch and PR decision.
49
+
50
+ Never `git push --force` a shared branch.
51
+
52
+ ## Architecture & Decisions
53
+
54
+ `src/index.ts` is the current public entry point (see the `exports` map in
55
+ `package.json`). Everything under `src/internal/`, if you create it, is
56
+ private and must never be re-exported.
57
+
58
+ ## Agent Operating Model
59
+
60
+ **Hub-and-spoke**: the hub plans and dispatches to spokes, and never writes
61
+ `src/`/test code itself — enforced by `.claude/hooks/guard-hub-src-writes.mjs`
62
+ and `disallowedTools: Agent` on every spoke. For a piece of work with a clear
63
+ contract:
64
+
65
+ 1. `test-author` writes failing tests from the contract (RED phase), and
66
+ confirms they fail for the right reason.
67
+ 2. `code-implementer` makes them pass with the minimal correct
68
+ implementation, then refactors while green (GREEN phase).
69
+ 3. Read-only review spokes (`code-reviewer` always; `silent-failure-hunter`
70
+ when the diff has error-handling paths) run in parallel over the diff.
71
+ Must-fix findings route back to `code-implementer`, and the loop repeats
72
+ until clean.
73
+
74
+ Full dispatch-sizing and recovery guidance: `.claude/rules/agent-dispatch.md`
75
+ (auto-loads when editing `.claude/skills/**` or `.claude/agents/**`).
76
+
77
+ ## Coding, errors & tests
78
+
79
+ Path-scoped rules auto-load on matching files:
80
+
81
+ - `src/**` → `.claude/rules/src.md`
82
+ - `**/tests/**`, `**/*.test.ts` → `.claude/rules/tests.md`
83
+ - `src/**`, `**/tests/**` → `.claude/rules/refactoring.md` (behavior-preserving changes)
84
+ - `.claude/skills/**`, `.claude/agents/**` → `.claude/rules/agent-dispatch.md`
85
+
86
+ ## Security
87
+
88
+ Never log secrets, tokens, or caller data. Validate external input at the
89
+ public API boundary. `.claude/hooks/guard-secret-writes.mjs` blocks writing
90
+ a real secret to disk at edit time; keep it that way rather than relying on
91
+ CI to catch it after the fact.
92
+
93
+ ## Definition of Done
94
+
95
+ `pnpm verify` passes; a public API change carries a Conventional Commit with
96
+ the correct semver impact; new/changed exports have TSDoc and tests. If you
97
+ touched the harness itself (hooks, agents, skills, rules, `settings.json`),
98
+ `pnpm verify`'s `harness` step (`bin/check-harness.mjs`) must stay green: it
99
+ fails on broken wiring and only warns on quality.
100
+ If you touched the TypeScript toolchain (`tsconfig*.json`, `eslint.config.js`,
101
+ `vitest.config.ts`, `bin/lib/verify-steps.mjs`, the toolchain pins in
102
+ `package.json`), the `toolchain` step (`bin/check-toolchain.mjs`) must stay
103
+ green the same way: it fails on wiring `tsc` and ESLint do not catch (a build
104
+ project that emits nowhere, a verify step naming a script that does not exist)
105
+ and only warns on quality (a missing strict flag, an option TypeScript has
106
+ deprecated). Never silence it by deleting the check or lowering a threshold --
107
+ fix the config it points at.
108
+
109
+ ## Forbidden Patterns
110
+
111
+ **Enforced at write time by hooks:** `any` implied by CommonJS constructs
112
+ (`require`, `module.exports`, `__dirname`, `__filename`), a missing `.js`
113
+ extension on a relative import, a hand-edit to `dist/` or `coverage/`, a
114
+ write to `src/`/`tests/` while on `main`, a real secret written to disk.
115
+
116
+ **No automated guard — need conscious care:** no `any` in the public API;
117
+ never swallow an error silently; no top-level side effects; never
118
+ `git push --force`.
119
+
120
+ ## Freshness
121
+
122
+ This baseline is frozen at the moment `m3l-groundwork` last emitted it. Run
123
+ `/customize`'s guidance pass — or `.claude/skills/typescript-guidance/` /
124
+ `.claude/skills/harness-guidance/` directly in refresh mode — periodically
125
+ to sweep the toolchain and harness against current upstream guidance. See
126
+ `docs/research/typescript-refresh.md` and `docs/research/harness-refresh.md`
127
+ for the living trackers.
@@ -0,0 +1,24 @@
1
+ # __PROJECT_NAME__
2
+
3
+ Bootstrapped by [m3l-groundwork](https://github.com/monte3l/m3l-groundwork) —
4
+ a deterministic TypeScript + Claude Code project bootstrapper.
5
+
6
+ ## Getting started
7
+
8
+ ```bash
9
+ pnpm install
10
+ pnpm verify
11
+ ```
12
+
13
+ `pnpm verify` runs the same checks CI runs: format, lint, typecheck, build,
14
+ and test with coverage. See `CLAUDE.md` for the full command reference and
15
+ the project's conventions.
16
+
17
+ ## Customize this baseline
18
+
19
+ This project shipped with a frozen, universal TypeScript + Claude Code
20
+ baseline. Run `/customize` inside Claude Code to tailor it: answer a short
21
+ interview (project kind, runtime target, test strictness, CI depth), then
22
+ let the guidance pass validate the result against current official
23
+ TypeScript and Anthropic guidance rather than what was true when the
24
+ baseline was built.
@@ -0,0 +1,19 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output (tsc-owned; never committed)
5
+ dist/
6
+ *.tsbuildinfo
7
+
8
+ # Test / coverage artifacts
9
+ coverage/
10
+
11
+ # Editor / OS
12
+ .DS_Store
13
+
14
+ # Local overrides
15
+ lefthook-local.yml
16
+
17
+ # Scratch state written by opt-in harness-extras pack hooks (e.g. the
18
+ # compaction-handoff artifact) -- harmless if the pack isn't installed.
19
+ tmp/
@@ -0,0 +1 @@
1
+ engine-strict=true