dev-harness-cli 1.0.5 → 1.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 +158 -230
- package/cli/commands/checkpoint.mjs +2 -2
- package/cli/commands/config.mjs +12 -12
- package/cli/commands/contract.mjs +10 -10
- package/cli/commands/detect-tool.mjs +5 -4
- package/cli/commands/init.mjs +10 -10
- package/cli/commands/learn.mjs +3 -3
- package/cli/commands/pause.mjs +1 -1
- package/cli/commands/phase.mjs +6 -6
- package/cli/commands/resume.mjs +3 -3
- package/cli/commands/rollback.mjs +9 -9
- package/cli/commands/set-mode.mjs +5 -5
- package/cli/commands/status.mjs +9 -9
- package/cli/commands/validate.mjs +7 -7
- package/cli/commands/worktree.mjs +6 -6
- package/cli/{harness-dev.mjs → dev-harness.mjs} +2 -2
- package/cli/lib/config-registry.mjs +2 -2
- package/cli/lib/contract.mjs +3 -3
- package/cli/lib/gates.mjs +11 -9
- package/cli/lib/help.mjs +28 -28
- package/cli/lib/paths.mjs +87 -8
- package/cli/lib/ralph-inner.mjs +2 -2
- package/cli/lib/ralph-outer.mjs +3 -3
- package/cli/lib/ralph-output.mjs +1 -1
- package/cli/lib/scaffold.mjs +18 -18
- package/cli/lib/state.mjs +1 -1
- package/cli/lib/templates.mjs +38 -1
- package/package.json +8 -4
- package/schema/feature-list.schema.json +63 -0
- package/templates/AGENTS.md +19 -15
- package/templates/ci/github-actions.yml +2 -2
- package/templates/ci/gitlab-ci.yml +2 -2
- package/templates/docs/agents/generator.md +1 -1
- package/templates/docs/agents/planner.md +1 -1
- package/templates/docs/agents/simplifier.md +1 -1
- package/templates/docs/phases/build.md +3 -3
- package/templates/docs/phases/define.md +3 -3
- package/templates/docs/phases/plan.md +3 -3
- package/templates/docs/phases/review.md +2 -2
- package/templates/docs/phases/ship.md +3 -3
- package/templates/docs/phases/simplify.md +3 -3
- package/templates/docs/phases/verify.md +2 -2
- package/templates/harness-config.json +42 -0
- package/templates/init.ps1 +1 -1
- package/templates/progress.md +18 -0
package/README.md
CHANGED
|
@@ -1,298 +1,226 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# Dev Harness
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
### Agent-agnostic development pipeline CLI
|
|
6
|
+
|
|
7
|
+
Scaffold · Phase orchestration · Gate validation · Iteration
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/dev-harness-cli)
|
|
10
|
+
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](#)
|
|
13
|
+
|
|
14
|
+
**Works with any coding agent:** Claude Code · Codex · Cursor · Aider · Continue · OpenCode · Windsurf · Gemini · GitHub Copilot · Cline · Roo · Kilo Code · Amazon Q · and more
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## What is this?
|
|
21
|
+
|
|
22
|
+
**Dev Harness** is a CLI tool that brings structure to AI-assisted software development. Instead of ad-hoc prompting, it enforces a **phase pipeline** with **gate validation** — ensuring specs are written before code, code is reviewed before shipping, and nothing gets skipped.
|
|
4
23
|
|
|
5
|
-
```bash
|
|
6
|
-
npx dev-harness-cli init --stack python --target my-project
|
|
7
|
-
cd my-project
|
|
8
|
-
npx dev-harness-cli phase define
|
|
9
24
|
```
|
|
25
|
+
define → plan → build → verify → [simplify] → review → ship
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Each phase has **deterministic gates** (checks) that must pass before advancing. The agent does the work; harness validates the result.
|
|
10
29
|
|
|
11
30
|
## Install
|
|
12
31
|
|
|
13
32
|
```bash
|
|
14
33
|
# Quick start (no install)
|
|
15
|
-
npx dev-harness-cli --
|
|
34
|
+
npx dev-harness-cli init --stack python --target my-project
|
|
16
35
|
|
|
17
36
|
# Global install
|
|
18
37
|
npm install -g dev-harness-cli
|
|
19
|
-
harness
|
|
20
|
-
|
|
21
|
-
# Or clone and install
|
|
22
|
-
git clone https://github.com/bakr-bagaber/dev-harness.git
|
|
23
|
-
cd dev-harness && npm install -g .
|
|
38
|
+
dev-harness --help
|
|
24
39
|
```
|
|
25
40
|
|
|
26
|
-
Requires **Node.js >= 18**.
|
|
41
|
+
Requires **Node.js >= 18**. Zero runtime dependencies.
|
|
27
42
|
|
|
28
43
|
## Quick Start
|
|
29
44
|
|
|
30
45
|
```bash
|
|
31
|
-
# Scaffold a new project
|
|
32
|
-
harness
|
|
33
|
-
|
|
34
|
-
# Check status
|
|
46
|
+
# 1. Scaffold a new project
|
|
47
|
+
dev-harness init --stack node --target my-app
|
|
35
48
|
cd my-app
|
|
36
|
-
harness-dev status
|
|
37
49
|
|
|
38
|
-
#
|
|
39
|
-
harness
|
|
50
|
+
# 2. Check status
|
|
51
|
+
dev-harness status
|
|
52
|
+
|
|
53
|
+
# 3. Run the DEFINE phase (agent writes specs)
|
|
54
|
+
dev-harness phase define
|
|
55
|
+
|
|
56
|
+
# 4. Validate (run gate checks)
|
|
57
|
+
dev-harness validate
|
|
58
|
+
|
|
59
|
+
# 5. Continue through pipeline
|
|
60
|
+
dev-harness phase plan
|
|
61
|
+
dev-harness phase build
|
|
62
|
+
dev-harness phase verify
|
|
63
|
+
dev-harness phase review
|
|
64
|
+
dev-harness phase ship
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Project Structure
|
|
68
|
+
|
|
69
|
+
When you run `dev-harness init`, all harness-managed files go into a `harness/` subfolder — keeping your project root clean:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
my-project/
|
|
73
|
+
├── AGENTS.md # Agent instructions (root — tools expect it here)
|
|
74
|
+
├── .gitignore # Git ignore rules
|
|
75
|
+
├── package.json # Your project's package file
|
|
76
|
+
├── src/ # Your source code
|
|
77
|
+
├── tests/ # Your tests
|
|
78
|
+
└── harness/ # All harness-managed files
|
|
79
|
+
├── config.json # Harness configuration + state
|
|
80
|
+
├── progress.md # Session state + lessons learned
|
|
81
|
+
├── sprint-contract.md # Pre-build agreement
|
|
82
|
+
├── evaluator-rubric.md # Quality scorecard
|
|
83
|
+
├── session-handoff.md # Context for session transitions
|
|
84
|
+
├── clean-state-checklist.md
|
|
85
|
+
├── features/
|
|
86
|
+
│ ├── feature-list.json # Feature tracking
|
|
87
|
+
│ └── feature-list.schema.json
|
|
88
|
+
├── docs/
|
|
89
|
+
│ ├── ARCHITECTURE.md # Architecture decisions
|
|
90
|
+
│ ├── CONSTRAINTS.md # Technical constraints
|
|
91
|
+
│ ├── DECISIONS.md # Decision log
|
|
92
|
+
│ ├── api-patterns.md # API conventions
|
|
93
|
+
│ ├── agents/ # Agent role guides
|
|
94
|
+
│ │ ├── planner.md
|
|
95
|
+
│ │ ├── generator.md
|
|
96
|
+
│ │ ├── evaluator.md
|
|
97
|
+
│ │ └── simplifier.md
|
|
98
|
+
│ └── phases/ # Phase instructions
|
|
99
|
+
│ ├── define.md
|
|
100
|
+
│ ├── plan.md
|
|
101
|
+
│ ├── build.md
|
|
102
|
+
│ ├── verify.md
|
|
103
|
+
│ ├── simplify.md
|
|
104
|
+
│ ├── review.md
|
|
105
|
+
│ └── ship.md
|
|
106
|
+
├── ci/
|
|
107
|
+
│ ├── github-actions.yml
|
|
108
|
+
│ └── gitlab-ci.yml
|
|
109
|
+
└── scripts/
|
|
110
|
+
├── init.sh
|
|
111
|
+
└── init.ps1
|
|
40
112
|
```
|
|
41
113
|
|
|
42
114
|
## Supported Stacks
|
|
43
115
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
|
47
|
-
|
|
48
|
-
| Kotlin | `build.gradle.kts`, `*.kt` | `build.gradle.kts` |
|
|
116
|
+
31 built-in stacks + custom stack support:
|
|
117
|
+
|
|
118
|
+
| Stack | Detection Files | Config File |
|
|
119
|
+
|-------|----------------|-------------|
|
|
49
120
|
| Node.js | `package.json`, `*.js`, `*.ts` | `package.json` |
|
|
50
|
-
|
|
|
121
|
+
| Python | `pyproject.toml`, `setup.py`, `*.py` | `pyproject.toml` |
|
|
51
122
|
| Rust | `Cargo.toml`, `*.rs` | `Cargo.toml` |
|
|
52
|
-
|
|
|
53
|
-
|
|
|
123
|
+
| Go | `go.mod`, `*.go` | `go.mod` |
|
|
124
|
+
| Java | `pom.xml`, `build.gradle`, `*.java` | `pom.xml` |
|
|
125
|
+
| C/C++ | `*.c`, `*.cpp`, `*.hpp` | `CMakeLists.txt` |
|
|
54
126
|
| .NET | `*.cs`, `*.fs` | `global.json` |
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
127
|
+
| Ruby | `Gemfile`, `*.rb` | `Gemfile` |
|
|
128
|
+
| PHP | `composer.json`, `*.php` | `composer.json` |
|
|
129
|
+
| Swift | `Package.swift`, `*.swift` | `Package.swift` |
|
|
130
|
+
| + 21 more | | |
|
|
131
|
+
|
|
132
|
+
**Custom stacks:** Pass any name to `--stack` and fill `stackMeta` in `harness/config.json` during DEFINE phase.
|
|
59
133
|
|
|
60
134
|
## Commands
|
|
61
135
|
|
|
62
136
|
| Command | Description |
|
|
63
137
|
|---------|-------------|
|
|
64
|
-
| `init` | Scaffold project
|
|
65
|
-
| `status` | Show current
|
|
66
|
-
| `phase <name>` | Invoke a phase |
|
|
67
|
-
| `validate` | Run gate checks |
|
|
68
|
-
| `config
|
|
69
|
-
| `
|
|
70
|
-
| `set
|
|
71
|
-
| `
|
|
138
|
+
| `init` | Scaffold a new project with harness structure |
|
|
139
|
+
| `status` | Show current phase, stack, features, gates |
|
|
140
|
+
| `phase <name>` | Invoke a pipeline phase |
|
|
141
|
+
| `validate` | Run gate checks for current phase |
|
|
142
|
+
| `config list` | List all 29 configurable parameters |
|
|
143
|
+
| `config get <key>` | Get a config value |
|
|
144
|
+
| `config set <key> <value>` | Set a config value |
|
|
145
|
+
| `set-mode <copilot\|autopilot>` | Switch execution mode |
|
|
146
|
+
| `pause` / `resume` | Pause/resume autopilot |
|
|
72
147
|
| `contract propose/review/status/escalate` | Sprint contract negotiation |
|
|
73
|
-
| `
|
|
74
|
-
| `checkpoint create <label>` |
|
|
75
|
-
| `rollback list/to/branch` |
|
|
148
|
+
| `learn <message>` | Save a lesson to progress.md |
|
|
149
|
+
| `checkpoint create <label>` | Create a manual checkpoint |
|
|
150
|
+
| `rollback list/to/branch` | Restore to checkpoint |
|
|
151
|
+
| `worktree create/list/remove` | Git worktree management |
|
|
152
|
+
| `detect-tool` | Detect available agent tools |
|
|
76
153
|
|
|
77
|
-
##
|
|
154
|
+
## Agent Tool Integration
|
|
78
155
|
|
|
79
|
-
|
|
80
|
-
INIT → DEFINE → PLAN → BUILD → VERIFY → [SIMPLIFY] → REVIEW → SHIP
|
|
81
|
-
```
|
|
156
|
+
Harness works with any coding agent. Use `--agent-tool` during init to generate tool-specific files:
|
|
82
157
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
## Output Contracts
|
|
158
|
+
```bash
|
|
159
|
+
# Claude Code → generates CLAUDE.md
|
|
160
|
+
dev-harness init --stack node --agent-tool claude-code --target my-app
|
|
88
161
|
|
|
89
|
-
|
|
162
|
+
# Cursor → generates .cursorrules
|
|
163
|
+
dev-harness init --stack node --agent-tool cursor --target my-app
|
|
90
164
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"currentPhase":"define","mode":"copilot","recentLessons":[]}
|
|
165
|
+
# GitHub Copilot → generates .github/copilot-instructions.md
|
|
166
|
+
dev-harness init --stack node --agent-tool copilot --target my-app
|
|
94
167
|
```
|
|
95
168
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Exit codes: `0` success, `1` validation failure, `2` usage error, `3` internal error
|
|
169
|
+
**18 supported tools:** claude-code, cursor, windsurf, gemini, copilot, cline, roo, kilo-code, amazon-q, codex, opencode, continue, aider, antigravity, openclaw, pi, hermes, generic.
|
|
99
170
|
|
|
100
|
-
|
|
171
|
+
See [docs/TOOL_INTEGRATION.md](docs/TOOL_INTEGRATION.md) for per-tool setup guides.
|
|
101
172
|
|
|
102
|
-
|
|
103
|
-
cli/
|
|
104
|
-
├── harness-dev.mjs — Entry point + command router
|
|
105
|
-
├── lib/
|
|
106
|
-
│ ├── args.mjs — Argument parser
|
|
107
|
-
│ ├── errors.mjs — Error handling + exit codes
|
|
108
|
-
│ ├── help.mjs — Help text + per-command help
|
|
109
|
-
│ ├── detect-stack.mjs — 13-stack detection engine
|
|
110
|
-
│ ├── vars.mjs — Stack variable resolution
|
|
111
|
-
│ ├── templates.mjs — Template engine ({{VAR}} substitution)
|
|
112
|
-
│ ├── state.mjs — Config I/O + phase transitions
|
|
113
|
-
│ ├── phases.mjs — Pure phase pipeline logic
|
|
114
|
-
│ ├── progress.mjs — progress.md reader/writer
|
|
115
|
-
│ ├── gates.mjs — Phase gate validation
|
|
116
|
-
│ ├── ralph-inner.mjs — Inner loop engine
|
|
117
|
-
│ ├── ralph-outer.mjs — Outer loop engine
|
|
118
|
-
│ ├── ralph-output.mjs — Phase instruction text builders
|
|
119
|
-
│ ├── modes.mjs — Copilot/autopilot modes
|
|
120
|
-
│ ├── contract.mjs — Sprint contract negotiation
|
|
121
|
-
│ ├── git.mjs — Centralized git operations
|
|
122
|
-
│ ├── paths.mjs — Centralized path resolution
|
|
123
|
-
│ ├── file-io.mjs — JSON/text I/O helpers
|
|
124
|
-
│ ├── output.mjs — JSON/human output helpers
|
|
125
|
-
│ ├── command-helpers.mjs— Shared arg parsing + phaseLabel
|
|
126
|
-
│ ├── constants.mjs — Centralized magic numbers
|
|
127
|
-
│ ├── scaffold.mjs — Stack-specific scaffolding assets
|
|
128
|
-
│ ├── validate-schema.mjs— Minimal JSON-schema validator
|
|
129
|
-
│ └── schemas/
|
|
130
|
-
│ └── stacks.json — 13-stack metadata (CLI-internal)
|
|
131
|
-
├── commands/ — 13 command handlers
|
|
132
|
-
│ ├── init.mjs, status.mjs, phase.mjs, validate.mjs, config.mjs
|
|
133
|
-
│ ├── learn.mjs, set-mode.mjs, pause.mjs, resume.mjs
|
|
134
|
-
│ └── contract.mjs, worktree.mjs, rollback.mjs, checkpoint.mjs
|
|
135
|
-
templates/ — Scaffold templates (AGENTS.md, init.sh, ci/, docs/, etc.)
|
|
136
|
-
schema/ — Published JSON schemas (harness-config, feature-list)
|
|
137
|
-
test/ — Test suites (test-t*.mjs + run-all.mjs)
|
|
138
|
-
dist/install.sh — One-liner installation script (curl-pipe-bash)
|
|
139
|
-
adapters/ — Tool adapters (claude-code, cursor, codex, hermes, generic)
|
|
140
|
-
docs/ — TOOL_INTEGRATION.md (per-tool setup guides)
|
|
141
|
-
references/ — Historical audit reports
|
|
142
|
-
history/ — Project audit log, changelog, decisions, issues
|
|
143
|
-
docs-site-templates/ — Docusaurus/Sphinx scaffolds (experimental)
|
|
144
|
-
```
|
|
173
|
+
## Gates
|
|
145
174
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
harness-dev works with any coding agent via stdout JSON contracts and AGENTS.md project conventions. Use `--agent-tool` at scaffold time to generate tool-specific files, or `detect-tool` to discover which tools are configured.
|
|
175
|
+
Gates are deterministic checks that must pass before advancing to the next phase. Enable with:
|
|
149
176
|
|
|
150
177
|
```bash
|
|
151
|
-
|
|
152
|
-
harness-dev init --stack node --agent-tool claude-code --target my-project
|
|
153
|
-
|
|
154
|
-
# Or scaffold generically (AGENTS.md only — works with most tools)
|
|
155
|
-
harness-dev init --stack node --target my-project
|
|
156
|
-
|
|
157
|
-
# Detect which tools are configured
|
|
158
|
-
harness-dev detect-tool --target my-project
|
|
178
|
+
dev-harness config set gates.enabled true
|
|
159
179
|
```
|
|
160
180
|
|
|
161
|
-
|
|
181
|
+
| Phase | Gates |
|
|
182
|
+
|-------|-------|
|
|
183
|
+
| DEFINE | feature-branch, contract-agreed |
|
|
184
|
+
| PLAN | git-clean |
|
|
185
|
+
| BUILD | (coverage if enabled) |
|
|
186
|
+
| VERIFY | (coverage if enabled) |
|
|
187
|
+
| SIMPLIFY | git-clean, no-empty-dirs |
|
|
188
|
+
| REVIEW | branch-up-to-date, rubric-exists, readme-exists, architecture-doc, decisions-logged |
|
|
189
|
+
| SHIP | git-clean, tagged, changelog, readme-exists, license-exists, changelog-content, contributing-exists, no-empty-dirs |
|
|
162
190
|
|
|
163
|
-
|
|
191
|
+
## Configuration
|
|
164
192
|
|
|
165
|
-
|
|
193
|
+
All configuration lives in `harness/config.json`. View with:
|
|
166
194
|
|
|
167
195
|
```bash
|
|
168
|
-
|
|
169
|
-
cd my-project
|
|
170
|
-
# Claude reads CLAUDE.md automatically
|
|
171
|
-
harness-dev phase build
|
|
172
|
-
# Claude follows the phase instructions, runs:
|
|
173
|
-
harness-dev validate
|
|
196
|
+
dev-harness config list
|
|
174
197
|
```
|
|
175
198
|
|
|
176
|
-
|
|
199
|
+
29 parameters across 8 groups: Execution, Stack, Agent Tool, Gates, Git, Phases, Agent Tones, Runtime State.
|
|
177
200
|
|
|
178
|
-
|
|
179
|
-
harness-dev init --stack go --agent-tool codex --target my-project
|
|
180
|
-
cd my-project
|
|
181
|
-
# Codex reads AGENTS.md from project root
|
|
182
|
-
harness-dev status --json
|
|
183
|
-
# → Machine-readable state for agent decision-making
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Cursor
|
|
201
|
+
See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for full reference.
|
|
187
202
|
|
|
188
|
-
|
|
189
|
-
harness-dev init --stack rust --agent-tool cursor --target my-project
|
|
190
|
-
cd my-project
|
|
191
|
-
# .cursorrules generated with harness conventions
|
|
192
|
-
harness-dev phase build
|
|
193
|
-
```
|
|
203
|
+
## JSON Output
|
|
194
204
|
|
|
195
|
-
|
|
205
|
+
All commands support `--json` for machine-parseable output:
|
|
196
206
|
|
|
197
207
|
```bash
|
|
198
|
-
harness
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
# → Agent implements → calls `harness-dev validate`
|
|
202
|
-
# → Gate passes → `harness-dev phase verify`
|
|
208
|
+
dev-harness status --json
|
|
209
|
+
dev-harness phase define --json
|
|
210
|
+
dev-harness validate --json
|
|
203
211
|
```
|
|
204
212
|
|
|
205
|
-
## API Reference
|
|
206
|
-
|
|
207
|
-
### JSON Output Contract (all commands)
|
|
208
|
-
|
|
209
213
|
```json
|
|
210
214
|
{
|
|
211
|
-
"command": "
|
|
212
|
-
"status": "ok"
|
|
213
|
-
"
|
|
215
|
+
"command": "status",
|
|
216
|
+
"status": "ok",
|
|
217
|
+
"currentPhase": "define",
|
|
218
|
+
"stack": "node",
|
|
219
|
+
"mode": "copilot"
|
|
214
220
|
}
|
|
215
221
|
```
|
|
216
222
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
### Error Contract
|
|
220
|
-
|
|
221
|
-
```json
|
|
222
|
-
{
|
|
223
|
-
"error": "CliError",
|
|
224
|
-
"message": "Description of the problem",
|
|
225
|
-
"exitCode": 1
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Errors always go to **stderr** so stdout stays parseable.
|
|
230
|
-
|
|
231
|
-
### Exit Codes
|
|
232
|
-
|
|
233
|
-
| Code | Meaning |
|
|
234
|
-
|------|---------|
|
|
235
|
-
| 0 | Success |
|
|
236
|
-
| 1 | Validation failure |
|
|
237
|
-
| 2 | Usage error |
|
|
238
|
-
| 3 | Internal error |
|
|
239
|
-
|
|
240
|
-
### All Commands
|
|
241
|
-
|
|
242
|
-
| Command | JSON Fields | Description |
|
|
243
|
-
|---------|-------------|-------------|
|
|
244
|
-
| `init` | `project`, `stack`, `filesCreated` | Scaffold harness project |
|
|
245
|
-
| `status` | `currentPhase`, `mode`, `stack`, `gateStatus`, `checksPassing`, `checksTotal`, `recentLessons`, `nextAction` | Show current state |
|
|
246
|
-
| `phase <name>` | `phase`, `previousPhase`, `gateResult`, `iteration` | Invoke a phase |
|
|
247
|
-
| `validate` | `phase`, `checks[]`, `overall`, `failures[]` | Run gate checks |
|
|
248
|
-
| `config get <key>` | `key`, `value` | Read config value |
|
|
249
|
-
| `config set <key> <value>` | `key`, `previous`, `current` | Write config value |
|
|
250
|
-
| `learn <msg>` | `lesson` | Append a lesson |
|
|
251
|
-
| `set-mode copilot\|autopilot` | `previous`, `current` | Switch mode |
|
|
252
|
-
| `pause` / `resume` | `paused` | Control autopilot |
|
|
253
|
-
| `contract propose\|review\|status\|escalate` | `status`, `agreed`, `round`, `pinned` | Sprint contract |
|
|
254
|
-
| `worktree create\|list\|prune\|remove` | `worktrees[]`, `action`, `name` | Git worktree |
|
|
255
|
-
| `checkpoint create <label>` | `tag`, `commit` | Git checkpoint |
|
|
256
|
-
| `rollback list\|to\|branch` | `checkpoints[]`, `restored` | Rollback |
|
|
257
|
-
|
|
258
|
-
## Project Structure
|
|
259
|
-
|
|
260
|
-
```
|
|
261
|
-
cli/ — CLI source
|
|
262
|
-
├── harness-dev.mjs — Entry point + command router
|
|
263
|
-
├── lib/ — Core libraries
|
|
264
|
-
│ ├── git.mjs — Centralized git operations
|
|
265
|
-
│ ├── state.mjs — Config I/O + phase transitions (re-exports phases.mjs)
|
|
266
|
-
│ ├── phases.mjs — Pure phase pipeline logic
|
|
267
|
-
│ ├── ralph-inner.mjs — Inner loop (work → validate → retry)
|
|
268
|
-
│ ├── ralph-outer.mjs — Outer loop (phase auto-advance)
|
|
269
|
-
│ ├── ralph-output.mjs — Phase instruction text builders
|
|
270
|
-
│ ├── gates.mjs — Phase gate validation
|
|
271
|
-
│ ├── contract.mjs — Sprint contract negotiation
|
|
272
|
-
│ ├── paths.mjs — Centralized path resolution
|
|
273
|
-
│ ├── file-io.mjs — JSON/text I/O helpers
|
|
274
|
-
│ ├── output.mjs — JSON/human output helpers
|
|
275
|
-
│ ├── command-helpers.mjs — Shared arg parsing + phaseLabel
|
|
276
|
-
│ ├── constants.mjs — Centralized magic numbers
|
|
277
|
-
│ ├── scaffold.mjs — Stack-specific scaffolding assets
|
|
278
|
-
│ ├── templates.mjs — Template engine
|
|
279
|
-
│ ├── detect-stack.mjs — Stack detection
|
|
280
|
-
│ ├── validate-schema.mjs — Minimal JSON-schema validator
|
|
281
|
-
│ └── schemas/stacks.json — Stack metadata (CLI-internal)
|
|
282
|
-
├── commands/ — Command handlers (13 commands)
|
|
283
|
-
templates/ — Scaffold templates (AGENTS.md, init.sh, ci/, docs/, etc.)
|
|
284
|
-
schema/ — Published JSON schemas (harness-config, feature-list)
|
|
285
|
-
test/ — Test suites (test-t*.mjs + run-all.mjs)
|
|
286
|
-
dist/install.sh — One-liner install script
|
|
287
|
-
adapters/ — Tool adapters (claude-code, cursor, codex, hermes, generic)
|
|
288
|
-
docs/ — TOOL_INTEGRATION.md (per-tool setup guides)
|
|
289
|
-
references/ — Historical audit reports (T5-T14)
|
|
290
|
-
history/ — Project audit log, changelog, decisions, issues
|
|
291
|
-
docs-site-templates/ — Docusaurus/Sphinx scaffolds (experimental, T25)
|
|
292
|
-
PROJECT_PLAN.md — Full task breakdown (T1-T20)
|
|
293
|
-
SPEC.md — Original architecture specification
|
|
294
|
-
dev-harness.md — Internal project note (Obsidian)
|
|
295
|
-
```
|
|
223
|
+
Errors go to stderr. Exit codes: `0` success, `1` validation, `2` usage, `3` internal.
|
|
296
224
|
|
|
297
225
|
## License
|
|
298
226
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* save named recovery points (e.g. "before-refactor") that appear
|
|
10
10
|
* in `rollback list` and can be used with `rollback to/branch`.
|
|
11
11
|
*
|
|
12
|
-
* Usage: harness
|
|
12
|
+
* Usage: dev-harness checkpoint create <label>
|
|
13
13
|
*/
|
|
14
14
|
import { die, CliError, EXIT } from '../lib/errors.mjs';
|
|
15
15
|
import { execGit, getGitRoot, gitTagExists, createGitTag } from '../lib/git.mjs';
|
|
@@ -21,7 +21,7 @@ export default async function checkpointCommand(args) {
|
|
|
21
21
|
const label = args.positionals[0];
|
|
22
22
|
|
|
23
23
|
if (sub !== 'create' || !label) {
|
|
24
|
-
die(new CliError('Usage: harness
|
|
24
|
+
die(new CliError('Usage: dev-harness checkpoint create <label> [--force]', EXIT.USAGE_ERROR), json);
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
package/cli/commands/config.mjs
CHANGED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
* Uses state.mjs for dot-notation read/write with persistence.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* harness
|
|
8
|
-
* harness
|
|
9
|
-
* harness
|
|
7
|
+
* dev-harness config list — list all parameters with descriptions
|
|
8
|
+
* dev-harness config get [key] — get a value or all config
|
|
9
|
+
* dev-harness config set <key> <value> — set a value
|
|
10
10
|
*
|
|
11
11
|
* Examples:
|
|
12
|
-
* harness
|
|
13
|
-
* harness
|
|
14
|
-
* harness
|
|
15
|
-
* harness
|
|
16
|
-
* harness
|
|
12
|
+
* dev-harness config list
|
|
13
|
+
* dev-harness config list --json
|
|
14
|
+
* dev-harness config get gates.enabled
|
|
15
|
+
* dev-harness config set gates.enabled true
|
|
16
|
+
* dev-harness config set maxRetries 5
|
|
17
17
|
*/
|
|
18
18
|
import { resolve } from 'node:path';
|
|
19
19
|
import { die, CliError, EXIT } from '../lib/errors.mjs';
|
|
@@ -29,7 +29,7 @@ export default async function configCommand(args) {
|
|
|
29
29
|
|
|
30
30
|
if (!sub || (sub !== 'get' && sub !== 'set' && sub !== 'list')) {
|
|
31
31
|
die(new CliError(
|
|
32
|
-
'Usage: harness
|
|
32
|
+
'Usage: dev-harness config list | config get [key] | config set <key> <value>',
|
|
33
33
|
EXIT.USAGE_ERROR,
|
|
34
34
|
), json);
|
|
35
35
|
return;
|
|
@@ -75,7 +75,7 @@ export default async function configCommand(args) {
|
|
|
75
75
|
// Human output — grouped table
|
|
76
76
|
process.stdout.write('═══ Harness Configuration ═══\n\n');
|
|
77
77
|
if (!ok) {
|
|
78
|
-
process.stdout.write(' No harness
|
|
78
|
+
process.stdout.write(' No harness/config.json found. Run: dev-harness init\n\n');
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -102,7 +102,7 @@ export default async function configCommand(args) {
|
|
|
102
102
|
process.stdout.write('\n');
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
process.stdout.write('Edit with: harness
|
|
105
|
+
process.stdout.write('Edit with: dev-harness config set <key> <value>\n');
|
|
106
106
|
process.stdout.write('Full docs: docs/CONFIGURATION.md\n');
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
@@ -141,7 +141,7 @@ export default async function configCommand(args) {
|
|
|
141
141
|
if (sub === 'set') {
|
|
142
142
|
if (pos.length < 2) {
|
|
143
143
|
die(new CliError(
|
|
144
|
-
'Usage: harness
|
|
144
|
+
'Usage: dev-harness config set <key> <value>\n' +
|
|
145
145
|
' String values: config set mode copilot\n' +
|
|
146
146
|
' Boolean values: config set gates.enabled true\n' +
|
|
147
147
|
' Numeric values: config set maxRetries 5',
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Manages the generator-evaluator agreement loop.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* harness
|
|
8
|
-
* harness
|
|
9
|
-
* harness
|
|
10
|
-
* harness
|
|
7
|
+
* dev-harness contract propose [--scope "msg"] [--exclusions "msg"]
|
|
8
|
+
* dev-harness contract review [--agreed|--needs-revision]
|
|
9
|
+
* dev-harness contract status
|
|
10
|
+
* dev-harness contract escalate [--reason "msg"]
|
|
11
11
|
*/
|
|
12
12
|
import { resolve } from 'node:path';
|
|
13
13
|
import { die, CliError, EXIT } from '../lib/errors.mjs';
|
|
@@ -22,7 +22,7 @@ export default async function contractCommand(args) {
|
|
|
22
22
|
const sub = args.subcommand;
|
|
23
23
|
|
|
24
24
|
if (!sub || !SUBCOMMANDS.includes(sub)) {
|
|
25
|
-
die(new CliError(`Usage: harness
|
|
25
|
+
die(new CliError(`Usage: dev-harness contract ${SUBCOMMANDS.join('|')}`, EXIT.USAGE_ERROR), json);
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -34,7 +34,7 @@ export default async function contractCommand(args) {
|
|
|
34
34
|
|
|
35
35
|
if (!scope) {
|
|
36
36
|
die(new CliError(
|
|
37
|
-
'Usage: harness
|
|
37
|
+
'Usage: dev-harness contract propose --scope "I will build X" [--exclusions "W"] [--criteria "test1|test2"]',
|
|
38
38
|
EXIT.USAGE_ERROR,
|
|
39
39
|
), json);
|
|
40
40
|
return;
|
|
@@ -53,7 +53,7 @@ export default async function contractCommand(args) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
if (result.ok) {
|
|
56
|
-
process.stdout.write('✓ Contract proposed. Run: harness
|
|
56
|
+
process.stdout.write('✓ Contract proposed. Run: dev-harness contract review\n');
|
|
57
57
|
} else {
|
|
58
58
|
process.stderr.write(`✗ ${result.error}\n`);
|
|
59
59
|
}
|
|
@@ -68,7 +68,7 @@ export default async function contractCommand(args) {
|
|
|
68
68
|
|
|
69
69
|
if (!agreed && !needsRevision) {
|
|
70
70
|
die(new CliError(
|
|
71
|
-
'Usage: harness
|
|
71
|
+
'Usage: dev-harness contract review --agreed [--notes "msg"] OR --needs-revision [--notes "msg"]',
|
|
72
72
|
EXIT.USAGE_ERROR,
|
|
73
73
|
), json);
|
|
74
74
|
return;
|
|
@@ -116,7 +116,7 @@ export default async function contractCommand(args) {
|
|
|
116
116
|
rounds,
|
|
117
117
|
message: status
|
|
118
118
|
? `Contract ${status} (round ${rounds}/5)`
|
|
119
|
-
: 'No sprint-contract.md found. Run: harness
|
|
119
|
+
: 'No sprint-contract.md found. Run: dev-harness contract propose',
|
|
120
120
|
}) + '\n');
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
@@ -124,7 +124,7 @@ export default async function contractCommand(args) {
|
|
|
124
124
|
if (status) {
|
|
125
125
|
process.stdout.write(`Contract status: ${status} (round ${rounds}/5)\n`);
|
|
126
126
|
} else {
|
|
127
|
-
process.stdout.write('No sprint-contract.md found. Run: harness
|
|
127
|
+
process.stdout.write('No sprint-contract.md found. Run: dev-harness contract propose\n');
|
|
128
128
|
}
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Also reads harness-config.json agentTool field if present.
|
|
13
13
|
*
|
|
14
14
|
* Usage:
|
|
15
|
-
* harness
|
|
15
|
+
* dev-harness detect-tool [--target <dir>] [--json]
|
|
16
16
|
*/
|
|
17
17
|
import { existsSync } from 'node:fs';
|
|
18
18
|
import { resolve } from 'node:path';
|
|
@@ -20,12 +20,13 @@ import { parseCommandArgs } from '../lib/command-helpers.mjs';
|
|
|
20
20
|
import { emitJson, emitHuman } from '../lib/output.mjs';
|
|
21
21
|
import { loadConfig } from '../lib/state.mjs';
|
|
22
22
|
import { getAllDetectionSignatures, AGENTS_MD_TOOLS, TOOL_REGISTRY } from '../lib/tool-registry.mjs';
|
|
23
|
+
import { AGENTS_PATH } from '../lib/paths.mjs';
|
|
23
24
|
|
|
24
25
|
export default async function detectToolCommand(args) {
|
|
25
26
|
const { json, targetDir } = parseCommandArgs(args);
|
|
26
27
|
|
|
27
28
|
const detected = [];
|
|
28
|
-
const hasAgentsMd = existsSync(
|
|
29
|
+
const hasAgentsMd = existsSync(AGENTS_PATH(targetDir));
|
|
29
30
|
|
|
30
31
|
// 1. Scan for tool-specific detection files (from registry)
|
|
31
32
|
for (const { tool, file } of getAllDetectionSignatures()) {
|
|
@@ -79,7 +80,7 @@ export default async function detectToolCommand(args) {
|
|
|
79
80
|
status: 'ok',
|
|
80
81
|
message: detected.length > 0
|
|
81
82
|
? `Detected ${detected.length} agent tool(s): ${detected.join(', ')}`
|
|
82
|
-
: 'No agent tools detected. Run: harness
|
|
83
|
+
: 'No agent tools detected. Run: dev-harness init',
|
|
83
84
|
available: detected,
|
|
84
85
|
configured: configuredTool,
|
|
85
86
|
recommended,
|
|
@@ -103,7 +104,7 @@ export default async function detectToolCommand(args) {
|
|
|
103
104
|
}
|
|
104
105
|
} else {
|
|
105
106
|
emitHuman(` No agent tools detected.\n`);
|
|
106
|
-
emitHuman(` Run: harness
|
|
107
|
+
emitHuman(` Run: dev-harness init to scaffold a project.\n`);
|
|
107
108
|
}
|
|
108
109
|
if (hasAgentsMd) {
|
|
109
110
|
emitHuman(`\n AGENTS.md present — tools that read it natively are available.\n`);
|