create-harness-vibe-coding 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -32
- package/package.json +5 -2
- package/src/generator.js +407 -53
- package/src/index.js +236 -22
- package/templates/common/.claude/agents/architect.md +4 -4
- package/templates/common/.claude/agents/debugger.md +1 -1
- package/templates/common/.claude/agents/docs-researcher.md +4 -4
- package/templates/common/.claude/agents/implementer.md +1 -1
- package/templates/common/.claude/agents/planner.md +3 -3
- package/templates/common/.claude/agents/researcher.md +4 -4
- package/templates/common/.claude/agents/reviewer.md +1 -1
- package/templates/common/.claude/agents/test-writer.md +2 -2
- package/templates/common/.claude/agents/verifier.md +1 -1
- package/templates/common/.claude/commands/wf.md +18 -0
- package/templates/common/.claude/rules/ecc/common.md +16 -6
- package/templates/common/.claude/skills/harness-build-loop/SKILL.md +4 -3
- package/templates/common/.claude/skills/harness-context/SKILL.md +4 -3
- package/templates/common/.claude/skills/harness-lifecycle/SKILL.md +3 -3
- package/templates/common/.claude/skills/harness-research/SKILL.md +4 -4
- package/templates/common/.claude/skills/harness-router/SKILL.md +7 -5
- package/templates/common/.claude/skills/readme-optimizer/SKILL.md +48 -0
- package/templates/common/.claude/skills/subagent-orchestrator/SKILL.md +36 -0
- package/templates/common/.claude/skills/wf-mode/SKILL.md +48 -0
- package/templates/common/AGENTS.md +2 -2
- package/templates/common/CLAUDE.md +39 -71
- package/templates/common/MEMORY.md +42 -33
- package/templates/common/README.md +41 -0
- package/templates/common/SETUP.md +149 -41
- package/templates/common/docs/README.md +72 -47
- package/templates/common/docs/domain/ports.md +1 -1
- package/templates/common/docs/features/_template.md +20 -10
- package/templates/common/docs/harness/PLAN.md +25 -2
- package/templates/common/docs/harness/WF.md +136 -0
- package/templates/common/docs/harness/agent-workflow.md +8 -8
- package/templates/common/docs/harness/context-loading.md +17 -14
- package/templates/common/docs/harness/data-flow.md +1 -1
- package/templates/common/docs/harness/dispatch.md +6 -0
- package/templates/common/docs/harness/extension.md +20 -8
- package/templates/common/docs/harness/lifecycle.md +2 -2
- package/templates/common/docs/harness/subagents.md +140 -0
- package/templates/common/docs/research/PRD.md +1 -1
- package/templates/common/docs/research/README.md +5 -5
- package/templates/common/memory/agent-lessons-patterns.md +21 -0
- package/templates/common/memory/tool-usage-reflections.md +21 -0
- package/templates/common/memory/user-corrections-preferences.md +21 -0
- package/templates/common/scripts/validate-harness.mjs +217 -46
- package/templates/optional/catalog.json +43 -0
- package/templates/optional/skills/browser-e2e/.claude/skills/browser-e2e/SKILL.md +42 -0
- package/templates/optional/skills/browser-e2e/docs/workflows/browser-e2e.md +42 -0
- package/templates/optional/skills/github-pr-review/.claude/skills/github-pr-review/SKILL.md +40 -0
- package/templates/optional/skills/github-pr-review/docs/workflows/github-pr-review.md +28 -0
- package/templates/optional/skills/python-backend/.claude/skills/python-backend/SKILL.md +40 -0
- package/templates/optional/skills/python-backend/docs/workflows/python-backend.md +34 -0
- package/templates/optional/skills/ts-react-frontend/.claude/skills/ts-react-frontend/SKILL.md +43 -0
- package/templates/optional/skills/ts-react-frontend/docs/workflows/ts-react-frontend.md +35 -0
- package/templates/optional/skills/ui-ux-review/.claude/skills/ui-ux-review/SKILL.md +40 -0
- package/templates/optional/skills/ui-ux-review/docs/workflows/ui-ux-review.md +26 -0
|
@@ -7,10 +7,11 @@ const args = new Set(process.argv.slice(2));
|
|
|
7
7
|
const strict = args.has('--strict') || args.has('--post-bootstrap');
|
|
8
8
|
|
|
9
9
|
if (args.has('--help') || args.has('-h')) {
|
|
10
|
-
console.log(`Usage: node scripts/validate-harness.mjs [--strict]
|
|
10
|
+
console.log(`Usage: node Harness/scripts/validate-harness.mjs [--strict]
|
|
11
11
|
|
|
12
12
|
Default mode checks scaffold structure, links, agents, and skills.
|
|
13
|
-
--strict also fails when project fact docs still contain {{
|
|
13
|
+
--strict also fails when project fact docs still contain unresolved {{TOKEN}} placeholders.
|
|
14
|
+
Literal explanatory {{...}} text is allowed.`);
|
|
14
15
|
process.exit(0);
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -32,39 +33,53 @@ const commonSkills = [
|
|
|
32
33
|
'harness-research',
|
|
33
34
|
'harness-context',
|
|
34
35
|
'harness-build-loop',
|
|
36
|
+
'wf-mode',
|
|
37
|
+
'subagent-orchestrator',
|
|
38
|
+
'readme-optimizer',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const memoryFiles = [
|
|
42
|
+
'Harness/memory/tool-usage-reflections.md',
|
|
43
|
+
'Harness/memory/user-corrections-preferences.md',
|
|
44
|
+
'Harness/memory/agent-lessons-patterns.md',
|
|
35
45
|
];
|
|
36
46
|
|
|
37
47
|
const required = [
|
|
38
48
|
'AGENTS.md',
|
|
39
49
|
'CLAUDE.md',
|
|
40
|
-
'
|
|
50
|
+
'README.md',
|
|
51
|
+
'Harness/MEMORY.md',
|
|
52
|
+
'Harness/WF.md',
|
|
53
|
+
...memoryFiles,
|
|
41
54
|
'.claude/settings.json',
|
|
55
|
+
'.claude/commands/wf.md',
|
|
42
56
|
'.claude/rules/ecc/common.md',
|
|
43
57
|
...commonAgents.map(agent => `.claude/agents/${agent}.md`),
|
|
44
58
|
...commonSkills.map(skill => `.claude/skills/${skill}/SKILL.md`),
|
|
45
|
-
'
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
'
|
|
49
|
-
'
|
|
50
|
-
'
|
|
51
|
-
'
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'
|
|
59
|
-
'
|
|
59
|
+
'Harness/README.md',
|
|
60
|
+
'Harness/PLAN.md',
|
|
61
|
+
'Harness/lifecycle.md',
|
|
62
|
+
'Harness/subagents.md',
|
|
63
|
+
'Harness/dispatch.md',
|
|
64
|
+
'Harness/extension.md',
|
|
65
|
+
'Harness/context-loading.md',
|
|
66
|
+
'Harness/agent-workflow.md',
|
|
67
|
+
'Harness/architecture.md',
|
|
68
|
+
'Harness/data-flow.md',
|
|
69
|
+
'Harness/state-machines.md',
|
|
70
|
+
'Harness/features/_template.md',
|
|
71
|
+
'Harness/research/README.md',
|
|
72
|
+
'Harness/research/research-results.md',
|
|
73
|
+
'Harness/research/PRD.md',
|
|
74
|
+
'Harness/domain/ports.md',
|
|
60
75
|
];
|
|
61
76
|
|
|
62
77
|
const projectFacts = [
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
'
|
|
66
|
-
'
|
|
67
|
-
'
|
|
78
|
+
'Harness/PLAN.md',
|
|
79
|
+
'Harness/research/PRD.md',
|
|
80
|
+
'Harness/research/research-results.md',
|
|
81
|
+
'Harness/architecture.md',
|
|
82
|
+
'Harness/domain/ports.md',
|
|
68
83
|
];
|
|
69
84
|
|
|
70
85
|
const contextPacks = [
|
|
@@ -80,6 +95,13 @@ const contextPacks = [
|
|
|
80
95
|
'Verifier:',
|
|
81
96
|
];
|
|
82
97
|
|
|
98
|
+
const durableCommunicationDocs = [
|
|
99
|
+
'Harness/README.md',
|
|
100
|
+
'Harness/subagents.md',
|
|
101
|
+
'Harness/dispatch.md',
|
|
102
|
+
'Harness/context-loading.md',
|
|
103
|
+
];
|
|
104
|
+
|
|
83
105
|
const errors = [];
|
|
84
106
|
|
|
85
107
|
function read(rel) {
|
|
@@ -97,69 +119,193 @@ function frontmatterField(text, field) {
|
|
|
97
119
|
return match ? match[1].trim() : '';
|
|
98
120
|
}
|
|
99
121
|
|
|
122
|
+
function listDirectories(rel) {
|
|
123
|
+
const dir = path.join(root, rel);
|
|
124
|
+
if (!fs.existsSync(dir)) return [];
|
|
125
|
+
return fs.readdirSync(dir, { withFileTypes: true })
|
|
126
|
+
.filter(entry => entry.isDirectory())
|
|
127
|
+
.map(entry => entry.name);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function listMarkdownFiles(rel) {
|
|
131
|
+
const dir = path.join(root, rel);
|
|
132
|
+
if (!fs.existsSync(dir)) return [];
|
|
133
|
+
const normalizedRel = rel.replaceAll(path.sep, '/');
|
|
134
|
+
return fs.readdirSync(dir, { withFileTypes: true })
|
|
135
|
+
.filter(entry => entry.isFile() && entry.name.endsWith('.md'))
|
|
136
|
+
.map(entry => `${normalizedRel}/${entry.name}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function unresolvedTemplatePlaceholders(text) {
|
|
140
|
+
const placeholders = [];
|
|
141
|
+
const pattern = /\{\{([^{}\r\n]+)\}\}/g;
|
|
142
|
+
|
|
143
|
+
for (const match of text.matchAll(pattern)) {
|
|
144
|
+
const token = match[1].trim();
|
|
145
|
+
if (token === '...') continue;
|
|
146
|
+
placeholders.push(`{{${token}}}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return [...new Set(placeholders)];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function registeredSkillFiles(...texts) {
|
|
153
|
+
const files = new Set();
|
|
154
|
+
const pattern = /(?:\.\.\/)?(\.claude\/skills\/[a-z0-9-]+\/SKILL\.md)/g;
|
|
155
|
+
|
|
156
|
+
for (const text of texts) {
|
|
157
|
+
for (const match of text.matchAll(pattern)) {
|
|
158
|
+
files.add(match[1]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return [...files].sort();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function registeredWorkflowFiles(...texts) {
|
|
166
|
+
const files = new Set();
|
|
167
|
+
const pattern = /(?:Harness\/)?workflows\/([A-Za-z0-9._-]+\.md)/g;
|
|
168
|
+
|
|
169
|
+
for (const text of texts) {
|
|
170
|
+
for (const match of text.matchAll(pattern)) {
|
|
171
|
+
files.add(`Harness/workflows/${match[1]}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return [...files].sort();
|
|
176
|
+
}
|
|
177
|
+
|
|
100
178
|
for (const rel of required) {
|
|
101
179
|
if (!fs.existsSync(path.join(root, rel))) {
|
|
102
180
|
errors.push(`missing required file: ${rel}`);
|
|
103
181
|
}
|
|
104
182
|
}
|
|
105
183
|
|
|
106
|
-
if (fs.existsSync(path.join(root, '
|
|
107
|
-
errors.push('legacy research file should be renamed:
|
|
184
|
+
if (fs.existsSync(path.join(root, 'Harness/research/scaffolds.md'))) {
|
|
185
|
+
errors.push('legacy research file should be renamed: Harness/research/scaffolds.md -> Harness/research/research-results.md');
|
|
108
186
|
}
|
|
109
187
|
|
|
110
188
|
if (strict) {
|
|
189
|
+
console.log('Strict placeholder scope:');
|
|
190
|
+
for (const rel of projectFacts) {
|
|
191
|
+
console.log(`- ${rel}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
111
194
|
for (const rel of projectFacts) {
|
|
112
195
|
const text = read(rel);
|
|
113
|
-
|
|
114
|
-
errors.push(`template
|
|
196
|
+
for (const placeholder of unresolvedTemplatePlaceholders(text)) {
|
|
197
|
+
errors.push(`template placeholder remains in project fact file: ${rel}: ${placeholder}`);
|
|
115
198
|
}
|
|
116
199
|
}
|
|
117
200
|
}
|
|
118
201
|
|
|
119
|
-
const docsReadme = read('
|
|
202
|
+
const docsReadme = read('Harness/README.md');
|
|
120
203
|
if (docsReadme) {
|
|
121
204
|
for (const marker of ['## Keyword Routing', '## Load By Task', 'When to Read', 'Keywords']) {
|
|
122
|
-
if (!docsReadme.includes(marker)) errors.push(`
|
|
205
|
+
if (!docsReadme.includes(marker)) errors.push(`Harness/README.md missing router marker: ${marker}`);
|
|
123
206
|
}
|
|
124
207
|
}
|
|
125
208
|
|
|
126
|
-
const
|
|
209
|
+
for (const rel of durableCommunicationDocs) {
|
|
210
|
+
requireText(rel, 'project files are the only durable communication channel', 'durable filesystem communication invariant');
|
|
211
|
+
requireText(rel, 'chat/subagent transcript state is non-authoritative', 'non-authoritative transcript invariant');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
requireText('CLAUDE.md', 'same tool/use pattern fails 3+ times', 'tool reflection trigger');
|
|
215
|
+
requireText('CLAUDE.md', 'user corrects the same assumption/pattern 2+ times', 'user correction reflection trigger');
|
|
216
|
+
requireText('CLAUDE.md', 'If `Harness/` exists, this repository is governed by the Harness contract', 'Harness binding contract');
|
|
217
|
+
requireText('CLAUDE.md', 'Harness/MEMORY.md` is the memory/resource router', 'memory/resource router');
|
|
218
|
+
requireText('CLAUDE.md', 'Harness/README.md#Load By Task', 'Harness task router');
|
|
219
|
+
requireText('CLAUDE.md', 'Harness/SETUP.md` exists, follow it before normal project work', 'setup bootstrap contract');
|
|
220
|
+
requireText('CLAUDE.md', 'subagent-orchestrator` and `Harness/subagents.md', 'subagent orchestrator entry trigger');
|
|
221
|
+
for (const heading of ['## 2. Think Before Coding', '## 3. Simplicity First', '## 4. Surgical Changes', '## 5. Goal-Driven Execution']) {
|
|
222
|
+
requireText('CLAUDE.md', heading, `Karpathy-style rule heading: ${heading}`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const plan = read('Harness/PLAN.md');
|
|
127
226
|
if (plan) {
|
|
128
|
-
for (const heading of ['## Current Goal', '## Phase', '## Success Criteria', '## Loaded Context', '## Tasks', '## Parallel Dispatch', '## Verification']) {
|
|
129
|
-
if (!plan.includes(heading)) errors.push(`
|
|
227
|
+
for (const heading of ['## Current Goal', '## Phase', '## Heartbeat', '## Success Criteria', '## Loaded Context', '## Tasks', '## Parallel Dispatch', '## Subagent Synthesis', '## Verification']) {
|
|
228
|
+
if (!plan.includes(heading)) errors.push(`Harness/PLAN.md missing heading: ${heading}`);
|
|
229
|
+
}
|
|
230
|
+
for (const marker of ['Next beat trigger', 'Recovery action']) {
|
|
231
|
+
if (!plan.includes(marker)) errors.push(`Harness/PLAN.md missing heartbeat marker: ${marker}`);
|
|
130
232
|
}
|
|
131
233
|
}
|
|
132
234
|
|
|
133
|
-
const dispatch = read('
|
|
235
|
+
const dispatch = read('Harness/dispatch.md');
|
|
134
236
|
if (dispatch) {
|
|
135
237
|
for (const agent of commonAgents) {
|
|
136
|
-
if (!dispatch.includes(`\`${agent}\``)) errors.push(`
|
|
238
|
+
if (!dispatch.includes(`\`${agent}\``)) errors.push(`Harness/dispatch.md missing common agent: ${agent}`);
|
|
137
239
|
}
|
|
138
|
-
if (!dispatch.includes('## Handoff Format')) errors.push('
|
|
240
|
+
if (!dispatch.includes('## Handoff Format')) errors.push('Harness/dispatch.md missing heading: ## Handoff Format');
|
|
139
241
|
}
|
|
140
242
|
|
|
141
|
-
const contextLoading = read('
|
|
243
|
+
const contextLoading = read('Harness/context-loading.md');
|
|
142
244
|
if (contextLoading) {
|
|
143
|
-
if (!contextLoading.includes('
|
|
144
|
-
errors.push('
|
|
245
|
+
if (!contextLoading.includes('Harness/README.md` is the primary router')) {
|
|
246
|
+
errors.push('Harness/context-loading.md must declare Harness/README.md as the primary router');
|
|
145
247
|
}
|
|
146
248
|
for (const pack of contextPacks) {
|
|
147
|
-
if (!contextLoading.includes(pack)) errors.push(`
|
|
249
|
+
if (!contextLoading.includes(pack)) errors.push(`Harness/context-loading.md missing subagent pack: ${pack}`);
|
|
148
250
|
}
|
|
149
251
|
}
|
|
150
252
|
|
|
151
|
-
const memory = read('MEMORY.md');
|
|
253
|
+
const memory = read('Harness/MEMORY.md');
|
|
152
254
|
if (memory) {
|
|
153
255
|
for (const agent of commonAgents) {
|
|
154
256
|
const rel = `.claude/agents/${agent}.md`;
|
|
155
|
-
if (!memory.includes(rel)) errors.push(`MEMORY.md missing agent registration: ${rel}`);
|
|
257
|
+
if (!memory.includes(rel)) errors.push(`Harness/MEMORY.md missing agent registration: ${rel}`);
|
|
156
258
|
}
|
|
157
259
|
for (const skill of commonSkills) {
|
|
158
260
|
const rel = `.claude/skills/${skill}/SKILL.md`;
|
|
159
|
-
if (!memory.includes(rel)) errors.push(`MEMORY.md missing skill registration: ${rel}`);
|
|
261
|
+
if (!memory.includes(rel)) errors.push(`Harness/MEMORY.md missing skill registration: ${rel}`);
|
|
262
|
+
}
|
|
263
|
+
for (const rel of memoryFiles) {
|
|
264
|
+
const relativeRel = rel.replace(/^Harness\//, '');
|
|
265
|
+
if (!memory.includes(rel) && !memory.includes(relativeRel)) {
|
|
266
|
+
errors.push(`Harness/MEMORY.md missing memory file registration: ${rel}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
for (const workflow of listMarkdownFiles('Harness/workflows')) {
|
|
272
|
+
const relativeWorkflow = workflow.replace(/^Harness\//, '');
|
|
273
|
+
if (!docsReadme.includes(workflow) && !docsReadme.includes(relativeWorkflow) && !memory.includes(workflow) && !memory.includes(relativeWorkflow)) {
|
|
274
|
+
errors.push(`workflow is not registered in Harness/README.md or Harness/MEMORY.md: ${workflow}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
for (const skillFile of registeredSkillFiles(docsReadme, memory)) {
|
|
279
|
+
if (!fs.existsSync(path.join(root, skillFile))) {
|
|
280
|
+
errors.push(`registered skill file is missing: ${skillFile}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
for (const workflowFile of registeredWorkflowFiles(docsReadme, memory)) {
|
|
285
|
+
if (!fs.existsSync(path.join(root, workflowFile))) {
|
|
286
|
+
errors.push(`registered workflow file is missing: ${workflowFile}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function requireUiSelectorContract(rel) {
|
|
291
|
+
const text = read(rel);
|
|
292
|
+
if (!text) return;
|
|
293
|
+
|
|
294
|
+
const markers = [
|
|
295
|
+
'data-testid',
|
|
296
|
+
'accessible labels/roles',
|
|
297
|
+
'inputs, buttons, filters, rows, empty/error/loading states',
|
|
298
|
+
];
|
|
299
|
+
|
|
300
|
+
if (markers.some(marker => !text.includes(marker))) {
|
|
301
|
+
errors.push(`${rel} missing stable UI selector contract`);
|
|
160
302
|
}
|
|
161
303
|
}
|
|
162
304
|
|
|
305
|
+
requireUiSelectorContract('Harness/workflows/browser-e2e.md');
|
|
306
|
+
requireUiSelectorContract('Harness/workflows/ts-react-frontend.md');
|
|
307
|
+
requireUiSelectorContract('Harness/features/_template.md');
|
|
308
|
+
|
|
163
309
|
for (const skill of commonSkills) {
|
|
164
310
|
const rel = `.claude/skills/${skill}/SKILL.md`;
|
|
165
311
|
const text = read(rel);
|
|
@@ -168,6 +314,17 @@ for (const skill of commonSkills) {
|
|
|
168
314
|
if (!frontmatterField(text, 'description')) errors.push(`${rel} missing frontmatter field: description`);
|
|
169
315
|
}
|
|
170
316
|
|
|
317
|
+
for (const skill of listDirectories('.claude/skills')) {
|
|
318
|
+
if (commonSkills.includes(skill)) continue;
|
|
319
|
+
|
|
320
|
+
const rel = `.claude/skills/${skill}/SKILL.md`;
|
|
321
|
+
const text = read(rel);
|
|
322
|
+
if (!text) continue;
|
|
323
|
+
|
|
324
|
+
if (frontmatterField(text, 'name') !== skill) errors.push(`${rel} frontmatter name does not match directory`);
|
|
325
|
+
if (!frontmatterField(text, 'description')) errors.push(`${rel} missing frontmatter field: description`);
|
|
326
|
+
}
|
|
327
|
+
|
|
171
328
|
for (const agent of commonAgents) {
|
|
172
329
|
const rel = `.claude/agents/${agent}.md`;
|
|
173
330
|
const text = read(rel);
|
|
@@ -191,9 +348,23 @@ for (const agent of commonAgents) {
|
|
|
191
348
|
}
|
|
192
349
|
}
|
|
193
350
|
|
|
194
|
-
requireText('
|
|
195
|
-
requireText('
|
|
196
|
-
requireText('
|
|
351
|
+
requireText('Harness/extension.md', 'Skills should extend the harness');
|
|
352
|
+
requireText('Harness/agent-workflow.md', 'Harness/PLAN.md');
|
|
353
|
+
requireText('Harness/research/README.md', 'research-results.md');
|
|
354
|
+
requireText('Harness/WF.md', 'Ralph-style harness loop', 'WF loop description');
|
|
355
|
+
requireText('Harness/WF.md', 'Heartbeat Protocol', 'heartbeat protocol');
|
|
356
|
+
requireText('.claude/skills/wf-mode/SKILL.md', 'Harness/WF.md', 'wf-mode loads WF document');
|
|
357
|
+
requireText('.claude/skills/wf-mode/SKILL.md', 'Harness/subagents.md', 'wf-mode loads subagent orchestration');
|
|
358
|
+
requireText('.claude/skills/subagent-orchestrator/SKILL.md', 'Harness/subagents.md', 'subagent-orchestrator loads subagents doc');
|
|
359
|
+
requireText('.claude/skills/harness-context/SKILL.md', 'Harness/subagents.md', 'harness-context loads subagents doc');
|
|
360
|
+
requireText('.claude/skills/readme-optimizer/SKILL.md', 'README.md', 'readme-optimizer loads README');
|
|
361
|
+
requireText('.claude/skills/readme-optimizer/SKILL.md', 'Harness/architecture.md', 'readme-optimizer links architecture docs');
|
|
362
|
+
requireText('Harness/subagents.md', '## Source Attribution', 'subagent source attribution');
|
|
363
|
+
requireText('Harness/subagents.md', 'npx skills find', 'find-skills discovery attribution');
|
|
364
|
+
requireText('Harness/subagents.md', 'superpowers:dispatching-parallel-agents', 'parallel-agent source attribution');
|
|
365
|
+
requireText('Harness/subagents.md', 'superpowers:subagent-driven-development', 'subagent-driven source attribution');
|
|
366
|
+
requireText('Harness/subagents.md', '## Efficiency Ladder', 'subagent efficiency ladder');
|
|
367
|
+
requireText('Harness/subagents.md', '## Review Gates', 'subagent review gates');
|
|
197
368
|
|
|
198
369
|
if (errors.length) {
|
|
199
370
|
console.error(`Harness validation failed${strict ? ' (strict)' : ''}:`);
|
|
@@ -203,5 +374,5 @@ if (errors.length) {
|
|
|
203
374
|
|
|
204
375
|
console.log(`Harness validation passed${strict ? ' (strict)' : ''}.`);
|
|
205
376
|
if (!strict) {
|
|
206
|
-
console.log('Tip: run `node scripts/validate-harness.mjs --strict` after bootstrap to check unresolved project placeholders.');
|
|
377
|
+
console.log('Tip: run `node Harness/scripts/validate-harness.mjs --strict` after bootstrap to check unresolved project placeholders.');
|
|
207
378
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skills": [
|
|
3
|
+
{
|
|
4
|
+
"id": "browser-e2e",
|
|
5
|
+
"title": "Browser E2E",
|
|
6
|
+
"description": "Mandatory real-browser smoke workflow using Playwright, Chrome DevTools/CDP, or documented manual evidence.",
|
|
7
|
+
"files": ["skills/browser-e2e"],
|
|
8
|
+
"tags": ["e2e", "browser", "playwright", "cdp"]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": "ui-ux-review",
|
|
12
|
+
"title": "UI/UX Review",
|
|
13
|
+
"description": "Screenshot-driven responsive, accessibility, and visual polish review workflow.",
|
|
14
|
+
"files": ["skills/ui-ux-review"],
|
|
15
|
+
"tags": ["ui", "ux", "accessibility", "review"]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "github-pr-review",
|
|
19
|
+
"title": "GitHub PR Review",
|
|
20
|
+
"description": "GitHub CLI based PR diff, checks, review findings, and CI evidence workflow.",
|
|
21
|
+
"files": ["skills/github-pr-review"],
|
|
22
|
+
"tags": ["github", "pr", "review", "ci"]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "python-backend",
|
|
26
|
+
"title": "Python Backend",
|
|
27
|
+
"description": "Python backend workflow for FastAPI or similar APIs with unittest or pytest verification.",
|
|
28
|
+
"files": ["skills/python-backend"],
|
|
29
|
+
"tags": ["python", "fastapi", "unittest", "pytest", "api"]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "ts-react-frontend",
|
|
33
|
+
"title": "TypeScript React Frontend",
|
|
34
|
+
"description": "TypeScript React workflow for typecheck, component tests, builds, and browser smoke.",
|
|
35
|
+
"files": ["skills/ts-react-frontend"],
|
|
36
|
+
"tags": ["typescript", "react", "vite", "frontend"]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"presets": {
|
|
40
|
+
"web-app": ["ts-react-frontend", "browser-e2e", "ui-ux-review"],
|
|
41
|
+
"fullstack": ["ts-react-frontend", "python-backend", "browser-e2e", "github-pr-review"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser-e2e
|
|
3
|
+
description: Mandatory real-browser smoke and end-to-end verification using Playwright, Chrome DevTools/CDP, or documented manual browser evidence.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Browser E2E
|
|
7
|
+
|
|
8
|
+
## When To Use
|
|
9
|
+
|
|
10
|
+
Use this skill when a change affects browser-visible behavior, navigation, forms, routing, layout, or client-side integration. Web/UI acceptance requires loading the app in a real browser before claiming the UI is done.
|
|
11
|
+
|
|
12
|
+
## Docs To Load
|
|
13
|
+
|
|
14
|
+
- `Harness/workflows/browser-e2e.md`
|
|
15
|
+
- `Harness/PLAN.md`
|
|
16
|
+
- Existing project test, build, and run instructions.
|
|
17
|
+
|
|
18
|
+
## Required Inputs
|
|
19
|
+
|
|
20
|
+
- Target URL or command to start the app.
|
|
21
|
+
- User flows or pages to verify.
|
|
22
|
+
- Expected behavior and supported viewport/browser scope.
|
|
23
|
+
- Selector contract: stable accessible labels/roles and `data-testid` hooks for critical inputs, buttons, filters, rows, empty/error/loading states, and other targetable UI states.
|
|
24
|
+
|
|
25
|
+
## Allowed Writes
|
|
26
|
+
|
|
27
|
+
- Browser test files in the project's existing test locations.
|
|
28
|
+
- Evidence artifacts such as screenshots, traces, or reports in existing artifact folders.
|
|
29
|
+
- Notes in `Harness/PLAN.md` when the active task asks for plan tracking.
|
|
30
|
+
|
|
31
|
+
## Output Format
|
|
32
|
+
|
|
33
|
+
Return changed files, commands run, browser evidence paths, verified flows, failures, and follow-up risks.
|
|
34
|
+
Include the selectors used for CDP/Playwright/manual verification.
|
|
35
|
+
|
|
36
|
+
## PLAN.md Updates
|
|
37
|
+
|
|
38
|
+
Update `Harness/PLAN.md` only when executing a tracked plan item or recording evidence requested by the current task.
|
|
39
|
+
|
|
40
|
+
## dispatch.md Usage
|
|
41
|
+
|
|
42
|
+
Use `Harness/dispatch.md` only when splitting independent browser checks across workers is explicitly useful.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Browser E2E Workflow
|
|
2
|
+
|
|
3
|
+
## Required Evidence
|
|
4
|
+
|
|
5
|
+
- App start command and URL.
|
|
6
|
+
- Real-browser load of the changed app before any web/UI acceptance claim.
|
|
7
|
+
- Console, runtime, and network check result, including whether React/Vite/client startup errors or failed requests appeared.
|
|
8
|
+
- Stable accessible labels/roles and stable test hooks such as `data-testid` are required for critical UI controls and states: inputs, buttons, filters, rows, empty/error/loading states.
|
|
9
|
+
- CDP, Playwright, and manual verification must target those selectors for the critical interaction path instead of brittle DOM paths.
|
|
10
|
+
- Viewports and browsers checked.
|
|
11
|
+
- Screenshot, trace, video, or documented manual screenshot artifact for each critical UI flow.
|
|
12
|
+
- Final pass/fail result with exact command output summary.
|
|
13
|
+
|
|
14
|
+
## Chrome DevTools / CDP / MCP Checklist
|
|
15
|
+
|
|
16
|
+
- Start the app with the project command and record the URL and port.
|
|
17
|
+
- Open a real browser target through available CDP, MCP, browser automation, or manual tooling.
|
|
18
|
+
- Wait for a stable app selector, route, or page-ready state, not just HTTP 200.
|
|
19
|
+
- Capture runtime exceptions, console errors, and failed network requests before and after the flow.
|
|
20
|
+
- Interact through stable accessible labels/roles or `data-testid`, not brittle DOM paths.
|
|
21
|
+
- Verify at least one critical flow end-to-end in the real browser target.
|
|
22
|
+
- Save screenshot, trace, video, or result artifact paths and record them in `Harness/PLAN.md` or the feature doc.
|
|
23
|
+
- Clean up any dev server or browser processes started for verification.
|
|
24
|
+
|
|
25
|
+
## Common Commands
|
|
26
|
+
|
|
27
|
+
```powershell
|
|
28
|
+
npm run dev
|
|
29
|
+
npx playwright test
|
|
30
|
+
npx playwright test --headed
|
|
31
|
+
npx playwright show-report
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If Playwright is not installed, prefer an existing browser test command from `package.json`. Chrome DevTools/CDP, manual screenshot evidence, or framework-specific tools are acceptable when the method, URL, flow, console/runtime/network result, and artifacts are documented.
|
|
35
|
+
|
|
36
|
+
## Fallback
|
|
37
|
+
|
|
38
|
+
When no browser automation is available, run the app locally in a real browser, inspect critical flows manually, capture screenshots, and report console or network errors. Do not claim web/UI acceptance from typecheck, build, or unit tests alone. Do not install new dependencies unless the user approves.
|
|
39
|
+
|
|
40
|
+
## Windows Notes
|
|
41
|
+
|
|
42
|
+
Use PowerShell syntax for environment variables, for example `$env:PORT='3000'; npm run dev`. Quote paths that contain spaces.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-pr-review
|
|
3
|
+
description: GitHub pull request review workflow using available GitHub CLI, local git diff, checks, and CI evidence.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub PR Review
|
|
7
|
+
|
|
8
|
+
## When To Use
|
|
9
|
+
|
|
10
|
+
Use this skill when reviewing a GitHub pull request, responding to PR feedback, checking CI status, or summarizing review findings.
|
|
11
|
+
|
|
12
|
+
## Docs To Load
|
|
13
|
+
|
|
14
|
+
- `Harness/workflows/github-pr-review.md`
|
|
15
|
+
- `Harness/PLAN.md`
|
|
16
|
+
- Repository contribution, test, and review guidelines.
|
|
17
|
+
|
|
18
|
+
## Required Inputs
|
|
19
|
+
|
|
20
|
+
- PR number, branch, or comparison range.
|
|
21
|
+
- Review goal: bug hunt, approval readiness, CI diagnosis, or feedback response.
|
|
22
|
+
- Expected test and check requirements.
|
|
23
|
+
|
|
24
|
+
## Allowed Writes
|
|
25
|
+
|
|
26
|
+
- Local files needed to address approved review feedback.
|
|
27
|
+
- Review notes or evidence in existing docs only when requested.
|
|
28
|
+
- `Harness/PLAN.md` when tracking review work.
|
|
29
|
+
|
|
30
|
+
## Output Format
|
|
31
|
+
|
|
32
|
+
Return findings first by severity with file and line references, then open questions, tests/checks run, and change summary if edits were made.
|
|
33
|
+
|
|
34
|
+
## PLAN.md Updates
|
|
35
|
+
|
|
36
|
+
Update `Harness/PLAN.md` only when the PR review is part of a tracked implementation plan.
|
|
37
|
+
|
|
38
|
+
## dispatch.md Usage
|
|
39
|
+
|
|
40
|
+
Use `Harness/dispatch.md` when independent review areas can be assigned separately, such as backend, frontend, and CI.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# GitHub PR Review Workflow
|
|
2
|
+
|
|
3
|
+
## Required Evidence
|
|
4
|
+
|
|
5
|
+
- PR URL or number and base/head refs.
|
|
6
|
+
- Diff or changed-file summary.
|
|
7
|
+
- CI/check status and relevant failing logs.
|
|
8
|
+
- Review findings with exact file and line references when available.
|
|
9
|
+
|
|
10
|
+
## Common Commands
|
|
11
|
+
|
|
12
|
+
```powershell
|
|
13
|
+
gh pr view --web
|
|
14
|
+
gh pr view --json number,title,baseRefName,headRefName,mergeStateStatus,statusCheckRollup
|
|
15
|
+
gh pr diff
|
|
16
|
+
git diff --stat
|
|
17
|
+
npm test
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use repository-specific test commands when they differ from npm.
|
|
21
|
+
|
|
22
|
+
## Fallback
|
|
23
|
+
|
|
24
|
+
If `gh` is unavailable or unauthenticated, use local git refs, remote URLs, and `git diff` against the target branch. Ask for missing PR context only when it cannot be inferred.
|
|
25
|
+
|
|
26
|
+
## Windows Notes
|
|
27
|
+
|
|
28
|
+
Quote branch names containing special characters. In PowerShell, pipe JSON output to tools that are available locally, or read it directly if `jq` is not installed.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python-backend
|
|
3
|
+
description: Python backend workflow for API changes, service logic, FastAPI-style routes, and unittest or pytest verification.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Python Backend
|
|
7
|
+
|
|
8
|
+
## When To Use
|
|
9
|
+
|
|
10
|
+
Use this skill when changing Python API routes, service logic, persistence boundaries, background jobs, or backend tests.
|
|
11
|
+
|
|
12
|
+
## Docs To Load
|
|
13
|
+
|
|
14
|
+
- `Harness/workflows/python-backend.md`
|
|
15
|
+
- `Harness/PLAN.md`
|
|
16
|
+
- Project backend README, API docs, dependency files, and test configuration.
|
|
17
|
+
|
|
18
|
+
## Required Inputs
|
|
19
|
+
|
|
20
|
+
- Target behavior, endpoint, service, or bug.
|
|
21
|
+
- Existing test command and runtime setup.
|
|
22
|
+
- Database, environment variable, or fixture constraints.
|
|
23
|
+
|
|
24
|
+
## Allowed Writes
|
|
25
|
+
|
|
26
|
+
- Python source, tests, fixtures, and backend docs in the task scope.
|
|
27
|
+
- Local evidence artifacts such as test output snippets.
|
|
28
|
+
- `Harness/PLAN.md` when the task requires plan tracking.
|
|
29
|
+
|
|
30
|
+
## Output Format
|
|
31
|
+
|
|
32
|
+
Return files changed, API or behavior summary, tests run, important logs, migration/config notes, and remaining risks.
|
|
33
|
+
|
|
34
|
+
## PLAN.md Updates
|
|
35
|
+
|
|
36
|
+
Update `Harness/PLAN.md` only when executing a tracked plan item or recording required validation evidence.
|
|
37
|
+
|
|
38
|
+
## dispatch.md Usage
|
|
39
|
+
|
|
40
|
+
Use `Harness/dispatch.md` for separable backend work such as API implementation, database changes, and test coverage.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Python Backend Workflow
|
|
2
|
+
|
|
3
|
+
## Required Evidence
|
|
4
|
+
|
|
5
|
+
- Python executable, version, and dependency manager detected.
|
|
6
|
+
- Unit/integration test command and result.
|
|
7
|
+
- API smoke evidence for changed endpoints when applicable.
|
|
8
|
+
- Migration, fixture, or environment assumptions.
|
|
9
|
+
|
|
10
|
+
## Common Commands
|
|
11
|
+
|
|
12
|
+
```powershell
|
|
13
|
+
python --version
|
|
14
|
+
py --version
|
|
15
|
+
python3 --version
|
|
16
|
+
python -m unittest discover -s tests
|
|
17
|
+
py -m unittest discover -s tests
|
|
18
|
+
python3 -m unittest discover -s tests
|
|
19
|
+
python -m pytest
|
|
20
|
+
python -m pytest tests
|
|
21
|
+
uv run pytest
|
|
22
|
+
poetry run pytest
|
|
23
|
+
python -m uvicorn app.main:app --reload
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Prefer commands already documented by the project. When no project-specific command is documented, detect an available Python executable in the current shell (`python`, then `py`, then `python3`) and run the matching `-m unittest discover -s tests` or pytest command. `unittest` is first-class for standard-library test suites; do not require pytest when the project already uses unittest.
|
|
27
|
+
|
|
28
|
+
## Fallback
|
|
29
|
+
|
|
30
|
+
If unittest, pytest, or the app runner is unavailable, run targeted Python modules, import checks, or framework-specific tests that already exist. Do not create or install a new backend stack without approval.
|
|
31
|
+
|
|
32
|
+
## Windows Notes
|
|
33
|
+
|
|
34
|
+
Virtual environment activation is usually `.\\.venv\\Scripts\\Activate.ps1`. If script execution is blocked, use the environment's Python executable directly, for example `.\\.venv\\Scripts\\python.exe -m unittest discover -s tests` or `.\\.venv\\Scripts\\python.exe -m pytest`.
|