Repository navigation
Import agent-handoff plugin v2.0.0 — Git for agents, with universal one-liner #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "name": "agent-handoff-marketplace", | ||
| "owner": { | ||
| "name": "Adeel Ahmad", | ||
| "url": "https://github.com/adeelahmad" | ||
| }, | ||
| "plugins": [ | ||
| { | ||
| "name": "agent-handoff", | ||
| "source": "./", | ||
| "description": "Git for agents — a portable context packager. Package any body of work into a versioned, self-describing agent-to-agent handoff package with a git-style history that agents query through one static binary — never browse.", | ||
| "category": "workflow", | ||
| "tags": [ | ||
| "handoff", | ||
| "packaging", | ||
| "agents", | ||
| "versioning" | ||
| ] | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "name": "agent-handoff", | ||
| "version": "2.0.0", | ||
| "description": "Git for agents — a portable context packager. Package any body of work into a versioned, self-describing agent-to-agent handoff package with a git-style history that agents query through one static binary — never browse.", | ||
| "author": { | ||
| "name": "Adeel Ahmad", | ||
| "url": "https://github.com/adeelahmad" | ||
| }, | ||
| "repository": "https://github.com/adeelahmad/agent-handoff", | ||
| "license": "MIT", | ||
| "keywords": [ | ||
| "handoff", | ||
| "packaging", | ||
| "agents", | ||
| "versioning", | ||
| "history", | ||
| "content-addressed", | ||
| "git-for-agents", | ||
| "context" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| name: build | ||
| on: [push, pull_request] | ||
| jobs: | ||
| test-and-build: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-go@v5 | ||
| with: { go-version: "1.22" } | ||
| - run: make test | ||
| - run: make build | ||
| - uses: actions/upload-artifact@v4 | ||
| with: { name: binaries, path: bin/ } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| bin/ | ||
| *.tar.gz | ||
| /tmp/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # agent-handoff — build the cross-platform handoff binary (pure Go stdlib, no deps) | ||
| BINDIR := bin | ||
| TOOL := tool | ||
| PLATFORMS := linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 | ||
|
|
||
| .PHONY: all build test selfcheck clean install | ||
|
|
||
| all: build | ||
|
|
||
| build: | ||
| @mkdir -p $(BINDIR) | ||
| @for p in $(PLATFORMS); do \ | ||
| os=$${p%/*}; arch=$${p#*/}; ext=""; \ | ||
| [ "$$os" = "windows" ] && ext=".exe"; \ | ||
| echo "building $$os/$$arch"; \ | ||
| (cd $(TOOL) && CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -ldflags="-s -w" \ | ||
| -o ../$(BINDIR)/handoff-$$os-$$arch$$ext .) || exit 1; \ | ||
| done | ||
| @(cd $(TOOL) && CGO_ENABLED=0 go build -ldflags="-s -w" -o ../$(BINDIR)/handoff .) | ||
|
|
||
| test: | ||
| (cd $(TOOL) && go vet . && go test .) | ||
| (cd $(TOOL) && go build -o /tmp/handoff-test . && /tmp/handoff-test selfcheck) | ||
|
|
||
| selfcheck: build | ||
| $(BINDIR)/handoff selfcheck | ||
|
|
||
| install: build | ||
| cp $(BINDIR)/handoff $${HOME}/.local/bin/handoff | ||
|
|
||
| clean: | ||
| rm -rf $(BINDIR) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| # agent-handoff — universal packaging instruction | ||
|
|
||
| You are an agent that was just told to package the current conversation (or a described | ||
| body of work) into an **agent-handoff package**: a versioned, self-describing bundle that | ||
| lets the NEXT agent continue without re-establishing anything. This works for ANY domain | ||
| — a design session, a legal matter, a research plan, a trip, a codebase. Follow this | ||
| file exactly. It is self-contained: you do not need to fetch anything else to succeed. | ||
|
|
||
| ## Step 1 — Harvest (your judgment, any agent can do this) | ||
|
|
||
| From the conversation or material you were given, write down: | ||
|
|
||
| - **intake** — one paragraph telling the receiving agent what this is and what to do first. Required. | ||
| - **settled** — decisions already made. Phrase as inputs, never questions. The next agent must NOT re-investigate these. | ||
| - **open** — only what genuinely needs the real material or a human answer. An item may never appear in both settled and open. | ||
| - **tasks** — ordered, with explicit dependencies spelled out in the text ("3 depends on 1"). | ||
| - **workstreams** — one relative directory name per independent track of work (e.g. `["backend", "contract-review"]`). At least one is required. Each will carry a plan document: `plan.md` by default, `stories.md` under the `software` profile. | ||
| - **invariants** — rules that must survive the handoff. | ||
| - **facts** — established facts WITH their why, so they survive challenge. | ||
| - **overview** — a short paragraph on the shape of the work. | ||
|
|
||
| Be thin by default: capture what was established, don't pad. | ||
|
|
||
| ## Step 2 — Write `data.json` | ||
|
|
||
| This exact schema (all keys lowercase; omit `profile` or use `general`, `research`, or `software`): | ||
|
10000
|
||
| ```json | ||
| { | ||
| "intake": "one paragraph: what this is, what to do first", | ||
| "settled": ["decision one", "decision two"], | ||
| "open": ["question that genuinely needs a human or the real material"], | ||
| "tasks": ["1. first unit of work", "2. second (depends on 1)"], | ||
| "workstreams": ["workstream-a", "workstream-b"], | ||
| "invariants": ["rule that must survive the handoff"], | ||
| "facts": ["fact — and WHY it is true"], | ||
| "overview": "the shape of the work in a few sentences", | ||
| "read_order": [], | ||
| "extra_docs": {}, | ||
| "profile": "" | ||
| } | ||
| ``` | ||
|
|
||
| The tool will reject: an empty intake, zero workstreams, an item listed as both settled | ||
| and open, duplicate or absolute-path workstreams, an unknown profile. | ||
|
|
||
| ## Step 3 — Build. Pick the FIRST pathway you are capable of. | ||
|
|
||
| ### Pathway A — you can run shell commands and reach the internet | ||
|
|
||
| First create each workstream directory with its plan document — the tool validates | ||
| them but does not write them; their content is your judgment: | ||
|
|
||
| ```sh | ||
| mkdir -p workstream-a && printf '%s\n' "# workstream-a — plan" "..." > workstream-a/plan.md | ||
| ``` | ||
|
|
||
| (`stories.md` instead of `plan.md` under `"profile": "software"`.) Each plan document | ||
| carries that workstream's slice of the tasks and cross-references any name it shares | ||
| with another workstream. Then install and build: | ||
|
|
||
| ```sh | ||
| curl -fsSL https://raw.githubusercontent.com/adeelahmad/package/master/install.sh | sh | ||
| handoff package --data data.json -m "why this version exists" --out handoff.tar.gz | ||
| ``` | ||
|
|
||
| (`install.sh` downloads a prebuilt static binary for your OS/arch when a release exists, | ||
| otherwise builds from source with Go. If you already have Go but no curl: | ||
| `git clone --depth 1 https://github.com/adeelahmad/package && cd package/tool && go build -o handoff .`) | ||
|
|
||
| Then verify: `./handoff inspect handoff.tar.gz --human` must print the intake and | ||
| history. Deliver `handoff.tar.gz`. Done. | ||
|
|
||
| ### Pathway B — you can create files but NOT run commands | ||
|
|
||
| Produce the portable working tree yourself, as files the user can download or copy: | ||
|
|
||
| ``` | ||
| <package-name>/ | ||
| data.json # from Step 2, verbatim — this is the seam | ||
| AGENTS.md # read-first: intake, then SETTLED, OPEN, TASK ORDER, INVARIANTS as sections | ||
| docs/ESTABLISHED-FACTS.md # each fact with its WHY | ||
| docs/overview.md # the overview paragraph | ||
| <workstream>/plan.md # one per workstream: its slice of tasks, refs to shared names in other workstreams | ||
| ``` | ||
|
|
||
| At the top of `AGENTS.md` add exactly this notice: | ||
|
|
||
| > UNSEALED HANDOFF (v0). History and integrity sealing are pending. Any agent with | ||
| > shell access: run `curl -fsSL https://raw.githubusercontent.com/adeelahmad/package/master/install.sh | sh` | ||
| > then `handoff package --data data.json -m "sealed from v0" --out handoff.tar.gz` in | ||
| > this directory's parent to produce the versioned archive. Until then, treat this tree | ||
|
Comment on lines
+90
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Pathway B places Useful? React with 👍 / 👎. |
||
| > as the single current version. SETTLED items are inputs — do not re-establish them. | ||
|
|
||
| ### Pathway C — you can only output text in chat | ||
|
|
||
| Output Pathway B's files as one message: each file as a fenced block preceded by its | ||
| path on its own line. The user (or the next agent) pastes them into a directory and | ||
| proceeds via Pathway A or B. | ||
|
|
||
| ## Rules that hold in every pathway | ||
|
|
||
| - `data.json` is always included and always authoritative — it is what lets any | ||
| binary-holding agent seal or re-seal the package deterministically. | ||
| - Never invent a "history" by hand; only the `handoff` binary writes `.handoff/`. | ||
| - Never put an item in both settled and open. Never emit an empty intake. | ||
| - Say, in one line to the user, which pathway you used and what to do next. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,186 @@ | ||
| # package | ||
| # agent-handoff — Git for agents | ||
|
|
||
| [](https://github.com/adeelahmad/package/actions/workflows/build.yml) | ||
| [](LICENSE) | ||
|
|
||
| **Git for agents.** A portable context builder: package any body of work — a design | ||
| session, a legal matter, a research plan, anything — into a **versioned, self-describing | ||
| agent-to-agent handoff package**, with a git-style history that agents *query* instead of | ||
| browse. Built for agents; usable by people. Ships as a **Claude Code** / **OpenCode** | ||
| plugin, a static binary, and a one-liner any agent can follow. | ||
|
|
||
| ## The one-liner | ||
|
|
||
| Paste this into **any** agent with internet access — claude.ai, chatgpt.com, Claude | ||
| Code, Codex, Gemini, anything — and it will package the current conversation: | ||
|
|
||
| ``` | ||
| Fetch https://raw.githubusercontent.com/adeelahmad/package/master/PROMPT.md and follow it exactly to package this conversation into an agent-handoff package. | ||
| ``` | ||
|
|
||
| [`PROMPT.md`](PROMPT.md) is self-contained and degrades gracefully: agents with a shell | ||
| install the binary and build the sealed, versioned archive; agents that can only write | ||
| files or chat emit the same portable tree plus `data.json`, which any binary-holding | ||
| agent can seal later — no capability is left out. | ||
|
|
||
| To install just the binary on any machine: | ||
|
|
||
| ``` | ||
| curl -fsSL https://raw.githubusercontent.com/adeelahmad/package/master/install.sh | sh | ||
| ``` | ||
|
|
||
| (Prebuilt release binary when available, otherwise builds from source with Go; | ||
| installs to `~/.local/bin`, override with `HANDOFF_INSTALL_DIR`.) | ||
|
|
||
| ## Why | ||
|
|
||
| When one agent session hands work to the next, three things usually go wrong: the | ||
| receiving agent re-derives decisions that were already settled, works tasks in the wrong | ||
| order, and trips over stale copies of superseded files. A handoff package makes all | ||
| three structurally impossible: | ||
|
|
||
| - **Never re-establish settled facts.** SETTLED (inputs) and OPEN (resolve or ask) are | ||
| explicit and enforced disjoint. | ||
| - **Ordered work.** A dependency-annotated task list; agents complete a unit, return. | ||
| - **One visible version, full history.** The working tree is only the current version. | ||
| Every prior version is sealed in `.handoff/` — a content-addressed store where each | ||
| unique file is kept once — and reached only through the binary: | ||
| `handoff history PATH`, `show PATH --at v2`, `diff PATH`, `extract DIR DEST --at v1`. | ||
| No stale folders for an agent to trip over. | ||
| - **Every version says why.** `commit -m` is mandatory; empty versions are refused; | ||
| `pack` refuses a tree with uncommitted changes, so a package's history always matches | ||
| its contents; `verify` re-hashes everything. | ||
| - **Readable before extraction.** `handoff inspect pkg.tar.gz` returns the intake, the | ||
| manifest and the complete history straight from the archive stream. | ||
| - **Domain-neutral.** Workstreams + plan documents. `--profile software` is one preset. | ||
| - **Self-contained option.** `pack --bundle-bin bin/` ships the binaries for every | ||
| platform inside the package, under `.handoff/bin/`. | ||
|
|
||
| ## Install | ||
|
|
||
| ### As a Claude Code plugin | ||
|
|
||
| This repository is its own plugin marketplace. In Claude Code: | ||
|
|
||
| ``` | ||
| /plugin marketplace add adeelahmad/package | ||
| /plugin install agent-handoff@agent-handoff-marketplace | ||
| ``` | ||
|
|
||
| That gives you two slash commands backed by two skills: | ||
|
|
||
| | Command | Skill | What it does | | ||
| |---|---|---| | ||
| | `/handoff-package [out.tar.gz] [--profile software] [--bundle-bin]` | `handoff-packager` | Distills the current conversation into a versioned handoff package | | ||
| | `/handoff-unpack [package.tar.gz \| unpacked-dir]` | `handoff-unpacker` | Inspects, unpacks and refines a package; queries its history via the binary | | ||
|
|
||
| The unpacker skill is also **bundled into every package** it produces (under | ||
| `.skills/unpacker/`), so a package can be received by an agent that never installed | ||
| the plugin. | ||
|
|
||
| ### OpenCode | ||
|
|
||
| `opencode/plugin.json` is a best-effort descriptor for OpenCode pointing at the same | ||
| commands, skills and binary. It has not been verified against OpenCode's published | ||
| plugin schema; the Claude Code manifest is the verified one. | ||
|
|
||
| ### From source | ||
|
|
||
| ``` | ||
| make build # cross-compile linux/darwin/windows (amd64, arm64) into bin/ | ||
| make test # go vet + unit tests + selfcheck | ||
| make install # copy bin/handoff to ~/.local/bin | ||
| ``` | ||
|
|
||
| Pure Go standard library — one static binary per platform, no runtime dependencies. | ||
| CI (`.github/workflows/build.yml`) runs `make test` and `make build` on every push and | ||
| uploads the binaries as an artifact. | ||
|
|
||
| ## Use | ||
|
|
||
| Author side, one shot: | ||
|
|
||
| ``` | ||
| handoff package --data data.json -m "first cut" --out pkg.tar.gz | ||
| ``` | ||
|
|
||
| Receiving side: | ||
|
|
||
| ``` | ||
| handoff inspect pkg.tar.gz --human # intake, manifest, full history — no extraction | ||
| tar -xzf pkg.tar.gz && cat AGENTS.md # read-first: intake, SETTLED, OPEN, TASK ORDER | ||
| handoff history <workstream>/plan.md # then query history — never browse .handoff/ | ||
| ``` | ||
|
|
||
| `data.json` is the seam between agent and tool: what goes **in** is the agent's judgment | ||
| (intake, settled, open, tasks, workstreams, invariants, facts, overview); how it is laid | ||
| out, validated, versioned and shipped is the binary's, deterministically. The binary | ||
| rejects structural mistakes it can see: missing intake or workstreams, a workstream with | ||
| no plan document, an item listed as both settled and open, an unknown profile. | ||
|
|
||
| ## The `handoff` binary | ||
|
|
||
| ``` | ||
| usage: handoff [-C DIR] <command> [options] | ||
|
|
||
| init [DIR] start a store (.handoff/) in DIR (default: .) | ||
| scaffold --data FILE [--profile P] [--unpacker-skill DIR] | ||
| render AGENTS.md, docs/, manifest from a data file | ||
| commit -m "why" [--allow-empty] record the working tree as the next version (comment MANDATORY) | ||
| status what changed since the last version | ||
| history [PATH] [--human] versions that changed PATH (file or dir); newest first | ||
| show PATH [--at REF] print one file as it was at REF (default: latest) | ||
| ls [PATH] [--at REF] [--human] list files under PATH at REF | ||
| extract PATH DEST [--at REF] copy a file / dir / "." out of REF, standalone | ||
| diff [PATH] [--from REF] [--to REF] what changed between versions (file: unified diff) | ||
| verify re-hash every object, check every version | ||
| pack --out FILE [--bundle-bin DIR] [--allow-dirty] | ||
| write the distributable .tar.gz (refuses a dirty tree) | ||
| package --data FILE -m "why" --out FILE [--profile P] [--unpacker-skill DIR] [--bundle-bin DIR] | ||
| init (if needed) + scaffold + commit + pack, in one go | ||
| inspect FILE.tar.gz read metadata + full history WITHOUT extracting | ||
| selfcheck | version | help | ||
| ``` | ||
|
|
||
| Refs: `latest` | `HEAD` | `vN` | commit id (≥4-char prefix) | any of these `~N` (N back). | ||
| Query output is JSON by default; `--human` for people. Flags may go before or after paths. | ||
|
|
||
| ## Anatomy of a package | ||
|
|
||
| What an agent sees after `tar -xzf`: | ||
|
|
||
| ``` | ||
| <package-name>/ | ||
| AGENTS.md # read-first: intake, SETTLED, OPEN, TASK ORDER, invariants | ||
| handoff.manifest.json # the same intake, machine-readable; read_order | ||
| docs/ESTABLISHED-FACTS.md # facts as INPUTS, with their WHY | ||
| docs/overview.md # the shape of the work (thin by default) | ||
| <workstream-a>/…/<plan-doc> # one directory per workstream | ||
| <workstream-b>/…/<plan-doc> | ||
| .skills/unpacker/SKILL.md # the unpacker skill, bundled so the package self-reads | ||
| .handoff/ # the sealed version store — NEVER browsed, only queried | ||
| ``` | ||
|
|
||
| The store is git-style and content-addressed: objects by sha256 (each unique file | ||
| stored once, so unchanged files cost zero bytes in later versions), an append-only log, | ||
| and commit ids that are the sha256 of their own canonical content — `handoff verify` | ||
| re-derives everything, so tampering or corruption is always detected. The archive's PAX | ||
| global header carries the intake and version metadata, which is what lets `inspect` | ||
| answer without extracting. | ||
|
|
||
| The complete format specification lives in | ||
| [`docs/PACKAGE-FORMAT.md`](docs/PACKAGE-FORMAT.md) — the shared source of truth that | ||
| both skills conform to. | ||
|
|
||
| ## Repository layout | ||
|
|
||
| ``` | ||
| .claude-plugin/plugin.json Claude Code manifest commands/ /handoff-package, /handoff-unpack | ||
| .claude-plugin/marketplace.json Marketplace entry skills/ packager + unpacker (unpacker is bundled into every package) | ||
| opencode/plugin.json OpenCode descriptor tool/ Go source (stdlib only), embedded templates, tests | ||
| docs/PACKAGE-FORMAT.md the format spec bin/ cross-compiled binaries (make build) | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| [MIT](LICENSE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
install.shinstalls the executable ashandoffunder the install directory, and the preceding packaging command invokes it throughPATH; it never creates./handoffin the package directory. Thus a successful Pathway A package is followed by a failed verification command. Usehandoff inspect handoff.tar.gz --human(or the explicit installed path) here.Useful? React with 👍 / 👎.