@harness-engineering/cli 2.6.1 → 2.7.1

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 (156) hide show
  1. package/dist/agents/skills/claude-code/align-design-system/SKILL.md +174 -0
  2. package/dist/agents/skills/claude-code/align-design-system/skill.yaml +57 -0
  3. package/dist/agents/skills/claude-code/audit-brand-compliance/SKILL.md +189 -0
  4. package/dist/agents/skills/claude-code/audit-brand-compliance/skill.yaml +50 -0
  5. package/dist/agents/skills/claude-code/audit-component-anatomy/SKILL.md +181 -0
  6. package/dist/agents/skills/claude-code/audit-component-anatomy/skill.yaml +51 -0
  7. package/dist/agents/skills/claude-code/copy-craft/SKILL.md +192 -0
  8. package/dist/agents/skills/claude-code/copy-craft/skill.yaml +52 -0
  9. package/dist/agents/skills/claude-code/detect-design-drift/SKILL.md +139 -0
  10. package/dist/agents/skills/claude-code/detect-design-drift/skill.yaml +50 -0
  11. package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +10 -0
  12. package/dist/agents/skills/claude-code/harness-design-craft/SKILL.md +212 -0
  13. package/dist/agents/skills/claude-code/harness-design-craft/skill.yaml +57 -0
  14. package/dist/agents/skills/claude-code/harness-design-pipeline/SKILL.md +266 -0
  15. package/dist/agents/skills/claude-code/harness-design-pipeline/skill.yaml +70 -0
  16. package/dist/agents/skills/claude-code/knowledge-craft/SKILL.md +180 -0
  17. package/dist/agents/skills/claude-code/knowledge-craft/skill.yaml +49 -0
  18. package/dist/agents/skills/claude-code/naming-craft/SKILL.md +244 -0
  19. package/dist/agents/skills/claude-code/naming-craft/skill.yaml +51 -0
  20. package/dist/agents/skills/claude-code/security-craft/SKILL.md +205 -0
  21. package/dist/agents/skills/claude-code/security-craft/skill.yaml +58 -0
  22. package/dist/agents/skills/claude-code/spec-craft/SKILL.md +184 -0
  23. package/dist/agents/skills/claude-code/spec-craft/skill.yaml +55 -0
  24. package/dist/agents/skills/claude-code/test-craft/SKILL.md +212 -0
  25. package/dist/agents/skills/claude-code/test-craft/skill.yaml +58 -0
  26. package/dist/agents/skills/codex/align-design-system/SKILL.md +174 -0
  27. package/dist/agents/skills/codex/align-design-system/skill.yaml +57 -0
  28. package/dist/agents/skills/codex/audit-brand-compliance/SKILL.md +189 -0
  29. package/dist/agents/skills/codex/audit-brand-compliance/skill.yaml +50 -0
  30. package/dist/agents/skills/codex/audit-component-anatomy/SKILL.md +181 -0
  31. package/dist/agents/skills/codex/audit-component-anatomy/skill.yaml +51 -0
  32. package/dist/agents/skills/codex/copy-craft/SKILL.md +192 -0
  33. package/dist/agents/skills/codex/copy-craft/skill.yaml +52 -0
  34. package/dist/agents/skills/codex/detect-design-drift/SKILL.md +139 -0
  35. package/dist/agents/skills/codex/detect-design-drift/skill.yaml +50 -0
  36. package/dist/agents/skills/codex/harness-accessibility/SKILL.md +10 -0
  37. package/dist/agents/skills/codex/harness-design-craft/SKILL.md +212 -0
  38. package/dist/agents/skills/codex/harness-design-craft/skill.yaml +57 -0
  39. package/dist/agents/skills/codex/harness-design-pipeline/SKILL.md +266 -0
  40. package/dist/agents/skills/codex/harness-design-pipeline/skill.yaml +70 -0
  41. package/dist/agents/skills/codex/knowledge-craft/SKILL.md +180 -0
  42. package/dist/agents/skills/codex/knowledge-craft/skill.yaml +49 -0
  43. package/dist/agents/skills/codex/naming-craft/SKILL.md +244 -0
  44. package/dist/agents/skills/codex/naming-craft/skill.yaml +51 -0
  45. package/dist/agents/skills/codex/security-craft/SKILL.md +205 -0
  46. package/dist/agents/skills/codex/security-craft/skill.yaml +58 -0
  47. package/dist/agents/skills/codex/spec-craft/SKILL.md +184 -0
  48. package/dist/agents/skills/codex/spec-craft/skill.yaml +55 -0
  49. package/dist/agents/skills/codex/test-craft/SKILL.md +212 -0
  50. package/dist/agents/skills/codex/test-craft/skill.yaml +58 -0
  51. package/dist/agents/skills/cursor/align-design-system/SKILL.md +174 -0
  52. package/dist/agents/skills/cursor/align-design-system/skill.yaml +57 -0
  53. package/dist/agents/skills/cursor/audit-brand-compliance/SKILL.md +189 -0
  54. package/dist/agents/skills/cursor/audit-brand-compliance/skill.yaml +50 -0
  55. package/dist/agents/skills/cursor/audit-component-anatomy/SKILL.md +181 -0
  56. package/dist/agents/skills/cursor/audit-component-anatomy/skill.yaml +51 -0
  57. package/dist/agents/skills/cursor/copy-craft/SKILL.md +192 -0
  58. package/dist/agents/skills/cursor/copy-craft/skill.yaml +52 -0
  59. package/dist/agents/skills/cursor/detect-design-drift/SKILL.md +139 -0
  60. package/dist/agents/skills/cursor/detect-design-drift/skill.yaml +50 -0
  61. package/dist/agents/skills/cursor/harness-accessibility/SKILL.md +10 -0
  62. package/dist/agents/skills/cursor/harness-design-craft/SKILL.md +212 -0
  63. package/dist/agents/skills/cursor/harness-design-craft/skill.yaml +57 -0
  64. package/dist/agents/skills/cursor/harness-design-pipeline/SKILL.md +266 -0
  65. package/dist/agents/skills/cursor/harness-design-pipeline/skill.yaml +70 -0
  66. package/dist/agents/skills/cursor/knowledge-craft/SKILL.md +180 -0
  67. package/dist/agents/skills/cursor/knowledge-craft/skill.yaml +49 -0
  68. package/dist/agents/skills/cursor/naming-craft/SKILL.md +244 -0
  69. package/dist/agents/skills/cursor/naming-craft/skill.yaml +51 -0
  70. package/dist/agents/skills/cursor/security-craft/SKILL.md +205 -0
  71. package/dist/agents/skills/cursor/security-craft/skill.yaml +58 -0
  72. package/dist/agents/skills/cursor/spec-craft/SKILL.md +184 -0
  73. package/dist/agents/skills/cursor/spec-craft/skill.yaml +55 -0
  74. package/dist/agents/skills/cursor/test-craft/SKILL.md +212 -0
  75. package/dist/agents/skills/cursor/test-craft/skill.yaml +58 -0
  76. package/dist/agents/skills/gemini-cli/align-design-system/SKILL.md +174 -0
  77. package/dist/agents/skills/gemini-cli/align-design-system/skill.yaml +57 -0
  78. package/dist/agents/skills/gemini-cli/audit-brand-compliance/SKILL.md +189 -0
  79. package/dist/agents/skills/gemini-cli/audit-brand-compliance/skill.yaml +50 -0
  80. package/dist/agents/skills/gemini-cli/audit-component-anatomy/SKILL.md +181 -0
  81. package/dist/agents/skills/gemini-cli/audit-component-anatomy/skill.yaml +51 -0
  82. package/dist/agents/skills/gemini-cli/copy-craft/SKILL.md +192 -0
  83. package/dist/agents/skills/gemini-cli/copy-craft/skill.yaml +52 -0
  84. package/dist/agents/skills/gemini-cli/detect-design-drift/SKILL.md +139 -0
  85. package/dist/agents/skills/gemini-cli/detect-design-drift/skill.yaml +50 -0
  86. package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +10 -0
  87. package/dist/agents/skills/gemini-cli/harness-design-craft/SKILL.md +212 -0
  88. package/dist/agents/skills/gemini-cli/harness-design-craft/skill.yaml +57 -0
  89. package/dist/agents/skills/gemini-cli/harness-design-pipeline/SKILL.md +266 -0
  90. package/dist/agents/skills/gemini-cli/harness-design-pipeline/skill.yaml +70 -0
  91. package/dist/agents/skills/gemini-cli/knowledge-craft/SKILL.md +180 -0
  92. package/dist/agents/skills/gemini-cli/knowledge-craft/skill.yaml +49 -0
  93. package/dist/agents/skills/gemini-cli/naming-craft/SKILL.md +244 -0
  94. package/dist/agents/skills/gemini-cli/naming-craft/skill.yaml +51 -0
  95. package/dist/agents/skills/gemini-cli/security-craft/SKILL.md +205 -0
  96. package/dist/agents/skills/gemini-cli/security-craft/skill.yaml +58 -0
  97. package/dist/agents/skills/gemini-cli/spec-craft/SKILL.md +184 -0
  98. package/dist/agents/skills/gemini-cli/spec-craft/skill.yaml +55 -0
  99. package/dist/agents/skills/gemini-cli/test-craft/SKILL.md +212 -0
  100. package/dist/agents/skills/gemini-cli/test-craft/skill.yaml +58 -0
  101. package/dist/{agents-md-2JUQ4FE2.js → agents-md-FKMKH6ZF.js} +4 -4
  102. package/dist/{analyzer-VY6DJVOU-4AHIJLNS.js → analyzer-H3AHBFSL-KPOPJYRB.js} +8 -8
  103. package/dist/{architecture-CXAVNB5X.js → architecture-LUR2I67H.js} +6 -6
  104. package/dist/{assess-project-M626SSPN.js → assess-project-OJWECOP2.js} +2 -1
  105. package/dist/bin/harness-mcp.js +17 -17
  106. package/dist/bin/harness.js +27 -27
  107. package/dist/{check-phase-gate-XMU6LLUQ.js → check-phase-gate-HS5KYLRO.js} +5 -5
  108. package/dist/{chunk-5XLLIYYL.js → chunk-6UHDQP2N.js} +1 -1
  109. package/dist/{chunk-I6K43QQS.js → chunk-7AF6C5GE.js} +3 -3
  110. package/dist/{chunk-372MGNTI.js → chunk-7PLIWP7U.js} +6899 -133
  111. package/dist/{chunk-VUCGB2KH.js → chunk-B2VAYLYI.js} +1 -1
  112. package/dist/{chunk-HFOB2MPQ.js → chunk-CZPOPMMI.js} +3 -3
  113. package/dist/{chunk-43M3RLFQ.js → chunk-FC4JPM6W.js} +2 -2
  114. package/dist/{chunk-6AX6R3LM.js → chunk-FEKBXX2J.js} +9 -9
  115. package/dist/{chunk-VTTNIZJL.js → chunk-FXZI6NJ2.js} +131 -6
  116. package/dist/{chunk-5JNSFYZU.js → chunk-GGSNWH7P.js} +6 -6
  117. package/dist/{chunk-BCFDGOMA.js → chunk-H2ZJOJ7A.js} +81 -1
  118. package/dist/{chunk-PFZEADQM.js → chunk-INBTDBV2.js} +79 -2
  119. package/dist/{chunk-Q6ZR2L6Q.js → chunk-KN3EMDZ5.js} +2 -2
  120. package/dist/{chunk-JFZOWO7D.js → chunk-LECXPXS3.js} +1 -1
  121. package/dist/{chunk-CQOMVZDC.js → chunk-LGYXR2KZ.js} +2237 -604
  122. package/dist/{chunk-QOKMDDBJ.js → chunk-LYIPI2SJ.js} +6 -6
  123. package/dist/{chunk-L5BCZ5XS.js → chunk-N5NSSLMU.js} +1 -1
  124. package/dist/{chunk-GWE5LL3R.js → chunk-NIVWM7OW.js} +10 -10
  125. package/dist/{chunk-24KCOJJG.js → chunk-O2ASYKA6.js} +1 -1
  126. package/dist/{chunk-K246XQ2L.js → chunk-PTHX545Q.js} +1 -1
  127. package/dist/{chunk-EPUKTTJZ.js → chunk-RC3OI5NK.js} +5 -1
  128. package/dist/{chunk-YP7I25SL.js → chunk-RJ2WEES5.js} +1 -1
  129. package/dist/{chunk-5FDBXUFW.js → chunk-TIH53QXY.js} +1 -1
  130. package/dist/{chunk-OA6SWTU4.js → chunk-VI4IS55S.js} +11 -8
  131. package/dist/{chunk-GWF2OILZ.js → chunk-VSIRUZQP.js} +1 -1
  132. package/dist/{chunk-YYRQCQPZ.js → chunk-WZY5U6NS.js} +178 -109
  133. package/dist/{chunk-SZEFU6XC.js → chunk-Y4T6ENKQ.js} +9 -9
  134. package/dist/{chunk-HMW3VKUF.js → chunk-Z3TMCCZB.js} +10 -10
  135. package/dist/{ci-workflow-3JNDZQYD.js → ci-workflow-MDSTHJOY.js} +4 -4
  136. package/dist/{dist-OHDQBTSO.js → dist-72ID44UE.js} +3 -3
  137. package/dist/{dist-QPWXPCPL.js → dist-R3TOOPJ7.js} +1 -1
  138. package/dist/{docs-5RYMDHN3.js → docs-2RFOJ6XY.js} +6 -6
  139. package/dist/{engine-GKGT5ULT.js → engine-BSFKOGPN.js} +4 -4
  140. package/dist/{entropy-DQTAPSSE.js → entropy-3UX6644G.js} +5 -5
  141. package/dist/{feedback-WH6XPQJS.js → feedback-CVCFYND4.js} +2 -2
  142. package/dist/{generate-agent-definitions-SZA4QIHN.js → generate-agent-definitions-HZ3XENWO.js} +5 -5
  143. package/dist/{glob-helper-XE2UGEOV.js → glob-helper-EX4YZKZO.js} +1 -1
  144. package/dist/{graph-loader-EQBOIHFZ.js → graph-loader-EIFEOUVI.js} +1 -1
  145. package/dist/index.d.ts +1012 -12
  146. package/dist/index.js +27 -27
  147. package/dist/{loader-BNKGM23C.js → loader-6RHWU5FH.js} +4 -4
  148. package/dist/{mcp-YKKPWUMH.js → mcp-OYR26JDI.js} +17 -17
  149. package/dist/{performance-54TMJOEU.js → performance-JJMIRXCH.js} +6 -6
  150. package/dist/{review-pipeline-OTDDVPNY.js → review-pipeline-BHQZIXWZ.js} +4 -4
  151. package/dist/{runtime-W5THSNAL.js → runtime-DALTAVTN.js} +4 -4
  152. package/dist/{scan-4PPP6ZXT.js → scan-LYKLM4EQ.js} +1 -1
  153. package/dist/{security-27HW7CYT.js → security-RMLMYFPB.js} +1 -1
  154. package/dist/{validate-QRVCD4GP.js → validate-R7DZRDFK.js} +5 -5
  155. package/dist/{validate-cross-check-BUAGBAPO.js → validate-cross-check-AUUZFNVL.js} +4 -4
  156. package/package.json +8 -7
@@ -0,0 +1,205 @@
1
+ # Security Craft
2
+
3
+ > LLM-judgment critique of security posture for TS/JS source — the ceiling counterpart to `harness-security-scan` (CVE/OWASP rule-based floor) and `harness-security-reviewer` (procedural review). Threat-modeling-as-skill rather than pattern-matching. Critiques whether trust boundaries are respected, where implicit privilege escalation lurks, whether the code defends in depth or just at the gate, whether principle of least authority is honored. Sixth non-design member of the craft-pipeline initiative (#10 of 10; the final sub-project). Emits 3-axis findings (tier × impact × confidence per ADR 0019).
4
+
5
+ ## When to Use
6
+
7
+ - During PR review on a substantively-changed handler / middleware / privileged op
8
+ - After authoring a new endpoint, before exposing it to traffic
9
+ - When onboarding a new contributor (audit security-relevant code they introduced)
10
+ - Periodically (per-sprint or per-release) to catch security-shape drift
11
+ - For threat-modeling shape questions a CVE scanner doesn't address (trust boundaries, fail-closed, authz ordering)
12
+ - NOT for CVE / dependency scanning (use `harness-security-scan` — rule-based floor)
13
+ - NOT for procedural review checklists (use `harness-security-reviewer`)
14
+ - NOT for IaC critique (v1.x — Dockerfile / k8s / Terraform have different rubric vocabulary)
15
+ - NOT for secret detection (floor concern; existing regex/entropy scanners cover this)
16
+ - NOT for autofix / security rewriting (this is judgment-only; v1.x may add `align-security` with aggressive safeguards)
17
+ - NOT for test files (v1 excludes — test security has a different shape; v1.x with dedicated rubrics)
18
+
19
+ ## Process
20
+
21
+ ### Phase 1: DISCOVER — Find source files
22
+
23
+ 1. Walk `packages/*/src/` recursively.
24
+ 2. Include `*.{ts,tsx,js,jsx,mjs,cjs}`; exclude test files (`*.test.*`, `*.spec.*`, `tests/`, `__tests__/`).
25
+ 3. Exclude generated / build / coverage dirs (`node_modules`, `dist`, `build`, `coverage`, `.next`, `.turbo`, `__snapshots__`).
26
+ 4. Honor `--packages` for explicit package scoping; `--files` overrides discovery.
27
+
28
+ ### Phase 2: SIGNAL — AST-driven security construct detection
29
+
30
+ For each source file, the TS Compiler API walks the AST once and emits `SecuritySignal`s. Files with zero signals are **skipped entirely** — this is the FP-management strategy from the spec (no path-heuristic fallback).
31
+
32
+ Detected signal kinds:
33
+
34
+ | Kind | What it matches |
35
+ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
36
+ | `http-handler` | `(req, res)` / `(req, res, next)` shapes; `app.get/post/...`; `@Get/@Post/...` |
37
+ | `middleware` | `(req, res, next) =>` arrow / `(ctx, next)` shapes |
38
+ | `auth-api` | `jwt.{sign,verify}`, `bcrypt.{hash,compare}`, `argon2.*`, `passport.*`, `req.session.*`, `res.cookie` |
39
+ | `privileged-op` | `child_process.{exec,spawn,...}`, `eval`, `new Function`, `vm.runIn*`, `fs.{writeFile,unlink,chmod,...}` |
40
+ | `data-egress` | `fetch`, `axios.*`, `http.request`, `https.request`, `net.connect` |
41
+ | `raw-query` | `*.query(\`...${x}...\`)`, `*.raw(...)`, `$queryRaw`, `$executeRaw` with SQL-shaped argument |
42
+ | `secret-handling` | Secret-named variable (`token`, `password`, `apiKey`, …) flowing into `console.*`, `logger.*`, `JSON.stringify`, template-literal sink |
43
+
44
+ AST awareness (not regex) avoids common false positives: `exec` in a comment, `eval` as a variable name, `token` in a CSS property name.
45
+
46
+ ### Phase 3: CRITIQUE — Per (file, signal, rubric) loop
47
+
48
+ 8 seed rubrics, each declaring `appliesToSignals` so per-signal pre-filtering minimizes LLM cost:
49
+
50
+ | Rubric | Title | Applies to signals |
51
+ | ---------- | ----------------------------------------------- | --------------------------------------------------- |
52
+ | `SEC-R001` | Trust boundary respected | http-handler, middleware, raw-query, privileged-op |
53
+ | `SEC-R002` | Principle of least authority honored | auth-api, privileged-op, http-handler |
54
+ | `SEC-R003` | Defense in depth (not gate-only) | auth-api, http-handler |
55
+ | `SEC-R004` | Assumed adversary realistic for the deployment | http-handler, middleware, auth-api |
56
+ | `SEC-R005` | Data flow across trust boundaries is visible | http-handler, raw-query, data-egress, privileged-op |
57
+ | `SEC-R006` | Fail closed, not open | auth-api, middleware, http-handler |
58
+ | `SEC-R007` | Secrets carried in a shape that resists leakage | secret-handling |
59
+ | `SEC-R008` | Authorization check happens before the action | http-handler, privileged-op |
60
+
61
+ For each (signal, rubric) pair where the rubric applies:
62
+
63
+ 1. Build a prompt with rubric description + file path + signal info + **1500-char window AROUND the signal line** (not the whole file — security-critical context is local).
64
+ 2. **Conservative-confidence system prompt** biases the LLM toward `medium` confidence by default; `high` requires a specific, named anti-pattern or visible missing guard.
65
+ 3. LLM returns fenced JSON: `null` (rubric doesn't apply / code is fine) OR `{ tier, impact, confidence, message }`.
66
+ 4. On non-null: emit a `SecurityFinding` with `cite.rubricId` populated for ADR 0020 traceability.
67
+
68
+ ### Phase 4: REPORT — Aggregate + cost telemetry
69
+
70
+ Emit `SecurityCraftOutput`:
71
+
72
+ ```ts
73
+ {
74
+ findings: SecurityFinding[];
75
+ summary: {
76
+ phaseRun: ['critique'];
77
+ mode: 'fast';
78
+ durationMs: number;
79
+ llmCalls: { provider, model, count, costUsd };
80
+ catalog: { rubricsApplied: string[] };
81
+ counts: { filesScanned, filesSkippedNoSignal, signalsDetected };
82
+ runId: string;
83
+ }
84
+ }
85
+ ```
86
+
87
+ `filesSkippedNoSignal` is tracked separately so report consumers can see how aggressively the AST pre-filter trimmed the corpus.
88
+
89
+ ## Harness Integration
90
+
91
+ - **`harness security-craft`** — CLI entry. `--files <glob>` / `--packages <names>` / `--max-files <n>` / `--max-signals-per-file <n>` / `--json` / `--verbose`.
92
+ - **`mcp__harness__security_craft`** — MCP tool. Same input/output. Consumed by agents.
93
+ - **Cross-cutting API:** `critiqueSecurityInFile(file, opts)` exported from `packages/cli/src/security-craft/index.ts`. Returns `[]` for files with no security signals (consistent with the orchestrator's FP-management strategy).
94
+ - **Shared craft infrastructure:** `LlmProvider`, `MockLlmProvider`, `derivePriority`, 3-axis types all live in `packages/cli/src/shared/craft/`.
95
+
96
+ ## Success Criteria
97
+
98
+ See `docs/changes/craft-pipeline/security-craft/proposal.md` for the full 29 success criteria. Highlights:
99
+
100
+ - 8 seed rubrics ship at `catalog/rubrics/<id>.ts` (file-per-rubric)
101
+ - AST detector emits signals for all 7 signal kinds; comment / string contents don't fire (AST-aware, not regex)
102
+ - Files with zero signals are skipped (`filesSkippedNoSignal` tracked)
103
+ - Per-rubric `appliesToSignals` pre-filter avoids irrelevant LLM calls
104
+ - 3-axis output preserved; confidence defaults to medium per the spec's Decision #3
105
+ - `cite.rubricId` populated on every finding (ADR 0020)
106
+ - `critiqueSecurityInFile` cross-cutting API works on a single file
107
+
108
+ ## Examples
109
+
110
+ ### Example: User input flowing into child_process
111
+
112
+ **Input:** `packages/api/src/handlers/run-script.ts`:
113
+
114
+ ```ts
115
+ import { exec } from 'child_process';
116
+ import type { Request, Response } from 'express';
117
+
118
+ export function runScript(req: Request, res: Response): void {
119
+ const userScript = req.body.script;
120
+ exec(`bash -c "${userScript}"`, (err, stdout) => {
121
+ res.json({ output: stdout });
122
+ });
123
+ }
124
+ ```
125
+
126
+ **Output (mock LLM):**
127
+
128
+ ```
129
+ SEC-R001 [foundational/large/high] child_process.exec:5
130
+ User-controlled `req.body.script` flows directly into `bash -c "${userScript}"`.
131
+ This is a textbook command-injection sink. Either reject the entire pattern
132
+ (no user-supplied shell strings) or move to `execFile` with an allowlist of
133
+ binaries and pre-validated arg arrays. Never templated into a shell.
134
+ SEC-R005 [foundational/large/high] child_process.exec:5
135
+ Untrusted input (`req.body.script`) crosses the trust boundary into a
136
+ privileged sink without any visible validation or escaping step. The crossing
137
+ is invisible — the variable is named generically and goes straight to exec.
138
+ ```
139
+
140
+ ### Example: Auth check after action
141
+
142
+ **Input:** `packages/api/src/handlers/get-doc.ts`:
143
+
144
+ ```ts
145
+ export async function getDoc(req: Request, res: Response) {
146
+ const doc = await db.docs.findOne({ id: req.params.id });
147
+ if (doc.ownerId !== req.user.id) return res.status(403).send();
148
+ return res.json(doc);
149
+ }
150
+ ```
151
+
152
+ **Output:**
153
+
154
+ ```
155
+ SEC-R008 [foundational/medium/medium] req,res:1
156
+ The document is loaded BEFORE the authorization check. Even though the
157
+ response is denied, the load has already executed — observable side effects
158
+ (audit logs, rate-limit counters, cache populations) leak existence
159
+ information about documents the caller can't access. Authorize against the
160
+ identifier first (`req.params.id` + `req.user.id`), then load.
161
+ ```
162
+
163
+ ### Example: File with no security signals
164
+
165
+ **Input:** A pure utility file with no http/auth/exec/fs/network constructs.
166
+
167
+ **Output:**
168
+
169
+ ```
170
+ No security findings.
171
+
172
+ Summary: 0 findings across 0 files (12 skipped, 0 signals, 8 rubrics, 0 LLM calls, $0.0000, 4ms)
173
+ ```
174
+
175
+ The 12 files were scanned for signals but skipped because none had security-relevant AST constructs — exactly the FP-management strategy at work.
176
+
177
+ ## Gates
178
+
179
+ - **No autofix.** Sibling `align-security` deferred to v2 with aggressive FP safeguards (security rewrites have asymmetric downside).
180
+ - **No IaC critique.** Dockerfile / k8s / Terraform need different rubrics; v1.x.
181
+ - **No multi-file auth-flow tracing.** Cross-file privilege-escalation analysis (handler → middleware → service) needs a graph traversal layer; v1.x once cross-file critique pays for itself elsewhere.
182
+ - **No dependency / CVE scanning.** `harness-security-scan` is the floor.
183
+ - **No secret detection** (floor concern).
184
+ - **No test-file critique.** Test security has a different shape; v1.x.
185
+ - **No path-heuristic fallback.** If AST scan finds zero signals, the file is skipped. Tight scoping is part of the FP-management strategy.
186
+ - **No B' bootstrap.**
187
+
188
+ ## Escalation
189
+
190
+ - **When LLM cost is too high:** drop `maxFiles` to 50 or `maxSignalsPerFile` to 5, or scope explicitly with `--packages <name>`. Per-file cost = (signals × applicable rubrics × per-call); typical handler fires ~3-5 rubrics, not 8.
191
+ - **When a specific rubric produces false positives:** v1 has no per-rubric disable; v1.x adds `craft.security.disabledRubrics: ['SEC-R004']`. Until then: filter findings by `cite.rubricId` downstream.
192
+ - **When the AST detector misses a framework you use** (tRPC, Convex, Cloudflare Workers, Hono RPC): v1 ships baseline coverage for Express / Hono / Fastify / Koa / NestJS-decorator. Adding a framework is a 1-line config in `signals.ts`. Track as v1.x.
193
+ - **When findings are too cautious (confidence floor):** the conservative-by-default is deliberate (FP management); v1.x adds `craft.security.confidenceFloor` to tighten further. Loosening below medium is intentionally not exposed.
194
+ - **When you want IaC critique:** v1.x. For v1, scope explicitly to source files and accept the gap.
195
+ - **When a finding is wrong:** dismiss it in your consumer; signal as a `suppressedAt` entry on the rubric for future catalog evolution.
196
+
197
+ ## Status
198
+
199
+ **v1 — in implementation.** See:
200
+
201
+ - Spec: `docs/changes/craft-pipeline/security-craft/proposal.md`
202
+ - Roadmap entry: `craft-pipeline sub-project #10` (the final sub-project; the craft-pipeline initiative completes with this PR)
203
+ - Sibling craft skills: `naming-craft` (#1), `spec-craft` (#6), `copy-craft` (#5), `test-craft` (#3), `knowledge-craft` (#9), `harness-design-craft` (design-pipeline #6)
204
+ - Shared infrastructure: `packages/cli/src/shared/craft/`
205
+ - Future: `align-security` (FIX side; aggressive safeguards), IaC critique, multi-file auth-flow tracing, test-file security, framework expansions (tRPC / Convex / Cloudflare Workers / Hono RPC).
@@ -0,0 +1,58 @@
1
+ name: security-craft
2
+ version: "0.1.0"
3
+ description: LLM-judgment critique of security posture (TS/JS source). Threat-modeling-as-skill — critiques whether trust boundaries are respected, where implicit privilege escalation lurks, whether the code defends in depth, whether least authority is honored. AST-driven signal detection fires only on files with security-relevant constructs; conservative confidence defaults manage the FP risk inherent in judgment-based security. Sixth non-design craft-pipeline ceiling skill (the final sub-project, #10 of 10).
4
+ stability: draft
5
+ cognitive_mode: constructive-architect
6
+ triggers:
7
+ - manual
8
+ - on_pr
9
+ - on_new_feature
10
+ platforms:
11
+ - claude-code
12
+ tools:
13
+ - Bash
14
+ - Read
15
+ - Glob
16
+ - Grep
17
+ cli:
18
+ command: harness security-craft
19
+ args:
20
+ - name: path
21
+ description: Project root path
22
+ required: false
23
+ - name: files
24
+ description: Optional file scope (overrides discovery)
25
+ required: false
26
+ - name: packages
27
+ description: Restrict to specific packages under packages/
28
+ required: false
29
+ - name: max-files
30
+ description: Cap source-file count (default 100)
31
+ required: false
32
+ - name: max-signals-per-file
33
+ description: Cap per-file signal critique (default 10)
34
+ required: false
35
+ mcp:
36
+ tool: security_craft
37
+ input:
38
+ path: string
39
+ type: rigid
40
+ tier: 2
41
+ phases:
42
+ - name: discover
43
+ description: Walk packages/STAR/src/ recursively; exclude tests + build dirs
44
+ required: true
45
+ - name: signal
46
+ description: AST-driven security construct detection (http handlers, middleware, auth APIs, child_process/eval, fs writes, raw queries, network egress, secret handling)
47
+ required: true
48
+ - name: critique
49
+ description: LLM-rubric loop per (file, signal, rubric) with conservative-confidence bias
50
+ required: true
51
+ - name: report
52
+ description: Aggregate findings + cost telemetry + file/signal counts
53
+ required: true
54
+ state:
55
+ persistent: false
56
+ depends_on:
57
+ - harness-security-scan
58
+ - harness-security-review
@@ -0,0 +1,184 @@
1
+ # Spec Craft
2
+
3
+ > LLM-judgment critique of spec quality (proposals + ADRs) against a curated rubric catalog from the spec-quality canon. Per-section critique with rubric-to-section mapping. Second member of the craft-pipeline initiative; highest-leverage craft skill because spec quality compounds across the entire planning → implementation → review lifecycle below it. Emits 3-axis findings (tier × impact × confidence per ADR 0019).
4
+
5
+ ## When to Use
6
+
7
+ - During PR review on a new or substantially-rewritten spec
8
+ - After authoring a proposal, before circulating it for review
9
+ - When onboarding a new contributor (audit specs they introduced)
10
+ - Periodically (per-sprint or per-release) to catch spec drift
11
+ - As the cross-cutting spec critic for harness-brainstorming (when newly-authored specs land)
12
+ - NOT for spec-structure enforcement (use `harness-soundness-review` — that's the rule-based floor)
13
+ - NOT for README / general-doc critique (use `docs-craft` #2)
14
+ - NOT for autofix / spec rewriting (this is judgment-only; v1.x may add `align-spec` sibling)
15
+ - NOT for source-code comment critique (use `code-craft` #4 or `docs-craft` #2)
16
+ - NOT for RFCs in v1 (v1.x)
17
+
18
+ ## Process
19
+
20
+ ### Phase 1: DISCOVER — Find spec files
21
+
22
+ 1. **Read project configuration.** Check `harness.config.json` for:
23
+ - `craft.spec.enabled` — gate (default `true`)
24
+ - `craft.spec.maxFiles` — doc count cap (default 50)
25
+ - `craft.spec.maxSectionsPerFile` — per-doc section cap (default 10)
26
+
27
+ 2. **Discover spec files:**
28
+ - **proposals:** `docs/changes/*/proposal.md` and `docs/changes/*/<sub>/proposal.md` (one level of nesting, for initiatives with sub-projects)
29
+ - **ADRs:** `docs/knowledge/decisions/*.md` (excluding README)
30
+ - Restrict via `--kinds proposal` or `--kinds adr` for single-kind runs.
31
+
32
+ ### Phase 2: PARSE — Split into named sections
33
+
34
+ For each spec file:
35
+
36
+ 1. **Strip YAML frontmatter** (`--- ... ---` block at top, if present).
37
+ 2. **Split by H2** (`## ...`) into named sections. Each section captures:
38
+ - `heading` — original H2 text (e.g., `"Decisions"`, `"Out-of-scope (v1)"`)
39
+ - `canonical` — normalized form for rubric matching (`"decisions"`, `"out-of-scope-v1"`)
40
+ - `body` — content between this H2 and the next
41
+ - `line` / `endLine` — line range
42
+ 3. Subsections (H3) stay part of the parent H2's body. v1.x may add per-H3 critique for sections like Decisions that have one row per H3.
43
+
44
+ ### Phase 3: CRITIQUE — Per (file, section, rubric) loop
45
+
46
+ 7 seed rubrics:
47
+
48
+ | Rubric | Title | Applies to |
49
+ | ----------- | ---------------------------------------- | ---------------------------------------- |
50
+ | `SPEC-R001` | Sharpness vs vagueness | `*` (all sections) |
51
+ | `SPEC-R002` | Cuts at the joints | `decisions`, `scope`, `technical-design` |
52
+ | `SPEC-R003` | Two readers, same understanding | `decisions`, `success-criteria` |
53
+ | `SPEC-R004` | Load-bearing decision vs ambient context | `decisions`, `overview` |
54
+ | `SPEC-R005` | Honest rationalizations | `rationalizations*` (regex) |
55
+ | `SPEC-R006` | Non-goals are non-goals | `out-of-scope*`, `non-goals*` (regex) |
56
+ | `SPEC-R007` | Stranger in 6 months | `*` (all sections) |
57
+
58
+ For each eligible (section, rubric) pair:
59
+
60
+ 1. Build prompt with rubric description + spec file path + section heading + section body (truncated to 2000 chars if longer for cost control).
61
+ 2. LLM returns fenced JSON: `null` (rubric doesn't apply / section is fine) OR `{ tier, impact, confidence, message }`.
62
+ 3. On non-null: emit a `SpecFinding` with `cite.rubricId` populated for ADR 0020 traceability.
63
+
64
+ ### Phase 4: REPORT — Aggregate + cost telemetry
65
+
66
+ Emit `SpecCraftOutput`:
67
+
68
+ ```ts
69
+ {
70
+ findings: SpecFinding[];
71
+ summary: {
72
+ phaseRun: ['critique'];
73
+ durationMs: number;
74
+ llmCalls: { provider, model, count, costUsd };
75
+ catalog: { rubricsApplied: string[] };
76
+ docsScanned: number;
77
+ sectionsScanned: number;
78
+ runId: string;
79
+ }
80
+ }
81
+ ```
82
+
83
+ ## Harness Integration
84
+
85
+ - **`harness spec-craft`** — CLI entry. `--files <glob>` / `--kinds proposal,adr` / `--sections decisions,scope` / `--max-files <n>` / `--max-sections-per-file <n>` / `--json` / `--verbose`.
86
+ - **`mcp__harness__spec_craft`** — MCP tool. Same input/output. Consumed by agents.
87
+ - **Cross-cutting API:** `critiqueSpecFile(file, opts)` exported from `packages/cli/src/spec-craft/index.ts`. Future craft skills (or `harness-brainstorming`) can call this when they have a doc in hand without re-walking the project.
88
+ - **Shared craft infrastructure (extracted on this PR):** `LlmProvider`, `MockLlmProvider`, `derivePriority`, 3-axis types all live in `packages/cli/src/shared/craft/`. design-craft + naming-craft + spec-craft import from there; design-craft + naming-craft keep their old import paths via re-export shims.
89
+
90
+ ## Success Criteria
91
+
92
+ See `docs/changes/craft-pipeline/spec-craft/proposal.md` for the full 34 success criteria. Highlights:
93
+
94
+ - 7 seed rubrics ship at `catalog/rubrics/<id>.ts` (file-per-rubric, matches naming-craft)
95
+ - 3-axis output preserved (tier × impact × confidence, never collapsed)
96
+ - `cite.rubricId` populated on every finding (ADR 0020)
97
+ - Section parser strips frontmatter; splits by H2 only
98
+ - Rubric-to-section mapping skips silently when rubric doesn't apply
99
+ - `critiqueSpecFile` cross-cutting API works on a single file without project walk
100
+ - All existing design-craft + naming-craft tests still pass after shared/craft extraction (zero behavior change)
101
+
102
+ ## Examples
103
+
104
+ ### Example: Vague Decisions section
105
+
106
+ **Input:** A proposal's `## Decisions` section reads:
107
+
108
+ ```
109
+ | Decision | Why |
110
+ |----------|-----|
111
+ | Use modern stack | scalable and clean |
112
+ | Defer auth | not in scope |
113
+ ```
114
+
115
+ **Output (mock LLM):**
116
+
117
+ ```
118
+ SPEC-R001 [polish/medium/medium] ## Decisions:34
119
+ "Modern stack" and "scalable and clean" are vague — no concrete framework
120
+ named, no metric for "scalable", no operational definition of "clean".
121
+ Sharpen: name the framework, state the scale target (req/sec, team size),
122
+ define what "clean" means in observable terms.
123
+ SPEC-R004 [polish/medium/medium] ## Decisions:34
124
+ The Decisions section pads load-bearing choices with vague qualifiers
125
+ rather than naming the trade-off chosen and the rejected alternative.
126
+ ```
127
+
128
+ ### Example: Strawmanned Rationalizations
129
+
130
+ **Input:** A `## Rationalizations to reject` section reads:
131
+
132
+ ```
133
+ | "Use a different framework" | Other frameworks are worse |
134
+ ```
135
+
136
+ **Output:**
137
+
138
+ ```
139
+ SPEC-R005 [foundational/large/high] ## Rationalizations to reject:88
140
+ "Other frameworks are worse" is a strawman — not stated charitably, not
141
+ paired with a specific reason. Steelman the rejected position: name the
142
+ competing framework, name its strongest feature, then explain the specific
143
+ trade-off that made it unsuitable here.
144
+ ```
145
+
146
+ ### Example: Empty project — no specs
147
+
148
+ **Input:** Project has no `docs/changes/` or `docs/knowledge/decisions/` directory.
149
+
150
+ **Output:**
151
+
152
+ ```
153
+ No spec findings.
154
+
155
+ Summary: 0 findings across 0 docs (0 sections, 7 rubrics, 0 LLM calls, $0.0000, 3ms)
156
+ ```
157
+
158
+ ## Gates
159
+
160
+ - **No autofix.** Sibling `align-spec` deferred until signal warrants safe-to-apply rewrites.
161
+ - **No README / general doc critique.** docs-craft (#2) territory.
162
+ - **No source-code comment critique.** code-craft / docs-craft territory.
163
+ - **No B' bootstrap.** Same posture as naming-craft v1.
164
+ - **No graph persistence.** Phase 1 MVP.
165
+ - **No vision/deep mode.** Specs are text.
166
+ - **No structural floor enforcement.** harness-soundness-review checks the floor; spec-craft assumes the floor is satisfied and critiques the ceiling.
167
+
168
+ ## Escalation
169
+
170
+ - **When LLM cost is too high:** drop `maxSectionsPerFile` to 5 or `maxFiles` to 25. Per-doc cost = sections × rubrics × per-call. Rubric-to-section mapping already prunes most calls; further: use `--sections decisions` to target the highest-value section.
171
+ - **When a rubric produces high false-positive rate:** v1 has no per-rubric disable; v1.x adds `craft.spec.disabledRubrics: ['SPEC-R007']`. Until then: filter findings by `cite.rubricId` in your consumer.
172
+ - **When a spec has intentionally aspirational vagueness (e.g., a manifesto-style Overview):** SPEC-R001 will flag it; low-confidence findings are de-emphasized per ADR 0019. v1.x adds per-section opt-out via `<!-- spec-craft:skip -->` HTML comment.
173
+ - **When you want a doc-level summary instead of per-section findings:** v1 is per-section only; v1.x adds a `--mode doc` opt-in for whole-doc critique.
174
+ - **When you want to critique RFCs:** v1.x. For now, point `--files <rfc.md>` at a single file — the section parser works on any markdown.
175
+
176
+ ## Status
177
+
178
+ **v1 — in implementation.** See:
179
+
180
+ - Spec: `docs/changes/craft-pipeline/spec-craft/proposal.md`
181
+ - Roadmap entry: `craft-pipeline sub-project #6` (the highest-leverage craft skill)
182
+ - Sibling craft skills: `harness-design-craft` (design-pipeline #6), `naming-craft` (craft-pipeline #1)
183
+ - Shared infrastructure: `packages/cli/src/shared/craft/` (extracted on this PR)
184
+ - Future: `align-spec` (FIX side), docs-craft (#2), test-craft (#3), code-craft (#4) — each can call `critiqueSpecFile` if they want spec-level critique for a doc they're already processing.
@@ -0,0 +1,55 @@
1
+ name: spec-craft
2
+ version: "0.1.0"
3
+ description: LLM-judgment critique of spec quality (proposals + ADRs) against a curated rubric catalog. Per-section critique with rubric-to-section mapping. Second craft-pipeline ceiling skill; highest-leverage because spec quality compounds across the lifecycle below it. Triggered the shared craft infrastructure extraction.
4
+ stability: draft
5
+ cognitive_mode: constructive-architect
6
+ triggers:
7
+ - manual
8
+ - on_pr
9
+ - on_new_feature
10
+ platforms:
11
+ - claude-code
12
+ tools:
13
+ - Bash
14
+ - Read
15
+ - Glob
16
+ - Grep
17
+ cli:
18
+ command: harness spec-craft
19
+ args:
20
+ - name: path
21
+ description: Project root path
22
+ required: false
23
+ - name: files
24
+ description: Optional spec file/glob scope
25
+ required: false
26
+ - name: kinds
27
+ description: Restrict to proposal / adr
28
+ required: false
29
+ - name: sections
30
+ description: Restrict to canonical section names
31
+ required: false
32
+ mcp:
33
+ tool: spec_craft
34
+ input:
35
+ path: string
36
+ type: rigid
37
+ tier: 2
38
+ phases:
39
+ - name: discover
40
+ description: Glob docs/changes/*/proposal.md + docs/knowledge/decisions/*.md
41
+ required: true
42
+ - name: parse
43
+ description: Markdown H2 section splitter (frontmatter-aware)
44
+ required: true
45
+ - name: critique
46
+ description: LLM-rubric loop per (file, section, rubric) where rubric applies
47
+ required: true
48
+ - name: report
49
+ description: Aggregate findings + cost telemetry + doc/section counts
50
+ required: true
51
+ state:
52
+ persistent: false
53
+ depends_on:
54
+ - harness-soundness-review
55
+ - harness-design-craft