Two capable coding agents can still waste an afternoon. Both inspect the same bug, both edit the
same file, and each assumes the other will run the final test. The code may be sound. The missing
piece is coordination.
I use a small handoff contract whenever more than one agent shares a repository or an external
account. It gives each agent enough state to continue the work without replaying the full session.
Give each agent a bounded objective
An assignment should name one result and one ownership boundary.
objective: Add request validation to the webhook endpoint
owns:
- src/webhooks/webhook.controller.ts
- src/webhooks/webhook.schema.ts
does_not_own:
- database migrations
- deployment configuration
The does_not_own list helps when two tasks sit close together. An agent working on validation may
notice a schema issue, but it should record that issue instead of editing a migration owned by
another task.
File ownership alone may be too narrow. One agent can own the API contract while another owns the
consumer, even if both need to read the same files. Write access needs a clear owner. Read access
does not.
Record state as a small state machine
Free-form status notes become hard to compare. A short set of states gives the coordinator a
stable signal:
-
reading: gathering evidence, no edits yet -
editing: changing owned files -
verifying: running tests or checking the live flow -
waiting: blocked on approval or an external system -
done: objective met and evidence recorded
Store one timestamp with the state. The timestamp distinguishes a live task from an abandoned one
without guessing from a long transcript.
{
"state": "verifying",
"updatedAt": "2026-08-25T14:20:00Z"
}
Separate observations from mutations
Agents should log facts they read and actions they took in different fields.
observed:
- POST /webhooks accepts an empty event type
changed:
- Added an enum check for event type
- Added a 400 response test
That split prevents a coordinator from treating a proposed fix as completed work. It also makes
external actions easier to audit. A draft message, a sent message, and an approved message are
three different states.
For actions that spend money, publish content, deploy code, or contact another person, record the
approval gate next to the action:
external_action:
destination: production deployment
status: waiting_for_approval
prepared: true
Attach evidence to the result
Tests pass is too vague for a handoff. Record the command, result, and scope.
verification:
- command: pnpm test webhook.controller.spec.ts
result: 8 passed
- command: pnpm lint src/webhooks
result: passed
Live checks need the same treatment. Name the route, account, environment, or browser flow that
you checked. Another agent should know whether the result came from a unit test, a local service,
or the production interface.
Evidence also prevents duplicate verification. The next agent can trust a fresh, scoped test and
focus on the missing layer.
Use cursors for monitoring
Reading the full transcript on each poll costs time and hides new events inside old output. Store
the last line, event ID, or timestamp that the coordinator consumed.
monitor:
session_id: 7d4c...
last_line: 1842
The next poll starts at line 1843. If the agent changes state, submits an external action, or
finishes verification, the coordinator reports that change and advances the cursor.
This pattern works outside coding sessions too. Proposal queues, support inboxes, and deployment
logs all benefit from a durable boundary between reviewed and new items.
Define the final handoff
A completed task should leave five fields:
result: Empty webhook event types now return 400
files_changed:
- src/webhooks/webhook.controller.ts
- src/webhooks/webhook.schema.ts
verification:
- unit tests: 8 passed
open_risks:
- Existing clients may send the legacy "unknown" event type
next_action:
- Confirm legacy client behavior before deployment
The next_action field should contain work that remains. Leave it empty when the task is complete.
That rule keeps agents from inventing a follow-up to avoid saying they are done.
Handle stale ownership
An agent can crash after claiming a task. Add a lease or stale threshold to each ownership record.
The coordinator may reassign the work after the threshold, but it should inspect the worktree and
handoff first. Uncommitted edits may still contain useful work.
Shared repositories need one more rule: agents preserve changes they do not own. They should not
reset a branch, remove a worktree, or revert an unfamiliar edit to make their task easier.
A compact contract is enough
The contract does not need a new service. A JSON file, a database row, or a session handoff can
carry the same fields:
- objective and ownership
- state and timestamp
- observations and mutations
- approval gates
- verification evidence
- monitor cursor
- open risks and next action
These fields turn parallel agents into a coordinated team. Each agent can read the current state,
claim a bounded slice, leave proof, and stop without colliding with the next one.
Top comments (0)