CLI reference / Carrying work
Carrying work
Start work, save batons, pass work on, catch it, and end, block or close it.
A carrier is the handle that holds a piece of work now. A baton is the short note that tells the next carrier where the work stands. A leg is one carrier's stretch on the work. A lease is how long the carrier holds the work. Each accepted save or renew starts the lease again. To learn more, read The baton and Leases and carriers.
Each command also takes the global options, such as --as, --session, --leg and --json. The CLI reference explains them. The examples act as two agent handles, build-agent and review-agent, with --as. One person owns both.
In each command, <WORK> is the work's reference, such as BILL-42, or its id.
The examples run in the order of this page, on one piece of work. The first baton is the baton.md file from Your first relay. Before the save, the file was edited. The continue example prints the saved version.
handsoff open
Starts a piece of work with a reference, a title and a first baton. You become its carrier, with a new leg and a lease.
Usage: handsoff open [OPTIONS] --title <TITLE> --baton <BATON> <REFERENCE>
Arguments:
<REFERENCE>
Options:
--server <SERVER>
--title <TITLE>
--baton <BATON> path to a Markdown baton file, or /dev/stdin to read it from standard input; headings in order: True now, Next action (with Done when), Traps, Evidence, References
--workspace <WORKSPACE>
--as <HANDLE>
--lease <LEASE>
--session <SESSION>
--transcript <TRANSCRIPT>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
<REFERENCE> | The work's reference, such as BILL-42. No other work in the workspace may have it. |
--title <TITLE> | A short title for the work. |
--baton <BATON> | The first baton: a Markdown file, or /dev/stdin to read it from standard input. |
--lease <LEASE> | How long you hold the work, such as 1h. From 1 minute to 12 hours. Without it, the workspace's default lease applies. |
--transcript <TRANSCRIPT> | Where this session's transcript lives, as text. Only person handles see it, in the history. Handsoff never opens it. |
handsoff open BILL-42 --title "Billing v2 migration" --as build-agent --baton baton.md
Opened BILL-42 at r1 (work 56)
Leg 109; lease expires 2026-10-05T04:57:58.060543+00:00
r1 is the baton's first revision. The number after work is the work's id. If the baton does not have the five headings in order, the tool refuses it and saves nothing.
handsoff save
Saves a new baton for work you carry. The tool prints accepted as and the new revision only after the service stores the baton.
Usage: handsoff save [OPTIONS] <WORK>
Arguments:
<WORK>
Options:
--baton <BATON> path to a Markdown baton file, or /dev/stdin; without --baton, save reads the baton from standard input (for example a heredoc); headings in order: True now, Next action (with Done when), Traps, Evidence, References
--server <SERVER>
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
<WORK> | The work to save. |
--baton <BATON> | The new baton: a Markdown file, or /dev/stdin. Without it, save reads the baton from standard input. |
handsoff save BILL-42 --as build-agent --baton baton.md
accepted as r2
An agent can save in one command. It gives the baton in a heredoc: handsoff save BILL-42 --baton /dev/stdin <<'EOF', then the baton, then a line that holds only EOF. If standard input is a terminal, save refuses and names both ways to give the baton.
While your offer waits, the service refuses your saves. Retract the offer first, or let it be caught.
handsoff offer
Offers work you carry to another handle, or to any handle. The work waits for a catch until the deadline. A work has at most one waiting offer.
Usage: handsoff offer [OPTIONS] <WORK>
Arguments:
<WORK>
Options:
--server <SERVER>
--to <TO>
--any
--workspace <WORKSPACE>
--as <HANDLE>
--deadline <DEADLINE>
--baton <BATON> path to a Markdown baton file, or /dev/stdin to read it from standard input; headings in order: True now, Next action (with Done when), Traps, Evidence, References
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
--to <TO> | The handle to offer the work to. You cannot offer it to your own handle. |
--any | Offers the work to any enabled handle in the workspace. Use it in place of --to. |
--deadline <DEADLINE> | How long the offer waits, such as 2h. From 1 minute to 7 days. Without it, the workspace's default offer deadline applies. |
--baton <BATON> | Saves a new baton and offers it in one step. Without it, the offer carries the current revision. |
handsoff offer BILL-42 --as build-agent --to review-agent
Offered BILL-42 at r2 to review-agent until 2026-10-06T04:13:10.299175+00:00
After you offer, end your leg with handsoff end <work> --reason clean. The example under handsoff end shows both steps. Offers, catches and drops explains what each next step means.
handsoff retract
Takes back a waiting offer. The passer can retract it, while its leg is live or after the leg ended. The owner can retract any offer.
Usage: handsoff retract [OPTIONS] <WORK>
Arguments:
<WORK>
Options:
--server <SERVER>
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
<WORK> | The work whose offer to take back. |
handsoff retract BILL-42 --as build-agent
Retracted offer for BILL-42; now held
The line ends with the work's new state. It is held when the passer's leg is still live. When the passer's leg ended before the retract, the work drops, and any handle can catch it.
handsoff end
Ends your leg on the work, with a reason. If your offer waits, it keeps waiting until its deadline. If no offer waits, the work drops at once.
Usage: handsoff end [OPTIONS] --reason <REASON> <WORK>
Arguments:
<WORK>
Options:
--reason <REASON> [possible values: clean, limit, crash, killed, other]
--server <SERVER>
--note <NOTE>
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
--reason <REASON> | Why the leg ends. The list below says what each reason means. |
--note <NOTE> | A short note to keep with the end. |
The reasons:
clean: you stopped on purpose, with nothing half done.limit: the session hit a usage limit.crash: the session failed.killed: someone stopped the process.other: you cannot tell why it stopped.
After the retract above, build-agent offers the work again, this time with a deadline. Then it ends its leg:
handsoff offer BILL-42 --as build-agent --to review-agent --deadline 2h
Offered BILL-42 at r2 to review-agent until 2026-10-05T06:13:12.087227+00:00
handsoff end BILL-42 --as build-agent --reason clean
Ended BILL-42: clean
After any reason but clean, whoever catches the work gets a warning. It says the last carrier may be further along than its last baton shows.
handsoff continue
Catches work: an offer waiting for your handle or for any handle, or work that dropped. You become the carrier, with a new leg and lease. The tool prints warnings first, then the baton, then what to do now.
Usage: handsoff continue [OPTIONS] <NAME>
Arguments:
<NAME>
Options:
--lease <LEASE>
--server <SERVER>
--take-over
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
<NAME> | The work's reference or id. |
--lease <LEASE> | How long you hold the work after the catch. From 1 minute to 12 hours. Without it, the workspace's default lease applies. |
--take-over | Moves your own handle's live hold from another session into this one. The old session can no longer write to the work. |
If this session already holds the work, continue prints it again and catches nothing. If you have no workspace selected, continue looks in every workspace you can see.
handsoff continue BILL-42 --as review-agent
Caught BILL-42 at r2 from build-agent via offer
Attention
This machine has no pending writes.
## True now
The v2 invoice tables exist in staging. Invoices 1 to 1200 of 4800 are copied.
## Next action
Copy invoices 1201 to 4800, then compare the row counts.
Done when: The row counts match between the old and new tables.
## Traps
The old table stores amounts in cents. The new one stores whole currency units. Divide by 100 when you copy.
## Evidence
The copy script ran for invoices 1 to 1200. It reported 1,200 rows written.
## References
- [required] source: migrations/0042_invoices_v2.sql -- creates the v2 tables (check: bun test billing)
- work: BILL-41 -- the schema change this copy follows
What to do now
Check that each required reference can be reached; if one cannot, run `handsoff block BILL-42 --reason ...` and stop. If the warning above says contact was lost, the former carrier may have done more than one step after its last save: before you do each step of the next action, and any step the baton names as in flight, check that step's outcome through the references, even a step that looks safe to repeat; skip it if it was done, do only the rest if it was partly done, and if you cannot establish its outcome, block and stop. Then do the next action's steps that are not done. Save as you go; offer or end before you stop.
…
HELD Leg 110; lease expires 2026-10-05T04:58:16.696389+00:00
The … stands for the save command and the end command that the tool prints for this work. When the work dropped, a warning comes first under Attention. After an interruption explains what to do with it.
handsoff renew
Starts your lease again from now, and changes nothing else. Each accepted save renews the lease too. The agent adapters renew it while the agent works.
Usage: handsoff renew [OPTIONS] <WORK>
Arguments:
<WORK>
Options:
--server <SERVER>
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
<WORK> | The work you carry. |
handsoff renew BILL-42 --as review-agent
Renewed BILL-42; lease expires 2026-10-05T04:58:23.756863+00:00
handsoff note
Adds a note to a work. Any enabled handle in the workspace can add one. The next carrier sees the notes made since the last catch.
Usage: handsoff note [OPTIONS] --text <TEXT> <WORK>
Arguments:
<WORK>
Options:
--server <SERVER>
--text <TEXT>
--kind <KIND> [default: info] [possible values: refusal, skipped, question, info]
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
--text <TEXT> | The note. |
--kind <KIND> | refusal for a refusal you met, skipped for a step you skipped, question for an open question, or info. Without it, info. |
handsoff note BILL-42 --as review-agent --kind question --text "Should credit notes move with the invoices?"
Note accepted for BILL-42
handsoff block
Marks work as blocked, with a reason. Use it when you cannot reach a required reference, or cannot tell whether a step already ran. You keep holding the work. Blocked work shows first in every list until the carrier or the owner unblocks it. The carrier or the owner can block work.
Usage: handsoff block [OPTIONS] --reason <REASON> <WORK>
Arguments:
<WORK>
Options:
--reason <REASON>
--server <SERVER>
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
--reason <REASON> | Why the work cannot go on. |
handsoff block BILL-42 --as review-agent --reason "Waiting for read access to the old invoice table"
Blocked BILL-42; now held
handsoff unblock
Removes the block, so the work can go on. The carrier or the owner can unblock work.
Usage: handsoff unblock [OPTIONS] <WORK>
Arguments:
<WORK>
Options:
--server <SERVER>
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
<WORK> | The blocked work. |
handsoff unblock BILL-42 --as review-agent
Unblocked BILL-42; now held
handsoff close
Closes work for good, with a reason and evidence. Closing ends the current leg and takes back any waiting offer. After that, every handle in the workspace can still read it, but nobody can change it. The carrier or the owner can close work.
Usage: handsoff close [OPTIONS] <WORK>
Arguments:
<WORK>
Options:
--reason <REASON>
--server <SERVER>
--evidence <EVIDENCE>
--workspace <WORKSPACE>
--as <HANDLE>
--session <SESSION>
--runtime <RUNTIME>
--model <MODEL>
--leg <LEG>
--account <ACCOUNT>
--json
-h, --help Print help
| Option | What it does |
|---|---|
--reason <REASON> | The reason to close the work. |
--evidence <EVIDENCE> | What shows where the work ended: commits, results or documents. If there is none, write none: and why. |
The help does not mark them as required, but you must give both. Without them, the tool refuses before it contacts the service.
handsoff close BILL-42 --as review-agent --reason "All 4800 invoices copied and checked" --evidence "Row counts match at 4800; commit 3f2a91c"
Closed BILL-42; now closed
You cannot open a closed work's reference again. Use a new reference.