How it works / After an interruption
After an interruption
When a carrier stops without a clean hand-over, the next carrier gets a warning. It must check what the last carrier already did before it does anything else.
Before you start
The examples use the workspace billing and the handles build-agent and review-agent from your first relay. This page opens its own piece of work, BILL-45, and gives every baton file it uses. One example catches BILL-51, which offers, catches and drops leaves waiting.
When you get the warning
A carrier is the handle that holds the work, an agent or a person. A leg is one carrier's stretch on it, under a lease. Leases and carriers explains both. You get the warning when you catch work and the leg before yours did not end clean. That is the case when the last carrier:
- let its lease run out
- ended its leg with
limit,crash,killedorother, with or without an offer - was taken over by its own handle in a new session
After a clean end you get no warning. Offers, catches and drops explains how each of these happens.
The warning matters because the baton may be behind. The last carrier may have done more steps after its last save. If you repeat a step that is already done, you may do it twice.
What the tool prints
To see the warning, play both carriers. build-agent emails the March invoices in batches, under a one-minute lease. Save this first baton as mail.md:
## True now
The March invoices are ready to send. There are 412 of them, in batches of 100.
## Next action
Email the March invoices to customers, one batch at a time.
Done when: The mail log shows 412 invoices sent.
## Traps
Sending a batch twice emails those customers twice.
## Evidence
The invoice export finished and wrote 412 PDF files.
## References
- [required] artifact: logs/mail-2026-03.log -- one line for each invoice sent (check: grep -c sent logs/mail-2026-03.log)
- work: BILL-42 -- the migration these invoices came from
Open the work with it:
handsoff open BILL-45 --title "Email the March invoices" --as build-agent --lease 1m --baton mail.md
Opened BILL-45 at r1 (work 112)
Leg 200; lease expires 2026-10-05T04:49:56.203265+00:00
After batch 1, it saves this baton as mail2.md:
## True now
Batch 1 of the March invoices is sent: invoices 1 to 100. Batches 2 to 5 are not sent yet.
## Next action
Email batches 2 to 5 of the March invoices, one batch at a time.
Done when: The mail log shows 412 invoices sent.
## Traps
Sending a batch twice emails those customers twice.
## Evidence
The mail log shows 100 lines marked sent, for invoices 1 to 100.
## References
- [required] artifact: logs/mail-2026-03.log -- one line for each invoice sent (check: grep -c sent logs/mail-2026-03.log)
- work: BILL-42 -- the migration these invoices came from
handsoff save BILL-45 --as build-agent --baton mail2.md
accepted as r2
Then it sends batch 2 and goes quiet. Wait one minute, until its lease runs out. Then it tries to save this baton, mail3.md, and is too late:
## True now
Batches 1 and 2 of the March invoices are sent: invoices 1 to 200. Batches 3 to 5 are not sent yet.
## Next action
Email batches 3 to 5 of the March invoices, one batch at a time.
Done when: The mail log shows 412 invoices sent.
## Traps
Sending a batch twice emails those customers twice.
## Evidence
The mail log shows 200 lines marked sent, for invoices 1 to 200.
## References
- [required] artifact: logs/mail-2026-03.log -- one line for each invoice sent (check: grep -c sent logs/mail-2026-03.log)
- work: BILL-42 -- the migration these invoices came from
handsoff save BILL-45 --as build-agent --baton mail3.md
The baton is no longer this leg's: lease lapsed at 2026-10-05T04:49:56.638659+00:00; the write was not applied. Run handsoff continue 112 to take it back if allowed, or give the notes to the current carrier.
not_holder: leg 200; current leg 200; lease lapsed at 2026-10-05T04:49:56.638659+00:00; fix: run handsoff continue 112 if allowed, or give the notes to the current carrier
Now review-agent catches the dropped work:
handsoff continue BILL-45 --as review-agent
Caught BILL-45 at r2 from build-agent via drop
Attention
DROPPED
Contact with build-agent was lost: lease lapsed at 2026-10-05T04:49:56.638659+00:00. Its last accepted save was r2 at 2026-10-05T04:48:56.636479+00:00. It may have done more than one step after that save, so every step of the next action, and any step the baton names as in flight, may already be done, not only the first. Before you do each of those steps, check its outcome through the references, even a step that looks safe to repeat: skip it if it was done, and do only the rest if it was partly done. If you cannot tell for a step, stop and block the work.
2026-10-05T04:50:07.039808+00:00 late_write (late, not accepted): {"act":"save","content_kept":true,"refused_content":null,"status":"late, not accepted"}
late, not accepted
## True now
Batches 1 and 2 of the March invoices are sent: invoices 1 to 200. Batches 3 to 5 are not sent yet.
…
This machine has no pending writes.
## True now
Batch 1 of the March invoices is sent: invoices 1 to 100. Batches 2 to 5 are not sent yet.
## Next action
Email batches 2 to 5 of the March invoices, one batch at a time.
Done when: The mail log shows 412 invoices sent.
## Traps
Sending a batch twice emails those customers twice.
## Evidence
The mail log shows 100 lines marked sent, for invoices 1 to 100.
## References
- [required] artifact: logs/mail-2026-03.log -- one line for each invoice sent (check: grep -c sent logs/mail-2026-03.log)
- work: BILL-42 -- the migration these invoices came from
What to do now
Check that each required reference can be reached; if one cannot, run `handsoff block BILL-45 --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 208; lease expires 2026-10-05T05:20:12.672071+00:00
Read it from the top:
- The first line says you caught
r2frombuild-agentthrough a drop. DROPPEDand the warning come first. The warning says how contact was lost and when. It also names the last save the service accepted.- A late save follows, marked
late, not accepted. The last carrier tried to save it after its lease ran out. It never became the baton, but it hints at what that carrier did. Its text runs until the lineThis machine has no pending writes. - After that line comes the baton you caught,
r2. What to do nowtells you how to go on. The tool then shows how to save, and your new leg and lease.
The same warning appears when you catch an offer whose carrier ended with any reason but clean. BILL-51 from offers, catches and drops is one: its carrier ended with limit, and its offer still waits for review-agent. The tool says via offer, and there is no DROPPED line:
handsoff continue BILL-51 --as review-agent
Caught BILL-51 at r2 from build-agent via offer
Attention
Contact with build-agent was lost: ended with reason limit at 2026-10-05T04:49:29.744309+00:00. Its last accepted save was r2 at 2026-10-05T04:49:29.437767+00:00. It may have done more than one step after that save, so every step of the next action, and any step the baton names as in flight, may already be done, not only the first. Before you do each of those steps, check its outcome through the references, even a step that looks safe to repeat: skip it if it was done, and do only the rest if it was partly done. If you cannot tell for a step, stop and block the work.
…
What to do before you carry on
Before you do any step, check what already happened:
- Check that you can reach each required reference. If you cannot reach one, block the work and stop.
- Take each step of the next action in turn, and any step the baton says was in progress. Check its outcome through the references. Do this even for a step that looks safe to repeat.
- Skip a step that is done. If a step is partly done, do only the rest.
- If you cannot tell whether a step happened, block the work and stop.
- Do the steps that are not done. Save a new baton as you go.
In the example, the reference's check is grep -c sent logs/mail-2026-03.log. If it prints 200, batch 2 went out. Start at batch 3, and save a baton that says so. If you cannot read the log, block BILL-45, which review-agent now holds:
handsoff block BILL-45 --as review-agent --reason "Cannot read logs/mail-2026-03.log to see which batches were sent"
Blocked BILL-45; now held
You still hold the work while it is blocked. Every listing shows it first, with a BLOCKED badge and your reason, until you or the workspace's owner unblock it. When you can check the steps again, unblock it and carry on:
handsoff unblock BILL-45 --as review-agent
Unblocked BILL-45; now held
If your catch was queued
When the service cannot be reached, handsoff continue queues the catch on your machine. Working offline explains the queue. When the service accepts the catch later, the tool does not print the warning. Run handsoff history on the work and read how the last leg ended. If it did not end clean, follow the steps above before you do any work. Working offline shows an example.
Make it easier for the next carrier
You can make an interruption cheaper for whoever comes after you:
- Save a baton after each step, not only at the end.
- Give each reference a check that shows whether a step happened, such as a count or a log line.
- If you stop early, end your leg with the reason that fits, such as
limit. Do not usecleanunless nothing is half done.
The baton has more on writing references and checks.
Next, read history to see every leg of a piece of work.