devcontour-harness 0.1.0-alpha.11 → 0.1.0-alpha.13
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 +37 -5
- package/docs/architecture.md +6 -5
- package/docs/connectors.md +26 -0
- package/docs/quickstart.md +1 -1
- package/docs/release-notes/0.1.0-alpha.12.md +66 -0
- package/docs/release-notes/0.1.0-alpha.13.md +91 -0
- package/docs/standalone.md +25 -4
- package/docs/turbo-starter.md +2 -1
- package/docs/upgrade.md +14 -14
- package/examples/turbo-starter/setup.mjs +9 -2
- package/lib/connectors/files.js +2 -0
- package/lib/integrations/connector/commands.d.ts +11 -4
- package/lib/integrations/connector/commands.js +16 -2
- package/lib/integrations/connector/config.d.ts +5 -0
- package/lib/integrations/connector/config.js +18 -1
- package/lib/integrations/connector/index.d.ts +1 -1
- package/lib/integrations/connector/index.js +1 -1
- package/lib/integrations/connector/snapshot.d.ts +22 -1
- package/lib/integrations/connector/snapshot.js +60 -3
- package/lib/integrations/connector/source.d.ts +4 -0
- package/lib/integrations/connector/source.js +1 -0
- package/package.json +1 -1
- package/skills/harness/SKILL.md +17 -15
- package/skills/harness-setup/SKILL.md +478 -0
- package/templates/controller-mode/README.md +5 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-setup
|
|
3
|
+
description: Install, configure or upgrade devcontour-harness for a new or existing npm/pnpm Git repository, including pnpm/Turborepo monorepos such as Turbo Starter and task sources such as Relay — decide every routine choice yourself from the repository, ask the user only at real forks (which vendor writes and which accepts, a missing Relay fact, isolation or Docker, rule conflicts, commits, writes to Relay, live model calls), install the exact version in `.harness-tools/`, run `harness init`, and hand over to the `harness` skill; upgrade an installed version with a state copy and a compatibility check.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Harness setup
|
|
7
|
+
|
|
8
|
+
This skill installs and upgrades the `devcontour-harness` package for one
|
|
9
|
+
repository and leaves it ready for work. Running work orders (plan, run,
|
|
10
|
+
explain, result) is the job of the `harness` skill shipped inside the package
|
|
11
|
+
(`<tooldir>/node_modules/devcontour-harness/skills/harness/SKILL.md`); read it
|
|
12
|
+
once the package is installed.
|
|
13
|
+
|
|
14
|
+
This skill only explains the route. Gates, review, write scope, budgets and
|
|
15
|
+
the reviewer vendor rule are enforced by the harness itself; nothing here
|
|
16
|
+
replaces or relaxes them.
|
|
17
|
+
|
|
18
|
+
Every `harness` command prints one JSON envelope on stdout (`ok` with `data`,
|
|
19
|
+
or `error`); exit codes: 0 success, 2 invalid input, 3 refusal or block,
|
|
20
|
+
4 infrastructure. Below `$H` is the installed CLI:
|
|
21
|
+
`H=<tooldir>/node_modules/.bin/harness`, and `<pkg>` is
|
|
22
|
+
`<tooldir>/node_modules/devcontour-harness`.
|
|
23
|
+
|
|
24
|
+
Modes: **install** (first setup), **upgrade** (change the installed version),
|
|
25
|
+
**check** (report what is installed; read only). Pick the mode from the
|
|
26
|
+
request; when the repository already has `.harness/` and a pinned or
|
|
27
|
+
installed `$H`, it is upgrade or check, not install.
|
|
28
|
+
|
|
29
|
+
## Decide or ask
|
|
30
|
+
|
|
31
|
+
Decide everything you can from the repository and the defaults below, and
|
|
32
|
+
report each decision with its reason at the end; the user overrides any of
|
|
33
|
+
them by saying so. Ask only at a fork — a choice that changes who is trusted,
|
|
34
|
+
what leaves the machine, what is spent or which project rule gives way — and
|
|
35
|
+
ask all open forks of a step in one round (multiple choice where the host
|
|
36
|
+
supports it).
|
|
37
|
+
|
|
38
|
+
| Choice | Default (decide yourself) | Ask when |
|
|
39
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| Writer and reviewer vendor | — | always: which of `claude` / `codex` writes; the other one reviews and accepts |
|
|
41
|
+
| Same vendor for review | never | only one runtime is installed, or the user asked for it |
|
|
42
|
+
| Models and effort | runtime defaults | the user named models |
|
|
43
|
+
| Branch | new branch `harness-setup` from the current branch; an existing `harness/accepted` is reported and left alone | the working tree is not clean |
|
|
44
|
+
| Install location | `<repo>/.harness-tools` | the user asked for a directory outside the repository |
|
|
45
|
+
| Package source | npm `@alpha` resolved to the exact version | the user gave a version or a tarball |
|
|
46
|
+
| Stack profile | built-in by lockfile; a local `.harness/profile.json` when the project does not have its scripts (below) | — |
|
|
47
|
+
| Gates | derived from the project's own commands (step 6), each reported with its command | a check the project or its CI runs would be left out, or no command can prove behaviour without new dependencies |
|
|
48
|
+
| Plan approval | `agent` (`init` default) | the user wants to approve plans themselves (`operator`) |
|
|
49
|
+
| Task source | Relay when the repository or the request names it, otherwise graph files | both are plausible |
|
|
50
|
+
| Relay connection | discovered from the repository and environment | a fact is missing: endpoint or binary/config, `projectId`, which tasks |
|
|
51
|
+
| Relay completion | `review-only` (a human closes the task) | the user wants `complete` |
|
|
52
|
+
| Controller mode | — | the product AGENTS.md tells agents to manage worktrees, commits, merges or Relay history: the overlay then takes precedence over those rules (step 9) |
|
|
53
|
+
| OS isolation | on | prepare or gates fail inside the sandbox (store, network, Docker socket) |
|
|
54
|
+
| Docker environment | none | gates need a database or other service |
|
|
55
|
+
| Project rule conflicts | — | a project rule forbids what setup creates (for example new `.md` files: `.harness/README.md`) |
|
|
56
|
+
| Commit, Relay writes, runs | — | always confirm: committing the setup, `run --source` / `source-deliver` / `source-reconcile`, any live `run` or `review-plan` |
|
|
57
|
+
|
|
58
|
+
## Install
|
|
59
|
+
|
|
60
|
+
### 1. Preconditions
|
|
61
|
+
|
|
62
|
+
Node.js ≥ 24.3, `git`, `npm` (or `pnpm` for a pnpm project) and the runtime
|
|
63
|
+
CLIs (`claude --version`, `codex --version`). Whether a runtime is signed in
|
|
64
|
+
is not detectable without a model call: the user confirms it. A missing or
|
|
65
|
+
signed-out runtime is the user's to fix.
|
|
66
|
+
|
|
67
|
+
The package manager version is checked exactly: the built-in profiles pin
|
|
68
|
+
one (`npm-ci` pins npm `11.4.2`), and `package.json#packageManager`
|
|
69
|
+
(`npm@<version>` / `pnpm@<version>`) overrides that pin. Another version is
|
|
70
|
+
`NOT_READY` (`TOOL_VERSION`) at `init`; adding `packageManager` to an existing
|
|
71
|
+
project is the user's decision.
|
|
72
|
+
|
|
73
|
+
### 2. Repository
|
|
74
|
+
|
|
75
|
+
**Existing.** It must be the top level of a Git repository with at least one
|
|
76
|
+
commit and exactly one lockfile: `package-lock.json` (profile `npm-ci`) or
|
|
77
|
+
`pnpm-lock.yaml` (profile `pnpm-frozen`). With both or none, write a local
|
|
78
|
+
profile (step 6).
|
|
79
|
+
|
|
80
|
+
**New.** Create it only with the user's consent, at the path they gave:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
git init <repo> && cd <repo>
|
|
84
|
+
npm init -y && npm install # writes package-lock.json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The built-in `npm-ci` profile needs two scripts: `check` and `test`, where
|
|
88
|
+
`test` writes JUnit to `.reports/junit.xml`. A minimal set for Node's test
|
|
89
|
+
runner, with the installed npm version pinned:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
"packageManager": "npm@<npm --version>",
|
|
93
|
+
"scripts": {
|
|
94
|
+
"check": "node --check index.js",
|
|
95
|
+
"test": "mkdir -p .reports && node --test --test-reporter=spec --test-reporter-destination=stdout --test-reporter=junit --test-reporter-destination=.reports/junit.xml"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Add `.reports/` and `node_modules/` to `.gitignore`, a first source file and
|
|
100
|
+
a passing test, then commit. The first commit must pass its own gates: a
|
|
101
|
+
project failing on its base is a separate first task, not a reason to relax
|
|
102
|
+
a gate.
|
|
103
|
+
|
|
104
|
+
### 3. Branch
|
|
105
|
+
|
|
106
|
+
`git status` must be clean (ask the user about local changes; never stash or
|
|
107
|
+
discard them yourself). Then `git switch -c harness-setup`.
|
|
108
|
+
|
|
109
|
+
`run` creates `refs/heads/harness/accepted` from the `HEAD` of the main
|
|
110
|
+
checkout when that ref does not exist yet. Keep the setup branch checked out,
|
|
111
|
+
with the setup committed (step 11), until the first `run`: otherwise
|
|
112
|
+
`harness/accepted` starts from a commit without it. When `harness/accepted`
|
|
113
|
+
already exists, report its SHA and leave it alone. Accepted work lands in
|
|
114
|
+
`harness/accepted`, not in the setup branch; merging it anywhere is the
|
|
115
|
+
user's decision.
|
|
116
|
+
|
|
117
|
+
### 4. Install the exact version
|
|
118
|
+
|
|
119
|
+
Resolve `@alpha` to the exact version first and install that:
|
|
120
|
+
`npm view devcontour-harness@alpha version`. For a tarball, compare
|
|
121
|
+
`shasum -a 256 <file.tgz>` with the sha256 the user gave and stop on a
|
|
122
|
+
mismatch.
|
|
123
|
+
|
|
124
|
+
**Inside the project** — `<tooldir>` = `<repo>/.harness-tools`:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
T=<repo>/.harness-tools
|
|
128
|
+
mkdir -p "$T"
|
|
129
|
+
npm install --prefix "$T" --save-exact --omit=dev --ignore-scripts devcontour-harness@<version>
|
|
130
|
+
printf 'node_modules/\n' > "$T/.gitignore"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The version is pinned by `.harness-tools/package.json` and its
|
|
134
|
+
`package-lock.json`, not by a directory name; both are committed with the
|
|
135
|
+
setup, `node_modules/` is not. The project's own `package.json` and lockfile
|
|
136
|
+
do not change. When the project declares npm `workspaces` or a
|
|
137
|
+
`pnpm-workspace.yaml` whose globs match `.harness-tools`, or lint/type/test
|
|
138
|
+
globs that would read it, tell the user before going on.
|
|
139
|
+
|
|
140
|
+
In a fresh clone, or after `node_modules/` was removed, restore the pinned
|
|
141
|
+
version without changing the pin:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
npm ci --prefix <repo>/.harness-tools --omit=dev --ignore-scripts
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
A tarball source records a local `file:` path in `.harness-tools/package.json`
|
|
148
|
+
that does not exist on other machines: install it the same way, but keep the
|
|
149
|
+
whole directory out of Git with `.git/info/exclude` instead of committing it:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
npm install --prefix "$T" --omit=dev --ignore-scripts <file.tgz>
|
|
153
|
+
grep -qxF '.harness-tools/' <repo>/.git/info/exclude || echo '.harness-tools/' >> <repo>/.git/info/exclude
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Outside the project** — any directory the user names, the same commands
|
|
157
|
+
with `--prefix <tooldir>`; nothing is written into the repository.
|
|
158
|
+
|
|
159
|
+
Then:
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
H=<tooldir>/node_modules/.bin/harness
|
|
163
|
+
$H --version
|
|
164
|
+
$H doctor
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Never install the package into the project's own dependencies as part of this
|
|
168
|
+
route, and never put the execution state inside the repository.
|
|
169
|
+
|
|
170
|
+
### 5. Read the project
|
|
171
|
+
|
|
172
|
+
Before choosing gates read: the root and package `package.json` scripts, the
|
|
173
|
+
lockfile, `pnpm-workspace.yaml`, `turbo.json`, every `AGENTS.md`, CI
|
|
174
|
+
workflows (they show which commands the project trusts), code generators
|
|
175
|
+
(OpenAPI, SDK, Prisma) and Relay traces (`relay.config.json`,
|
|
176
|
+
`relay.workspace.json`, `.artifacts/relay/`, Relay commands in AGENTS.md).
|
|
177
|
+
|
|
178
|
+
### 6. Stack profile and gates
|
|
179
|
+
|
|
180
|
+
**A built-in profile fits** when the project already has the scripts it
|
|
181
|
+
calls (`npm-ci` / `pnpm-frozen`: `check`, and `test` writing JUnit to
|
|
182
|
+
`.reports/junit.xml`). Then skip to step 7.
|
|
183
|
+
|
|
184
|
+
**Otherwise write `.harness/profile.json`** (`<pkg>/schemas/stack-profile.schema.json`)
|
|
185
|
+
and pass `--profile ./.harness/profile.json` to `init`. This is the usual
|
|
186
|
+
case for a pnpm/Turborepo monorepo; Turbo Starter is the worked example
|
|
187
|
+
(`<pkg>/docs/turbo-starter.md`, `<pkg>/examples/turbo-starter/policy.json`):
|
|
188
|
+
|
|
189
|
+
- `prepare`: `pnpm install --frozen-lockfile`.
|
|
190
|
+
- check gates (`kind: check`): the project's own type and build commands per
|
|
191
|
+
package, called directly — `pnpm --filter <package> run check-types`,
|
|
192
|
+
`… run build`, with `dependsOn` where one needs another's output. Prefer
|
|
193
|
+
the per-package commands a root script runs when the root script also
|
|
194
|
+
does work that cannot run in a worktree (for example an environment check
|
|
195
|
+
that fails on the pinned Node); that keeps every check the root script
|
|
196
|
+
makes. Leaving out a check the project or its CI runs is the user's
|
|
197
|
+
decision. Never call `turbo run` without `--force` (a cache hit proves
|
|
198
|
+
nothing), and `pnpm exec turbo` only with an exactly pinned `turbo`.
|
|
199
|
+
- test gates (`kind: test`, at least one, with
|
|
200
|
+
`report: { type: junit, path: .artifacts/junit/<gate>.xml }`): an existing
|
|
201
|
+
test command that can write JUnit without new dependencies (Node's test
|
|
202
|
+
runner `--test-reporter=junit --test-reporter-destination=…`, Vitest's
|
|
203
|
+
built-in `junit` reporter). When the project has none, or its AGENTS.md
|
|
204
|
+
forbids tests in product code, put acceptance tests in
|
|
205
|
+
`.harness/acceptance/*.test.mjs` run by `node --test`, as the example does.
|
|
206
|
+
When no command can prove behaviour without adding a dependency, ask.
|
|
207
|
+
- code generation (OpenAPI, SDK): a test gate that runs the project's pinned
|
|
208
|
+
generator and fails on any difference in the generated paths
|
|
209
|
+
(`<pkg>/examples/turbo-starter/harness/acceptance/generation.test.mjs`).
|
|
210
|
+
Generated outputs are not `generatedPaths` (that list means "protected");
|
|
211
|
+
orders that change generated code list the outputs in their write scope.
|
|
212
|
+
`generatedPaths` is only for ignored outputs nobody edits (Prisma client).
|
|
213
|
+
- `protectedPaths`: lockfile, every `package.json`, `pnpm-workspace.yaml`,
|
|
214
|
+
`turbo.json`, `.npmrc`, `scripts/`, `infra/`, CI, every `AGENTS.md`,
|
|
215
|
+
generator inputs and configuration, `.harness/`, `.harness-tools/`.
|
|
216
|
+
- `toolchain`: the package manager version from `packageManager`, and
|
|
217
|
+
`node: ">=24.3"`.
|
|
218
|
+
- `environment.values` for variables the commands need to stay local
|
|
219
|
+
(for example `DOTENV_CONFIG_PATH: /dev/null`, `CHECKPOINT_DISABLE: 1`);
|
|
220
|
+
secrets only by name in `environment.secrets`, never their values.
|
|
221
|
+
|
|
222
|
+
A gate that is red on the current base stays: fixing the base is a separate
|
|
223
|
+
first work order. List the gates with the command each one runs in the
|
|
224
|
+
report.
|
|
225
|
+
|
|
226
|
+
### 7. `harness init`
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
$H init --repository <repo> --writer <claude|codex> --plan
|
|
230
|
+
$H init --repository <repo> --writer <claude|codex>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Add `--profile ./.harness/profile.json` with a local profile. The first call
|
|
234
|
+
writes nothing: read `data.files`, `data.conflicts`,
|
|
235
|
+
`data.toolchain.problems`, `data.facts` and `data.manifest.paths.state`, and
|
|
236
|
+
resolve every conflict or problem with the table of the `harness` skill
|
|
237
|
+
(step 3) before the second call. `init` is create-only: `.harness/.gitignore`,
|
|
238
|
+
`.harness/README.md`, `.harness/project.json` (local, not under Git) and
|
|
239
|
+
`.harness/policy.json`. The state lives outside the repository
|
|
240
|
+
(`HARNESS_STATE_HOME`, `XDG_STATE_HOME` or `~/.local/state/devcontour-harness`).
|
|
241
|
+
|
|
242
|
+
### 8. Runtimes, approval, isolation
|
|
243
|
+
|
|
244
|
+
Edit `.harness/policy.json` only as the decisions require:
|
|
245
|
+
|
|
246
|
+
- models: `model` on `roles.<role>.writer` and on `review.code.reviewer`,
|
|
247
|
+
`review.plan.reviewer`, `review.contract.reviewer`;
|
|
248
|
+
- effort: `effort` (`low`, `medium`, `high`, `xhigh`) only on bindings whose
|
|
249
|
+
`runtime` is `codex`; on any other runtime it is refused;
|
|
250
|
+
- a reviewer of the writer's vendor (an explicit yes only): on
|
|
251
|
+
`review.code` and/or `review.contract`, set `reviewer.runtime` to the
|
|
252
|
+
writer's runtime and add `"vendor": "same-vendor-allowed"`. Leave
|
|
253
|
+
`review.plan` with the other vendor: `init` reads the saved writer from the
|
|
254
|
+
plan reviewer, so changing it makes every later `init --plan` report
|
|
255
|
+
`content-differs` on `policy.json`. When the user wants it anyway, say so
|
|
256
|
+
and let them decide;
|
|
257
|
+
- operator approval: top-level `"approvalMode": "operator"`;
|
|
258
|
+
- isolation: keep `isolation.mode: os`. When `doctor` or a first `prepare`
|
|
259
|
+
shows the sandbox blocking the package store, the network or the Docker
|
|
260
|
+
socket, show the diagnosis and ask between `isolation.domains` and
|
|
261
|
+
`isolation.mode: none`;
|
|
262
|
+
- with the version pin committed inside the project: `.harness-tools/` in
|
|
263
|
+
`repositories[0].protectedPaths` (already there when the local profile
|
|
264
|
+
lists it).
|
|
265
|
+
|
|
266
|
+
Never remove or weaken anything `init` wrote. Keep the writer runtime as
|
|
267
|
+
`init` wrote it: a different writer vendor is a new `init --writer` decision.
|
|
268
|
+
|
|
269
|
+
Check after editing:
|
|
270
|
+
|
|
271
|
+
```sh
|
|
272
|
+
$H doctor --policy <repo>/.harness/policy.json
|
|
273
|
+
$H init --repository <repo> --plan
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`doctor` checks the policy schema, runtimes and toolchain only; `init --plan`
|
|
277
|
+
must show `data.conflicts` = 0. The cross-checks of the policy (effort on a
|
|
278
|
+
non-codex runtime, the reviewer vendor rule, unknown gates) run in
|
|
279
|
+
`$H validate --graph <graph> --policy <repo>/.harness/policy.json`: run it
|
|
280
|
+
for the first graph before any review or run, and fix the policy, not the
|
|
281
|
+
check, when it fails.
|
|
282
|
+
|
|
283
|
+
**Services.** When gates need a database or another service, ask before
|
|
284
|
+
using Docker. With a yes, copy `<pkg>/examples/turbo-starter/harness/`
|
|
285
|
+
(`compose-bridge.mjs`, `compose.acceptance.yml`, `env/`) into `.harness/`,
|
|
286
|
+
adapt the compose model to the project and add `repositories[0].lifecycle`
|
|
287
|
+
(setup, ready, teardown) and the secret names as in
|
|
288
|
+
`<pkg>/docs/turbo-starter.md`; gates that need the service run through
|
|
289
|
+
`node .harness/compose-bridge.mjs exec -- <command>`.
|
|
290
|
+
|
|
291
|
+
### 9. Controller mode
|
|
292
|
+
|
|
293
|
+
When the product AGENTS.md tells an agent to create worktrees, commit, merge,
|
|
294
|
+
move tasks or keep Relay history itself, the harness controller does those
|
|
295
|
+
operations instead, and the worker needs the controller-mode overlay
|
|
296
|
+
(`<pkg>/templates/controller-mode/README.md`). The overlay takes precedence
|
|
297
|
+
over those product rules, so ask first: show the rules it overrides and say
|
|
298
|
+
that the overlay text names Turbo Starter commands (`pnpm worktree:create`,
|
|
299
|
+
`pnpm rest-api-sdk:generate`) as examples. Without a yes, keep controller
|
|
300
|
+
mode off; the harness still refuses a worker commit (`scope-violation`).
|
|
301
|
+
With a yes, build the pack from the committed AGENTS.md files:
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
node --input-type=module -e "
|
|
305
|
+
import { controllerContext } from '<pkg>/examples/turbo-starter/setup.mjs';
|
|
306
|
+
import { execFileSync } from 'node:child_process';
|
|
307
|
+
const repo = '<repo>';
|
|
308
|
+
const baselineSha = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: repo }).toString().trim();
|
|
309
|
+
controllerContext({ repo, baselineSha, upstream: null }, repo + '/.harness/work/context');
|
|
310
|
+
"
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
It writes `.harness/work/context/controller-mode/` (the unchanged overlay,
|
|
314
|
+
`references/` with the product AGENTS.md files, `provenance.json`); a rebuild
|
|
315
|
+
starts from an empty directory and never lists `.harness/`. The pack is not
|
|
316
|
+
committed to the repository (some projects forbid new `.md` files): keep it
|
|
317
|
+
out of Git and rebuild it in a fresh clone with the same command. Its
|
|
318
|
+
`provenance.json` records the `HEAD` it was built on, so a rebuild on another
|
|
319
|
+
commit is a new pack digest and the next Relay snapshot needs a new approval
|
|
320
|
+
even when no AGENTS.md changed.
|
|
321
|
+
|
|
322
|
+
```sh
|
|
323
|
+
grep -qxF '.harness/work/context/controller-mode/' <repo>/.git/info/exclude \
|
|
324
|
+
|| echo '.harness/work/context/controller-mode/' >> <repo>/.git/info/exclude
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
File graphs list `"context": ["controller-mode"]` on every order; Relay tasks
|
|
328
|
+
list it in `tasks[].context` of the connector (step 10). A changed AGENTS.md
|
|
329
|
+
or overlay means rebuilding the pack, and the next snapshot needs a new
|
|
330
|
+
approval; a result already accepted is still delivered.
|
|
331
|
+
|
|
332
|
+
### 10. Task source
|
|
333
|
+
|
|
334
|
+
**Graph files.** Nothing more to configure; the `harness` skill plans the
|
|
335
|
+
first graph.
|
|
336
|
+
|
|
337
|
+
**Relay.** Write `.harness/connector.json` from `<pkg>/docs/connectors.md`
|
|
338
|
+
("Конфигурация"):
|
|
339
|
+
|
|
340
|
+
- `"version": 1` and `"provider": "relay-v1-http"` or `"relay-v2-cli"`,
|
|
341
|
+
always explicit — never guessed from a binary named `relay`;
|
|
342
|
+
- `projectId` and `actor` (`harness-controller`) at the top level;
|
|
343
|
+
`repository.id` is the policy repository id (`app` after `init`);
|
|
344
|
+
- adapter settings nested under `relay`: v1 `relay.endpoint`; Relay-2
|
|
345
|
+
absolute `relay.binary` and `relay.config`, `relay.project` for a workspace,
|
|
346
|
+
`relay.env` that may set `RELAY_HOME` (and on macOS `DYLD_LIBRARY_PATH` to
|
|
347
|
+
SQLite ≥ 3.44) but never `RELAY_CONFIG` or `RELAY_ACTOR`;
|
|
348
|
+
- `tasks[]`: `ref`; `role` and `gates` only from `data.facts` of `init`;
|
|
349
|
+
`writeScope` (required) = the role's `writePaths` from the facts, or, when
|
|
350
|
+
the role has none, `["."]` (the whole repository) or the narrower paths the
|
|
351
|
+
task names (with generated outputs when it changes them); `criteria` mapped
|
|
352
|
+
to a gate and a JUnit `testId`; `"context": ["controller-mode"]` with
|
|
353
|
+
controller mode (step 9) — the pack is read from `contextDir`, by default
|
|
354
|
+
`work/context` next to `connector.json`;
|
|
355
|
+
- `completion: { "mode": "review-only" }` unless the user chose `complete`;
|
|
356
|
+
`eligibility.columns` from the project's board; `history.enabled: true`;
|
|
357
|
+
- no `stateDir` (pass `--state <manifest.paths.state>`), no secret values.
|
|
358
|
+
|
|
359
|
+
Checks that do not write to Relay:
|
|
360
|
+
|
|
361
|
+
```sh
|
|
362
|
+
$H source-check --source <repo>/.harness/connector.json --policy <repo>/.harness/policy.json --state <state>
|
|
363
|
+
$H source-snapshot --source <repo>/.harness/connector.json --policy <repo>/.harness/policy.json --state <state> --out <dir outside the repo>
|
|
364
|
+
$H validate --graph <dir outside the repo>/graph.json --policy <repo>/.harness/policy.json --context <dir outside the repo>/context.json
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
`source-check` is read only. `source-snapshot` reads Relay but records the
|
|
368
|
+
snapshot in the connector state under `--state` and writes `graph.json`,
|
|
369
|
+
`context.json` and `manifest.json` to `--out`; its output names the pinned
|
|
370
|
+
local packs (`localContext`) and a context over the limits as
|
|
371
|
+
`LIMIT_EXCEEDED`. `run --source`,
|
|
372
|
+
`source-deliver` and `source-reconcile` write to Relay: run them only after
|
|
373
|
+
the user says so.
|
|
374
|
+
|
|
375
|
+
### 11. Commit
|
|
376
|
+
|
|
377
|
+
With the user's yes: commit on the setup branch `.harness/.gitignore`,
|
|
378
|
+
`.harness/README.md`, `.harness/policy.json`, `.harness/profile.json`,
|
|
379
|
+
`.harness/connector.json`, `.harness/acceptance/` and the bridge files when
|
|
380
|
+
present, and, for an npm source inside the project,
|
|
381
|
+
`.harness-tools/.gitignore`, `.harness-tools/package.json`,
|
|
382
|
+
`.harness-tools/package-lock.json`. Never `project.json`, `node_modules/` or
|
|
383
|
+
the state or the controller-mode pack. Do not push or merge.
|
|
384
|
+
|
|
385
|
+
### 12. Report and hand over
|
|
386
|
+
|
|
387
|
+
Report: installed version (and the tarball sha256), `doctor`, every decision
|
|
388
|
+
of the table with its reason, the gates with their commands, the policy
|
|
389
|
+
edits, controller mode, the connector check and snapshot (`graphId`,
|
|
390
|
+
`graphDigest`, eligibility per task), the commit SHA. Then continue with the
|
|
391
|
+
`harness` skill: brief → `plan-request` → draft → `plan-check` → `validate`
|
|
392
|
+
→ `run` (for Relay: `review-plan` and `run --source`). A live `run` or
|
|
393
|
+
`review-plan` calls paid models: start it when the user asks.
|
|
394
|
+
|
|
395
|
+
## Upgrade
|
|
396
|
+
|
|
397
|
+
An upgrade changes only the package. Policy, profiles, graphs, accepted
|
|
398
|
+
results and `.harness/project.json` stay as they are unless the user decides
|
|
399
|
+
otherwise in step 7.
|
|
400
|
+
|
|
401
|
+
1. **Current and target.** `$H --version`; target from the user, or
|
|
402
|
+
`npm view devcontour-harness dist-tags`. Install the target into a scratch
|
|
403
|
+
directory outside the repository (`N=<scratch>/node_modules/.bin/harness`)
|
|
404
|
+
and read its `docs/release-notes/<version>.md` and the format matrix of
|
|
405
|
+
`docs/upgrade.md` for every version in between.
|
|
406
|
+
2. **Stop the writers.** `$H status --state <state>`; `$H pause --state <state>`;
|
|
407
|
+
wait for active attempts to finish or ask the user to stop them; stop every
|
|
408
|
+
`run` process on this state. A paused queue alone is not enough.
|
|
409
|
+
3. **Record.** `git rev-parse refs/heads/harness/accepted` and
|
|
410
|
+
`$H result --state <state> --work <id>` for the accepted orders.
|
|
411
|
+
4. **Copy the state** while nothing writes: `cp -Rp <state> <state>.bak-<old version>`.
|
|
412
|
+
5. **Check on a second copy** with the target version: `$N doctor --state <copy>`
|
|
413
|
+
and `$N status --state <copy>`. Hash the copy's files before and after;
|
|
414
|
+
they must not change. Stop and report when `doctor` shows
|
|
415
|
+
`data.state.compatible: false` or `status` fails with
|
|
416
|
+
`STATE_VERSION_UNSUPPORTED`.
|
|
417
|
+
6. **Install** into the same `<tooldir>`:
|
|
418
|
+
`npm install --prefix <tooldir> --save-exact --omit=dev --ignore-scripts devcontour-harness@<new>`
|
|
419
|
+
(or the new `.tgz` after its sha256 check).
|
|
420
|
+
7. **Verify.**
|
|
421
|
+
- `$H --version`; `$H doctor --state <state> --policy <repo>/.harness/policy.json`.
|
|
422
|
+
- `$H init --repository <repo> --plan` must show `data.conflicts` = 0.
|
|
423
|
+
`content-differs` on `.harness/project.json` means a saved decision no
|
|
424
|
+
longer matches: the built-in profile digest changed (compare
|
|
425
|
+
`$H profile --profile <id>` with the pin in `project.json`), the
|
|
426
|
+
repository moved (`root`, `projectId`), or the API version changed.
|
|
427
|
+
Show the difference to the user. With their yes, move the manifest out
|
|
428
|
+
of the repository, next to the state copy of step 4
|
|
429
|
+
(`mv <repo>/.harness/project.json <state>.bak-<old version>/project.json`),
|
|
430
|
+
and run
|
|
431
|
+
`$H init --repository <repo> --profile <saved profile.ref> --writer <saved runtimes.writer> --state <saved paths.state>`
|
|
432
|
+
with the values of the moved manifest, so the profile choice and the state
|
|
433
|
+
path are kept; never edit the manifest by hand.
|
|
434
|
+
- The policy is not regenerated. List gates or defaults of the new profile
|
|
435
|
+
that the policy lacks and add them only with the user's yes; never weaken
|
|
436
|
+
the existing ones. A changed policy changes the facts of planning, so
|
|
437
|
+
graphs may need plan review or approval again (`explain` names it).
|
|
438
|
+
- `$H validate --graph <graph> --policy <repo>/.harness/policy.json` for
|
|
439
|
+
every `.harness/work/*.json` graph.
|
|
440
|
+
- Read the release notes for new options the setup should use (for
|
|
441
|
+
example `tasks[].context` of the connector for controller mode) and
|
|
442
|
+
propose them; do not apply them unasked.
|
|
443
|
+
8. **Resume.** `$H resume --state <state>`, then `run` as before. Attempts that
|
|
444
|
+
were active at the stop are not continued with old tokens; recovery either
|
|
445
|
+
accepts a saved integration SHA or ends the attempt.
|
|
446
|
+
9. **Commit** the changed `.harness-tools/package.json` and
|
|
447
|
+
`package-lock.json` on a branch, with the user's yes.
|
|
448
|
+
|
|
449
|
+
Rollback: stop the writers again; reinstall the old exact version; when the
|
|
450
|
+
new version already wrote state the old one cannot read, restore the copy of
|
|
451
|
+
step 4 and reconcile `harness/accepted` with the recorded SHAs
|
|
452
|
+
(`docs/upgrade.md`, "Откат"). Never `git reset --hard` the user's repository.
|
|
453
|
+
|
|
454
|
+
## Check
|
|
455
|
+
|
|
456
|
+
Read only: `$H --version`, `$H doctor`, `$H init --repository <repo> --plan`,
|
|
457
|
+
`$H status --state <paths.state>`, and the pin in
|
|
458
|
+
`.harness-tools/package.json` when present. Report a mismatch between the pin
|
|
459
|
+
and `$H --version`, or a missing `node_modules/` (restore with `npm ci`, step
|
|
460
|
+
4); do not fix it unasked.
|
|
461
|
+
|
|
462
|
+
## Don'ts
|
|
463
|
+
|
|
464
|
+
- Do not ask what the repository answers, and do not decide a fork of the
|
|
465
|
+
table for the user: the vendors, a reviewer of the writer's vendor,
|
|
466
|
+
controller mode, a left-out project check, isolation, Docker, project rule
|
|
467
|
+
conflicts, commits, writes to Relay and live runs are theirs.
|
|
468
|
+
- Do not install into the project's dependencies, edit its `package.json` or
|
|
469
|
+
lockfile (except when bootstrapping a new project with consent), or put the
|
|
470
|
+
state inside the repository.
|
|
471
|
+
- Do not weaken gates, budgets, isolation or the reviewer rule, and do not set
|
|
472
|
+
`same-vendor-allowed` without an explicit yes.
|
|
473
|
+
- Do not overwrite `.harness/project.json` or `.harness/policy.json` on a
|
|
474
|
+
`content-differs`; that is a decision to show to the user.
|
|
475
|
+
- Do not write to Relay, call live models, push, tag or publish without being
|
|
476
|
+
asked.
|
|
477
|
+
- Do not upgrade while a controller writes the state, and do not skip the
|
|
478
|
+
state copy.
|
|
@@ -27,6 +27,11 @@ not a file committed to the target repository. Some projects forbid new
|
|
|
27
27
|
4. Add `"context": ["controller-mode"]` to every order of the graph. Writer
|
|
28
28
|
and reviewers then see the same pinned bytes, and a changed overlay
|
|
29
29
|
requires a new plan approval.
|
|
30
|
+
For tasks read from Relay, list the pack in the connector instead:
|
|
31
|
+
`"context": ["controller-mode"]` on each entry of `tasks[]`, with the
|
|
32
|
+
directory at `<contextDir>/controller-mode` (`contextDir` defaults to
|
|
33
|
+
`work/context` next to `connector.json`). The snapshot pins it the same
|
|
34
|
+
way, and a changed overlay needs a new snapshot and approval.
|
|
30
35
|
5. Protect the product AGENTS.md files and the harness setup through the
|
|
31
36
|
policy's `protectedPaths`. The worker cannot change the rules it runs
|
|
32
37
|
under.
|