agents-handoff 0.0.0-stage → 2.0.2
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/CHANGELOG.md +150 -0
- package/LICENSE +21 -0
- package/README.md +110 -2
- package/SKILL.md +147 -0
- package/capability-registry.json +27 -0
- package/docs/ARCHITECTURE.md +164 -0
- package/docs/CHANGELOG.md +151 -0
- package/docs/CLI.md +196 -0
- package/docs/COMPATIBILITY.md +124 -0
- package/docs/CONTRIBUTING.md +134 -0
- package/docs/FORMAT.md +157 -0
- package/docs/INSTALL.md +179 -0
- package/docs/INTEGRATION.md +188 -0
- package/docs/LEVEL4.md +202 -0
- package/docs/LEVEL5.md +96 -0
- package/docs/PERMISSIONS.md +145 -0
- package/docs/PROVENANCE.md +83 -0
- package/docs/SECURITY.md +93 -0
- package/docs/SESSIONS.md +66 -0
- package/docs/TROUBLESHOOTING.md +158 -0
- package/docs/UNINSTALL.md +122 -0
- package/docs/UPGRADE.md +139 -0
- package/docs/_config.yml +16 -0
- package/docs/_data/nav.yml +36 -0
- package/docs/_layouts/default.html +31 -0
- package/docs/assets/style.css +88 -0
- package/docs/index.md +83 -0
- package/handoff.config.example.json +35 -0
- package/handoff.config.schema.json +117 -0
- package/install/CHANGELOG.md +48 -0
- package/install/README.md +76 -0
- package/install/install.mjs +856 -0
- package/install/package.json +39 -0
- package/package.json +66 -4
- package/permission-policy.json +33 -0
- package/refs/ADAPTERS.md +33 -0
- package/refs/bootstrap.md +59 -0
- package/refs/brief-checklist.md +79 -0
- package/refs/handbook.md +58 -0
- package/refs/protocol.md +117 -0
- package/refs/roles.md +75 -0
- package/refs/validator.md +73 -0
- package/schemas/handoff.schema.json +275 -0
- package/skill.json +147 -0
- package/templates/HANDOFF.llm.schema.json +144 -0
- package/templates/HANDOFF.template.md +40 -0
- package/tests/acceptance/acceptance.yaml +209 -0
- package/tests/fixtures/minimal-transcript.jsonl +2 -0
- package/tools/agent-handoff.mjs +410 -0
- package/tools/capability-registry.mjs +120 -0
- package/tools/handoff.mjs +398 -0
- package/tools/handoff.test.mjs +465 -0
- package/tools/lib/handoff-root.mjs +161 -0
- package/tools/runtime-engine.mjs +330 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Changelog
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Changelog
|
|
6
|
+
|
|
7
|
+
All notable changes to agent-handoff are recorded here.
|
|
8
|
+
|
|
9
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
10
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases before 2.0.0
|
|
11
|
+
were development builds and were never published, so they are not listed.
|
|
12
|
+
|
|
13
|
+
The version in [package.json](https://github.com/Alot1z/agent-handoff/blob/main/package.json)
|
|
14
|
+
and [skill.json](https://github.com/Alot1z/agent-handoff/blob/main/skill.json) is the release
|
|
15
|
+
version. The version of the separate installer package is in
|
|
16
|
+
[install/package.json](https://github.com/Alot1z/agent-handoff/blob/main/install/package.json)
|
|
17
|
+
and has its own
|
|
18
|
+
[changelog](https://github.com/Alot1z/agent-handoff/blob/main/install/CHANGELOG.md).
|
|
19
|
+
|
|
20
|
+
## [Unreleased]
|
|
21
|
+
|
|
22
|
+
Add entries under the matching heading as changes land.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **[Session index](https://alot1z.github.io/agent-handoff/SESSIONS.html)** (`docs/SESSIONS.md`):
|
|
27
|
+
a page rendered from a real handoff store, listing the captured sessions in
|
|
28
|
+
`examples/sessions/` with their project, harness, turn count, revision, manifest hash and
|
|
29
|
+
integrity verdict, plus the commands that reproduce each check. The sample store is built by
|
|
30
|
+
the engine from the two transcripts this repository ships, and
|
|
31
|
+
`.github/scripts/build-sessions-index.mjs --check` fails the build when the page and the store
|
|
32
|
+
disagree.
|
|
33
|
+
- The installer is published to npm from the release workflow: a tag publishes `install/` as
|
|
34
|
+
`agents-handoff`, skips a version npm already has, and reports — without failing the
|
|
35
|
+
release — when `NPM_TOKEN` is not configured.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- `npx agents-handoff` now installs the skill as documented. The published package
|
|
40
|
+
carries `install/` alone, so the installer downloads the archive for the requested version and
|
|
41
|
+
copies from it. It previously looked for the skill files beside itself, found none, and
|
|
42
|
+
reported success while installing nothing.
|
|
43
|
+
- The clean-checkout suite builds its fixture from the shipped projection rather than the
|
|
44
|
+
development tree, which is what let the installer's broken source paths pass every local test.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- The installer lost fourteen files whenever it ran outside the development tree: `README.md`,
|
|
49
|
+
`LICENSE` and the twelve guides were addressed under `repo-upstream/<path>`, a directory only
|
|
50
|
+
the development tree has. Sources are written in the shipped tree's terms and resolved against
|
|
51
|
+
both layouts, and an install that cannot resolve a source now fails with the missing paths
|
|
52
|
+
instead of warning and continuing.
|
|
53
|
+
- CI failed on every run: the runtime-layer smoke test ran `agent-handoff.mjs list`, which is not
|
|
54
|
+
a verb of that tool (it exits 2). The step builds a handoff into a scratch store and runs
|
|
55
|
+
`index`, a verb that exists.
|
|
56
|
+
- The shipped version disagreed across files: `SKILL.md` said 2.0.0 while `skill.json` and
|
|
57
|
+
`package.json` said 2.0.1, and the installer carried its own 2.0.0 constant, so every install
|
|
58
|
+
reported the previous version. `SKILL.md` is now the single source of truth, the installer
|
|
59
|
+
reads it, and the suite asserts the two agree.
|
|
60
|
+
- `install/package.json` pointed `repository` at a different repository from the one serving the
|
|
61
|
+
package; it now names this repository, with `homepage` and `bugs`.
|
|
62
|
+
- `handoff.config.schema.json` declared its `$id` under a path that does not serve the schema.
|
|
63
|
+
- `examples/demo/example-usage.md` addressed the engine as `../../../tools/handoff.mjs`, one
|
|
64
|
+
directory above the repository root, so every command in it failed when pasted.
|
|
65
|
+
- `tests/acceptance/acceptance.yaml` described the development tree: it listed documents that
|
|
66
|
+
are not published, scanned a directory that is not published, and asserted two behaviours the
|
|
67
|
+
shipped CLI does not have (`--help` exiting 0, `list` succeeding on an empty store). Every
|
|
68
|
+
entry was re-run against a clean checkout and now states what was observed.
|
|
69
|
+
- Documentation stopped describing files that are not published: `src/` was listed as part of an
|
|
70
|
+
installation in `INSTALL.md`, `UNINSTALL.md` and `UPGRADE.md`, and documented as a repository
|
|
71
|
+
directory in `CONTRIBUTING.md`.
|
|
72
|
+
- `ARCHITECTURE.md` claimed nothing in the repository makes a network call, which stopped being
|
|
73
|
+
true once the installer fetched archives.
|
|
74
|
+
|
|
75
|
+
## [2.0.1] — 2026-10-09
|
|
76
|
+
|
|
77
|
+
Documentation release. No behaviour changed; no public interface changed.
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- **[Command reference](https://github.com/Alot1z/agent-handoff/blob/main/docs/CLI.md)**
|
|
82
|
+
(`docs/CLI.md`): every executable, verb, flag, exit code, environment variable and file
|
|
83
|
+
written, in one place.
|
|
84
|
+
- **[Architecture](https://github.com/Alot1z/agent-handoff/blob/main/docs/ARCHITECTURE.md)**
|
|
85
|
+
(`docs/ARCHITECTURE.md`): the five layers, the data flow, store-root resolution, the
|
|
86
|
+
write-safety discipline, and the boundaries the tool does not cross.
|
|
87
|
+
- **[Troubleshooting](https://github.com/Alot1z/agent-handoff/blob/main/docs/TROUBLESHOOTING.md)**
|
|
88
|
+
(`docs/TROUBLESHOOTING.md`): symptom, cause and fix, keyed to the real exit codes.
|
|
89
|
+
- This changelog, and a Changelog page on the site rendered from it, so the repository file
|
|
90
|
+
and the published page cannot drift apart.
|
|
91
|
+
- A docs-consistency check (`.github/scripts/check-docs.mjs`) run in CI: every page under
|
|
92
|
+
`docs/` must appear in the navigation, and every relative link must resolve where it is
|
|
93
|
+
read.
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
- README now links the published [installation guide](https://alot1z.github.io/agent-handoff/INSTALL.html)
|
|
98
|
+
and the [documentation site](https://alot1z.github.io/agent-handoff/) at the top, and its
|
|
99
|
+
documentation table covers every page.
|
|
100
|
+
- Links in `docs/` that pointed outside the published site are absolute URLs, so they resolve
|
|
101
|
+
for a reader of the documentation instead of returning 404.
|
|
102
|
+
- `package.json` homepage points at the documentation site.
|
|
103
|
+
|
|
104
|
+
## [2.0.0] — 2026-10-08
|
|
105
|
+
|
|
106
|
+
The first public release: a capture engine, a runtime layer over it, an installer, and the
|
|
107
|
+
documentation site.
|
|
108
|
+
|
|
109
|
+
### Added
|
|
110
|
+
|
|
111
|
+
- **Capture engine** (`tools/handoff.mjs`, published as the `agent-handoff` bin). `build`
|
|
112
|
+
reads a JSONL or plain-text transcript and writes a handoff directory:
|
|
113
|
+
`HANDOFF.md`, `HANDOFF.summary.json`, `HANDOFF.llm.json`, `timeline.jsonl`, `TOOLS.md`,
|
|
114
|
+
`manifest.json`. Also `list`, `show`, `verify`, `rename`, `retitle` and `config`.
|
|
115
|
+
- **Incremental builds.** Each build appends only the turns above the recorded `watermark`
|
|
116
|
+
and leaves `timeline.jsonl` untouched, so re-running over a longer transcript extends the
|
|
117
|
+
handoff instead of duplicating it. A rebuild with no new turns and an unchanged source hash
|
|
118
|
+
prints `handoff: up-to-date` and writes nothing.
|
|
119
|
+
- **sha256 provenance.** `manifest.json` carries `raw_sha256` over the source bytes and a
|
|
120
|
+
self-hash `manifest_sha256` over itself. `verify` recomputes the self-hash, checks the
|
|
121
|
+
`timeline.jsonl` line count against `turn_count`, and parses `HANDOFF.llm.json`.
|
|
122
|
+
- **Store-root resolution** (`tools/lib/handoff-root.mjs`): `HANDOFFS_ROOT`, then
|
|
123
|
+
`handoff.config.json` found by walking up, then a `handoffs/` directory on the same walk,
|
|
124
|
+
then the skill directory. Reported by `handoff.mjs config`.
|
|
125
|
+
- **Runtime layer** (`tools/agent-handoff.mjs`): `auto`, `verify-gate`, `promote`, `merge`,
|
|
126
|
+
`federated-merge`, `self-improve`, `index`. Every mutating command takes a lock, backs up
|
|
127
|
+
before writing, verifies after applying, and rolls back on failure.
|
|
128
|
+
- **Bounded execution** (`tools/runtime-engine.mjs`): risk classes `R0`–`R4` evaluated against
|
|
129
|
+
`permission-policy.json` before any operation runs, resumable jobs with sealed checkpoints,
|
|
130
|
+
and a per-decision record in the state directory.
|
|
131
|
+
- **Capability probes** (`tools/capability-registry.mjs`): `file-exists`, `dir-writable` and
|
|
132
|
+
`command` probes that report `healthy` / `unhealthy` / `unknown` with the evidence behind
|
|
133
|
+
each verdict.
|
|
134
|
+
- **Installer** (`install/`, package `agents-handoff`): `install`, `update`, `remove`,
|
|
135
|
+
`verify`, `list`, `where`, targeting a resolved global root, `./local/skills/agent-handoff`,
|
|
136
|
+
or `./skills/agent-handoff`.
|
|
137
|
+
- **Documentation site** at <https://alot1z.github.io/agent-handoff/>, built by GitHub Pages
|
|
138
|
+
from `docs/`.
|
|
139
|
+
- **CI** (`.github/workflows/ci.yml`): the test suite on Node 18, 20 and 22, a runtime-layer
|
|
140
|
+
smoke test, installer help, and a required-file and JSON-validity check.
|
|
141
|
+
|
|
142
|
+
### Security
|
|
143
|
+
|
|
144
|
+
- The engine reads transcripts and writes handoff files. It makes no network calls, and it
|
|
145
|
+
never writes secrets. The limits of what the provenance chain proves are stated in
|
|
146
|
+
[docs/PROVENANCE.md](https://github.com/Alot1z/agent-handoff/blob/main/docs/PROVENANCE.md),
|
|
147
|
+
not implied.
|
|
148
|
+
|
|
149
|
+
[Unreleased]: https://github.com/Alot1z/agent-handoff/compare/v2.0.1...main
|
|
150
|
+
[2.0.1]: https://github.com/Alot1z/agent-handoff/compare/v2.0.0...v2.0.1
|
|
151
|
+
[2.0.0]: https://github.com/Alot1z/agent-handoff/tree/v2.0.0
|
package/docs/CLI.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Command reference
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Command reference
|
|
6
|
+
|
|
7
|
+
Every executable in this repository. Each one is a standalone Node script with zero
|
|
8
|
+
dependencies; there is no build step and nothing to install to run them from a checkout.
|
|
9
|
+
|
|
10
|
+
| Executable | Role | Invoked as |
|
|
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>` |
|
|
14
|
+
| [`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
|
+
| [`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
|
+
| [`install/install.mjs`](https://github.com/Alot1z/agent-handoff/blob/main/install/install.mjs) | Installs, updates and removes the skill. | `npx agents-handoff <verb>` |
|
|
17
|
+
|
|
18
|
+
Requires Node.js 18 or newer.
|
|
19
|
+
|
|
20
|
+
## `tools/handoff.mjs` — capture engine
|
|
21
|
+
|
|
22
|
+
Reads a transcript and writes a handoff directory. The source is never written; every
|
|
23
|
+
output file is a render of it. The folder layout, the manifest fields and the provenance
|
|
24
|
+
chain are in [FORMAT.md](FORMAT.md).
|
|
25
|
+
|
|
26
|
+
| Verb | Effect |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `build --source <file>` | Build or update a handoff from a transcript. |
|
|
29
|
+
| `--handoff --source <file>` | Alias of `build`. |
|
|
30
|
+
| `list [project-or-prefix]` | List sessions, newest first. |
|
|
31
|
+
| `show <id-prefix>` | Print the rendered brief. |
|
|
32
|
+
| `verify <id-prefix>` | Re-check the provenance chain and the file set. |
|
|
33
|
+
| `rename <id-prefix> <new-project>` | Move a session to another project. |
|
|
34
|
+
| `retitle <id-prefix> <new-name>` | Give a session a readable directory name. |
|
|
35
|
+
| `config` | Report the resolved store root, the rule that chose it, the config file, the schema path and the configured project. |
|
|
36
|
+
|
|
37
|
+
### `build` flags
|
|
38
|
+
|
|
39
|
+
| Flag | Meaning |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `--source <file>` | Required. A `.jsonl` file is read line by line; any other extension is read as text. |
|
|
42
|
+
| `--session <id>` | Session id. Defaults to the `session` field on the first JSONL line, else the source file name without its extension. |
|
|
43
|
+
| `--harness <name>` | Harness name recorded in the manifest. Defaults to the source's own field, else `unknown`. |
|
|
44
|
+
| `--model <name>` | Model recorded in the manifest. Defaults to the source's own field, else empty. |
|
|
45
|
+
| `--project <name>` | Project slug. The session directory is created under `projects/<project>/`. |
|
|
46
|
+
| `--objective <text>` | Objective line for the brief. |
|
|
47
|
+
|
|
48
|
+
`build` is incremental. It appends the turns with `seq` above the manifest's `watermark`,
|
|
49
|
+
sets the watermark to the highest `seq` seen, and increments `revisions`. `timeline.jsonl`
|
|
50
|
+
is append-only; the renders are rewritten. A rebuild with no new turns and an unchanged
|
|
51
|
+
source hash writes nothing and prints `handoff: up-to-date`.
|
|
52
|
+
|
|
53
|
+
### Exit codes
|
|
54
|
+
|
|
55
|
+
| Code | Meaning |
|
|
56
|
+
|---|---|
|
|
57
|
+
| 0 | Success. For `verify`, all checks passed. |
|
|
58
|
+
| 1 | `verify` failed: the manifest hash, the timeline line count or the LLM payload does not match. |
|
|
59
|
+
| 2 | Usage error, for example `build` without `--source`. |
|
|
60
|
+
| 3 | The id prefix matched more than one session, or none. |
|
|
61
|
+
| 4 | No match for `show`/`verify`/`rename`/`retitle`; also `build` when no turn could be parsed from the source. |
|
|
62
|
+
|
|
63
|
+
## `tools/agent-handoff.mjs` — runtime layer
|
|
64
|
+
|
|
65
|
+
Acts on the state of the store rather than being invoked per file. Every mutating command
|
|
66
|
+
takes a lock in `<root>/.locks/`, so two runs cannot capture or merge the same session at
|
|
67
|
+
once. Behaviour per command is described in [LEVEL4.md](LEVEL4.md).
|
|
68
|
+
|
|
69
|
+
| Verb | Effect |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `auto --source <file>` | Build only when the source is newer than the stored manifest; skip within `--min-fresh-ms` (default 60000). |
|
|
72
|
+
| `verify-gate <id-prefix>` | Five checks: `sha`, `counts`, `payload`, `contract`, `evidence`. |
|
|
73
|
+
| `promote <id-prefix>` | Stamp `promoted_at` and `promoted_by` on the manifest. |
|
|
74
|
+
| `merge <a> <b>` | Compose two sessions of one project into `<a>+merge+<b>`. |
|
|
75
|
+
| `dispatch <id-prefix> --task <objective>` | Hand the continuation to a worker. See [LEVEL5.md](LEVEL5.md). |
|
|
76
|
+
| `federated-merge --from <root> [--from <root> …] [--dry-run]` | Import sessions from another store root. |
|
|
77
|
+
| `self-improve` | Scan for brief shortfalls and write a rules candidate file. |
|
|
78
|
+
| `index` | Rebuild `INDEX.json` and report sessions with no `HANDOFF.md`. |
|
|
79
|
+
|
|
80
|
+
`auto` flags: `--source` (required), `--session`, `--harness`, `--project`, `--min-fresh-ms`.
|
|
81
|
+
`dispatch` flags: `--task` (required), `--role` (default `implementation-agent`), `--parent`
|
|
82
|
+
(default `handoff:<id>`), `--broker <root>`, `--live`.
|
|
83
|
+
|
|
84
|
+
`verify-gate` exits 0 for both `VERIFIED` and `REJECTED`. Read `ok` or `verdict` from the
|
|
85
|
+
JSON; the exit code alone does not report a rejection. `promote` prints the gate result but
|
|
86
|
+
does not enforce it — run `verify-gate` and branch on the verdict first.
|
|
87
|
+
|
|
88
|
+
### Exit codes
|
|
89
|
+
|
|
90
|
+
| Code | Meaning |
|
|
91
|
+
|---|---|
|
|
92
|
+
| 0 | Success. |
|
|
93
|
+
| 1 | A mutating command failed; the lock was released. |
|
|
94
|
+
| 2 | Usage or configuration error, including an unresolvable store root. |
|
|
95
|
+
| 3 | A lock is held, an id prefix is ambiguous or missing, or a referenced path is missing. |
|
|
96
|
+
| 4 | No session matches the prefix. |
|
|
97
|
+
|
|
98
|
+
## `tools/runtime-engine.mjs` — bounded execution
|
|
99
|
+
|
|
100
|
+
Evaluates every operation against [permission-policy.json](https://github.com/Alot1z/agent-handoff/blob/main/permission-policy.json)
|
|
101
|
+
before it runs, and records the decision whether it was allowed, refused or failed. Levels,
|
|
102
|
+
risk classes and grants are in [PERMISSIONS.md](PERMISSIONS.md).
|
|
103
|
+
|
|
104
|
+
| Verb | Effect |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `evaluate --risk R0..R4 [--target <path>] [--json]` | Classify the target and return the verdict without running anything. |
|
|
107
|
+
| `run --risk R0\|R1 --op read --target <path>` | Evaluate, then read the file when allowed. |
|
|
108
|
+
| `run --risk R1 --op spawn --args "<node args>"` | Evaluate, then run the local node binary with a 15000 ms timeout. |
|
|
109
|
+
| `job --session <s> --steps <n> [--fail-at <k>] [--json]` | Run a checkpointed job of `n` steps, gated at `R1`. |
|
|
110
|
+
| `resume --session <s> --steps <n> [--json]` | Continue from the last sealed checkpoint. |
|
|
111
|
+
| `status --session <s> [--json]` | Report the durable state of a session's job. |
|
|
112
|
+
| `policy` | Print the loaded policy. |
|
|
113
|
+
|
|
114
|
+
Verdicts are `ALLOWED`, `DENIED` and `NEEDS_AUTH`. A denied or personal-data target is
|
|
115
|
+
refused at any risk class and is never executed.
|
|
116
|
+
|
|
117
|
+
| Code | Meaning |
|
|
118
|
+
|---|---|
|
|
119
|
+
| 0 | Allowed, executed, or completed. |
|
|
120
|
+
| 1 | Execution error, or the child produced no exit code. |
|
|
121
|
+
| 2 | Usage or configuration error. |
|
|
122
|
+
| 3 | Denied. |
|
|
123
|
+
| 4 | Needs authorization, or no checkpoint to resume from. |
|
|
124
|
+
| 5 | Checkpoint corrupt, or its integrity seal does not match. |
|
|
125
|
+
| 137 | Simulated abrupt kill (`--fail-at`). |
|
|
126
|
+
| other | The captured exit code of the spawned child. |
|
|
127
|
+
|
|
128
|
+
## `tools/capability-registry.mjs` — capability probes
|
|
129
|
+
|
|
130
|
+
Runs a real probe per declared capability and reports what it observed. An unknown probe
|
|
131
|
+
kind, a probe error and an unreadable target are reported as `unknown` or `unhealthy` with
|
|
132
|
+
the evidence — never interpreted into a passing verdict.
|
|
133
|
+
|
|
134
|
+
| Verb | Effect |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `check [--registry <file>] [--json] [<id>]` | Probe every capability, or one by id; write the state file. |
|
|
137
|
+
| `list [--registry <file>] [--json]` | Show declared capabilities with the verdict from the last check. |
|
|
138
|
+
|
|
139
|
+
Probe kinds: `file-exists`, `dir-writable`, `command` (with `command` and `args`; the token
|
|
140
|
+
`<node>` means the running node binary).
|
|
141
|
+
|
|
142
|
+
| Code | Meaning |
|
|
143
|
+
|---|---|
|
|
144
|
+
| 0 | Every required capability is `healthy`. |
|
|
145
|
+
| 1 | A required capability is `unhealthy` or `unknown` — `unknown` is never accepted as healthy. |
|
|
146
|
+
| 2 | The registry file is missing, not valid JSON, or has no `capabilities` array. |
|
|
147
|
+
| 4 | Unknown capability id, or a usage error. |
|
|
148
|
+
|
|
149
|
+
State is written to `<state>/capability-state.json`, where `<state>` is
|
|
150
|
+
`AGENT_HANDOFF_STATE_DIR` or `.agent-handoff/`.
|
|
151
|
+
|
|
152
|
+
## `install/install.mjs` — installer
|
|
153
|
+
|
|
154
|
+
Published as `agents-handoff`. Location resolution is documented in
|
|
155
|
+
[INSTALL.md](INSTALL.md).
|
|
156
|
+
|
|
157
|
+
| Verb | Effect |
|
|
158
|
+
|---|---|
|
|
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. |
|
|
165
|
+
|
|
166
|
+
| Flag | Meaning |
|
|
167
|
+
|---|---|
|
|
168
|
+
| `--location global\|local\|project` | Target location. Default `global`. |
|
|
169
|
+
| `--path <dir>` | Install to an exact directory. |
|
|
170
|
+
| `--version latest\|<v>` | Version to install. Default `latest`. |
|
|
171
|
+
| `--force`, `-f` | Skip confirmations and overwrite. |
|
|
172
|
+
|
|
173
|
+
## Environment variables
|
|
174
|
+
|
|
175
|
+
| Variable | Read by | Effect |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `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`. |
|
|
179
|
+
| `AGENT_HANDOFF_GLOBAL_DIR` | installer | Overrides the resolved global install root. |
|
|
180
|
+
|
|
181
|
+
## Files written
|
|
182
|
+
|
|
183
|
+
| Path | Written by |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `<root>/INDEX.json` | `build`, `index` |
|
|
186
|
+
| `<root>/projects/<project>/<session>/` | `build`, `merge`, `federated-merge`, `retitle`, `rename` |
|
|
187
|
+
| `<root>/links/<project>.md` | `merge` |
|
|
188
|
+
| `<root>/.locks/<hash>.lock` | every mutating runtime command |
|
|
189
|
+
| `<state>/executions/<id>.json` | `runtime-engine run`, `job` |
|
|
190
|
+
| `<state>/checkpoints/<session>.json` | `runtime-engine job`, `resume` |
|
|
191
|
+
| `<state>/jobs/<session>/work.log` | `runtime-engine job` |
|
|
192
|
+
| `<state>/capability-state.json` | `capability-registry check` |
|
|
193
|
+
| `<skill>/docs/self-improve-candidates.json` | `self-improve` |
|
|
194
|
+
|
|
195
|
+
`self-improve` writes inside the skill directory on purpose: the candidate file describes the
|
|
196
|
+
skill's brief rules, so a configured store never collects rule candidates.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Compatibility
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Compatibility
|
|
6
|
+
|
|
7
|
+
## Platforms
|
|
8
|
+
|
|
9
|
+
| Platform | Level | Notes |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Windows 10 / 11 | SUPPORTED | Primary development platform |
|
|
12
|
+
| macOS 12+ | SUPPORTED | Uses only portable Node APIs |
|
|
13
|
+
| Linux | SUPPORTED | Uses only portable Node APIs |
|
|
14
|
+
|
|
15
|
+
## Runtime
|
|
16
|
+
|
|
17
|
+
| Requirement | Version | Why |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| Node.js | 18.0.0 or newer | ES modules and `node:` built-ins |
|
|
20
|
+
| npm | 9.0.0 or newer | Only if you install from the registry |
|
|
21
|
+
|
|
22
|
+
The engine and the runtime install no packages at run time. `package.json` declares no
|
|
23
|
+
dependencies.
|
|
24
|
+
|
|
25
|
+
## Architectures
|
|
26
|
+
|
|
27
|
+
| Architecture | Level | Notes |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| x64 | SUPPORTED | Primary |
|
|
30
|
+
| arm64 (Apple silicon) | TESTED | macOS |
|
|
31
|
+
| arm64 (Linux) | UNTESTED | Expected to work; no CI runner exercises it |
|
|
32
|
+
|
|
33
|
+
## Node version matrix
|
|
34
|
+
|
|
35
|
+
| Version | Level |
|
|
36
|
+
|---|---|
|
|
37
|
+
| 18.x | SUPPORTED (minimum) |
|
|
38
|
+
| 20.x | SUPPORTED |
|
|
39
|
+
| 22.x | SUPPORTED |
|
|
40
|
+
| < 18 | UNSUPPORTED |
|
|
41
|
+
|
|
42
|
+
## Input formats the engine parses
|
|
43
|
+
|
|
44
|
+
| Format | How it is detected | Fields read |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| JSONL | `.jsonl` extension | `seq`, `ts`/`timestamp`, `role`, `kind`, and the text from `text`, `content`, or `parts[].text` |
|
|
47
|
+
| Plain text | Any other extension | A line opening with `user:`, `human:`, `assistant:`, `ai:`, `system:` or `tool:` (or `>` instead of `:`); following lines are appended to that turn |
|
|
48
|
+
|
|
49
|
+
Turn classification, in this order: `kind` containing `tool`, or `role: "tool"`, becomes `TOOL`;
|
|
50
|
+
`kind` containing `reason` or `think` becomes `THOUGHT`; `role: "user"` (or `kind: "human"`) becomes
|
|
51
|
+
`USER`; `role: "assistant"` (or `kind: "ai"`) becomes `AGENT`; everything else becomes `OTHER`.
|
|
52
|
+
Malformed JSONL lines and turns with empty text are skipped.
|
|
53
|
+
|
|
54
|
+
## Session sources
|
|
55
|
+
|
|
56
|
+
Harness stores are read by adapters that normalise a store into the canonical JSONL shape; the
|
|
57
|
+
engine has no harness-specific code. See [../refs/ADAPTERS.md](https://github.com/Alot1z/agent-handoff/blob/main/refs/ADAPTERS.md).
|
|
58
|
+
|
|
59
|
+
| Source shape | Route |
|
|
60
|
+
|---|---|
|
|
61
|
+
| JSONL session directory | Adapter projects each session file to canonical JSONL |
|
|
62
|
+
| SQLite session database | Adapter reads the database read-only and projects rows to canonical JSONL |
|
|
63
|
+
| Exported JSONL | Passed directly to `build --source` |
|
|
64
|
+
| Plain text or Markdown log | Role-marker parser built into the engine |
|
|
65
|
+
|
|
66
|
+
## Filesystem
|
|
67
|
+
|
|
68
|
+
| Feature | Windows | macOS | Linux |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| Path separators | `\` and `/` | `/` | `/` |
|
|
71
|
+
| Case sensitivity | Insensitive (typical) | Sensitive | Sensitive |
|
|
72
|
+
| Symlinks | Limited | Full | Full |
|
|
73
|
+
| Permissions | ACLs | POSIX | POSIX |
|
|
74
|
+
|
|
75
|
+
Path handling goes through `node:path`; no path is hard-coded in the engine.
|
|
76
|
+
|
|
77
|
+
## Environment variables
|
|
78
|
+
|
|
79
|
+
| Variable | Required | Effect |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `HANDOFFS_ROOT` | No | Sets the store root and takes precedence over every other rule |
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
`handoff.config.json` is optional. It is discovered by walking up from the current directory, a
|
|
86
|
+
maximum of 10 levels, and validated against `handoff.config.schema.json`. The keys the engine acts
|
|
87
|
+
on are `storage.path`, `handoff_dir`, `project_name` and `linking.enabled`. A relative
|
|
88
|
+
`handoff_dir` resolves against the directory that holds the config.
|
|
89
|
+
|
|
90
|
+
Root resolution order, first match wins: `HANDOFFS_ROOT`, then a config-declared directory, then a
|
|
91
|
+
`handoffs/` directory found by the same upward walk, then the skill directory itself. Run
|
|
92
|
+
`node tools/handoff.mjs config` to see which rule applied.
|
|
93
|
+
|
|
94
|
+
## Exit codes
|
|
95
|
+
|
|
96
|
+
| Code | Meaning |
|
|
97
|
+
|---|---|
|
|
98
|
+
| 0 | Success |
|
|
99
|
+
| 1 | Integrity failure (manifest mismatch, corrupted manifest) or an unexpected error |
|
|
100
|
+
| 2 | Usage error, missing source file, or an invalid config |
|
|
101
|
+
| 3 | Ambiguous session-id prefix |
|
|
102
|
+
| 4 | No parsable turns, no handoffs, or no match for the prefix |
|
|
103
|
+
|
|
104
|
+
## CI
|
|
105
|
+
|
|
106
|
+
The suite is `node tools/handoff.test.mjs`. It needs no install step, so a CI job is checkout plus
|
|
107
|
+
Node 18/20/22. GitHub Actions workflows are under `.github/workflows/`.
|
|
108
|
+
|
|
109
|
+
| Platform | Level | Notes |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| GitHub Actions | SUPPORTED | Workflows included |
|
|
112
|
+
| GitLab CI, Azure DevOps, Jenkins | UNTESTED | Any runner with Node 18+ works |
|
|
113
|
+
|
|
114
|
+
## Offline use
|
|
115
|
+
|
|
116
|
+
The engine makes no network requests. The installer is the one component that reaches the
|
|
117
|
+
network: run from a checkout or an unpacked archive it copies the files beside it, and run as the
|
|
118
|
+
published package it downloads that version's archive from this repository. Either way the
|
|
119
|
+
network is needed once, while installing; after that the installed skill is offline.
|
|
120
|
+
|
|
121
|
+
## MCP
|
|
122
|
+
|
|
123
|
+
The engine is a CLI with text and JSON output, so an MCP server can wrap it. No MCP server ships
|
|
124
|
+
with this repository.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Contributing
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Contributing
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
Node.js 18 or newer. The tools import `node:*` only, so there is no runtime dependency to
|
|
10
|
+
install and no lockfile to keep in sync.
|
|
11
|
+
|
|
12
|
+
## Run the suite
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
node tools/handoff.test.mjs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`npm test` runs the same command. The suite uses `node:test` and `node:assert` only, and
|
|
19
|
+
drives the real CLIs through `spawnSync`. It is hermetic: every test builds into a temporary
|
|
20
|
+
`HANDOFFS_ROOT`, batch runtime state goes to a temporary `AGENT_HANDOFF_STATE_DIR`, and both
|
|
21
|
+
are removed afterwards. A bare run leaves no files behind.
|
|
22
|
+
|
|
23
|
+
| Area | Asserted |
|
|
24
|
+
|---|---|
|
|
25
|
+
| Engine: build, verify, list | Build from the shipped fixture, `verify` prints `PASS` and exits 0, a tampered manifest fails `verify` with exit 1, `list` shows the session under its project, a malformed source exits 4, a missing source exits 2, usage errors exit 2, a rebuild of identical input stays up to date without a new revision. |
|
|
26
|
+
| Capability registry | Required capabilities probe healthy, an unknown capability id exits 4, an unknown probe kind is never reported healthy, a missing registry file exits 2. |
|
|
27
|
+
| Permission engine | Evaluation precedes execution (records carry `enforced_before_execution`), a personal-data read is denied with exit 3 and never executed, `R2` on the workspace is `NEEDS_AUTH` with exit 4, a bounded spawn propagates the child's exit code, an unknown risk class is default-denied, an approved workspace outranks a broad personal-data root, a traversal target is denied. |
|
|
28
|
+
| Checkpoint and resume | A job killed mid-run resumes from disk alone with no step duplicated or lost, a missing checkpoint exits 4, a tampered checkpoint fails its seal with exit 5, a second job refuses an existing session checkpoint, a mismatched `--steps` exits 2. |
|
|
29
|
+
|
|
30
|
+
## Drive a CLI by hand
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
node tools/handoff.mjs build --source tests/fixtures/minimal-transcript.jsonl --project demo
|
|
34
|
+
node tools/handoff.mjs list
|
|
35
|
+
node tools/handoff.mjs show minimal-transcript
|
|
36
|
+
node tools/handoff.mjs verify minimal-transcript
|
|
37
|
+
node tools/handoff.mjs config
|
|
38
|
+
|
|
39
|
+
node tools/runtime-engine.mjs policy
|
|
40
|
+
node tools/runtime-engine.mjs evaluate --risk R0 --target tests/fixtures/minimal-transcript.jsonl
|
|
41
|
+
|
|
42
|
+
node tools/capability-registry.mjs check --registry capability-registry.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`build`, `rename` and `retitle` write into the resolved store. Point `HANDOFFS_ROOT` at a
|
|
46
|
+
temporary directory while experimenting so a test session is not added to your own store:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
HANDOFFS_ROOT=/tmp/ah-scratch node tools/handoff.mjs build --source tests/fixtures/minimal-transcript.jsonl
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
On Windows use `set HANDOFFS_ROOT=...` in cmd, or `$env:HANDOFFS_ROOT="..."` in PowerShell.
|
|
53
|
+
|
|
54
|
+
| Tool | Exit codes |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `tools/handoff.mjs` | 0 success, 1 verification failure or I/O error, 2 usage or invalid config, 3 ambiguous id prefix, 4 no matching handoff or no usable turns |
|
|
57
|
+
| `tools/runtime-engine.mjs` | 0 allowed, 2 usage or config error, 3 denied, 4 needs authorization or missing checkpoint, 5 corrupt checkpoint, 137 simulated kill, otherwise the child's exit code |
|
|
58
|
+
| `tools/capability-registry.mjs` | 0 all required capabilities healthy, 1 a required capability is unknown or unhealthy, 2 registry missing or invalid, 4 unknown capability id |
|
|
59
|
+
|
|
60
|
+
## Add a harness adapter
|
|
61
|
+
|
|
62
|
+
The engine consumes one canonical input shape, so an adapter is anything that turns a
|
|
63
|
+
session store into that shape. One JSONL line:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{"seq":0,"ts":"<epoch or ISO>","harness":"<name>","source":"<origin path>","session":"<id>",
|
|
67
|
+
"thread":"<project/thread>","role":"user|assistant|system|tool","kind":"<reasoning|tool_use|text>",
|
|
68
|
+
"text":"<message body>"}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Rules the parser applies. Text is taken from `text`, then `content`, then `parts[].text`. A
|
|
72
|
+
JSONL line that does not parse, or whose text is blank, is skipped. The class comes from
|
|
73
|
+
`kind` and `role`: `tool` in `kind`, or `role: tool`, is `TOOL`; `reason` or `think` in
|
|
74
|
+
`kind` is `THOUGHT`; `role: user` or `kind: human` is `USER`; `role: assistant` or `kind: ai`
|
|
75
|
+
is `AGENT`; anything else is `OTHER`. A `.txt` or `.md` source is read as role-marked text
|
|
76
|
+
instead (`user:`, `assistant:`, `tool:`, optionally prefixed with `#`).
|
|
77
|
+
|
|
78
|
+
Checklist:
|
|
79
|
+
|
|
80
|
+
1. Produce the canonical JSONL from the store, without modifying the store.
|
|
81
|
+
2. Build from it with `HANDOFFS_ROOT` set to a temporary directory and read the result.
|
|
82
|
+
3. Add a row to [ADAPTERS.md](https://github.com/Alot1z/agent-handoff/blob/main/refs/ADAPTERS.md): store path, adapter route, status. Claim
|
|
83
|
+
`VERIFIED` only for a source you actually ran.
|
|
84
|
+
4. If the parser changed, add a fixture under `tests/fixtures/` and a test to
|
|
85
|
+
`tools/handoff.test.mjs`.
|
|
86
|
+
|
|
87
|
+
## Rules for a change
|
|
88
|
+
|
|
89
|
+
- Add no runtime dependency. The engine stays importable and runnable with a bare Node
|
|
90
|
+
installation.
|
|
91
|
+
- Keep the exit codes. They are contracts (see the table above and
|
|
92
|
+
[INTEGRATION.md](INTEGRATION.md)).
|
|
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
|
|
95
|
+
session. Test input belongs in `tests/fixtures/`.
|
|
96
|
+
- A behaviour change comes with a test in `tools/handoff.test.mjs` and an update to the
|
|
97
|
+
document that owns the contract: [FORMAT.md](FORMAT.md) for the files and fields,
|
|
98
|
+
[PERMISSIONS.md](PERMISSIONS.md) for policy semantics, [INTEGRATION.md](INTEGRATION.md)
|
|
99
|
+
for the command surface.
|
|
100
|
+
- Run the suite before proposing the change and report its actual result, including
|
|
101
|
+
failures you could not fix.
|
|
102
|
+
|
|
103
|
+
## Repository layout
|
|
104
|
+
|
|
105
|
+
| Path | Contents |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `SKILL.md` | The skill definition a harness reads: when to use it, its commands and its rules. |
|
|
108
|
+
| `docs/` | These documents. |
|
|
109
|
+
| `install/` | `install.mjs`, the `npx` installer, and its own README. |
|
|
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. |
|
|
112
|
+
| `tools/runtime-engine.mjs` | Permission policy, bounded execution, checkpoints and resume. |
|
|
113
|
+
| `tools/capability-registry.mjs` | Probes declared capabilities and reports honest verdicts. |
|
|
114
|
+
| `tools/handoff.test.mjs` | The test suite. |
|
|
115
|
+
| `tools/lib/handoff-root.mjs` | The single definition of where handoffs are stored. |
|
|
116
|
+
| `schemas/` | `handoff.schema.json`, the portable payload contract. |
|
|
117
|
+
| `templates/` | The handoff render template. |
|
|
118
|
+
| `refs/` | Reference documents: harness adapters, protocol, roles, validator, brief checklist. |
|
|
119
|
+
| `tests/fixtures/` | Deterministic inputs for the suite. |
|
|
120
|
+
| `permission-policy.json` | The default permission policy. |
|
|
121
|
+
| `capability-registry.json` | The default capability declarations. |
|
|
122
|
+
| `handoff.config.schema.json`, `handoff.config.example.json` | Schema and example for `handoff.config.json`. |
|
|
123
|
+
| `.github/workflows/` | Continuous integration and release workflows. |
|
|
124
|
+
|
|
125
|
+
## Documentation is part of the contract
|
|
126
|
+
|
|
127
|
+
A claim in these documents is expected to be checkable against the code. If you change a
|
|
128
|
+
file layout, a field, a flag or an exit code, update the document that states it in the same
|
|
129
|
+
change. Do not document an option that a tool does not implement; if something is reserved
|
|
130
|
+
but not implemented, say so, as `handoff.config.schema.json` does for `auto_capture`.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT. By contributing you agree your contribution is distributed under it.
|