How it works

One task, five commands, any agents.

The relay below is the whole product: plan, pass, take, coordinate, merge. Scroll through it, then read what each step actually does on disk.

Session handoff
01

Plan

baton new cuts a branch (baton/my-task) plus an isolated git worktree at .baton/wt/my-task. Claude Code plans there — no other agent's files in reach — while every session event streams into a JSONL buffer.

git worktree add · branch baton/my-task · session → JSONL
$ baton start my-task --agent claude
02

Pass

One command distills that buffer into HANDOFF.md: objective, plan, remaining checklist, and an estimated cost to finish. Plain markdown in the worktree — it survives crashed sessions and diffs like code.

frontmatter: objective · plan · remaining · est_cost_usd
$ baton pass my-task --to cursor
03

Take

Cursor picks the brief up: the execution prompt prints, the task flips to in-progress — same worktree, same branch, zero re-explaining. If commits landed after the brief was written, a stale-brief warning says: trust git, not the brief.

prompt prints between delimiters — pipe it into any CLI agent
$ baton take my-task
04

Coordinate

Editor hooks record every file touch as an edit signal in a local SQLite store; the daemon streams them over SSE. Two agents on one file flashes an overlap — before the conflict, not at merge time.

agents ask check_files over MCP before touching a path
$ baton signals
05

Done & merge

done files a completion report to .baton/reports/ — what shipped, what it cost. merge squash-merges the branch back and reclaims the worktree; baton history keeps every file's trail queryable.

squash merge · report archived · per-file history stays
$ baton done my-task
How it's built, file by file — read the architecture →

The same five steps, on disk.

01 · Plan

$ baton start my-task --agent claude

Every task starts as a standard git worktree: its own branch, its own working directory, zero contact with any other agent's checkout. The planning agent works there while Baton records the session — plan updates, files touched, token spend — into a JSONL buffer it can distill later. Nothing proprietary: kill the session and the worktree, branch, and buffer are all still on disk.

git worktree add · branch baton/my-task · session → JSONL
02 · Pass

$ baton pass my-task --to cursor

The pass is a curated brief, not a raw history dump. Baton merges the session transcript with the agent-agnostic progress ledger, drops anything that predates the last commit (that work already landed — git is the truth for it), and writes a single HANDOFF.md under a hard character budget: objective, plan, remaining checklist, and an estimated cost to finish on the receiving model.

frontmatter: objective · plan · remaining · est_cost_usd
03 · Take

$ baton take my-task

The receiving agent doesn't need Baton integration: take prints the execution prompt between delimiters, so you can paste it — or pipe it — into any CLI agent. The brief's status flips to in-progress in the same file, and if commits landed in the worktree after the brief was written, a stale-brief warning is prepended inside the delimiters so even a piped agent sees it.

prompt prints between delimiters — pipe it into any CLI agent
04 · Coordinate

$ baton signals

While agents work in parallel, editor hooks write every file touch into a local SQLite signal store. The daemon reconciles those signals against what git actually reports dirty — a signal whose holder is provably gone is cleared, one it can't verify is kept — and streams the live picture over server-sent events. Agents ask check_files over MCP before touching a path; two agents on one file get warned before the merge conflict exists.

agents ask check_files over MCP before touching a path
05 · Done & merge

$ baton done my-task

Finishing is bookkeeping, not archaeology: done files a completion report — what shipped, what it cost — into .baton/reports/, and merge squash-merges the task branch back and reclaims the worktree. The per-file edit history stays queryable afterwards, so 'who touched this file, in which task' has an answer months later.

squash merge · report archived · per-file history stays

Run the relay yourself.