agents-handoff 2.0.2 → 2.0.3

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/docs/CLI.md CHANGED
@@ -9,8 +9,9 @@ dependencies; there is no build step and nothing to install to run them from a c
9
9
 
10
10
  | Executable | Role | Invoked as |
11
11
  |---|---|---|
12
- | [`tools/handoff.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/tools/handoff.mjs) | Capture engine: transcript in, handoff folder out. | `node tools/handoff.mjs <verb>`, or the published `agent-handoff` bin |
13
- | [`tools/agent-handoff.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/tools/agent-handoff.mjs) | Runtime layer: acts on the state of the store. | `node tools/agent-handoff.mjs <verb>` |
12
+ | [`tools/handoff.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/tools/handoff.mjs) | Capture engine: transcript in, handoff folder out. | `node tools/handoff.mjs <verb>`, or the published `agents-handoff` bin |
13
+ | [`tools/agents-handoff.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/tools/agents-handoff.mjs) | Runtime layer: acts on the state of the store. | `node tools/agents-handoff.mjs <verb>` |
14
+ | [`tools/agent-handoff.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/tools/agent-handoff.mjs) | Compatibility forwarder: the runtime layer's pre-rename path, kept so older notes and hooks keep working. | `node tools/agent-handoff.mjs <verb>` (forwards to `tools/agents-handoff.mjs`) |
14
15
  | [`tools/runtime-engine.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/tools/runtime-engine.mjs) | Bounded execution: evaluates an operation against the policy before running it. | `node tools/runtime-engine.mjs <verb>` |
15
16
  | [`tools/capability-registry.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/tools/capability-registry.mjs) | Health probes for declared capabilities. | `node tools/capability-registry.mjs <verb>` |
16
17
  | [`install/install.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/install/install.mjs) | Installs, updates and removes the skill. | `npx agents-handoff <verb>` |
@@ -60,7 +61,7 @@ source hash writes nothing and prints `handoff: up-to-date`.
60
61
  | 3 | The id prefix matched more than one session, or none. |
61
62
  | 4 | No match for `show`/`verify`/`rename`/`retitle`; also `build` when no turn could be parsed from the source. |
62
63
 
63
- ## `tools/agent-handoff.mjs` — runtime layer
64
+ ## `tools/agents-handoff.mjs` — runtime layer
64
65
 
65
66
  Acts on the state of the store rather than being invoked per file. Every mutating command
66
67
  takes a lock in `<root>/.locks/`, so two runs cannot capture or merge the same session at
@@ -77,6 +78,11 @@ once. Behaviour per command is described in [LEVEL4.md](LEVEL4.md).
77
78
  | `self-improve` | Scan for brief shortfalls and write a rules candidate file. |
78
79
  | `index` | Rebuild `INDEX.json` and report sessions with no `HANDOFF.md`. |
79
80
 
81
+ `tools/agent-handoff.mjs` is a forwarder, not a second implementation: it spawns
82
+ `tools/agents-handoff.mjs`, passes every argument through, and exits with the same code. Its
83
+ stdout and stderr are the runtime's own. Use the new path in anything you write today; the
84
+ old one exists only so a command that already names it does not break.
85
+
80
86
  `auto` flags: `--source` (required), `--session`, `--harness`, `--project`, `--min-fresh-ms`.
81
87
  `dispatch` flags: `--task` (required), `--role` (default `implementation-agent`), `--parent`
82
88
  (default `handoff:<id>`), `--broker <root>`, `--live`.
@@ -147,21 +153,41 @@ Probe kinds: `file-exists`, `dir-writable`, `command` (with `command` and `args`
147
153
  | 4 | Unknown capability id, or a usage error. |
148
154
 
149
155
  State is written to `<state>/capability-state.json`, where `<state>` is
150
- `AGENT_HANDOFF_STATE_DIR` or `.agent-handoff/`.
156
+ `AGENT_HANDOFF_STATE_DIR` or `.agents-handoff/`.
151
157
 
152
158
  ## `install/install.mjs` — installer
153
159
 
154
160
  Published as `agents-handoff`. Location resolution is documented in
155
161
  [INSTALL.md](INSTALL.md).
156
162
 
157
- | Verb | Effect |
163
+ A bare verb and its flag form are the same command: `npx agents-handoff update` and
164
+ `npx agents-handoff --update` behave identically.
165
+
166
+ | Verb | Flag form | Effect |
167
+ |---|---|---|
168
+ | `install` (default), `i` | `--install` | Install the skill into every selected target. |
169
+ | `update`, `u` | `--update` | Update to the latest or a named version. |
170
+ | `remove`, `rm` | `--remove` | Remove the installation, keeping everything that is not the installer's. |
171
+ | `verify`, `v` | `--verify` | Verify each installation against the record written when it was installed. |
172
+ | `verify-package`, `vp` | `--verify-package` | Verify each installation against the tarball npm publishes for its version. |
173
+ | `list`, `ls` | `--list` | List every installed location, with its provenance state. |
174
+ | `where` | — | Show the resolved global root and why it was chosen. |
175
+ | `doctor` | `--doctor` | Report which harnesses exist here, what is installed where, and whether each installation still matches its record. Read-only: it never installs. |
176
+ | `help` | `--help`, `-h` | Print the usage block. |
177
+
178
+ Harness targets. With no harness flag the installer keeps its historical single target
179
+ (`--location` / `--path`); any of these switches to named targets, and several may be combined
180
+ in one run — each target gets its own copy and its own install record.
181
+
182
+ | Flag | Target |
158
183
  |---|---|
159
- | `install` (default) | Install the skill. |
160
- | `update` | Update to the latest or a specified version. |
161
- | `remove` | Remove the installation. |
162
- | `verify` | Verify installation integrity. |
163
- | `list` | List every installed location. |
164
- | `where` | Show the resolved global root and why it was chosen. |
184
+ | `--claude` | `~/.claude/skills/` — Claude Code personal skills. |
185
+ | `--codex` | `~/.codex/skills/` — Codex CLI personal skills. |
186
+ | `--agents` | `~/.agents/skills/` — the harness-neutral store. |
187
+ | `--harness <a,b>` | Named harnesses, comma separated; repeatable. |
188
+ | `--all` | Every harness whose directory exists on this machine. |
189
+ | `--skills-dir <dir>` | Any other stack, exactly; repeatable. |
190
+ | `--project` | Use the per-repository form of the harness directories (`./.claude/skills`, `./.codex/skills`). |
165
191
 
166
192
  | Flag | Meaning |
167
193
  |---|---|
@@ -169,13 +195,89 @@ Published as `agents-handoff`. Location resolution is documented in
169
195
  | `--path <dir>` | Install to an exact directory. |
170
196
  | `--version latest\|<v>` | Version to install. Default `latest`. |
171
197
  | `--force`, `-f` | Skip confirmations and overwrite. |
198
+ | `--provenance` | With `verify`: print the install record the check was run against. |
199
+ | `--record` | With `verify-package`: store the fetched tarball hashes in the install record. |
200
+
201
+ ### `update` and `verify` with no harness flag
202
+
203
+ A machine can hold the same skill in several places at once — `~/.claude/skills` for Claude
204
+ Code, `~/.agents/skills` for a neutral store, an account-skill store a desktop client reads.
205
+ With no harness flag, `update` and `verify` act on **every** installation they can find rather
206
+ than on the single target the resolver happens to pick, because updating only the resolved one
207
+ is how a second harness keeps an old engine without anyone noticing.
208
+
209
+ The search covers the resolved global root, `./local/skills`, `./skills`, `~/.claude/skills`,
210
+ `~/.codex/skills`, `~/.agents/skills`, each harness's per-repository form, and every
211
+ account-skill root discovered under the platform's application-data directories. `update`
212
+ reports one line per installation, with the version before and after; `verify` fails the run
213
+ when any copy fails. Neither touches a store, `handoff.config.json` or any file the install
214
+ manifest does not name.
215
+
216
+ ### Exit codes
217
+
218
+ | Code | Meaning |
219
+ |---|---|
220
+ | 0 | The command ran and everything it checked passed. |
221
+ | 1 | Any failure: a usage error, nothing installed to act on, a verification that did not match, or a `verify-package` mismatch. |
222
+
223
+ ### The install record
224
+
225
+ Every install writes `.agents-handoff-install.json` into the copy it just made. [FORMAT.md](FORMAT.md)
226
+ lists the fields and [PROVENANCE.md](PROVENANCE.md) states what the record does and does not prove.
227
+
228
+ | Field | Contents |
229
+ |---|---|
230
+ | `schema_version` | `1.0-install-provenance`. |
231
+ | `product`, `version` | `agents-handoff`, and the version read back out of the installed `SKILL.md`. |
232
+ | `installer_version` | The installer package's own version. |
233
+ | `installed_at` | ISO timestamp of the write. |
234
+ | `harness` | The harness the copy went into, or `null` for the resolved single target. |
235
+ | `target` | Absolute install directory. |
236
+ | `source` | What the copy was made from: `{kind: "tree", path}` for a checkout or release archive, or `{kind: "archive", ref, label, archive_url, archive_sha256}` for a fetched tag archive. |
237
+ | `package` | The npm identity this install should match: `name`, `version`, `registry`, `tarball`, `sha256`, `sha512`, `integrity`, `shasum`, `verified_at`. The hashes are `null` until `verify-package --record` fills them, because a copy made from a tree is not the published tarball. |
238
+ | `file_count`, `manifest_entries` | Files present, and entries in the installer's manifest. |
239
+ | `files_sha256` | One sha256 folded over every manifest path together with that file's own hash. |
240
+ | `files` | Per-path sha256, or `missing` for a path this version does not have. |
241
+
242
+ ### What `verify` compares
243
+
244
+ For each installation: that every manifest file exists (a path the version never had is
245
+ reported as not part of that version rather than failed), that `SKILL.md` carries a name and a
246
+ version, that the engine actually runs — `tools/handoff.mjs config` must exit 0 with its
247
+ resolved-root marker, which also proves the import graph resolves — and that a recomputed
248
+ `files_sha256` equals the recorded one. An installation made before this record existed is
249
+ reported as having none, never silently passed.
250
+
251
+ ### What `verify-package` checks, and in what order
252
+
253
+ Each step makes the next one meaningful:
254
+
255
+ 1. **The registry's own hashes.** The tarball is downloaded for the installed version and must
256
+ match the `integrity` (sha512) and `shasum` (sha1) the registry declares for it; otherwise
257
+ "the published package" is just whatever the network handed over.
258
+ 2. **Per-file identity.** The manifest is compared file by file against the extracted tarball,
259
+ and every difference is named (`not installed`, `not in the published package`, or
260
+ `content differs`).
261
+ 3. **The recorded hash.** When the install record already holds a package `sha256`, it must
262
+ match too.
263
+
264
+ Without `--record` nothing is written; with it, the fetched `sha256`, `sha512`, `integrity`
265
+ and `shasum` are stored in `package`. A version that is not on the registry cannot pass this
266
+ check, and it says so rather than reporting success.
267
+
268
+ ### What `remove` deletes
269
+
270
+ `remove` deletes what the install manifest owns, plus the record it wrote itself and the
271
+ `private` `package.json` stub it created — and nothing else. Store directories, notes, a
272
+ `handoff.config.json`, and any file a later version treats as user data survive by default,
273
+ and every entry that was left is printed under `Kept — not the installer's to delete:`.
172
274
 
173
275
  ## Environment variables
174
276
 
175
277
  | Variable | Read by | Effect |
176
278
  |---|---|---|
177
279
  | `HANDOFFS_ROOT` | capture engine, runtime layer | Store root. Always wins over every other rule. |
178
- | `AGENT_HANDOFF_STATE_DIR` | runtime engine, capability registry | State directory for executions, checkpoints, jobs and capability state. Default `<repo>/.agent-handoff`. |
280
+ | `AGENT_HANDOFF_STATE_DIR` | runtime engine, capability registry | State directory for executions, checkpoints, jobs and capability state. Default `<repo>/.agents-handoff`. |
179
281
  | `AGENT_HANDOFF_GLOBAL_DIR` | installer | Overrides the resolved global install root. |
180
282
 
181
283
  ## Files written
@@ -191,6 +293,7 @@ Published as `agents-handoff`. Location resolution is documented in
191
293
  | `<state>/jobs/<session>/work.log` | `runtime-engine job` |
192
294
  | `<state>/capability-state.json` | `capability-registry check` |
193
295
  | `<skill>/docs/self-improve-candidates.json` | `self-improve` |
296
+ | `<install>/.agents-handoff-install.json` | `install`, `update`, `verify-package --record` |
194
297
 
195
298
  `self-improve` writes inside the skill directory on purpose: the candidate file describes the
196
299
  skill's brief rules, so a configured store never collects rule candidates.
@@ -91,7 +91,7 @@ Checklist:
91
91
  - Keep the exit codes. They are contracts (see the table above and
92
92
  [INTEGRATION.md](INTEGRATION.md)).
93
93
  - Never commit session data or credentials: no `handoffs/`, `projects/`, `links/`,
94
- `.agent-handoff/`, no `*.key`, `*.pem`, `*.token`, and no transcript copied from a real
94
+ `.agents-handoff/`, no `*.key`, `*.pem`, `*.token`, and no transcript copied from a real
95
95
  session. Test input belongs in `tests/fixtures/`.
96
96
  - A behaviour change comes with a test in `tools/handoff.test.mjs` and an update to the
97
97
  document that owns the contract: [FORMAT.md](FORMAT.md) for the files and fields,
@@ -108,7 +108,7 @@ Checklist:
108
108
  | `docs/` | These documents. |
109
109
  | `install/` | `install.mjs`, the `npx` installer, and its own README. |
110
110
  | `tools/handoff.mjs` | The handoff engine: build, list, show, verify, rename, retitle, config. |
111
- | `tools/agent-handoff.mjs` | The runtime verbs layered over the engine. |
111
+ | `tools/agents-handoff.mjs` | The runtime verbs layered over the engine. |
112
112
  | `tools/runtime-engine.mjs` | Permission policy, bounded execution, checkpoints and resume. |
113
113
  | `tools/capability-registry.mjs` | Probes declared capabilities and reports honest verdicts. |
114
114
  | `tools/handoff.test.mjs` | The test suite. |
package/docs/FORMAT.md CHANGED
@@ -62,6 +62,34 @@ project recorded in its manifest.
62
62
  Renders (`HANDOFF.md`, the two JSON payloads) are rewritten on every build; `timeline.jsonl`
63
63
  is not.
64
64
 
65
+ ## Installed-copy artifacts (not part of a session)
66
+
67
+ Two files belong to an INSTALLATION rather than to a session, and neither is written by the
68
+ capture engine. They sit in the directory the installer copied into, beside `SKILL.md`, and
69
+ nothing above in this document describes them.
70
+
71
+ | File | Written by | Contents |
72
+ |---|---|---|
73
+ | `package.json` | `install`, `update` | Only when the directory has none. A minimal manifest marked `private`, so the copy can report its own version and cannot be published to npm by accident. |
74
+ | `.agents-handoff-install.json` | `install`, `update` | The install record: what version landed, from which source, and a sha256 over the installed file set. |
75
+
76
+ The install record:
77
+
78
+ | Field | Meaning |
79
+ |---|---|
80
+ | `schema_version` | `1.0-install-provenance`. |
81
+ | `product`, `version` | The skill this is a copy of, and the version that landed, read back out of the installed `SKILL.md`. |
82
+ | `installer_version`, `installed_at` | The installer that wrote the record, and when. |
83
+ | `harness`, `target` | The harness the copy went to (`claude`, `codex`, `agents`) when one was named, else `null`, and the absolute target path. |
84
+ | `source` | `{kind: 'tree', path}` for a copy made from a tree beside the installer, or `{kind: 'archive', ref, label, archive_url, archive_sha256}` when the copy was fetched instead. |
85
+ | `file_count`, `files_sha256` | How many manifest files the copy holds, and one sha256 over all of them. |
86
+ | `files` | Per-path sha256 values, so a mismatch names the file that changed. |
87
+
88
+ `verify` re-hashes the manifest files, recomputes `files_sha256` and fails when one changed or
89
+ went missing. An installation made before this record existed has none: `verify` says so and
90
+ checks everything else, and treats the absence as neither a pass nor a failure.
91
+ [PROVENANCE.md](PROVENANCE.md) states what the record proves and what it cannot.
92
+
65
93
  ## manifest.json
66
94
 
67
95
  | Field | Meaning |
package/docs/INSTALL.md CHANGED
@@ -4,7 +4,7 @@ title: Installation
4
4
 
5
5
  # Installation
6
6
 
7
- agent-handoff turns a working session into a portable handoff folder, and verifies that folder
7
+ agents-handoff turns a working session into a portable handoff folder, and verifies that folder
8
8
  later. It is a Node.js command-line skill with no runtime dependencies.
9
9
 
10
10
  ## Requirements
@@ -13,16 +13,23 @@ later. It is a Node.js command-line skill with no runtime dependencies.
13
13
  |---|---|
14
14
  | Node.js >= 18.0.0 | The engine uses ES modules and `node:fs`. |
15
15
  | `unzip` | Only needed to extract a release archive by hand. |
16
- | No network at run time | The engine never makes a network call. |
16
+ | `tar` | Only needed when the installer fetches an archive instead of copying the tree beside it. |
17
+ | No network at run time | The engine never makes a network call. `npx` and `--verify-package` do. |
17
18
 
18
19
  ## Quick start
19
20
 
20
21
  ```bash
21
- npx agents-handoff
22
+ npx agents-handoff --all # every harness found on this machine
22
23
  ```
23
24
 
24
- The installer copies the skill files into the resolved global root, then reports how many files
25
- it copied. Confirm the installation:
25
+ One run covers one harness, several, or a directory of your own; the table in
26
+ [Install into the harness you use](#install-into-the-harness-you-use) has the whole set. The
27
+ installer copies the skill files into the resolved global root (or the harness directories
28
+ named), then reports how many files it copied. The published package carries the whole tree, so
29
+ this needs no download; only a bare copy of `install/` falls back to fetching the archive for
30
+ the requested version.
31
+
32
+ Confirm the installation:
26
33
 
27
34
  ```bash
28
35
  node "<install-path>/tools/handoff.mjs" config
@@ -37,6 +44,99 @@ handoff: config file=none
37
44
  handoff: config schema=<dir>/handoff.config.schema.json
38
45
  ```
39
46
 
47
+ ## Installing from GitHub
48
+
49
+ Two ways, and both install the same tree:
50
+
51
+ ```bash
52
+ # npm runs the repository's own package straight from GitHub — no registry copy involved
53
+ npx github:Alot1z/agent-handoff --all
54
+
55
+ # or clone it and run the installer from the checkout
56
+ git clone https://github.com/Alot1z/agent-handoff.git
57
+ cd agent-handoff
58
+ node install/install.mjs --all
59
+ ```
60
+
61
+ The clone is also the way to install a version that is not on npm at all: a branch, a commit or
62
+ a tag. The installer accepts the same flags either way, and a checkout installs the tree in front
63
+ of it.
64
+
65
+ ## Install into the harness you use
66
+
67
+ With no harness flag the installer uses the resolved global root (next section). A harness flag
68
+ puts the skill where that tool reads its skills, and several flags cover several tools in one
69
+ run:
70
+
71
+ ```bash
72
+ npx agents-handoff --claude # Claude Code
73
+ npx agents-handoff --codex # Codex CLI
74
+ npx agents-handoff --agents # the harness-neutral store
75
+ npx agents-handoff --all # every harness found on this machine
76
+ npx agents-handoff --claude --codex # exactly these two, one run
77
+ npx agents-handoff --harness claude,codex
78
+ npx agents-handoff --skills-dir ~/.config/mytool/skills
79
+ npx agents-handoff --project --claude # this repository only (./.claude/skills)
80
+ ```
81
+
82
+ | Flag | Harness | User-level directory | Per-repository directory, with `--project` |
83
+ |---|---|---|---|
84
+ | `--claude` | Claude Code | `~/.claude/skills` | `./.claude/skills` |
85
+ | `--codex` | Codex CLI | `~/.codex/skills` | `./.codex/skills` |
86
+ | `--agents` | the harness-neutral store | `~/.agents/skills` | `./.agents/skills` |
87
+ | `--harness <a,b>` | named harness(es), comma separated, repeatable | as above | as above |
88
+ | `--skills-dir <dir>` | any other stack, exactly | `<dir>` | `<dir>` |
89
+ | `--all` | every harness whose configuration directory exists here | as above | — |
90
+
91
+ Each target gets the skill folder `agents-handoff/` below that directory, so Claude Code finds
92
+ `~/.claude/skills/agents-handoff/`. Targets are installed, reported and recorded one by one,
93
+ and the run ends with a summary:
94
+
95
+ ```
96
+ ── target 1 of 2: claude ──
97
+ ✓ Installed agents-handoff v<version> to <dir>/agents-handoff
98
+ Provenance: the tree beside the installer (.) · file-set sha256 3dab5c0d754a27fd… (.agents-handoff-install.json)
99
+
100
+ ── target 2 of 2: custom dir <dir> ──
101
+ …
102
+
103
+ Summary
104
+ ✓ installed <dir> — v<version>
105
+ ✓ installed <dir> — v<version>
106
+ ```
107
+
108
+ `--all` installs into the harnesses whose configuration directory exists in your home directory
109
+ and names the ones it skipped; `--claude` and its siblings install there whether or not the
110
+ directory exists yet. Detection is a suggestion, never a decision.
111
+
112
+ Ask what this machine has, and whether what is installed is still intact:
113
+
114
+ ```bash
115
+ npx agents-handoff doctor
116
+ ```
117
+
118
+ ```
119
+ agents-handoff doctor
120
+ product v<version> · installer v<version> · node v<node version>
121
+
122
+ Harnesses
123
+ ✓ claude present <home>/.claude/skills
124
+ v<version> · 39/39 files · provenance OK
125
+ · codex not found <home>/.codex/skills
126
+ ✓ agents present <home>/.agents/skills
127
+
128
+ Global resolution
129
+ <dir> — <reason>
130
+
131
+ Store (where handoffs are written)
132
+ handoff: config root=<dir>
133
+
134
+ Verdict
135
+ 1 harness installation(s) found.
136
+ ```
137
+
138
+ `doctor` reads and reports. It never installs, updates or removes anything.
139
+
40
140
  ## Where a global install goes
41
141
 
42
142
  `--location global` does not point at a fixed directory. The installer searches for a store and
@@ -45,7 +145,7 @@ reports the reason it chose one. The order is:
45
145
  | # | Condition | Result |
46
146
  |---|---|---|
47
147
  | 1 | `AGENT_HANDOFF_GLOBAL_DIR` is set | that directory |
48
- | 2 | A skill store already holds an `agent-handoff` install | the newest such location |
148
+ | 2 | A skill store already holds an `agents-handoff` install | the newest such location |
49
149
  | 3 | `~/.agents/skills` exists | `~/.agents/skills` |
50
150
  | 4 | A skill store exists | its first account-skill root |
51
151
  | 5 | Nothing found | the default store, created on install |
@@ -53,7 +153,7 @@ reports the reason it chose one. The order is:
53
153
  An account-skill store keeps skills two identifier levels below the store itself:
54
154
 
55
155
  ```
56
- <store>/<account-id>/<profile-id>/agent-handoff/
156
+ <store>/<account-id>/<profile-id>/agents-handoff/
57
157
  ```
58
158
 
59
159
  `<store>` is `%APPDATA%\<client>\account-skills` on Windows, and `~/.<client>/account-skills` or
@@ -72,17 +172,18 @@ Global install root: <dir>
72
172
  override with: AGENT_HANDOFF_GLOBAL_DIR=<dir> or --path <dir>
73
173
  ```
74
174
 
75
- `--list` shows the resolved root, the local location, every candidate root, the harness skills
76
- home, and — inside a git repository — the project location. Each installed location is printed
77
- with its version and the number of manifest files present.
175
+ `--list` shows the resolved root, the local location, every candidate root, each harness
176
+ directory (whether or not it exists on this machine), and — inside a git repository — the
177
+ project location. Each installation found is printed with its version, the number of manifest
178
+ files present, and whether it still matches its install record.
78
179
 
79
180
  ## Locations
80
181
 
81
182
  | Location | Target directory |
82
183
  |---|---|
83
- | `global` (default) | `<resolved global root>/agent-handoff` |
84
- | `local` | `./local/skills/agent-handoff` |
85
- | `project` | `./skills/agent-handoff` |
184
+ | `global` (default) | `<resolved global root>/agents-handoff` |
185
+ | `local` | `./local/skills/agents-handoff` |
186
+ | `project` | `./skills/agents-handoff` |
86
187
  | `--path <dir>` | exactly `<dir>` |
87
188
 
88
189
  ## Options
@@ -93,21 +194,31 @@ with its version and the number of manifest files present.
93
194
  | `--path <dir>` | none | Use this directory instead of a resolved location. |
94
195
  | `--version <v>` | `latest` | Request a version. Confirm what landed with `--verify`, which prints the installed version. |
95
196
  | `--force`, `-f` | off | Skip confirmations and overwrite an existing installation. |
197
+ | `--claude`, `--codex`, `--agents` | none | Install into that harness's skills directory (table above). Repeatable, and combinable. |
198
+ | `--harness <a,b>` | none | Named harness(es), comma separated. Repeatable. |
199
+ | `--all` | none | Every harness whose configuration directory exists on this machine. |
200
+ | `--skills-dir <dir>` | none | Any other stack, exactly. Repeatable. |
201
+ | `--project` | off | With a harness flag: use the per-repository directory instead of the user-level one. |
202
+ | `--provenance` | off | With `verify`: print the install record the verification was checked against. |
203
+ | `--record` | off | With `verify-package`: store the tarball hashes in the install record. |
96
204
  | `--help`, `-h` | — | Print the installer usage text. |
97
205
 
98
206
  The installer accepts both bare verbs and flag forms: `install`/`--install`, `update`/`--update`,
99
- `remove`/`--remove`, `verify`/`--verify`, `list`/`--list`.
207
+ `remove`/`--remove`, `verify`/`--verify`, `verify-package`/`--verify-package`, `list`/`--list`,
208
+ `doctor`/`--doctor`.
100
209
 
101
210
  ## Commands
102
211
 
103
212
  | Command | Description |
104
213
  |---|---|
105
214
  | `install`, `i` (default) | Copy the skill files to the target. |
106
- | `update`, `u` | Reinstall over an existing installation. See [UPGRADE.md](UPGRADE.md). |
107
- | `remove`, `rm` | Remove the installation. See [UNINSTALL.md](UNINSTALL.md). |
108
- | `verify`, `v` | Check every manifest file, the skill metadata, and that the engine runs. |
109
- | `list`, `ls` | List installed locations with version and manifest file count. |
215
+ | `update`, `u` | Update every installation found, or the harnesses named. See [UPGRADE.md](UPGRADE.md). |
216
+ | `remove`, `rm` | Remove an installation, keeping everything the manifest does not own. See [UNINSTALL.md](UNINSTALL.md). |
217
+ | `verify`, `v` | Check every installation found: each manifest file, the skill metadata, that the engine runs, and the install record. |
218
+ | `verify-package`, `vp` | Check an installation against the published npm tarball for its version. |
219
+ | `list`, `ls` | List installed locations with version, manifest file count and provenance state. |
110
220
  | `where` | Print the global root and why it was chosen. |
221
+ | `doctor` | Which harnesses are present here, what is installed where, and whether each installation still matches its record. |
111
222
 
112
223
  ## Verify an installation
113
224
 
@@ -115,18 +226,115 @@ The installer accepts both bare verbs and flag forms: `install`/`--install`, `up
115
226
  npx agents-handoff --verify
116
227
  ```
117
228
 
118
- Verification runs three kinds of check:
229
+ Verification runs four kinds of check:
119
230
 
120
231
  1. every file named in the installer manifest exists in the target;
121
232
  2. `SKILL.md` declares both `name` and `version`;
122
233
  3. `node tools/handoff.mjs config` exits 0 and prints the `handoff: config root=` marker — this
123
- exercises the engine's module graph, so a missing module fails here.
234
+ exercises the engine's module graph, so a missing module fails here;
235
+ 4. the installation still matches the provenance record written when it was installed.
124
236
 
125
237
  Each check is printed with a pass or fail mark. On success the installer also prints the
126
- installed location and version; on failure it exits non-zero and tells you to reinstall.
238
+ installed location and version; on failure it exits non-zero and names the files that changed.
239
+
240
+ With no harness flag, `--verify` verifies **every installation found on this machine**, not just
241
+ the one the global resolver would pick: a machine that holds the skill in `~/.claude/skills` and
242
+ in `~/.agents/skills` has two copies, and both are checked. A harness flag or `--skills-dir`
243
+ scopes the run to those targets. The run fails if any installation fails.
127
244
 
128
245
  There is no `--verbose` flag.
129
246
 
247
+ ## Prove an installation matches the published package
248
+
249
+ `--verify` compares an installation with its own record. `--verify-package` compares it with the
250
+ artifact npm is actually serving for its version — the strongest check available, and it works
251
+ whichever way the install happened: from a tree, from a GitHub archive, or from `npx`.
252
+
253
+ ```bash
254
+ npx agents-handoff --verify-package
255
+ npx agents-handoff --verify-package --record
256
+ ```
257
+
258
+ It runs three checks, in this order, because each one makes the next meaningful:
259
+
260
+ 1. the downloaded tarball matches the hashes the **registry declares** for that version
261
+ (`dist.integrity` and `dist.shasum`) — otherwise "the published package" would be whatever
262
+ the network handed over;
263
+ 2. every file named in the installer manifest is byte-identical to the file of that name in the
264
+ published tarball — each difference is named, with `not installed`, `not in the published
265
+ package` or `content differs`;
266
+ 3. the tarball's sha256 matches the one recorded for this installation, when one was recorded.
267
+
268
+ It prints the package name and version, the tarball URL and the tarball's sha256. `--record`
269
+ stores that sha256 (plus sha512, the integrity string and the shasum) in the `package` block of
270
+ the install record, so every later run compares against a stored value instead of re-deriving
271
+ one.
272
+
273
+ This check needs the network. When the registry cannot be reached, or the installed version is
274
+ not published, it fails and says so — it never passes by default.
275
+
276
+ ## The install record (provenance)
277
+
278
+ Every install writes `.agents-handoff-install.json` inside the installed copy. It records what
279
+ landed and what it was made from:
280
+
281
+ | Field | Meaning |
282
+ |---|---|
283
+ | `product`, `version`, `installer_version` | What was installed, and which installer did it. |
284
+ | `installed_at` | When. |
285
+ | `harness`, `target` | Which harness flag selected the target, and its absolute path. |
286
+ | `source` | `the tree beside the installer`, or the tag archive with its URL and sha256. |
287
+ | `package` | The npm identity this installation should match: `name`, `version`, `registry`, `tarball`, and — once `--verify-package --record` has run — `sha256`, `sha512`, `integrity`, `shasum` and `verified_at`. |
288
+ | `file_count`, `files_sha256` | The installed file set, folded into one hash. |
289
+ | `files` | Every manifest path with its own sha256. |
290
+
291
+ `verify` re-hashes the same file set and compares it with the record, so a changed, missing or
292
+ renamed file fails the check and is named. That is the difference between an installation being
293
+ present and being checkable: the file that changed is reported, not just `verification failed`.
294
+
295
+ ```bash
296
+ npx agents-handoff --verify --provenance
297
+ ```
298
+
299
+ `--provenance` prints the record it checked against, so the verification can be read without
300
+ opening the file:
301
+
302
+ ```
303
+ provenance record
304
+ installed_at: <iso timestamp>
305
+ source: the tree beside the installer (.)
306
+ harness: claude
307
+ files: 39 · file-set sha256 3dab5c0d754a27fd…
308
+ ```
309
+
310
+ An installation made before the record existed reports
311
+ `· no provenance record — installed before 2.0.3; reinstall to record one` and is otherwise
312
+ verified as before. Reinstall to write one.
313
+
314
+ The `package` block is the hook for the published-tarball check: installing from a tree cannot
315
+ know the hash of a tarball it did not download, so the hash is recorded the first time
316
+ `npx agents-handoff --verify-package --record` runs, and compared on every run after that.
317
+
318
+ ## What `remove` keeps
319
+
320
+ `remove` deletes exactly what the install manifest owns — the skill files, and the two files the
321
+ installer writes for itself — and nothing else. Everything the manifest does not own is kept and
322
+ listed:
323
+
324
+ ```
325
+ Kept — not the installer's to delete:
326
+ .agent-handoff/
327
+ handoff-session.md
328
+ handoff.config.json
329
+ handoffs/
330
+ projects/
331
+ ```
332
+
333
+ The rule is stated as a removal set rather than a keep list on purpose: a keep list deletes
334
+ whatever nobody remembered to name, so a store called anything other than the expected
335
+ directories would have gone with the skill. A `package.json` you wrote yourself is kept too; only
336
+ the installer's own private stub is removed.
337
+
130
338
  ## Installing again
131
339
 
132
340
  Installing over an existing installation does nothing by default when the requested version is
@@ -137,8 +345,9 @@ Installing over an existing installation does nothing by default when the reques
137
345
 
138
346
  Use the release archive when you cannot run `npx`.
139
347
 
140
- 1. Download the archive from the repository releases page: `agent-handoff-latest.zip`, or
141
- `agent-handoff-v<version>.zip` for a pinned version.
348
+ 1. Download the archive the release attaches: `agents-handoff-v<version>.zip` from the
349
+ [releases page](https://github.com/Alot1z/agent-handoff/releases) (there is no
350
+ `latest` asset — the newest release carries its own version in the file name).
142
351
  2. Extract it into the target directory with `unzip`.
143
352
  3. Confirm the engine runs: `node "<target>/tools/handoff.mjs" config`.
144
353
 
@@ -164,13 +373,19 @@ By default the engine stores handoff data under its own root, inside the install
164
373
  | Symptom | Cause and fix |
165
374
  |---|---|
166
375
  | `Cannot write to <dir>` | The target is not writable. Pick another location with `--path`, or fix permissions. |
167
- | `Not installed at <dir>` | `update` and `verify` require an existing installation. Run `install` first. |
376
+ | `Not installed at <dir>` | `--path` or a harness flag named a directory that holds no installation. Drop the flag to act on every installation found, or run `install` first. |
377
+ | `Nothing to update:` / `Nothing to verify:` | No installation was found anywhere the installer looks. Install one, or name a target with `--path`. |
378
+ | `verify-package` fails with `is not on the npm registry, or the registry is unreachable` | The installed version has no published tarball to compare against (a checkout install, or no network). The installation itself is untouched by that result. |
379
+ | `verify-package` fails with `does NOT match ... as published` | The check names each differing file. Reinstall with `--force`, then run it again; a file you edited on purpose will keep failing until it is reverted. |
168
380
  | `Incomplete install: <n> of <m> file(s) missing — …` | The tree the installer reads from is not a complete one. Install from a fresh clone, or from a freshly downloaded archive. |
169
381
  | `no published release found — fetching the main branch` | Not an error: `--version latest` found no release object, so the archive of `main` is used instead. Pass `--version <x>` to install a released tag. |
170
382
  | `Cannot extract the archive (tar exited …)` | `tar` is missing, or the download did not arrive intact. The message prints the `curl` and `tar` commands that do the same job by hand. |
171
383
  | The wrong root was chosen | Run `where` to see the reason, then set `AGENT_HANDOFF_GLOBAL_DIR` or pass `--path`. |
172
384
  | `remove` did nothing | Removal asks for confirmation, and refuses in a non-interactive shell. Pass `--force`. |
173
385
  | Verification fails | The output names the failing check. Fix it, or reinstall with `--force`. |
386
+ | `provenance: file-set sha256 matches the install record` fails | A file in the installation changed or went missing after it was installed. The changed paths are listed under the check; reinstall with `--force` to restore them, or keep the edit knowingly. |
387
+ | `no provenance record` | The installation predates the record. That is not a failure; reinstall to write one. |
388
+ | A harness install went somewhere unexpected | Harness directories are listed in the table above and by `doctor`/`list`. Use `--path` or `--skills-dir` to name the directory yourself. |
174
389
 
175
390
  ## See also
176
391
 
@@ -1,8 +1,8 @@
1
1
  ---
2
- title: Integrating agent-handoff
2
+ title: Integrating agents-handoff
3
3
  ---
4
4
 
5
- # Integrating agent-handoff
5
+ # Integrating agents-handoff
6
6
 
7
7
  The engine is a command-line program with a file contract. There is no daemon, no network
8
8
  call and no database. Integration means three things: getting a transcript into the canonical
@@ -170,9 +170,9 @@ and does not detect.
170
170
  env:
171
171
  HANDOFFS_ROOT: ${{ github.workspace }}/.handoffs
172
172
  run: |
173
- node skills/agent-handoff/tools/handoff.mjs build \
173
+ node skills/agents-handoff/tools/handoff.mjs build \
174
174
  --source exported-transcript.jsonl --project ci --harness generic
175
- node skills/agent-handoff/tools/handoff.mjs verify "$(ls .handoffs/projects/ci | head -1)"
175
+ node skills/agents-handoff/tools/handoff.mjs verify "$(ls .handoffs/projects/ci | head -1)"
176
176
  ```
177
177
 
178
178
  `HANDOFFS_ROOT` keeps the run off any configured store, and `verify` returns the exit code a