agent-harness-kit 0.3.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/.claude-plugin/marketplace.json +27 -0
- package/.claude-plugin/plugin.json +25 -0
- package/LICENSE +21 -0
- package/README.md +165 -0
- package/bin/cli.mjs +261 -0
- package/package.json +64 -0
- package/src/core/detect-stack.mjs +181 -0
- package/src/core/doctor.mjs +106 -0
- package/src/core/patch-package-json.mjs +53 -0
- package/src/core/render-templates.mjs +277 -0
- package/src/core/upgrade.mjs +274 -0
- package/src/templates/.claude/agents/api-consistency-reviewer.md +33 -0
- package/src/templates/.claude/agents/architecture-reviewer.md.hbs +41 -0
- package/src/templates/.claude/agents/performance-reviewer.md +35 -0
- package/src/templates/.claude/agents/reliability-reviewer.md +38 -0
- package/src/templates/.claude/agents/security-reviewer.md +39 -0
- package/src/templates/.claude/hooks/hooks.json.hbs +39 -0
- package/src/templates/.claude/settings.json.hbs +25 -0
- package/src/templates/.claude/skills/add-adr/SKILL.md +60 -0
- package/src/templates/.claude/skills/add-feature/SKILL.md.hbs +50 -0
- package/src/templates/.claude/skills/debug-flow/SKILL.md.hbs +38 -0
- package/src/templates/.claude/skills/doc-drift-scan/SKILL.md +43 -0
- package/src/templates/.claude/skills/eval-runner/SKILL.md +55 -0
- package/src/templates/.claude/skills/garbage-collection/SKILL.md.hbs +49 -0
- package/src/templates/.claude/skills/inspect-app/SKILL.md +57 -0
- package/src/templates/.claude/skills/inspect-module/SKILL.md.hbs +53 -0
- package/src/templates/.claude/skills/propose-harness-improvement/SKILL.md +43 -0
- package/src/templates/.claude/skills/structural-test-author/SKILL.md.hbs +46 -0
- package/src/templates/.claude/skills/write-skill/SKILL.md +39 -0
- package/src/templates/CLAUDE.md.hbs +70 -0
- package/src/templates/_adapter-python/.importlinter +14 -0
- package/src/templates/_adapter-python/harness/__init__.py +0 -0
- package/src/templates/_adapter-python/harness/eval_runner.py +281 -0
- package/src/templates/_adapter-python/harness/structural_test.py +195 -0
- package/src/templates/_adapter-typescript/.dependency-cruiser.cjs +27 -0
- package/src/templates/_adapter-typescript/eslint.config.mjs +38 -0
- package/src/templates/_adapter-typescript/harness/eval-runner.mjs +322 -0
- package/src/templates/_adapter-typescript/harness/structural-test.mjs +125 -0
- package/src/templates/_ci/.github/workflows/eval-nightly.yml +59 -0
- package/src/templates/_ci/.github/workflows/harness.yml +55 -0
- package/src/templates/docs/adr/0001-use-agent-harness-kit.md.hbs +56 -0
- package/src/templates/docs/agent-failures.md +25 -0
- package/src/templates/docs/architecture.md.hbs +47 -0
- package/src/templates/docs/core-beliefs.md.hbs +41 -0
- package/src/templates/docs/golden-principles.md.hbs +80 -0
- package/src/templates/docs/tech-debt-tracker.md +30 -0
- package/src/templates/feature_list.json.hbs +29 -0
- package/src/templates/harness.config.json.hbs +40 -0
- package/src/templates/scripts/dev-up.sh.hbs +51 -0
- package/src/templates/scripts/harness-report.mjs +189 -0
- package/src/templates/scripts/install-git-hooks.sh +18 -0
- package/src/templates/scripts/pre-push.sh +21 -0
- package/src/templates/scripts/precompletion-checklist.sh.hbs +99 -0
- package/src/templates/scripts/structural-test-on-edit.sh.hbs +53 -0
- package/src/templates/scripts/telemetry-on-skill.sh +26 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
|
|
3
|
+
"name": "agent-harness-kit-marketplace",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "Tuan Le"
|
|
6
|
+
},
|
|
7
|
+
"description": "Solo-dev harness engineering kit for Claude Code.",
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "agent-harness-kit",
|
|
11
|
+
"source": {
|
|
12
|
+
"source": "github",
|
|
13
|
+
"repo": "tuanle96/agent-harness-kit",
|
|
14
|
+
"ref": "v0.3.0"
|
|
15
|
+
},
|
|
16
|
+
"version": "0.3.0",
|
|
17
|
+
"description": "Solo-dev harness engineering kit — layered architecture, GC ritual, structural tests, review subagents.",
|
|
18
|
+
"category": "development",
|
|
19
|
+
"keywords": [
|
|
20
|
+
"harness",
|
|
21
|
+
"architecture",
|
|
22
|
+
"review",
|
|
23
|
+
"solo-dev"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-harness-kit",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Solo-dev harness engineering kit — layered architecture, garbage-collection ritual, structural tests, review subagents. Optimized for Claude Code 2.1+.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Tuan Le"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/tuanle96/agent-harness-kit",
|
|
9
|
+
"repository": "https://github.com/tuanle96/agent-harness-kit",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"harness-engineering",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"structural-tests",
|
|
15
|
+
"layered-architecture",
|
|
16
|
+
"solo-dev",
|
|
17
|
+
"code-review",
|
|
18
|
+
"agents",
|
|
19
|
+
"skills"
|
|
20
|
+
],
|
|
21
|
+
"skills": "./src/templates/.claude/skills/",
|
|
22
|
+
"agents": "./src/templates/.claude/agents/",
|
|
23
|
+
"hooks": "./src/templates/.claude/hooks/hooks.json",
|
|
24
|
+
"commands": "./src/templates/.claude/skills/"
|
|
25
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tuan Le
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# agent-harness-kit
|
|
2
|
+
|
|
3
|
+
Solo-dev harness engineering kit for Claude Code. One command, ~30 minutes,
|
|
4
|
+
and your hobby project gets the patterns OpenAI used to ship 1M lines of
|
|
5
|
+
agent-generated code: layered architecture, structural tests, garbage
|
|
6
|
+
collection, review subagents, JSON feature tracking, and pre-completion
|
|
7
|
+
checklists — without the Stripe/OpenAI overhead.
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
- Claude Code 2.1+ merged slash commands and Skills into one format.
|
|
12
|
+
- Plugins are now a stable distribution channel.
|
|
13
|
+
- LangChain proved harness changes alone can take a coding agent from Top 30
|
|
14
|
+
to Top 5 on Terminal-Bench 2.0.
|
|
15
|
+
- Mitchell Hashimoto's "engineer the harness" + Anthropic's two-fold
|
|
16
|
+
initializer/coding-agent pattern + OpenAI's golden-principles GC ritual
|
|
17
|
+
scale down nicely to one developer.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
Option A: scaffold into an existing repo
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx agent-harness-kit init
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Option B: install as a Claude Code plugin
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
/plugin marketplace add tuanle96/agent-harness-kit
|
|
31
|
+
/plugin install agent-harness-kit@agent-harness-kit-marketplace
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What ships
|
|
35
|
+
|
|
36
|
+
- 10 skills (`inspect-module`, `add-feature`, `garbage-collection`,
|
|
37
|
+
`propose-harness-improvement`, `write-skill`, `debug-flow`, `eval-runner`,
|
|
38
|
+
`add-adr`, `doc-drift-scan`, `structural-test-author`)
|
|
39
|
+
- 5 read-only review subagents (`architecture-reviewer`, `security-reviewer`,
|
|
40
|
+
`reliability-reviewer`, `performance-reviewer`, `api-consistency-reviewer`)
|
|
41
|
+
- 1 PostToolUse hook (structural-test on every edit) + 1 Stop hook
|
|
42
|
+
(pre-completion checklist with `stop_hook_active` loop guard)
|
|
43
|
+
- TypeScript adapter (ts-morph + eslint-plugin-boundaries +
|
|
44
|
+
dependency-cruiser)
|
|
45
|
+
- Python adapter (libcst + import-linter)
|
|
46
|
+
- Eval harness (outcome / process / style / efficiency dimensions)
|
|
47
|
+
|
|
48
|
+
## Slash commands generated
|
|
49
|
+
|
|
50
|
+
| Command | Purpose |
|
|
51
|
+
| -------------------------------- | -------------------------------------------------------- |
|
|
52
|
+
| `/inspect-module <path>` | Map a module before editing |
|
|
53
|
+
| `/add-feature <description>` | Implement one item from `feature_list.json` |
|
|
54
|
+
| `/garbage-collection` | Friday cleanup (top-3 fixes only at solo scale) |
|
|
55
|
+
| `/structural-test-author` | Codify a new architectural rule mechanically |
|
|
56
|
+
| `/propose-harness-improvement` | Convert an agent failure into a permanent prevention |
|
|
57
|
+
| `/eval-runner` | Regression-test the harness itself |
|
|
58
|
+
| `/write-skill` | Create a new SKILL.md with valid frontmatter |
|
|
59
|
+
| `/add-adr` | Add a numbered Architecture Decision Record |
|
|
60
|
+
| `/doc-drift-scan` | Find stale path/command references in `docs/` |
|
|
61
|
+
| `/debug-flow` | Run the failing flow before fixing it |
|
|
62
|
+
|
|
63
|
+
## Philosophy (4 axioms)
|
|
64
|
+
|
|
65
|
+
1. **CLAUDE.md is a table of contents, not an encyclopedia** (HumanLayer
|
|
66
|
+
measured ~150–200 instructions as the reliable cap; OpenAI's own root file
|
|
67
|
+
is ~100 lines). The kit's CLAUDE.md is 50–80 lines.
|
|
68
|
+
2. **Every agent failure becomes a permanent harness change** (Hashimoto's
|
|
69
|
+
discipline). The `/propose-harness-improvement` skill enforces this.
|
|
70
|
+
3. **Computational sensors before LLM sensors** (Fowler/Böckeler). The TS and
|
|
71
|
+
Python adapters ship one deterministic structural test per language; LLM
|
|
72
|
+
subagents are reserved for semantic judgment.
|
|
73
|
+
4. **Garbage collection over Friday cleanup, scaled to solo** (OpenAI's
|
|
74
|
+
ritual, shrunk to top-3 fixes per week).
|
|
75
|
+
|
|
76
|
+
## Directory the kit drops into your repo
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
your-repo/
|
|
80
|
+
├── CLAUDE.md # 50–80 line table of contents
|
|
81
|
+
├── AGENTS.md # symlink → CLAUDE.md
|
|
82
|
+
├── docs/
|
|
83
|
+
│ ├── architecture.md
|
|
84
|
+
│ ├── core-beliefs.md
|
|
85
|
+
│ ├── golden-principles.md
|
|
86
|
+
│ ├── tech-debt-tracker.md
|
|
87
|
+
│ └── adr/
|
|
88
|
+
│ └── 0001-use-agent-harness-kit.md
|
|
89
|
+
├── feature_list.json # JSON, not Markdown — Anthropic pattern
|
|
90
|
+
├── harness.config.json
|
|
91
|
+
├── .claude/
|
|
92
|
+
│ ├── settings.json
|
|
93
|
+
│ ├── skills/ # 10 skills as SKILL.md files
|
|
94
|
+
│ ├── agents/ # 5 reviewer personas
|
|
95
|
+
│ └── hooks/hooks.json
|
|
96
|
+
├── .harness/
|
|
97
|
+
│ ├── installed.json # kit lockfile (sha-tracked)
|
|
98
|
+
│ ├── PROGRESS.md # session log
|
|
99
|
+
│ └── structural-baseline.json # existing-violation baseline
|
|
100
|
+
└── scripts/
|
|
101
|
+
├── structural-test-on-edit.sh # PostToolUse hook target
|
|
102
|
+
├── precompletion-checklist.sh # Stop hook target
|
|
103
|
+
├── dev-up.sh
|
|
104
|
+
├── pre-push.sh
|
|
105
|
+
└── install-git-hooks.sh
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Configuration (`harness.config.json`)
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"version": "0.1.0",
|
|
113
|
+
"language": "typescript",
|
|
114
|
+
"framework": "nextjs",
|
|
115
|
+
"preset": "nextjs",
|
|
116
|
+
"domains": [
|
|
117
|
+
{
|
|
118
|
+
"name": "default",
|
|
119
|
+
"root": "src",
|
|
120
|
+
"layers": ["types", "config", "repo", "service", "runtime", "ui"]
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"providers": ["auth", "telemetry", "feature-flags"],
|
|
124
|
+
"models": {
|
|
125
|
+
"main": "claude-sonnet-4-6",
|
|
126
|
+
"reviewers": "claude-sonnet-4-6",
|
|
127
|
+
"explore": "claude-haiku-4-5"
|
|
128
|
+
},
|
|
129
|
+
"budgets": { "perRunUsd": 2.0, "perDayUsd": 10.0 }
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## CLI commands
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
agent-harness-kit init # scaffold a repo (interactive)
|
|
137
|
+
agent-harness-kit init --yes # accept all detected defaults
|
|
138
|
+
agent-harness-kit upgrade # non-destructive upgrade, preserves user edits
|
|
139
|
+
agent-harness-kit doctor # diagnose installed kit + Claude Code env
|
|
140
|
+
agent-harness-kit --version
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Token / cost expectations
|
|
144
|
+
|
|
145
|
+
A typical day with the default model split (Sonnet 4.6 main + Haiku 4.5
|
|
146
|
+
explore + Sonnet 4.6 reviewers) stays under ~$2 of API traffic for a single
|
|
147
|
+
developer. The `eval-runner` skill enforces a per-run budget set in
|
|
148
|
+
`harness.config.json`.
|
|
149
|
+
|
|
150
|
+
## Support matrix
|
|
151
|
+
|
|
152
|
+
| Stack | Adapter | Preset | Dev command | Status |
|
|
153
|
+
| ------------------------------ | ------------ | ----------- | -------------------------------------- | ------ |
|
|
154
|
+
| Next.js 14 + TypeScript | typescript | `nextjs` | `npm run dev` | v0.1 |
|
|
155
|
+
| Express | typescript | `node-api` | `node ./src/server.js` | v0.1 |
|
|
156
|
+
| Fastify | typescript | `node-api` | `node ./src/server.js` | v0.1 |
|
|
157
|
+
| NestJS | typescript | `node-api` | `npm run start:dev` | v0.1 |
|
|
158
|
+
| FastAPI | python | `fastapi` | `uvicorn app.main:app --reload` | v0.1 |
|
|
159
|
+
| Django | python | `django` | `python manage.py runserver` | v0.1 |
|
|
160
|
+
| Flask | python | `flask` | `flask --app app run --debug` | v0.1 |
|
|
161
|
+
| Go / Rust | core only | none | (manual) | v0.4 |
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
MIT.
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// agent-harness-kit CLI — solo-dev harness scaffolder for Claude Code.
|
|
3
|
+
// Implements: init, upgrade, doctor.
|
|
4
|
+
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import { input, select, confirm } from "@inquirer/prompts";
|
|
7
|
+
import pc from "picocolors";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { dirname, resolve } from "node:path";
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
|
|
12
|
+
import { detectStack } from "../src/core/detect-stack.mjs";
|
|
13
|
+
import { renderAll } from "../src/core/render-templates.mjs";
|
|
14
|
+
import { upgrade } from "../src/core/upgrade.mjs";
|
|
15
|
+
import { doctor } from "../src/core/doctor.mjs";
|
|
16
|
+
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const pkgJsonPath = resolve(__dirname, "..", "package.json");
|
|
19
|
+
const pkg = JSON.parse(await readFile(pkgJsonPath, "utf8"));
|
|
20
|
+
|
|
21
|
+
const program = new Command();
|
|
22
|
+
program
|
|
23
|
+
.name("agent-harness-kit")
|
|
24
|
+
.description(
|
|
25
|
+
"Solo-dev harness engineering kit for Claude Code (skills + subagents + hooks + structural tests).",
|
|
26
|
+
)
|
|
27
|
+
.version(pkg.version);
|
|
28
|
+
|
|
29
|
+
program
|
|
30
|
+
.command("init")
|
|
31
|
+
.description("Scaffold the harness into the current repository")
|
|
32
|
+
.option("-y, --yes", "accept all detected defaults", false)
|
|
33
|
+
.option("--cwd <path>", "target directory (defaults to process.cwd())")
|
|
34
|
+
.option("--no-hooks", "skip hook installation")
|
|
35
|
+
.option("--no-ci", "skip GitHub Actions workflow")
|
|
36
|
+
.option(
|
|
37
|
+
"--allow-polyglot-root",
|
|
38
|
+
"force init at the root of a polyglot monorepo (not recommended — kit enforces one layered architecture per init)",
|
|
39
|
+
false,
|
|
40
|
+
)
|
|
41
|
+
.option(
|
|
42
|
+
"--allow-unsupported",
|
|
43
|
+
"force init for languages without a structural-test adapter yet (go, rust, swift, kotlin)",
|
|
44
|
+
false,
|
|
45
|
+
)
|
|
46
|
+
.action(async (opts) => {
|
|
47
|
+
const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();
|
|
48
|
+
console.log(pc.bold(pc.cyan(`\nagent-harness-kit v${pkg.version}\n`)));
|
|
49
|
+
console.log(`Target: ${pc.dim(cwd)}\n`);
|
|
50
|
+
|
|
51
|
+
const stack = await detectStack(cwd);
|
|
52
|
+
console.log(
|
|
53
|
+
`Detected: ${pc.green(stack.language)} / ${pc.green(stack.framework ?? "generic")} ` +
|
|
54
|
+
`(package manager: ${pc.green(stack.packageManager)}` +
|
|
55
|
+
(stack.monorepo ? `, ${pc.yellow("monorepo")}` : "") +
|
|
56
|
+
")\n",
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
if (stack.polyglotSignals.length >= 2 && stack.appCandidates.length > 0) {
|
|
60
|
+
console.log(pc.yellow("⚠ Polyglot monorepo detected."));
|
|
61
|
+
console.log(
|
|
62
|
+
` Languages found in subdirectories: ${pc.yellow(stack.polyglotSignals.join(", "))}.`,
|
|
63
|
+
);
|
|
64
|
+
console.log(
|
|
65
|
+
` The kit's structural test enforces ${pc.yellow("one")} layered architecture per repo.`,
|
|
66
|
+
);
|
|
67
|
+
console.log(
|
|
68
|
+
` ${pc.bold("Recommended:")} run \`agent-harness-kit init\` once per app instead of at the root:`,
|
|
69
|
+
);
|
|
70
|
+
for (const app of stack.appCandidates.slice(0, 5)) {
|
|
71
|
+
console.log(` ${pc.dim("→")} cd ${app.path} && agent-harness-kit init ${pc.dim("# " + app.languages.join("+"))}`);
|
|
72
|
+
}
|
|
73
|
+
if (stack.appCandidates.length > 5) {
|
|
74
|
+
console.log(pc.dim(` ...and ${stack.appCandidates.length - 5} more.`));
|
|
75
|
+
}
|
|
76
|
+
console.log("");
|
|
77
|
+
|
|
78
|
+
if (!opts.allowPolyglotRoot) {
|
|
79
|
+
if (opts.yes) {
|
|
80
|
+
console.error(
|
|
81
|
+
pc.red(
|
|
82
|
+
`Aborting: refusing to init at the root of a polyglot monorepo in --yes mode.`,
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
console.error(
|
|
86
|
+
pc.dim(
|
|
87
|
+
` Run init in each app directory above, or pass --allow-polyglot-root to override.`,
|
|
88
|
+
),
|
|
89
|
+
);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const ok = await confirm({
|
|
93
|
+
message: "Continue init at root anyway?",
|
|
94
|
+
default: false,
|
|
95
|
+
});
|
|
96
|
+
if (!ok) {
|
|
97
|
+
console.log(pc.yellow("Aborted. Run init inside one of the listed app directories."));
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Unsupported-language guard. Kit ships TS + Python adapters today;
|
|
104
|
+
// initing at the root of a Go/Rust/Swift/Kotlin project produces a
|
|
105
|
+
// half-broken harness (structural test missing, ts-morph engine pinned).
|
|
106
|
+
// Skills + reviewers still work, but the user should opt in explicitly.
|
|
107
|
+
const UNSUPPORTED = new Set(["go", "rust", "swift", "kotlin"]);
|
|
108
|
+
if (UNSUPPORTED.has(stack.language) && !opts.allowUnsupported) {
|
|
109
|
+
console.log(
|
|
110
|
+
pc.yellow(
|
|
111
|
+
`⚠ No structural-test adapter for ${pc.bold(stack.language)} yet (deferred to v0.4).`,
|
|
112
|
+
),
|
|
113
|
+
);
|
|
114
|
+
console.log(
|
|
115
|
+
pc.dim(
|
|
116
|
+
` You'll get skills + reviewers + hooks, but \`harness:check\` will be a no-op.`,
|
|
117
|
+
),
|
|
118
|
+
);
|
|
119
|
+
if (opts.yes) {
|
|
120
|
+
console.error(
|
|
121
|
+
pc.red(`Aborting: pass --allow-unsupported to init anyway, or wait for v0.4.`),
|
|
122
|
+
);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
const ok = await confirm({
|
|
126
|
+
message: `Continue with the generic harness (skills + reviewers only)?`,
|
|
127
|
+
default: false,
|
|
128
|
+
});
|
|
129
|
+
if (!ok) {
|
|
130
|
+
console.log(pc.yellow("Aborted."));
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let projectName = stack.suggestedName;
|
|
136
|
+
let preset = stack.suggestedPreset;
|
|
137
|
+
let layers = ["types", "config", "repo", "service", "runtime", "ui"];
|
|
138
|
+
let installHooks = opts.hooks !== false;
|
|
139
|
+
let installCi = opts.ci !== false;
|
|
140
|
+
|
|
141
|
+
if (!opts.yes) {
|
|
142
|
+
projectName = await input({
|
|
143
|
+
message: "Project name",
|
|
144
|
+
default: stack.suggestedName,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const presetChoices = stack.availablePresets.map((p) => ({
|
|
148
|
+
name: p,
|
|
149
|
+
value: p,
|
|
150
|
+
}));
|
|
151
|
+
presetChoices.push({ name: "(none — generic)", value: "generic" });
|
|
152
|
+
preset = await select({
|
|
153
|
+
message: "Preset",
|
|
154
|
+
default: stack.suggestedPreset,
|
|
155
|
+
choices: presetChoices,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const layersOk = await confirm({
|
|
159
|
+
message: `Use default layer order [${layers.join(" → ")}]?`,
|
|
160
|
+
default: true,
|
|
161
|
+
});
|
|
162
|
+
if (!layersOk) {
|
|
163
|
+
const custom = await input({
|
|
164
|
+
message: "Custom layer order (comma separated, low → high)",
|
|
165
|
+
default: layers.join(","),
|
|
166
|
+
});
|
|
167
|
+
layers = custom.split(",").map((s) => s.trim()).filter(Boolean);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
installHooks = await confirm({
|
|
171
|
+
message: "Install Claude Code hooks (PostToolUse + Stop)?",
|
|
172
|
+
default: true,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
installCi = await confirm({
|
|
176
|
+
message: "Set up GitHub Actions nightly eval workflow?",
|
|
177
|
+
default: false,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const result = await renderAll({
|
|
182
|
+
cwd,
|
|
183
|
+
projectName,
|
|
184
|
+
preset,
|
|
185
|
+
layers,
|
|
186
|
+
stack,
|
|
187
|
+
installHooks,
|
|
188
|
+
installCi,
|
|
189
|
+
kitVersion: pkg.version,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
console.log("");
|
|
193
|
+
for (const f of result.written) {
|
|
194
|
+
console.log(` ${pc.green("✓")} ${pc.dim("wrote")} ${f}`);
|
|
195
|
+
}
|
|
196
|
+
if (result.skipped.length > 0) {
|
|
197
|
+
console.log("");
|
|
198
|
+
for (const f of result.skipped) {
|
|
199
|
+
console.log(` ${pc.yellow("~")} ${pc.dim("skipped (existed)")} ${f}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
console.log(pc.bold("\nNext steps:"));
|
|
204
|
+
const nextSteps = renderNextSteps(stack);
|
|
205
|
+
nextSteps.forEach((s, i) => console.log(` ${i + 1}. ${s}`));
|
|
206
|
+
console.log("");
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
program
|
|
210
|
+
.command("upgrade")
|
|
211
|
+
.description("Upgrade installed kit version, preserving user edits")
|
|
212
|
+
.option("--cwd <path>", "target directory (defaults to process.cwd())")
|
|
213
|
+
.option("-y, --yes", "apply without confirmation prompts", false)
|
|
214
|
+
.action(async (opts) => {
|
|
215
|
+
const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();
|
|
216
|
+
await upgrade({ cwd, kitVersion: pkg.version, yes: opts.yes });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
program
|
|
220
|
+
.command("doctor")
|
|
221
|
+
.description("Diagnose installed kit + Claude Code environment")
|
|
222
|
+
.option("--cwd <path>", "target directory (defaults to process.cwd())")
|
|
223
|
+
.action(async (opts) => {
|
|
224
|
+
const cwd = opts.cwd ? resolve(opts.cwd) : process.cwd();
|
|
225
|
+
await doctor({ cwd, kitVersion: pkg.version });
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
function renderNextSteps(stack) {
|
|
229
|
+
const out = [];
|
|
230
|
+
if (stack.language === "typescript") {
|
|
231
|
+
out.push(`Run ${pc.cyan("npm install")} to install dev dependencies.`);
|
|
232
|
+
} else if (stack.language === "python") {
|
|
233
|
+
out.push(
|
|
234
|
+
`Run ${pc.cyan("pip install -e '.[dev]'")} (or your tool of choice) to pull dev deps.`,
|
|
235
|
+
);
|
|
236
|
+
} else {
|
|
237
|
+
out.push(
|
|
238
|
+
`Install your language's deps manually — kit shipped without an adapter for ${pc.yellow(stack.language)}.`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
out.push(
|
|
242
|
+
`Run ${pc.cyan("bash scripts/install-git-hooks.sh")} to enable pre-push checks.`,
|
|
243
|
+
);
|
|
244
|
+
out.push(
|
|
245
|
+
`Open Claude Code in this repo and run ${pc.cyan("/inspect-module .")} to bootstrap context.`,
|
|
246
|
+
);
|
|
247
|
+
out.push(
|
|
248
|
+
`Try ${pc.cyan("/add-feature \"a small first feature\"")} to see the workflow end-to-end.`,
|
|
249
|
+
);
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
254
|
+
if (err && err.name === "ExitPromptError") {
|
|
255
|
+
console.error(pc.yellow("\naborted by user."));
|
|
256
|
+
process.exit(130);
|
|
257
|
+
}
|
|
258
|
+
console.error(pc.red("\nagent-harness-kit failed:"));
|
|
259
|
+
console.error(err && err.stack ? err.stack : err);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-harness-kit",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Solo-dev harness engineering kit for Claude Code. Layered architecture, structural tests, garbage-collection ritual, review subagents — without the enterprise overhead.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agent-harness-kit": "./bin/cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"src",
|
|
12
|
+
"schema.json",
|
|
13
|
+
".claude-plugin",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"claude-code",
|
|
22
|
+
"harness-engineering",
|
|
23
|
+
"layered-architecture",
|
|
24
|
+
"structural-tests",
|
|
25
|
+
"solo-dev",
|
|
26
|
+
"code-review",
|
|
27
|
+
"agents",
|
|
28
|
+
"skills"
|
|
29
|
+
],
|
|
30
|
+
"author": "Tuan Le",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"homepage": "https://github.com/tuanle96/agent-harness-kit",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/tuanle96/agent-harness-kit.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/tuanle96/agent-harness-kit/issues"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"test": "node --test tests/*.test.mjs",
|
|
42
|
+
"lint": "echo 'no-op (kit is plain ESM JS)'",
|
|
43
|
+
"selftest": "node bin/cli.mjs --version"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@inquirer/prompts": "^7.0.0",
|
|
47
|
+
"commander": "^12.1.0",
|
|
48
|
+
"handlebars": "^4.7.8",
|
|
49
|
+
"picocolors": "^1.1.1"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"ts-morph": ">=24",
|
|
53
|
+
"eslint-plugin-boundaries": ">=5",
|
|
54
|
+
"dependency-cruiser": ">=16"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"ts-morph": { "optional": true },
|
|
58
|
+
"eslint-plugin-boundaries": { "optional": true },
|
|
59
|
+
"dependency-cruiser": { "optional": true }
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
}
|
|
64
|
+
}
|