Installation
agents-handoff turns a working session into a portable handoff folder, and verifies that folder later. It is a Node.js command-line skill with no runtime dependencies.
Requirements
| Requirement | Notes |
|---|---|
| Node.js >= 18.0.0 | The engine uses ES modules and node:fs. |
unzip |
Only needed to extract a release archive by hand. |
tar |
Only needed when the installer fetches an archive instead of copying the tree beside it. |
| No network at run time | The engine never makes a network call. npx and --verify-package do. |
Quick start
npx agents-handoff --all # every harness found on this machine
One run covers one harness, several, or a directory of your own; the table in
Install into the harness you use has the whole set. The
installer copies the skill files into the resolved global root (or the harness directories
named), then reports how many files it copied. The published package carries the whole tree, so
this needs no download; only a bare copy of install/ falls back to fetching the archive for
the requested version.
Confirm the installation:
node "<install-path>/tools/handoff.mjs" config
That prints the handoff root the engine will use:
handoff: config root=<dir>
handoff: config source=default
handoff: config file=none
handoff: config schema=<dir>/handoff.config.schema.json
Installing from GitHub
Two ways, and both install the same tree:
# npm runs the repository's own package straight from GitHub — no registry copy involved
npx github:Alot1z/agents-handoff --all
# or clone it and run the installer from the checkout
git clone https://github.com/Alot1z/agents-handoff.git
cd agent-handoff
node install/install.mjs --all
The clone is also the way to install a version that is not on npm at all: a branch, a commit or a tag. The installer accepts the same flags either way, and a checkout installs the tree in front of it.
Install into the harness you use
With no harness flag the installer uses the resolved global root (next section). A harness flag puts the skill where that tool reads its skills, and several flags cover several tools in one run:
npx agents-handoff --claude # Claude Code
npx agents-handoff --codex # Codex CLI
npx agents-handoff --agents # the harness-neutral store
npx agents-handoff --all # every harness found on this machine
npx agents-handoff --claude --codex # exactly these two, one run
npx agents-handoff --harness claude,codex
npx agents-handoff --skills-dir ~/.config/mytool/skills
npx agents-handoff --project --claude # this repository only (./.claude/skills)
| Flag | Harness | User-level directory | Per-repository directory, with --project |
|---|---|---|---|
--claude |
Claude Code | ~/.claude/skills |
./.claude/skills |
--codex |
Codex CLI | ~/.codex/skills |
./.codex/skills |
--agents |
the harness-neutral store | ~/.agents/skills |
./.agents/skills |
--harness <a,b> |
named harness(es), comma separated, repeatable | as above | as above |
--skills-dir <dir> |
any other stack, exactly | <dir> |
<dir> |
--all |
every harness whose configuration directory exists here | as above | — |
Each target gets the skill folder agents-handoff/ below that directory, so Claude Code finds
~/.claude/skills/agents-handoff/. Targets are installed, reported and recorded one by one,
and the run ends with a summary:
── target 1 of 2: claude ──
✓ Installed agents-handoff v<version> to <dir>/agents-handoff
Provenance: the tree beside the installer (.) · file-set sha256 3dab5c0d754a27fd… (.agents-handoff-install.json)
── target 2 of 2: custom dir <dir> ──
…
Summary
✓ installed <dir> — v<version>
✓ installed <dir> — v<version>
--all installs into the harnesses whose configuration directory exists in your home directory
and names the ones it skipped; --claude and its siblings install there whether or not the
directory exists yet. Detection is a suggestion, never a decision.
Ask what this machine has, and whether what is installed is still intact:
npx agents-handoff doctor
agents-handoff doctor
product v<version> · installer v<version> · node v<node version>
Harnesses
✓ claude present <home>/.claude/skills
v<version> · 39/39 files · provenance OK
· codex not found <home>/.codex/skills
✓ agents present <home>/.agents/skills
Global resolution
<dir> — <reason>
Store (where handoffs are written)
handoff: config root=<dir>
Verdict
1 harness installation(s) found.
doctor reads and reports. It never installs, updates or removes anything.
Where a global install goes
--location global does not point at a fixed directory. The installer searches for a store and
reports the reason it chose one. The order is:
| # | Condition | Result |
|---|---|---|
| 1 | AGENT_HANDOFF_GLOBAL_DIR is set |
that directory |
| 2 | A skill store already holds an agents-handoff install |
the newest such location |
| 3 | ~/.agents/skills exists |
~/.agents/skills |
| 4 | A skill store exists | its first account-skill root |
| 5 | Nothing found | the default store, created on install |
An account-skill store keeps skills two identifier levels below the store itself:
<store>/<account-id>/<profile-id>/agents-handoff/
<store> is %APPDATA%\<client>\account-skills on Windows, and ~/.<client>/account-skills or
~/.config/<client>/account-skills on macOS and Linux, for whichever desktop client keeps
skills there. The installer searches every store it can find and never assumes one of them.
Inspect the decision before installing anything:
npx agents-handoff where
Global install root: <dir>
chosen because: <reason>
override with: AGENT_HANDOFF_GLOBAL_DIR=<dir> or --path <dir>
--list shows the resolved root, the local location, every candidate root, each harness
directory (whether or not it exists on this machine), and — inside a git repository — the
project location. Each installation found is printed with its version, the number of manifest
files present, and whether it still matches its install record.
Locations
| Location | Target directory |
|---|---|
global (default) |
<resolved global root>/agents-handoff |
local |
./local/skills/agents-handoff |
project |
./skills/agents-handoff |
--path <dir> |
exactly <dir> |
Options
| Option | Default | Effect |
|---|---|---|
--location <global\|local\|project> |
global |
Which location to install, update, remove or verify. |
--path <dir> |
none | Use this directory instead of a resolved location. |
--version <v> |
latest |
Request a version. Confirm what landed with --verify, which prints the installed version. |
--force, -f |
off | Skip confirmations and overwrite an existing installation. |
--claude, --codex, --agents |
none | Install into that harness’s skills directory (table above). Repeatable, and combinable. |
--harness <a,b> |
none | Named harness(es), comma separated. Repeatable. |
--all |
none | Every harness whose configuration directory exists on this machine. |
--skills-dir <dir> |
none | Any other stack, exactly. Repeatable. |
--project |
off | With a harness flag: use the per-repository directory instead of the user-level one. |
--provenance |
off | With verify: print the install record the verification was checked against. |
--record |
off | With verify-package: store the tarball hashes in the install record. |
--help, -h |
— | Print the installer usage text. |
The installer accepts both bare verbs and flag forms: install/--install, update/--update,
remove/--remove, verify/--verify, verify-package/--verify-package, list/--list,
doctor/--doctor.
Commands
| Command | Description |
|---|---|
install, i (default) |
Copy the skill files to the target. |
update, u |
Update every installation found, or the harnesses named. See UPGRADE.md. |
remove, rm |
Remove an installation, keeping everything the manifest does not own. See UNINSTALL.md. |
verify, v |
Check every installation found: each manifest file, the skill metadata, that the engine runs, and the install record. |
verify-package, vp |
Check an installation against the published npm tarball for its version. |
list, ls |
List installed locations with version, manifest file count and provenance state. |
where |
Print the global root and why it was chosen. |
doctor |
Which harnesses are present here, what is installed where, and whether each installation still matches its record. |
Verify an installation
npx agents-handoff --verify
Verification runs four kinds of check:
- every file named in the installer manifest exists in the target;
SKILL.mddeclares bothnameandversion;node tools/handoff.mjs configexits 0 and prints thehandoff: config root=marker — this exercises the engine’s module graph, so a missing module fails here;- the installation still matches the provenance record written when it was installed.
Each check is printed with a pass or fail mark. On success the installer also prints the installed location and version; on failure it exits non-zero and names the files that changed.
With no harness flag, --verify verifies every installation found on this machine, not just
the one the global resolver would pick: a machine that holds the skill in ~/.claude/skills and
in ~/.agents/skills has two copies, and both are checked. A harness flag or --skills-dir
scopes the run to those targets. The run fails if any installation fails.
There is no --verbose flag.
Prove an installation matches the published package
--verify compares an installation with its own record. --verify-package compares it with the
artifact npm is actually serving for its version — the strongest check available, and it works
whichever way the install happened: from a tree, from a GitHub archive, or from npx.
npx agents-handoff --verify-package
npx agents-handoff --verify-package --record
It runs three checks, in this order, because each one makes the next meaningful:
- the downloaded tarball matches the hashes the registry declares for that version
(
dist.integrityanddist.shasum) — otherwise “the published package” would be whatever the network handed over; - every file named in the installer manifest is byte-identical to the file of that name in the
published tarball — each difference is named, with
not installed,not in the published packageorcontent differs; - the tarball’s sha256 matches the one recorded for this installation, when one was recorded.
It prints the package name and version, the tarball URL and the tarball’s sha256. --record
stores that sha256 (plus sha512, the integrity string and the shasum) in the package block of
the install record, so every later run compares against a stored value instead of re-deriving
one.
This check needs the network. When the registry cannot be reached, or the installed version is not published, it fails and says so — it never passes by default.
The install record (provenance)
Every install writes .agents-handoff-install.json inside the installed copy. It records what
landed and what it was made from:
| Field | Meaning |
|---|---|
product, version, installer_version |
What was installed, and which installer did it. |
installed_at |
When. |
harness, target |
Which harness flag selected the target, and its absolute path. |
source |
the tree beside the installer, or the tag archive with its URL and sha256. |
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. |
file_count, files_sha256 |
The installed file set, folded into one hash. |
files |
Every manifest path with its own sha256. |
verify re-hashes the same file set and compares it with the record, so a changed, missing or
renamed file fails the check and is named. That is the difference between an installation being
present and being checkable: the file that changed is reported, not just verification failed.
npx agents-handoff --verify --provenance
--provenance prints the record it checked against, so the verification can be read without
opening the file:
provenance record
installed_at: <iso timestamp>
source: the tree beside the installer (.)
harness: claude
files: 39 · file-set sha256 3dab5c0d754a27fd…
An installation made before the record existed reports
· no provenance record — installed before 2.0.3; reinstall to record one and is otherwise
verified as before. Reinstall to write one.
The package block is the hook for the published-tarball check: installing from a tree cannot
know the hash of a tarball it did not download, so the hash is recorded the first time
npx agents-handoff --verify-package --record runs, and compared on every run after that.
What remove keeps
remove deletes exactly what the install manifest owns — the skill files, and the two files the
installer writes for itself — and nothing else. Everything the manifest does not own is kept and
listed:
Kept — not the installer's to delete:
.agent-handoff/
handoff-session.md
handoff.config.json
handoffs/
projects/
The rule is stated as a removal set rather than a keep list on purpose: a keep list deletes
whatever nobody remembered to name, so a store called anything other than the expected
directories would have gone with the skill. A package.json you wrote yourself is kept too; only
the installer’s own private stub is removed.
Installing again
Installing over an existing installation does nothing by default when the requested version is
latest: the installer reports the version already present, then stops. It tells you to use
--update to upgrade, or --force to reinstall the same files.
Manual installation
Use the release archive when you cannot run npx.
- Download the archive the release attaches:
agents-handoff-v<version>.zipfrom the releases page (there is nolatestasset — the newest release carries its own version in the file name). - Extract it into the target directory with
unzip. - Confirm the engine runs:
node "<target>/tools/handoff.mjs" config.
A complete installation contains SKILL.md, skill.json, the manifest JSON files,
tools/ (the engine and its runtime), tools/lib/, schemas/, refs/, templates/, docs/,
and tests/. That list is not a description: it is the installer’s manifest, and a run that
cannot resolve any entry fails rather than reporting an incomplete installation as a success.
Handoff storage is separate
Two environment variables decide two different things, and they are not interchangeable:
| Variable | Decides |
|---|---|
AGENT_HANDOFF_GLOBAL_DIR |
Where the installer puts the skill. |
HANDOFFS_ROOT |
Where the engine stores handoff data. |
By default the engine stores handoff data under its own root, inside the installation. Set
HANDOFFS_ROOT when you want handoffs somewhere else, for example in a versioned directory.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
Cannot write to <dir> |
The target is not writable. Pick another location with --path, or fix permissions. |
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. |
Nothing to update: / Nothing to verify: |
No installation was found anywhere the installer looks. Install one, or name a target with --path. |
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. |
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. |
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. |
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. |
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. |
| The wrong root was chosen | Run where to see the reason, then set AGENT_HANDOFF_GLOBAL_DIR or pass --path. |
remove did nothing |
Removal asks for confirmation, and refuses in a non-interactive shell. Pass --force. |
| Verification fails | The output names the failing check. Fix it, or reinstall with --force. |
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. |
no provenance record |
The installation predates the record. That is not a failure; reinstall to write one. |
| 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. |