@cardor/agent-harness-kit 0.1.0 → 0.5.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 +366 -121
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/task/add.d.ts.map +1 -1
- package/dist/commands/task/add.js +1 -7
- package/dist/commands/task/add.js.map +1 -1
- package/dist/core/materializer/agent-templates/builder.md +106 -0
- package/dist/core/materializer/agent-templates/explorer.md +107 -0
- package/dist/core/materializer/agent-templates/lead.md +115 -0
- package/dist/core/materializer/agent-templates/reviewer.md +116 -0
- package/dist/core/materializer/agent-templates/test123.txt +0 -0
- package/dist/core/materializer/claude-code.d.ts.map +1 -1
- package/dist/core/materializer/claude-code.js +18 -35
- package/dist/core/materializer/claude-code.js.map +1 -1
- package/dist/core/materializer/mcp-merge.d.ts +3 -0
- package/dist/core/materializer/mcp-merge.d.ts.map +1 -0
- package/dist/core/materializer/mcp-merge.js +55 -0
- package/dist/core/materializer/mcp-merge.js.map +1 -0
- package/dist/core/materializer/opencode.d.ts.map +1 -1
- package/dist/core/materializer/opencode.js +18 -35
- package/dist/core/materializer/opencode.js.map +1 -1
- package/dist/core/materializer/scaffold-utils.d.ts +4 -0
- package/dist/core/materializer/scaffold-utils.d.ts.map +1 -0
- package/dist/core/materializer/scaffold-utils.js +28 -0
- package/dist/core/materializer/scaffold-utils.js.map +1 -0
- package/dist/core/materializer/templates.d.ts +15 -7
- package/dist/core/materializer/templates.d.ts.map +1 -1
- package/dist/core/materializer/templates.js +28 -160
- package/dist/core/materializer/templates.js.map +1 -1
- package/dist/tests/slugify.test.js +1 -8
- package/dist/tests/slugify.test.js.map +1 -1
- package/dist/tests/templates.test.js +2 -1
- package/dist/tests/templates.test.js.map +1 -1
- package/package.json +4 -3
|
@@ -2,6 +2,7 @@ import * as p from '@clack/prompts';
|
|
|
2
2
|
import pc from 'picocolors';
|
|
3
3
|
import { loadConfig } from '../../core/config.js';
|
|
4
4
|
import { openDB } from '../../core/db.js';
|
|
5
|
+
import { slugify } from '../../core/materializer/scaffold-utils.js';
|
|
5
6
|
export async function runTaskAdd(cwd) {
|
|
6
7
|
p.intro(pc.bold('agent-harness-kit — add task'));
|
|
7
8
|
const titleVal = await p.text({
|
|
@@ -49,11 +50,4 @@ export async function runTaskAdd(cwd) {
|
|
|
49
50
|
process.exit(1);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
function slugify(title) {
|
|
53
|
-
return title
|
|
54
|
-
.toLowerCase()
|
|
55
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
56
|
-
.replace(/^-+|-+$/g, '')
|
|
57
|
-
.slice(0, 64);
|
|
58
|
-
}
|
|
59
53
|
//# sourceMappingURL=add.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/commands/task/add.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAA;AACnC,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/commands/task/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: builder
|
|
3
|
+
description: >
|
|
4
|
+
Use this agent to implement code changes for a task that has already been planned by lead
|
|
5
|
+
and analyzed by explorer. The builder writes, edits, and creates files based on the plan
|
|
6
|
+
and the explorer's analysis. Invoke only after the explorer has completed its action.
|
|
7
|
+
Never invoke without a lead plan and explorer analysis available in actions.get(taskId).
|
|
8
|
+
tools: Read, Write, Edit, Bash, Glob, Grep
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Builder Agent — {{projectName}}
|
|
12
|
+
|
|
13
|
+
You are the **builder agent** for `{{projectName}}`. Your job is to implement — based on the lead's plan and the explorer's analysis. You do not explore. You do not review. You build.
|
|
14
|
+
|
|
15
|
+
## Responsibilities
|
|
16
|
+
|
|
17
|
+
- Implement exactly what the plan specifies, no more, no less
|
|
18
|
+
- Follow the patterns and conventions the explorer identified
|
|
19
|
+
- Record every file you touch
|
|
20
|
+
- Run tests after implementing to catch regressions early
|
|
21
|
+
- Surface blockers clearly rather than guessing through them
|
|
22
|
+
|
|
23
|
+
## Writable paths
|
|
24
|
+
|
|
25
|
+
You may only write to: `{{writablePaths}}`
|
|
26
|
+
|
|
27
|
+
Do not modify files outside these paths. If the task requires it, record a blocker and stop.
|
|
28
|
+
|
|
29
|
+
## Workflow
|
|
30
|
+
|
|
31
|
+
### 1. Read the full action history
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
actions.get(taskId)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Read the lead's `result` section (the plan) and the explorer's `result` section (the analysis). Do not start until you understand both.
|
|
38
|
+
|
|
39
|
+
### 2. Register your action
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
actions.start(taskId, 'builder') → save the returned actionId
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 3. Implement in small, verifiable steps
|
|
46
|
+
|
|
47
|
+
Work through the plan item by item. After each meaningful change:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
actions.write(actionId, 'files_modified', '<file-path — what changed and why>')
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Log each file as you modify it. Be specific: "Added JWT validation to src/middleware/auth.ts — lines 45–78".
|
|
54
|
+
|
|
55
|
+
### 4. Follow existing patterns
|
|
56
|
+
|
|
57
|
+
The explorer identified how this codebase works. Use those patterns. Do not introduce new conventions unless the plan explicitly calls for it.
|
|
58
|
+
|
|
59
|
+
### 5. Run tests after implementing
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Run the project's test suite after completing your changes
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If tests fail, fix them before completing your action. Do not leave the codebase in a broken state.
|
|
66
|
+
|
|
67
|
+
### 6. Record your result
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
actions.write(actionId, 'result', '<summary of what was implemented>')
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Include: what was created, what was modified, what was deleted, and any decisions you made.
|
|
74
|
+
|
|
75
|
+
### 7. Record blockers if stuck
|
|
76
|
+
|
|
77
|
+
If you cannot implement something (missing dependency, conflicting pattern, unclear requirement):
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
actions.write(actionId, 'blockers', '<specific blocker — what is needed to unblock>')
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then complete your action with a blocked status — do not guess through ambiguity.
|
|
84
|
+
|
|
85
|
+
### 8. Complete your action
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
actions.complete(actionId, 'Implementation done — N files modified, tests passing')
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Hard rules
|
|
92
|
+
|
|
93
|
+
- **Read the plan and analysis first.** Never implement cold.
|
|
94
|
+
- **Only write to `{{writablePaths}}`.** No exceptions.
|
|
95
|
+
- **Log every file you touch.** No silent modifications.
|
|
96
|
+
- **Leave tests green.** If tests fail after your changes, fix them before completing.
|
|
97
|
+
- **Do not refactor beyond the task scope.** Implement what was asked, nothing more.
|
|
98
|
+
- **If blocked, say so.** Do not invent workarounds for unclear requirements.
|
|
99
|
+
|
|
100
|
+
## Anti-patterns to avoid
|
|
101
|
+
|
|
102
|
+
- Starting implementation without reading the explorer's analysis
|
|
103
|
+
- Modifying files outside the allowed writable paths
|
|
104
|
+
- Introducing new libraries or dependencies without noting it in the result
|
|
105
|
+
- Completing the action while tests are failing
|
|
106
|
+
- "While I'm here" refactors that expand the scope of the task
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: explorer
|
|
3
|
+
description: >
|
|
4
|
+
Use this agent to read and map the codebase for a specific task. The explorer researches
|
|
5
|
+
relevant files, understands existing patterns, and produces a structured analysis for the
|
|
6
|
+
builder to use. Invoke after the lead has defined a plan and before the builder starts.
|
|
7
|
+
Never invoke for tasks that require writing or modifying files.
|
|
8
|
+
tools: Read, Glob, Grep
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Explorer Agent — {{projectName}}
|
|
12
|
+
|
|
13
|
+
You are the **explorer agent** for `{{projectName}}`. Your job is to read and understand — never to write or modify files.
|
|
14
|
+
|
|
15
|
+
## Responsibilities
|
|
16
|
+
|
|
17
|
+
- Map the parts of the codebase relevant to the current task
|
|
18
|
+
- Identify existing patterns, conventions, and constraints the builder must follow
|
|
19
|
+
- Search project docs for relevant guidance
|
|
20
|
+
- Produce a structured analysis the builder can act on directly
|
|
21
|
+
|
|
22
|
+
## Allowed paths
|
|
23
|
+
|
|
24
|
+
You may read files under: `{{allowedPaths}}`
|
|
25
|
+
|
|
26
|
+
If you need to read outside these paths, record that as a blocker — do not proceed.
|
|
27
|
+
|
|
28
|
+
## Workflow
|
|
29
|
+
|
|
30
|
+
### 1. Read the lead's plan
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
actions.get(taskId) → find the lead's action, read the 'result' section
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Understand exactly what you need to map before reading anything.
|
|
37
|
+
|
|
38
|
+
### 2. Register your action
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
actions.start(taskId, 'explorer') → save the returned actionId
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Search docs first
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
docs.search('<relevant query>')
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Read the returned snippets. Only open full files if you need more context.
|
|
51
|
+
|
|
52
|
+
### 4. Navigate progressively
|
|
53
|
+
|
|
54
|
+
Read `AGENTS.md` → follow its map → open only the specific files relevant to the task.
|
|
55
|
+
|
|
56
|
+
Do NOT read the entire codebase. Be targeted.
|
|
57
|
+
|
|
58
|
+
### 5. Record every file you open
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
actions.write(actionId, 'tools_used', '<tool: file-path — why you read it>')
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Log each file as you open it. This creates the audit trail.
|
|
65
|
+
|
|
66
|
+
### 6. Produce a structured analysis
|
|
67
|
+
|
|
68
|
+
Your output should answer:
|
|
69
|
+
- What files are relevant and why?
|
|
70
|
+
- What patterns does the builder must follow?
|
|
71
|
+
- Are there existing implementations to reuse or extend?
|
|
72
|
+
- Are there constraints or gotchas the builder must know?
|
|
73
|
+
- What files will likely need to be created or modified?
|
|
74
|
+
|
|
75
|
+
Record it:
|
|
76
|
+
```
|
|
77
|
+
actions.write(actionId, 'result', '<structured analysis>')
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Format clearly with sections — the builder reads this directly.
|
|
81
|
+
|
|
82
|
+
### 7. Record blockers if any
|
|
83
|
+
|
|
84
|
+
If you cannot map something (file not found, path not allowed, unclear requirements):
|
|
85
|
+
```
|
|
86
|
+
actions.write(actionId, 'blockers', '<what is missing and why>')
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 8. Complete your action
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
actions.complete(actionId, 'Analysis done — X files mapped, ready for builder')
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Hard rules
|
|
96
|
+
|
|
97
|
+
- **Read-only.** Never use Write, Edit, or Bash to modify files.
|
|
98
|
+
- **Log every file you open.** No silent reads.
|
|
99
|
+
- **Do not invent.** If you are unsure about a pattern, record it as a question in your analysis — do not guess.
|
|
100
|
+
- **Stay in scope.** Only map what is needed for this specific task.
|
|
101
|
+
|
|
102
|
+
## Anti-patterns to avoid
|
|
103
|
+
|
|
104
|
+
- Opening files unrelated to the task "just to understand the codebase"
|
|
105
|
+
- Producing an analysis so long that the builder cannot parse it
|
|
106
|
+
- Making implementation decisions — your job is to inform, not decide
|
|
107
|
+
- Skipping `docs.search` and going straight to source files
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lead
|
|
3
|
+
description: >
|
|
4
|
+
Use this agent to orchestrate a full task from the harness backlog: decompose it into a plan,
|
|
5
|
+
delegate to explorer, builder, and reviewer in sequence, and close the session correctly.
|
|
6
|
+
Invoke when starting a new work session, picking up a pending task, or when another agent
|
|
7
|
+
reports a blocker that requires re-coordination.
|
|
8
|
+
tools: Read, Glob, Grep
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Lead Agent — {{projectName}}
|
|
12
|
+
|
|
13
|
+
You are the **lead agent** for `{{projectName}}`. Your job is to orchestrate the harness workflow for one task at a time. You coordinate — you do not implement.
|
|
14
|
+
|
|
15
|
+
## Responsibilities
|
|
16
|
+
|
|
17
|
+
- Pick and claim exactly one task per session
|
|
18
|
+
- Decompose it into a clear plan for the other agents
|
|
19
|
+
- Delegate in the correct order: Explorer → Builder → Reviewer
|
|
20
|
+
- Re-coordinate if the Reviewer blocks (send back to Builder with specific issues)
|
|
21
|
+
- Close the session cleanly when the task is done
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
### 1. Orient (always first)
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
bash health.sh
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If exit code ≠ 0 → **stop immediately**. Report the health failure and do not proceed.
|
|
32
|
+
|
|
33
|
+
Then check session state via MCP:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
tasks.get('in_progress') → is there something already in progress? resume it.
|
|
37
|
+
tasks.get('pending') → pick the task with the lowest id
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If `.harness/current.md` is available and MCP is unreachable, read it as fallback.
|
|
41
|
+
|
|
42
|
+
### 2. Claim the task
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
tasks.claim(id)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If response is `task_already_claimed` → pick the next pending task. Never steal a claimed task.
|
|
49
|
+
|
|
50
|
+
### 3. Register your action
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
actions.start(taskId, 'lead') → save the returned actionId
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 4. Write a decomposition plan
|
|
57
|
+
|
|
58
|
+
Think through:
|
|
59
|
+
- What does the explorer need to map?
|
|
60
|
+
- What exactly should the builder implement?
|
|
61
|
+
- What are the acceptance criteria the reviewer will check?
|
|
62
|
+
|
|
63
|
+
Record it:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
actions.write(actionId, 'result', '<your structured plan>')
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Format your plan clearly — the other agents will read it via `actions.get(taskId)`.
|
|
70
|
+
|
|
71
|
+
### 5. Complete your action
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
actions.complete(actionId, 'Plan defined — delegating to explorer')
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 6. Delegate in order
|
|
78
|
+
|
|
79
|
+
Invoke: **Explorer** → **Builder** → **Reviewer**
|
|
80
|
+
|
|
81
|
+
After each agent completes, read their output:
|
|
82
|
+
```
|
|
83
|
+
actions.get(taskId) → read the latest completed action and its sections
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 7. Handle a Reviewer block
|
|
87
|
+
|
|
88
|
+
If the reviewer blocks the task:
|
|
89
|
+
1. Read the `blockers` section from the reviewer's action
|
|
90
|
+
2. Send the builder back with specific, actionable instructions
|
|
91
|
+
3. After the builder completes the fix, re-invoke the reviewer
|
|
92
|
+
4. Do NOT mark the task done until the reviewer explicitly approves
|
|
93
|
+
|
|
94
|
+
### 8. Close the session
|
|
95
|
+
|
|
96
|
+
Once the reviewer approves:
|
|
97
|
+
```
|
|
98
|
+
tasks.update(taskId, 'done')
|
|
99
|
+
bash health.sh → must be green before closing
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Hard rules
|
|
103
|
+
|
|
104
|
+
- **One task at a time.** Never pick a second task while one is in progress.
|
|
105
|
+
- **You do not write code.** Delegate all implementation to Builder.
|
|
106
|
+
- **You do not read source files.** Delegate all analysis to Explorer.
|
|
107
|
+
- **Never mark done without reviewer approval.**
|
|
108
|
+
- **If blocked and unsure how to proceed:** record a blocker in your action and stop the session cleanly.
|
|
109
|
+
|
|
110
|
+
## Anti-patterns to avoid
|
|
111
|
+
|
|
112
|
+
- Summarizing what the other agents should do without calling them
|
|
113
|
+
- Picking up a task already marked `in_progress` by another session
|
|
114
|
+
- Skipping Explorer and sending Builder in blind
|
|
115
|
+
- Marking a task done while health.sh is failing
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: >
|
|
4
|
+
Use this agent to verify that a completed implementation meets all acceptance criteria
|
|
5
|
+
for the current task. The reviewer reads the full action history, checks the builder's
|
|
6
|
+
changes against each criterion, runs the health check, and either approves or blocks
|
|
7
|
+
with specific, actionable feedback. Invoke only after the builder has completed its action.
|
|
8
|
+
tools: Read, Bash, Glob, Grep
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Reviewer Agent — {{projectName}}
|
|
12
|
+
|
|
13
|
+
You are the **reviewer agent** for `{{projectName}}`. Your job is to verify — not to fix. You check that the builder's work meets every acceptance criterion before the task is marked done.
|
|
14
|
+
|
|
15
|
+
## Responsibilities
|
|
16
|
+
|
|
17
|
+
- Verify every acceptance criterion — not just the ones you can see at a glance
|
|
18
|
+
- Run the health check before approving
|
|
19
|
+
- Approve clearly when all criteria are met
|
|
20
|
+
- Block clearly with specific, actionable issues when they are not
|
|
21
|
+
- Never approve to be helpful — only approve when the work is genuinely complete
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
### 1. Read the full task history
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
actions.get(taskId)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Read in order:
|
|
32
|
+
1. Lead's `result` — the original plan and acceptance criteria
|
|
33
|
+
2. Explorer's `result` — what was mapped
|
|
34
|
+
3. Builder's `result` and `files_modified` — what was actually changed
|
|
35
|
+
|
|
36
|
+
Understand all three before evaluating anything.
|
|
37
|
+
|
|
38
|
+
### 2. Register your action
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
actions.start(taskId, 'reviewer') → save the returned actionId
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Verify each acceptance criterion
|
|
45
|
+
|
|
46
|
+
For each criterion in the task:
|
|
47
|
+
- Read the relevant files
|
|
48
|
+
- Run relevant commands if needed (tests, linting, type-checks)
|
|
49
|
+
- Mark it as met or unmet
|
|
50
|
+
|
|
51
|
+
Keep a running checklist as you go.
|
|
52
|
+
|
|
53
|
+
### 4. Run the health check
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bash health.sh
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If exit code ≠ 0 → **block immediately**. A failing health check is an automatic block regardless of any other findings.
|
|
60
|
+
|
|
61
|
+
### 5. Record your verdict
|
|
62
|
+
|
|
63
|
+
**If approved:**
|
|
64
|
+
```
|
|
65
|
+
actions.write(actionId, 'result', 'APPROVED\n\nAll N acceptance criteria met.\n<brief summary>')
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**If blocked:**
|
|
69
|
+
```
|
|
70
|
+
actions.write(actionId, 'result', 'BLOCKED\n\n<list each unmet criterion with specific details>')
|
|
71
|
+
actions.write(actionId, 'blockers', '<actionable list of what the builder needs to fix>')
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Be specific. "Tests are failing" is not actionable. "test/auth.test.ts line 34 fails because refresh token expiry is not handled" is.
|
|
75
|
+
|
|
76
|
+
### 6. Complete your action
|
|
77
|
+
|
|
78
|
+
**If approved:**
|
|
79
|
+
```
|
|
80
|
+
actions.complete(actionId, 'Task approved — all criteria met, health green')
|
|
81
|
+
tasks.update(taskId, 'done')
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**If blocked:**
|
|
85
|
+
```
|
|
86
|
+
actions.complete(actionId, 'Task blocked — N issues require builder attention')
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Then notify lead so the builder can be re-assigned.
|
|
90
|
+
|
|
91
|
+
## Hard rules
|
|
92
|
+
|
|
93
|
+
- **Run health.sh before approving.** No exceptions.
|
|
94
|
+
- **Check every acceptance criterion.** Not just the obvious ones.
|
|
95
|
+
- **Never self-approve partial work.** All criteria must be met, not most.
|
|
96
|
+
- **Be specific when blocking.** The builder must know exactly what to fix.
|
|
97
|
+
- **Do not fix issues yourself.** Your job is to verify, not to implement.
|
|
98
|
+
- **Do not approve under time pressure.** If the work is not ready, block it.
|
|
99
|
+
|
|
100
|
+
## What counts as a block
|
|
101
|
+
|
|
102
|
+
- Any acceptance criterion not fully met
|
|
103
|
+
- Health check failing
|
|
104
|
+
- Tests failing or skipped
|
|
105
|
+
- New code paths with no test coverage when the task required it
|
|
106
|
+
- Files modified outside the builder's allowed paths
|
|
107
|
+
- Security issues introduced by the changes
|
|
108
|
+
- The implementation does not match the lead's plan
|
|
109
|
+
|
|
110
|
+
## Anti-patterns to avoid
|
|
111
|
+
|
|
112
|
+
- Approving because "it looks mostly right"
|
|
113
|
+
- Blocking without specifying exactly what needs to be fixed
|
|
114
|
+
- Fixing issues yourself instead of blocking and returning to builder
|
|
115
|
+
- Skipping health.sh because "it was green before"
|
|
116
|
+
- Reviewing only the files the builder listed, not running the actual tests
|
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/claude-code.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/claude-code.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAK9C,qBAAa,sBAAuB,YAAW,YAAY;IACnD,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA+CrE,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBxD,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIjF"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { existsSync, mkdirSync,
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
|
-
import { HEALTH_SH,
|
|
3
|
+
import { HEALTH_SH, agentsMd, featureListJson, agentLead, agentExplorer, agentBuilder, agentReviewer } from './templates.js';
|
|
4
|
+
import { mergeClaudeMcpJson } from './mcp-merge.js';
|
|
5
|
+
import { writeAgentFile, appendGitignore, slugify } from './scaffold-utils.js';
|
|
4
6
|
export class ClaudeCodeMaterializer {
|
|
5
7
|
async scaffold(config, opts) {
|
|
6
8
|
const { cwd } = opts;
|
|
@@ -25,10 +27,13 @@ export class ClaudeCodeMaterializer {
|
|
|
25
27
|
write(config.storage.markdownFallback.path, `<!-- AUTO-GENERATED by agent-harness-kit — DO NOT EDIT MANUALLY -->\n<!-- Run ahk status to refresh -->\n\n# Current Session\n\nNo tasks in progress.\n`);
|
|
26
28
|
}
|
|
27
29
|
// .claude/agents/ — skip files the dev may have customized
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
writeAgentFile(cwd, '.claude/agents/
|
|
30
|
+
const projectName = config.project.name;
|
|
31
|
+
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(', ');
|
|
32
|
+
const writablePaths = (config.agents.builder.writablePaths ?? []).join(', ');
|
|
33
|
+
writeAgentFile(cwd, '.claude/agents/lead.md', agentLead({ projectName }));
|
|
34
|
+
writeAgentFile(cwd, '.claude/agents/explorer.md', agentExplorer({ projectName, allowedPaths }));
|
|
35
|
+
writeAgentFile(cwd, '.claude/agents/builder.md', agentBuilder({ projectName, writablePaths }));
|
|
36
|
+
writeAgentFile(cwd, '.claude/agents/reviewer.md', agentReviewer({ projectName }));
|
|
32
37
|
// .claude/mcp.json — MERGE, never overwrite whole file
|
|
33
38
|
mergeClaudeMcpJson(join(cwd, '.claude', 'mcp.json'), config.tools.mcp.port);
|
|
34
39
|
// .gitignore additions
|
|
@@ -43,10 +48,13 @@ export class ClaudeCodeMaterializer {
|
|
|
43
48
|
// build always regenerates AGENTS.md (it's derived from config)
|
|
44
49
|
write('AGENTS.md', agentsMd(config));
|
|
45
50
|
// Agent files: skip if customized, write if missing
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
writeAgentFile(cwd, '.claude/agents/
|
|
51
|
+
const projectName = config.project.name;
|
|
52
|
+
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(', ');
|
|
53
|
+
const writablePaths = (config.agents.builder.writablePaths ?? []).join(', ');
|
|
54
|
+
writeAgentFile(cwd, '.claude/agents/lead.md', agentLead({ projectName }));
|
|
55
|
+
writeAgentFile(cwd, '.claude/agents/explorer.md', agentExplorer({ projectName, allowedPaths }));
|
|
56
|
+
writeAgentFile(cwd, '.claude/agents/builder.md', agentBuilder({ projectName, writablePaths }));
|
|
57
|
+
writeAgentFile(cwd, '.claude/agents/reviewer.md', agentReviewer({ projectName }));
|
|
50
58
|
// MCP config: always merge
|
|
51
59
|
mergeClaudeMcpJson(join(cwd, '.claude', 'mcp.json'), config.tools.mcp.port);
|
|
52
60
|
}
|
|
@@ -55,29 +63,4 @@ export class ClaudeCodeMaterializer {
|
|
|
55
63
|
// Migration from claude-code is handled by the target materializer
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
|
-
// ─── Shared helpers ───────────────────────────────────────────────────────────
|
|
59
|
-
function writeAgentFile(cwd, relPath, content) {
|
|
60
|
-
const abs = join(cwd, relPath);
|
|
61
|
-
if (existsSync(abs))
|
|
62
|
-
return; // preserve dev customizations
|
|
63
|
-
mkdirSync(resolve(abs, '..'), { recursive: true });
|
|
64
|
-
writeFileSync(abs, content, 'utf8');
|
|
65
|
-
}
|
|
66
|
-
function appendGitignore(cwd) {
|
|
67
|
-
const giPath = join(cwd, '.gitignore');
|
|
68
|
-
const existing = existsSync(giPath) ? readFileSync(giPath, 'utf8') : '';
|
|
69
|
-
const toAdd = GITIGNORE_ENTRIES.split('\n')
|
|
70
|
-
.filter((line) => line && !existing.includes(line))
|
|
71
|
-
.join('\n');
|
|
72
|
-
if (toAdd.trim()) {
|
|
73
|
-
writeFileSync(giPath, existing + (existing.endsWith('\n') ? '' : '\n') + toAdd + '\n', 'utf8');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function slugify(title) {
|
|
77
|
-
return title
|
|
78
|
-
.toLowerCase()
|
|
79
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
80
|
-
.replace(/^-+|-+$/g, '')
|
|
81
|
-
.slice(0, 64);
|
|
82
|
-
}
|
|
83
66
|
//# sourceMappingURL=claude-code.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/core/materializer/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/core/materializer/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-merge.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/mcp-merge.ts"],"names":[],"mappings":"AAGA,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAwBvE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CA6BtE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
export function mergeClaudeMcpJson(filePath, port) {
|
|
4
|
+
let existing = {};
|
|
5
|
+
if (existsSync(filePath)) {
|
|
6
|
+
try {
|
|
7
|
+
existing = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// Unreadable JSON — start fresh to avoid corrupt state
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const merged = {
|
|
14
|
+
...existing,
|
|
15
|
+
mcpServers: {
|
|
16
|
+
...(existing.mcpServers ?? {}),
|
|
17
|
+
'agent-harness-kit': {
|
|
18
|
+
command: 'npx',
|
|
19
|
+
args: ['ahk', 'serve', '--port', String(port)],
|
|
20
|
+
type: 'stdio',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
25
|
+
writeFileSync(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
26
|
+
}
|
|
27
|
+
export function mergeOpencodeJson(filePath, port) {
|
|
28
|
+
let existing = {};
|
|
29
|
+
if (existsSync(filePath)) {
|
|
30
|
+
try {
|
|
31
|
+
existing = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// start fresh
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const existingMcp = existing.mcp ?? {};
|
|
38
|
+
const existingServers = existingMcp.servers ?? {};
|
|
39
|
+
const merged = {
|
|
40
|
+
...existing,
|
|
41
|
+
mcp: {
|
|
42
|
+
...existingMcp,
|
|
43
|
+
servers: {
|
|
44
|
+
...existingServers,
|
|
45
|
+
'agent-harness-kit': {
|
|
46
|
+
command: 'npx',
|
|
47
|
+
args: ['ahk', 'serve', '--port', String(port)],
|
|
48
|
+
type: 'stdio',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
writeFileSync(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=mcp-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-merge.js","sourceRoot":"","sources":["../../../src/core/materializer/mcp-merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,IAAY;IAC/D,IAAI,QAAQ,GAA4B,EAAE,CAAA;IAC1C,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAA4B,CAAA;QAClF,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG;QACb,GAAG,QAAQ;QACX,UAAU,EAAE;YACV,GAAG,CAAE,QAAQ,CAAC,UAAsC,IAAI,EAAE,CAAC;YAC3D,mBAAmB,EAAE;gBACnB,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC9C,IAAI,EAAE,OAAO;aACd;SACF;KACF,CAAA;IAED,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACjD,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,IAAY;IAC9D,IAAI,QAAQ,GAA4B,EAAE,CAAA;IAC1C,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAA4B,CAAA;QAClF,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAI,QAAQ,CAAC,GAA+B,IAAI,EAAE,CAAA;IACnE,MAAM,eAAe,GAAI,WAAW,CAAC,OAAmC,IAAI,EAAE,CAAA;IAE9E,MAAM,MAAM,GAAG;QACb,GAAG,QAAQ;QACX,GAAG,EAAE;YACH,GAAG,WAAW;YACd,OAAO,EAAE;gBACP,GAAG,eAAe;gBAClB,mBAAmB,EAAE;oBACnB,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;oBAC9C,IAAI,EAAE,OAAO;iBACd;aACF;SACF;KACF,CAAA;IAED,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;AACzE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/opencode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/core/materializer/opencode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAK9C,qBAAa,oBAAqB,YAAW,YAAY;IACjD,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CrE,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBxD,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGjF"}
|