dev-harness-cli 1.0.5 → 1.1.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 CHANGED
@@ -1,298 +1,226 @@
1
+ <div align="center">
2
+
1
3
  # Dev Harness
2
4
 
3
- **Agent-agnostic development pipeline CLI.** Scaffold, phase orchestrate, gate validate, and iterate any software project — works with any coding agent (Claude Code, Codex, OpenCode, Cursor, etc.).
5
+ ### Agent-agnostic development pipeline CLI
4
6
 
5
- ```bash
6
- npx dev-harness-cli init --stack python --target my-project
7
- cd my-project
8
- npx dev-harness-cli phase define
7
+ Scaffold · Phase orchestration · Gate validation · Iteration
8
+
9
+ [![npm version](https://img.shields.io/npm/v/dev-harness-cli.svg)](https://www.npmjs.com/package/dev-harness-cli)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![Node.js >=18](https://img.shields.io/badge/node-%3E%3D18-green.svg)](https://nodejs.org)
12
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-zero-blue.svg)](#)
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.
23
+
24
+ ```
25
+ define → plan → build → verify → [simplify] → review → ship
9
26
  ```
10
27
 
28
+ Each phase has **deterministic gates** (checks) that must pass before advancing. The agent does the work; harness validates the result.
29
+
11
30
  ## Install
12
31
 
13
32
  ```bash
14
33
  # Quick start (no install)
15
- npx dev-harness-cli --help
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
38
  harness-dev --help
20
-
21
- # Or clone and install
22
- git clone https://github.com/bakr-bagaber/dev-harness.git
23
- cd dev-harness && npm install -g .
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-dev init --stack python --target my-app
33
-
34
- # Check status
46
+ # 1. Scaffold a new project
47
+ harness-dev init --stack node --target my-app
35
48
  cd my-app
49
+
50
+ # 2. Check status
36
51
  harness-dev status
37
52
 
38
- # Start the DEFINE phase
53
+ # 3. Run the DEFINE phase (agent writes specs)
39
54
  harness-dev phase define
55
+
56
+ # 4. Validate (run gate checks)
57
+ harness-dev validate
58
+
59
+ # 5. Continue through pipeline
60
+ harness-dev phase plan
61
+ harness-dev phase build
62
+ harness-dev phase verify
63
+ harness-dev phase review
64
+ harness-dev phase ship
65
+ ```
66
+
67
+ ## Project Structure
68
+
69
+ When you run `harness-dev 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
- | Stack | Detection | Config File |
45
- |-------|-----------|-------------|
46
- | Python | `pyproject.toml`, `setup.py`, `*.py` | `pyproject.toml` |
47
- | Java | `pom.xml`, `build.gradle`, `*.java` | `pom.xml` |
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
- | Go | `go.mod`, `*.go` | `go.mod` |
121
+ | Python | `pyproject.toml`, `setup.py`, `*.py` | `pyproject.toml` |
51
122
  | Rust | `Cargo.toml`, `*.rs` | `Cargo.toml` |
52
- | C | `*.c` | `CMakeLists.txt` |
53
- | C++ | `*.cpp`, `*.hpp` | `CMakeLists.txt` |
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
- | MATLAB | `*.m` | (none) |
56
- | VHDL | `*.vhdl`, `*.vhd` | (none) |
57
- | Verilog | `*.v`, `*.sv` | (none) |
58
- | Generic | fallback | (none) |
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 (21 files) |
65
- | `status` | Show current state |
66
- | `phase <name>` | Invoke a phase |
67
- | `validate` | Run gate checks |
68
- | `config get/set` | Read/write config |
69
- | `learn <msg>` | Save a lesson |
70
- | `set-mode` | copilot / autopilot |
71
- | `pause` / `resume` | Control autopilot |
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
- | `worktree create/list/prune/remove` | Git worktree management |
74
- | `checkpoint create <label>` | Git tag checkpoint |
75
- | `rollback list/to/branch` | Rollback to checkpoint |
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
- ## Phase Pipeline
78
-
79
- ```
80
- INIT → DEFINE → PLAN → BUILD → VERIFY → [SIMPLIFY] → REVIEW → SHIP
81
- ```
154
+ ## Agent Tool Integration
82
155
 
83
- Two loop modes:
84
- - **Copilot** (default): one phase at a time, human decides when to advance
85
- - **Autopilot**: auto-advances through pipeline after each gate passes
156
+ Harness works with any coding agent. Use `--agent-tool` during init to generate tool-specific files:
86
157
 
87
- ## Output Contracts
158
+ ```bash
159
+ # Claude Code → generates CLAUDE.md
160
+ harness-dev init --stack node --agent-tool claude-code --target my-app
88
161
 
89
- All commands produce machine-parseable JSON with `--json`:
162
+ # Cursor generates .cursorrules
163
+ harness-dev init --stack node --agent-tool cursor --target my-app
90
164
 
91
- ```json
92
- {"command":"status","status":"ok","message":"Phase: define, Stack: Node.js",
93
- "currentPhase":"define","mode":"copilot","recentLessons":[]}
165
+ # GitHub Copilot → generates .github/copilot-instructions.md
166
+ harness-dev init --stack node --agent-tool copilot --target my-app
94
167
  ```
95
168
 
96
- Errors go to stderr: `{"error":"CliError","message":"...","exitCode":N}`
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.
97
170
 
98
- Exit codes: `0` success, `1` validation failure, `2` usage error, `3` internal error
171
+ See [docs/TOOL_INTEGRATION.md](docs/TOOL_INTEGRATION.md) for per-tool setup guides.
99
172
 
100
- ## Architecture
173
+ ## Gates
101
174
 
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
- ```
145
-
146
- ## Agent Integration
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
- # Scaffold with a specific tool
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
+ harness-dev config set gates.enabled true
159
179
  ```
160
180
 
161
- **Supported tools:** `claude-code` (CLAUDE.md), `cursor` (.cursorrules), `codex`, `aider`, `continue`, `opencode` (all read AGENTS.md), `hermes` (SKILL.md), `generic` (default).
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
- See [docs/TOOL_INTEGRATION.md](docs/TOOL_INTEGRATION.md) for per-tool setup guides and the adapter architecture.
191
+ ## Configuration
164
192
 
165
- ### Claude Code
193
+ All configuration lives in `harness/config.json`. View with:
166
194
 
167
195
  ```bash
168
- harness-dev init --stack node --agent-tool claude-code --target my-project
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
+ harness-dev config list
174
197
  ```
175
198
 
176
- ### Codex CLI
177
-
178
- ```bash
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
- ```
199
+ 29 parameters across 8 groups: Execution, Stack, Agent Tool, Gates, Git, Phases, Agent Tones, Runtime State.
185
200
 
186
- ### Cursor
201
+ See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for full reference.
187
202
 
188
- ```bash
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
- ### Generic Agent Workflow
205
+ All commands support `--json` for machine-parseable output:
196
206
 
197
207
  ```bash
198
- harness-dev phase build
199
- # Prints task instructions for agent
200
- # Agent reads AGENTS.md + progress.md + sprint-contract.md
201
- # → Agent implements → calls `harness-dev validate`
202
- # → Gate passes → `harness-dev phase verify`
203
- ```
204
-
205
- ## API Reference
206
-
207
- ### JSON Output Contract (all commands)
208
-
209
- ```json
210
- {
211
- "command": "<command_name>",
212
- "status": "ok" | "not_implemented" | "error",
213
- "message": "Human-readable status or error detail"
214
- }
208
+ harness-dev status --json
209
+ harness-dev phase define --json
210
+ harness-dev validate --json
215
211
  ```
216
212
 
217
- Additional command-specific fields are included (e.g. `currentPhase`, `stack`, `mode`).
218
-
219
- ### Error Contract
220
-
221
213
  ```json
222
214
  {
223
- "error": "CliError",
224
- "message": "Description of the problem",
225
- "exitCode": 1
215
+ "command": "status",
216
+ "status": "ok",
217
+ "currentPhase": "define",
218
+ "stack": "node",
219
+ "mode": "copilot"
226
220
  }
227
221
  ```
228
222
 
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
 
@@ -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-config.json found. Run: harness-dev init\n\n');
78
+ process.stdout.write(' No harness/config.json found. Run: harness-dev init\n\n');
79
79
  return;
80
80
  }
81
81
 
@@ -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(resolve(targetDir, 'AGENTS.md'));
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()) {
@@ -144,16 +144,16 @@ export default async function initCommand(args) {
144
144
  const harnessPaths = [];
145
145
  const projectPaths = [];
146
146
 
147
- // Template files — known template names
147
+ // Template files — known template names (mapped to harness/ paths by templates.mjs)
148
148
  const templateNames = [
149
- 'AGENTS.md', 'harness-config.json', 'init.sh',
150
- 'progress.md', 'sprint-contract.md', 'evaluator-rubric.md',
149
+ 'AGENTS.md', 'harness/config.json', 'harness/scripts/init.sh',
150
+ 'harness/progress.md', 'harness/sprint-contract.md', 'harness/evaluator-rubric.md',
151
151
  ];
152
152
  for (const name of templateNames) {
153
153
  harnessPaths.push(join(targetDir, name));
154
154
  }
155
155
 
156
- // Extra scaffold files
156
+ // Extra scaffold files (already have harness/ prefix from getExtraFiles)
157
157
  for (const relPath of Object.keys(extraFiles)) {
158
158
  harnessPaths.push(join(targetDir, relPath));
159
159
  }
@@ -190,8 +190,8 @@ export default async function initCommand(args) {
190
190
  // Ensure target directory exists
191
191
  mkdirSync(targetDir, { recursive: true });
192
192
 
193
- // Ensure docs/ directory exists
194
- mkdirSync(join(targetDir, 'docs'), { recursive: true });
193
+ // Ensure harness/ directory exists (all harness files go here)
194
+ mkdirSync(join(targetDir, 'harness'), { recursive: true });
195
195
 
196
196
  const created = [];
197
197
  const errors = [];
@@ -289,15 +289,15 @@ export default async function initCommand(args) {
289
289
  }
290
290
  }
291
291
 
292
- // Set agentTool in the generated harness-config.json
293
- const configPath = join(targetDir, 'harness-config.json');
292
+ // Set agentTool in the generated harness/config.json
293
+ const configPath = join(targetDir, 'harness', 'config.json');
294
294
  if (existsSync(configPath)) {
295
295
  try {
296
296
  const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
297
297
  cfg.agentTool = agentTool;
298
298
  writeFileSync(configPath, JSON.stringify(cfg, null, 2) + '\n', 'utf-8');
299
299
  } catch (err) {
300
- errors.push(`harness-config.json agentTool: ${err.message}`);
300
+ errors.push(`harness/config.json agentTool: ${err.message}`);
301
301
  }
302
302
  }
303
303
  }
@@ -161,9 +161,9 @@ export default async function rollbackCommand(args) {
161
161
 
162
162
  // Restore all files from the checkpoint
163
163
  const restoreFiles = [
164
- 'harness-config.json',
165
- 'progress.md',
166
- 'feature_list.json',
164
+ 'harness/config.json',
165
+ 'harness/progress.md',
166
+ 'harness/features/feature-list.json',
167
167
  ];
168
168
 
169
169
  // First, restore the whole working tree from the tag
@@ -61,7 +61,7 @@ export default async function statusCommand(args) {
61
61
  status: 'ok',
62
62
  message: configOk
63
63
  ? `Phase: ${phase || 'not started'}, Stack: ${stack.label}`
64
- : 'No harness-config.json found — run harness-dev init',
64
+ : 'No harness/config.json found — run harness-dev init',
65
65
  project: basename(targetDir),
66
66
  stack: stack.name,
67
67
  stackLabel: stack.label,
@@ -84,7 +84,7 @@ export default async function statusCommand(args) {
84
84
 
85
85
  // ── Human-readable output ─────────────────────────────────────────────
86
86
  let out = '';
87
- out += '═══ dev-harness Status ═══\n';
87
+ out += '═══ harness Status ═══\n';
88
88
  out += line('Project:', basename(targetDir)) + '\n';
89
89
  out += line('Stack:', `${stack.label}${stack.name !== 'generic' ? '' : ' (not detected)'}`) + '\n';
90
90
  out += line('Mode:', modeLabel(mode)) + '\n';
@@ -104,7 +104,7 @@ export default async function statusCommand(args) {
104
104
  out += ' Phase: not started.\n';
105
105
  out += '\n';
106
106
  } else {
107
- out += ' No harness-config.json found.\n';
107
+ out += ' No harness/config.json found.\n';
108
108
  out += '\n';
109
109
  }
110
110
 
package/cli/lib/gates.mjs CHANGED
@@ -18,6 +18,7 @@ import { loadConfig } from './state.mjs';
18
18
  import { getStackMeta, detectStack } from './detect-stack.mjs';
19
19
  import { validateContract } from './contract.mjs';
20
20
  import { execGitCheck as execCheck } from './git.mjs';
21
+ import { CONFIG_PATH, RUBRIC_PATH, ARCHITECTURE_PATH, DECISIONS_PATH, HARNESS_DIR } from './paths.mjs';
21
22
  import { COVERAGE_TIMEOUT, COVERAGE_THRESHOLD_DEFAULT } from './constants.mjs';
22
23
 
23
24
  function getStackLabel(targetDir) {
@@ -38,19 +39,20 @@ function checkGitRepo(targetDir) {
38
39
  }
39
40
 
40
41
  function checkConfigExists(targetDir) {
41
- const cfgPath = resolve(targetDir, 'harness-config.json');
42
+ const cfgPath = CONFIG_PATH(targetDir);
42
43
  const exists = existsSync(cfgPath);
43
44
  return {
44
45
  name: 'config-exists',
45
46
  pass: exists,
46
- detail: exists ? 'harness-config.json present' : 'Missing: harness-config.json',
47
+ detail: exists ? 'harness/config.json present' : 'Missing: harness/config.json',
47
48
  };
48
49
  }
49
50
 
50
51
  function checkInitExecutable(targetDir) {
52
+ // init.sh is now at harness/scripts/init.sh
53
+ const initSh = resolve(HARNESS_DIR(targetDir), 'scripts', 'init.sh');
51
54
  // Windows has no POSIX executable bit — skip the exec-bit check there.
52
55
  if (process.platform === 'win32') {
53
- const initSh = resolve(targetDir, 'init.sh');
54
56
  return {
55
57
  name: 'init-executable',
56
58
  pass: existsSync(initSh),
@@ -58,7 +60,7 @@ function checkInitExecutable(targetDir) {
58
60
  };
59
61
  }
60
62
  try {
61
- const { exitCode } = execCheck('test -x init.sh', targetDir);
63
+ const { exitCode } = execCheck(`test -x "${initSh}"`, targetDir);
62
64
  return {
63
65
  name: 'init-executable',
64
66
  pass: exitCode === 0,
@@ -177,11 +179,11 @@ function checkContractAgreed(targetDir) {
177
179
 
178
180
  /** Check that evaluator-rubric.md exists in the project. */
179
181
  function checkRubricExists(targetDir) {
180
- const found = existsSync(resolve(targetDir, 'evaluator-rubric.md'));
182
+ const found = existsSync(RUBRIC_PATH(targetDir));
181
183
  return {
182
184
  name: 'rubric-exists',
183
185
  pass: found,
184
- detail: found ? 'evaluator-rubric.md found' : 'evaluator-rubric.md missing — run init to scaffold',
186
+ detail: found ? 'harness/evaluator-rubric.md found' : 'harness/evaluator-rubric.md missing — run init to scaffold',
185
187
  };
186
188
  }
187
189
 
@@ -291,7 +293,7 @@ function checkChangelogContent(targetDir) {
291
293
 
292
294
  /** Check that ARCHITECTURE.md is filled in (if file exists, not just stub). */
293
295
  function checkArchitectureDoc(targetDir) {
294
- const archPath = resolve(targetDir, 'ARCHITECTURE.md');
296
+ const archPath = ARCHITECTURE_PATH(targetDir);
295
297
  if (!existsSync(archPath)) {
296
298
  return { name: 'architecture-doc', pass: true, detail: 'ARCHITECTURE.md not present (optional)' };
297
299
  }
@@ -304,7 +306,7 @@ function checkArchitectureDoc(targetDir) {
304
306
 
305
307
  /** Check that DECISIONS.md has at least one recorded decision (if file exists). */
306
308
  function checkDecisionsLogged(targetDir) {
307
- const decPath = resolve(targetDir, 'DECISIONS.md');
309
+ const decPath = DECISIONS_PATH(targetDir);
308
310
  if (!existsSync(decPath)) {
309
311
  return { name: 'decisions-logged', pass: true, detail: 'DECISIONS.md not present (optional)' };
310
312
  }
package/cli/lib/help.mjs CHANGED
@@ -53,7 +53,7 @@ Exit codes:
53
53
  2 Usage error (bad arguments)
54
54
  3 Internal error`;
55
55
 
56
- const VERSION = '1.0.5';
56
+ const VERSION = '1.1.0';
57
57
 
58
58
  // Help text for JSON output
59
59
  function buildJsonHelp() {
package/cli/lib/paths.mjs CHANGED
@@ -37,39 +37,118 @@ export const FEATURE_LIST_SCHEMA_PATH = resolve(SCHEMA_DIR, 'feature-list.schema
37
37
  export const STACKS_SCHEMA_PATH = resolve(LIB_DIR, 'schemas', 'stacks.json');
38
38
 
39
39
  // ── Project-relative paths (target project, not this CLI) ────────────────────
40
+ // All harness-managed files live under harness/ with subfolder grouping:
41
+ // harness/ — config, progress, contract, rubric, handoff, checklist
42
+ // harness/features/ — feature list + schema
43
+ // harness/docs/ — architecture, constraints, decisions, agent docs, phase docs
44
+ // harness/ci/ — CI/CD templates
45
+ // harness/scripts/ — init scripts
46
+ // AGENTS.md stays in root (agent tools expect it there).
40
47
 
41
48
  /**
42
- * Path to a project's harness-config.json.
49
+ * Harness root directory within a target project.
50
+ * @param {string} targetDir
51
+ * @returns {string}
52
+ */
53
+ export function HARNESS_DIR(targetDir) {
54
+ return resolve(targetDir, 'harness');
55
+ }
56
+
57
+ /**
58
+ * Path to a project's config.json (harness/config.json).
43
59
  * @param {string} targetDir
44
60
  * @returns {string}
45
61
  */
46
62
  export function CONFIG_PATH(targetDir) {
47
- return resolve(targetDir, 'harness-config.json');
63
+ return resolve(HARNESS_DIR(targetDir), 'config.json');
48
64
  }
49
65
 
50
66
  /**
51
- * Path to a project's feature_list.json.
67
+ * Path to a project's feature-list.json (harness/features/feature-list.json).
52
68
  * @param {string} targetDir
53
69
  * @returns {string}
54
70
  */
55
71
  export function FEATURE_LIST_PATH(targetDir) {
56
- return resolve(targetDir, 'feature_list.json');
72
+ return resolve(HARNESS_DIR(targetDir), 'features', 'feature-list.json');
57
73
  }
58
74
 
59
75
  /**
60
- * Path to a project's sprint-contract.md.
76
+ * Path to a project's sprint-contract.md (harness/sprint-contract.md).
61
77
  * @param {string} targetDir
62
78
  * @returns {string}
63
79
  */
64
80
  export function CONTRACT_PATH(targetDir) {
65
- return resolve(targetDir, 'sprint-contract.md');
81
+ return resolve(HARNESS_DIR(targetDir), 'sprint-contract.md');
66
82
  }
67
83
 
68
84
  /**
69
- * Path to a project's progress.md.
85
+ * Path to a project's progress.md (harness/progress.md).
70
86
  * @param {string} targetDir
71
87
  * @returns {string}
72
88
  */
73
89
  export function PROGRESS_PATH(targetDir) {
74
- return resolve(targetDir, 'progress.md');
90
+ return resolve(HARNESS_DIR(targetDir), 'progress.md');
91
+ }
92
+
93
+ /**
94
+ * Path to a project's evaluator-rubric.md (harness/evaluator-rubric.md).
95
+ * @param {string} targetDir
96
+ * @returns {string}
97
+ */
98
+ export function RUBRIC_PATH(targetDir) {
99
+ return resolve(HARNESS_DIR(targetDir), 'evaluator-rubric.md');
100
+ }
101
+
102
+ /**
103
+ * Path to a project's session-handoff.md (harness/session-handoff.md).
104
+ * @param {string} targetDir
105
+ * @returns {string}
106
+ */
107
+ export function HANDOFF_PATH(targetDir) {
108
+ return resolve(HARNESS_DIR(targetDir), 'session-handoff.md');
109
+ }
110
+
111
+ /**
112
+ * Path to a project's clean-state-checklist.md (harness/clean-state-checklist.md).
113
+ * @param {string} targetDir
114
+ * @returns {string}
115
+ */
116
+ export function CHECKLIST_PATH(targetDir) {
117
+ return resolve(HARNESS_DIR(targetDir), 'clean-state-checklist.md');
118
+ }
119
+
120
+ /**
121
+ * Path to a project's ARCHITECTURE.md (harness/docs/ARCHITECTURE.md).
122
+ * @param {string} targetDir
123
+ * @returns {string}
124
+ */
125
+ export function ARCHITECTURE_PATH(targetDir) {
126
+ return resolve(HARNESS_DIR(targetDir), 'docs', 'ARCHITECTURE.md');
127
+ }
128
+
129
+ /**
130
+ * Path to a project's CONSTRAINTS.md (harness/docs/CONSTRAINTS.md).
131
+ * @param {string} targetDir
132
+ * @returns {string}
133
+ */
134
+ export function CONSTRAINTS_PATH(targetDir) {
135
+ return resolve(HARNESS_DIR(targetDir), 'docs', 'CONSTRAINTS.md');
136
+ }
137
+
138
+ /**
139
+ * Path to a project's DECISIONS.md (harness/docs/DECISIONS.md).
140
+ * @param {string} targetDir
141
+ * @returns {string}
142
+ */
143
+ export function DECISIONS_PATH(targetDir) {
144
+ return resolve(HARNESS_DIR(targetDir), 'docs', 'DECISIONS.md');
145
+ }
146
+
147
+ /**
148
+ * Path to a project's AGENTS.md (stays in root — agent tools expect it there).
149
+ * @param {string} targetDir
150
+ * @returns {string}
151
+ */
152
+ export function AGENTS_PATH(targetDir) {
153
+ return resolve(targetDir, 'AGENTS.md');
75
154
  }
@@ -212,12 +212,13 @@ work/
212
212
  // ── Extra scaffolding files (not covered by templates) ───────────────────────
213
213
 
214
214
  /**
215
- * Inline content for files beyond the 5 template-based ones.
216
- * Key is relative output path, value is file content.
215
+ * Inline content for files beyond the template-based ones.
216
+ * Key is relative output path (under harness/), value is file content.
217
+ * All harness-managed files go under harness/ with subfolder grouping.
217
218
  */
218
219
  export function getExtraFiles(stack) {
219
220
  return {
220
- 'feature_list.json': JSON.stringify({
221
+ 'harness/features/feature-list.json': JSON.stringify({
221
222
  version: '0.1',
222
223
  features: [
223
224
  {
@@ -232,7 +233,7 @@ export function getExtraFiles(stack) {
232
233
  ],
233
234
  }, null, 2) + '\n',
234
235
 
235
- 'feature-list.schema.json': JSON.stringify({
236
+ 'harness/features/feature-list.schema.json': JSON.stringify({
236
237
  $schema: 'http://json-schema.org/draft-07/schema#',
237
238
  title: 'Feature List',
238
239
  type: 'object',
@@ -266,7 +267,7 @@ export function getExtraFiles(stack) {
266
267
  },
267
268
  }, null, 2) + '\n',
268
269
 
269
- 'session-handoff.md': `# Session Handoff
270
+ 'harness/session-handoff.md': `# Session Handoff
270
271
 
271
272
  ## Context
272
273
 
@@ -296,7 +297,7 @@ export function getExtraFiles(stack) {
296
297
  | ... | ... |
297
298
  `,
298
299
 
299
- 'clean-state-checklist.md': `# Clean State Checklist
300
+ 'harness/clean-state-checklist.md': `# Clean State Checklist
300
301
 
301
302
  Run this before starting any phase to ensure deterministic state.
302
303
 
@@ -308,10 +309,10 @@ Run this before starting any phase to ensure deterministic state.
308
309
 
309
310
  ## Harness
310
311
 
311
- - [ ] \`harness-config.json\` exists and valid
312
+ - [ ] \`harness/config.json\` exists and valid
312
313
  - [ ] Current phase matches what we're about to run
313
- - [ ] \`progress.md\` has latest Session State
314
- - [ ] \`feature_list.json\` up-to-date
314
+ - [ ] \`harness/progress.md\` has latest Session State
315
+ - [ ] \`harness/features/feature-list.json\` up-to-date
315
316
 
316
317
  ## Environment
317
318
 
@@ -320,7 +321,7 @@ Run this before starting any phase to ensure deterministic state.
320
321
  - [ ] No stale background processes
321
322
  `,
322
323
 
323
- 'ARCHITECTURE.md': `# Architecture
324
+ 'harness/docs/ARCHITECTURE.md': `# Architecture
324
325
 
325
326
  ## Module Structure
326
327
 
@@ -330,7 +331,7 @@ src/
330
331
  \`\`\`
331
332
  `,
332
333
 
333
- 'CONSTRAINTS.md': `# Constraints
334
+ 'harness/docs/CONSTRAINTS.md': `# Constraints
334
335
 
335
336
  ## Technical
336
337
 
@@ -351,7 +352,7 @@ src/
351
352
  - Fail fast, fail loud
352
353
  `,
353
354
 
354
- 'DECISIONS.md': `# Decisions
355
+ 'harness/docs/DECISIONS.md': `# Decisions
355
356
 
356
357
  <!-- Record architectural and design decisions here. Use the format below. -->
357
358
 
@@ -372,7 +373,7 @@ src/
372
373
  | | | |
373
374
  `,
374
375
 
375
- 'docs/api-patterns.md': `# API Patterns
376
+ 'harness/docs/api-patterns.md': `# API Patterns
376
377
 
377
378
  ## Conventions
378
379
 
@@ -417,11 +418,10 @@ export function getVersionFileContent(stack) {
417
418
  * Return .gitignore content for the given stack.
418
419
  */
419
420
  export function getGitignoreContent(stack) {
420
- return `# Harness scaffold
421
- harness-config.json
422
- feature_list.json
423
- feature-list.schema.json
424
- progress.md
421
+ return `# Harness runtime state (regenerated by harness-dev)
422
+ harness/config.json
423
+ harness/features/feature-list.json
424
+ harness/progress.md
425
425
 
426
426
  ${GITIGNORE_PATTERNS[stack] || GITIGNORE_PATTERNS.generic}
427
427
  # OS
@@ -111,6 +111,42 @@ export function discoverTemplates() {
111
111
  }
112
112
  }
113
113
 
114
+ /**
115
+ * Map a template's relative path to its output path under harness/.
116
+ * Templates that are harness-managed go into harness/ subfolders.
117
+ * AGENTS.md stays in project root (agent tools expect it there).
118
+ *
119
+ * Mapping:
120
+ * AGENTS.md → AGENTS.md (root)
121
+ * harness-config.json → harness/config.json
122
+ * progress.md → harness/progress.md
123
+ * sprint-contract.md → harness/sprint-contract.md
124
+ * evaluator-rubric.md → harness/evaluator-rubric.md
125
+ * init.sh / init.ps1 → harness/scripts/init.sh
126
+ * ci/* → harness/ci/*
127
+ * docs/* → harness/docs/*
128
+ *
129
+ * @param {string} relPath — relative path within templates/
130
+ * @returns {string} — relative output path within target
131
+ */
132
+ function mapTemplateOutput(relPath) {
133
+ // AGENTS.md stays in root
134
+ if (relPath === 'AGENTS.md') return relPath;
135
+ // harness-config.json → harness/config.json
136
+ if (relPath === 'harness-config.json') return 'harness/config.json';
137
+ // Top-level harness files → harness/
138
+ const harnessRootFiles = ['progress.md', 'sprint-contract.md', 'evaluator-rubric.md'];
139
+ if (harnessRootFiles.includes(relPath)) return `harness/${relPath}`;
140
+ // init scripts → harness/scripts/
141
+ if (relPath === 'init.sh' || relPath === 'init.ps1') return `harness/scripts/${relPath}`;
142
+ // ci/ → harness/ci/
143
+ if (relPath.startsWith('ci/')) return `harness/${relPath}`;
144
+ // docs/ → harness/docs/
145
+ if (relPath.startsWith('docs/')) return `harness/${relPath}`;
146
+ // Default: put under harness/
147
+ return `harness/${relPath}`;
148
+ }
149
+
114
150
  /**
115
151
  * Run the template engine.
116
152
  *
@@ -147,7 +183,8 @@ export function generateTemplates(opts) {
147
183
  const relativePath = tmplPath.startsWith(TEMPLATES_DIR + '/')
148
184
  ? tmplPath.slice(TEMPLATES_DIR.length + 1)
149
185
  : basename(tmplPath);
150
- const outPath = join(target, relativePath);
186
+ const outputRel = mapTemplateOutput(relativePath);
187
+ const outPath = join(target, outputRel);
151
188
  const outDir = dirname(outPath);
152
189
 
153
190
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dev-harness-cli",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "description": "Agent-agnostic software development harness CLI — scaffold, phase orchestration, gate validation for any coding agent",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,7 +37,11 @@
37
37
  "cli"
38
38
  ],
39
39
  "scripts": {
40
+ "lint": "eslint cli/",
41
+ "lint:fix": "eslint cli/ --fix",
40
42
  "check": "node --check cli/harness-dev.mjs && echo 'Syntax OK'",
43
+ "test": "node test/run-all.mjs",
44
+ "test:verbose": "node test/run-all.mjs --verbose",
41
45
  "postinstall": "node -e \"try{process.stdout.write('harness-dev installed. Run: npx harness-dev --help\\n')}catch(e){}\""
42
46
  },
43
47
  "devDependencies": {
@@ -0,0 +1,63 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Feature List",
4
+ "description": "Schema for feature_list.json — tracks features and their tasks through the pipeline",
5
+ "type": "object",
6
+ "required": ["version", "features"],
7
+ "properties": {
8
+ "version": {
9
+ "type": "string",
10
+ "description": "Schema version",
11
+ "default": "0.1"
12
+ },
13
+ "features": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "object",
17
+ "required": ["id", "name", "passes", "tasks"],
18
+ "properties": {
19
+ "id": {
20
+ "type": "string",
21
+ "description": "Unique feature identifier (e.g. feature-001)"
22
+ },
23
+ "name": {
24
+ "type": "string",
25
+ "description": "Human-readable feature name"
26
+ },
27
+ "description": {
28
+ "type": "string",
29
+ "description": "Optional feature description"
30
+ },
31
+ "passes": {
32
+ "type": "boolean",
33
+ "default": false,
34
+ "description": "All tasks completed and verified"
35
+ },
36
+ "tasks": {
37
+ "type": "array",
38
+ "items": {
39
+ "type": "object",
40
+ "required": ["id", "description", "status"],
41
+ "properties": {
42
+ "id": {
43
+ "type": "string",
44
+ "description": "Unique task identifier"
45
+ },
46
+ "description": {
47
+ "type": "string",
48
+ "description": "Task description"
49
+ },
50
+ "status": {
51
+ "type": "string",
52
+ "enum": ["pending", "in_progress", "complete", "blocked"],
53
+ "default": "pending",
54
+ "description": "Task status"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
@@ -18,7 +18,7 @@ harness-dev validate # Check gate criteria
18
18
 
19
19
  INIT → DEFINE → PLAN → BUILD → VERIFY → [SIMPLIFY] → REVIEW → SHIP
20
20
 
21
- See `docs/phases/` for phase-specific instructions.
21
+ See `harness/docs/phases/` for phase-specific instructions.
22
22
 
23
23
  ## Agent Roles
24
24
 
@@ -31,21 +31,25 @@ See `docs/phases/` for phase-specific instructions.
31
31
 
32
32
  ## Key Files
33
33
 
34
+ All harness-managed files live under `harness/` (except `AGENTS.md` which stays in root for agent tool compatibility).
35
+
34
36
  | File | Purpose |
35
37
  |------|---------|
36
- | `harness-config.json` | Config + state |
37
- | `feature_list.json` | Feature list with passes |
38
- | `progress.md` | Session state + lessons |
39
- | `sprint-contract.md` | Pre-build agreement |
40
- | `init.sh` | Install verify → start |
41
- | `evaluator-rubric.md` | Quality scorecard (6 dimensions, 0-2) |
42
- |
38
+ | `AGENTS.md` | This file agent instructions (root) |
39
+ | `harness/config.json` | Config + state |
40
+ | `harness/features/feature-list.json` | Feature list with passes |
41
+ | `harness/progress.md` | Session state + lessons |
42
+ | `harness/sprint-contract.md` | Pre-build agreement |
43
+ | `harness/scripts/init.sh` | Install verify start |
44
+ | `harness/evaluator-rubric.md` | Quality scorecard (6 dimensions, 0-2) |
45
+ | `harness/docs/` | Architecture, constraints, decisions, agent guides, phase guides |
46
+
43
47
  ## Rules (non-negotiable)
44
48
 
45
49
  1. No agent evaluates its own work — Evaluator always judges
46
- 2. Read `progress.md` + this file before each operation
50
+ 2. Read `harness/progress.md` + this file before each operation
47
51
  3. Commit frequently — each iteration is a checkpoint
48
- 4. If unsure → read the role guide in `docs/agents/`
52
+ 4. If unsure → read the role guide in `harness/docs/agents/`
49
53
  5. Never skip gates — run `harness-dev validate` after each phase
50
54
  6. Fresh context per retry — pass `--git-ops` to `harness-dev phase <name>` to auto-reset the working tree on retry (off by default; agent-agnostic)
51
55
  7. **No files in project root** unless they are harness-managed files (listed in Key Files above) or standard project files (README.md, LICENSE, CHANGELOG.md, CONTRIBUTING.md, .gitignore, and the stack config file like package.json/pyproject.toml/Cargo.toml). All source code, tests, scripts, and docs go in subdirectories.
@@ -74,5 +74,5 @@ jobs:
74
74
  runs-on: ubuntu-latest
75
75
  steps:
76
76
  - uses: actions/checkout@v4
77
- - run: npm install -g @dev-harness/cli
77
+ - run: npm install -g dev-harness-cli
78
78
  - run: harness-dev validate --json
@@ -54,6 +54,6 @@ gate:
54
54
  stage: gate
55
55
  image: node:lts
56
56
  script:
57
- - npm install -g @dev-harness/cli
57
+ - npm install -g dev-harness-cli
58
58
  - harness-dev validate --json
59
59
  needs: [coverage]
@@ -9,5 +9,5 @@ You design the approach. You write criteria. You set scope.
9
9
  - Set exclusions explicitly ("We will NOT build X")
10
10
  - Hand off to Generator when criteria are clear
11
11
  - In DEFINE: interview the user, write PRD in specs/*.md
12
- - In PLAN: decompose features into tasks in feature_list.json
12
+ - In PLAN: decompose features into tasks in harness/features/feature-list.json
13
13
  - Review gate criteria with Evaluator before proceeding
@@ -0,0 +1,42 @@
1
+ {
2
+ "version": "1.0",
3
+ "stack": "{{stack}}",
4
+ "stackMeta": null,
5
+ "agentTool": null,
6
+ "mode": "copilot",
7
+ "currentPhase": null,
8
+ "paused": false,
9
+ "features": {
10
+ "remaining": 0,
11
+ "passing": 0,
12
+ "total": 0
13
+ },
14
+ "gates": {
15
+ "enabled": false,
16
+ "checks": ["all"]
17
+ },
18
+ "git": {
19
+ "autoCommit": false,
20
+ "autoTag": false,
21
+ "resetOnRetry": false,
22
+ "branch": null,
23
+ "clean": true,
24
+ "hasUpstream": false,
25
+ "lastCommitMessage": null
26
+ },
27
+ "phases": {
28
+ "enabled": ["define", "plan", "build", "verify", "review", "ship"]
29
+ },
30
+ "agents": {
31
+ "tone": {
32
+ "planner": "Analytical and precise. Define clear boundaries.",
33
+ "generator": "Focused and practical. Build what's specified, nothing more.",
34
+ "evaluator": "Skeptical and thorough. Accept only compelling evidence.",
35
+ "simplifier": "Relentless about clarity. Delete more than you add."
36
+ }
37
+ },
38
+ "maxRetries": 3,
39
+ "retryCount": 0,
40
+ "pipelineIteration": 0,
41
+ "gateHistory": []
42
+ }
@@ -0,0 +1,18 @@
1
+ # Progress: {{stackLabel}}
2
+
3
+ ## Session State
4
+
5
+ Current Phase: not started
6
+ Current Feature: —
7
+ Gate Status: pending
8
+ Next Action: —
9
+ Retry Count: 0/{{maxRetries}}
10
+
11
+ ## Lessons
12
+
13
+ <!-- Use \`harness-dev learn "lesson here"\` to add lessons. -->
14
+
15
+ ## Checkpoints
16
+
17
+ | Tag | Phase | Date | Notes |
18
+ |-----|-------|------|-------|