7 min read

AI agent handoff: control active sessions overnight

AI agent handoff procedures for transferring active sessions, pending approvals, recovery actions, and audit evidence between on-call engineers.

AI agent handoff: control active sessions overnight

An AI agent handoff fails when the departing engineer passes along a story instead of custody. “The agent is still working on the deploy” tells the next person almost nothing. They need to know which process still has authority, what it can reach, which request awaits a human, where the evidence lives, and how to stop or recover the work.

The awkward part is that an agent can act while nobody watches the terminal. It may have a live SSH connection, a durable background task, a token in its environment, an approval prompt waiting on a laptop, or a partial remote change that will only become visible later. A good handoff converts all of that into a bounded operational state. A bad one transfers uncertainty and calls it continuity.

A handoff needs a custody record, not a chat summary

A usable handoff records authority and state separately, because they fail differently. State tells the incoming engineer what the agent has done and plans to do. Authority tells them what the agent can still do. Teams often document the first and omit the second, which is how a harmless-looking continuation becomes an unreviewed production write.

Write the record while the outgoing engineer can still inspect the machine and explain decisions. Do not reconstruct it from memory after a page wakes somebody up. A short document with exact identifiers beats a long narrative full of confidence.

For each active run, record these facts:

  • The agent process ID, session ID, working directory, and start time.
  • The human owner leaving the shift, the human owner taking it, and the time responsibility changes.
  • The intended task, the last completed external action, and the next proposed external action.
  • Every reachable target, such as a host alias, API base URL, repository, ticket, or deployment environment.
  • The stop command, the recovery command, and the evidence location.

Do not write “has staging access” when you can write “process 4182 can call the staging deployment API through approved session S-204.” Broad labels hide the detail that determines whether a successor can safely continue.

The custody record also needs a clear disposition for each run: continue, pause, cancel, or inspect before action. “Monitor” is not a disposition. It leaves the next engineer to infer whether they have permission to intervene.

A handoff is complete only when the incoming engineer acknowledges the record and can find the live process themselves. A message sent into a busy channel is delivery, not transfer. If no one accepts the custody, the outgoing engineer should pause or revoke external authority where the work allows it.

Find live authority before changing owners

You cannot transfer control of a session you have not located. Start with the local process tree, then inspect connections, environment exposure, and jobs created outside the immediate terminal. The agent interface may say a task is complete while a child process, shell multiplexer pane, or SSH master connection remains alive.

On macOS or Linux, begin with simple commands and save their output in the handoff evidence. Replace the example identifiers with the actual agent process or account.

ps -axo pid,ppid,user,lstart,command | grep -E '[a]gent|[c]laude|[m]cp'
pgrep -P 4182 -alf
lsof -nP -p 4182

The first command gives you a process row shaped like this:

4182  901 alex  Tue Mar 18 22:14:07 2025  agent-runner --task deploy-api

The second exposes child processes. The third shows open files and network endpoints. Look for inherited shells, open Unix sockets, TCP connections, local credential files, and pipes to approval helpers. Do not paste command output containing secrets into a ticket. Preserve it in the approved incident record or redact the sensitive value while retaining the file path and connection details.

SSH needs separate inspection because its connection model can outlive a single command. The OpenSSH ssh_config manual says that ControlPersist can keep a master connection open after the initial client exits. That behavior saves time during repeated commands. During a handoff, it also means “the command finished” does not prove remote access ended.

Check for master sockets and forwarding processes:

ps -axo pid,ppid,command | grep '[s]sh'
find ~/.ssh -type s -name '*control*' -print
lsof -nP -iTCP -sTCP:ESTABLISHED | grep '[s]sh'

Then ask a more important question than “is it connected?”: what does the remote side still execute? A remote build can continue after the local client disappears. A deployment command can have applied one change and failed before reporting the next. Capture the remote job identifier, the deployment record, or the service status before you decide whether to resume.

Do not equate an open port with malicious activity. Do treat every unexplained open channel as unresolved authority. The incoming engineer must either understand it, close it, or escalate it.

Pending approvals need a fate and an expiry

A pending approval is a proposed action, not a reservation made by the outgoing engineer. The person taking the shift should never inherit an approval prompt with only a message saying “please click this if it appears.” That sentence asks them to bless a decision without its context.

Attach five details to every pending request:

  1. The exact action, including method and target. “Update service” is inadequate. “POST to the deployment endpoint for production-api” gives someone a place to start.
  2. The reason for the action and the condition that made it necessary.
  3. The expected result and the observable evidence that confirms it.
  4. The deadline after which the request must expire and be generated again.
  5. The named person permitted to approve or reject it.

An approval that lacks these details should expire. Reissuing a request is cheaper than recovering from a blind write. This rule feels fussy during a quiet shift. It feels obvious after an approval card survives a laptop lock, a reconnect, and a change in incident scope.

Do not use a handoff to widen approval authority. If the outgoing engineer could approve a staging change, that does not make the incoming engineer authorized to approve a production version of it. Scope may have changed while the request sat there. Recheck the target, payload, and current incident state before a human acts.

There is also a timing issue. If a tool can prompt for an action long after an agent formed the request, make expiry part of the request design. A stale approval can act on a system that has recovered, failed over, or been changed manually. The prompt may describe a technically valid operation that is no longer the right operational decision.

I prefer a short approval note over attaching a sprawling transcript. The next engineer should be able to answer three questions in under a minute: what will happen, where will it happen, and why does it still need to happen now? If they cannot, reject it and ask the agent to inspect current state before proposing a new action.

Session ownership and secret ownership must stay separate

The person who supervises a session does not need a copy of every credential the session can use. Confusing those roles creates a familiar and expensive mess: someone exports a token into a shell profile “just for the handoff,” then the token outlives the incident, the engineer’s role, and the memory of why it existed.

A proper transfer changes who may supervise, approve, pause, or revoke an action. It does not deliver API tokens, SSH private keys, browser cookies, or temporary cloud credentials through chat, notes, or an agent prompt. The successor gets the session reference and the evidence required to operate it. The action executor retains the secret.

This distinction matters most when the outgoing engineer leaves a terminal open. An unlocked shell is not a legitimate transfer mechanism. It gives the next person a pile of inherited state: exported variables, command history, cached credentials, shell functions, port forwards, and half-finished commands. Some of that state may be useful. None of it is clear custody.

Use one of two approaches:

  • Continue the existing session only when the active operation is understood, the scope is bounded, the incoming engineer has accepted it, and stopping would create a worse operational outcome.
  • Stop the old session and launch a fresh one under the incoming engineer when the task is investigative, the authority is broad, the prompt history matters, or the agent has gone idle.

The second approach is usually safer than teams admit. People resist it because they fear losing context. Preserve context in the handoff packet, not inside an uninspected process. A fresh process has a clean approval boundary and makes the new owner’s responsibility unmistakable.

For teams using Sallyport, the agent can perform HTTP and SSH actions without receiving the underlying secrets, so a shift change can transfer supervision rather than credential material. Its vault gate denies actions while locked, which gives the incoming engineer a deliberate pause point before they authorize any continuation.

Do not mistake separation for immunity. If a successor can approve actions on a session, they still need the same discipline around scope and evidence. Keeping a secret out of a prompt prevents one class of failure. It does not make an unsafe request safe.

Recovery must start with containment, not continuation

Keep tokens out of prompts
Let agents use HTTP APIs through credential injection, without ever receiving bearer keys or custom headers.

When an agent run goes quiet or the outgoing engineer becomes unreachable, the incoming engineer should first prevent new external changes. They should not spend ten minutes trying to restore the exact conversational context while a background process continues to write.

Recovery has two tracks: preserve evidence and establish current state. Run them in that order when there is any chance that the process or host may disappear. Copy session identifiers, terminal output, task definitions, approvals, process listings, and audit references into the incident record. Then stop, revoke, or lock the action path according to the system’s normal controls.

After containment, inspect the target system. The agent’s claim that a call failed is weaker than a target-side record. An HTTP timeout can mean the server rejected a request, accepted it once, or accepted it and lost the response. Retrying without an idempotency mechanism can duplicate the action.

Use the target’s natural evidence:

  • For an API write, inspect the object, change record, request ID, or idempotency record.
  • For SSH work, inspect the remote process, service state, package manager history, or deployment marker.
  • For a code change, inspect the repository diff, commit, CI run, and deployment state separately.
  • For a queued operation, inspect the queue and worker status before submitting another job.

The distinction between retrying a request and recovering an operation matters. Retrying repeats a transport attempt. Recovery establishes whether the underlying state changed, then chooses the next action. Teams blur those terms when an agent presents a timeout as an invitation to click “run again.” It is not.

A recovery note should name the last trustworthy observation, not the last thing the agent said. For example: “The agent timed out after requesting deploy D42. The deployment service records D42 as running on two instances. New submissions paused at 02:17.” That gives the next operator a factual place to resume.

If you cannot establish state, raise the incident and keep authority restricted. A stalled deploy is often tolerable. A duplicate schema migration, repeated payment action, or accidental production deletion may not be.

Prove the record against evidence before accepting it

A handoff document is an operator’s interpretation. An audit record is evidence of what the system recorded. You need both, but do not treat them as interchangeable.

Before an incoming engineer accepts a live session, compare the custody record with evidence that the outgoing engineer did not edit by hand. Check the session start and end times, the target names, the sequence of actions, and the stated approval disposition. Investigate mismatches before someone continues the run.

A hash chain helps here because it makes record removal and reordering detectable. It does not prove intent, correctness, or the wisdom of an approval. That limit is healthy to state plainly. Cryptographic continuity answers “did this recorded sequence remain intact?” It does not answer “should we have sent that request?”

With Sallyport, teams can verify the encrypted audit chain offline with this command:

sp audit verify

Save the verifier result beside the handoff record, along with the time you ran it and the log range you reviewed. The verification does not need vault access, which is useful when an incoming engineer needs to check continuity before they unlock any action authority.

Do not create a habit of copying large audit excerpts into chat. Logs often contain sensitive operational metadata even when they omit secrets. Store a reference to the approved record, quote the small portion required to explain the handoff, and give the incoming engineer access through the normal incident path.

Audit review also catches a mundane but serious problem: an engineer may have started two agents with similar tasks and forgotten one. A process list shows what lives now. The audit sequence shows what each run already attempted. Read both before you accept responsibility.

A handoff packet should work when nobody remembers the incident

See who owns the run
A new agent process gets a per-session approval card that identifies its code-signing authority.

A useful packet lets an engineer who was asleep five minutes ago make a safe decision. It should not require scrolling through hundreds of chat messages or reopening an unbounded prompt transcript. Keep the packet near the incident record, use the same field order every time, and update it when authority changes.

Use this template as a starting point:

Incident or change:
Outgoing owner / incoming owner / transfer time:

Agent run:
- Session ID and local PID:
- Workspace and task reference:
- Current state: continue | pause | cancel | inspect
- Last confirmed external action:
- Next proposed action:

Authority:
- Targets reachable by this run:
- Approval status and expiry:
- Session revoke or stop method:
- Credentials remain held by:

Evidence:
- Activity or audit record reference:
- Target-side evidence checked:
- Process and connection capture:

Recovery:
- Known partial state:
- Safe first action for incoming owner:
- Escalation owner and trigger:

The line labeled “safe first action” earns its space. Write an action that gathers state without increasing impact, such as checking a deployment record, reading a queue depth, or comparing a service version. Do not write “continue investigation.” That phrase has no operational boundary.

The packet should also say what has changed since the agent began. Maybe a release freeze started, a database replica lagged, a customer reported a symptom, or a separate engineer made a manual correction. Agents act on the context they receive. The incoming human needs context that arrived after the prompt began.

Keep the language factual. “Agent seems confused” tells the successor to distrust it but gives them nothing to verify. “Agent proposed the same POST after the service showed request ID 7f3 as accepted” identifies a duplicate-risk condition and suggests the correct next check.

Shift changes create an authorization gap if you ignore timing

Handoffs without copied credentials
Keep API keys and SSH keys in Sallyport's encrypted vault while agents perform the approved action.

The gap appears when the outgoing engineer has mentally left the shift but their session can still act. It widens when the incoming engineer has not yet accepted ownership, cannot see the approval state, or assumes the agent is merely reading data. The process has authority during that gap without an attentive human responsible for its use.

A common failure looks like this. At the end of a shift, an engineer asks an agent to repair a failing deployment. The agent opens an SSH connection, edits a configuration file, and waits for an approval to restart a service. The engineer writes “restart pending, should be fine” in chat and signs off.

The next engineer sees the prompt an hour later. During that hour, a manual mitigation changed the service topology. The pending restart now affects a node that carries traffic the previous engineer did not know about. The approval still describes a valid command, but the situation that justified it has changed.

This failure does not require a compromised tool or careless person. It comes from treating authorization as permanent while operational context moves. An approval should bind to a short-lived request and a current owner. A session should lose authority when neither condition holds.

Set an explicit transfer deadline. If the incoming engineer has not accepted the session by that time, pause the agent and invalidate outstanding approvals. If a task cannot pause safely, state that fact in the runbook before the incident, define who may accept it, and set a direct escalation route. Do not discover the exception during a shift change.

Teams sometimes keep every session alive because restarting agents costs time. That recommendation is popular because it preserves local context and avoids re-explaining the task. It is wrong for broad or uncertain authority. The few minutes spent launching a clean session are cheap compared with trying to explain why an abandoned process changed a system after its owner went offline.

The incoming engineer should accept responsibility in a fixed order

The incoming engineer needs a repeatable acceptance sequence because handoffs happen when attention is fragmented. This is not bureaucracy for a quiet day. It prevents the person who woke up to a page from approving an action before they know which authority remains live.

Use this order:

  1. Read the current incident state and the custody record, then confirm the outgoing engineer and transfer time.
  2. Locate the named process or session and inspect active connections, child processes, and pending requests.
  3. Compare the record with audit evidence and target-side state.
  4. Choose continue, pause, or cancel. Reject every pending approval that no longer has a clear, current justification.
  5. Record acceptance, the first safe action, and the next review time.

The order matters. If you approve first and inspect later, you have already accepted the largest risk. If you inspect the target before preserving the session record, you may lose evidence when a process exits or a machine restarts. A fixed sequence protects against the natural urge to “just get it moving.”

The outgoing engineer also has a fixed obligation: remain available until the successor accepts custody or the session stops. If coverage ends before that happens, escalate rather than silently leave a running agent behind. An on call schedule assigns a person, not a vague hope that someone will notice a prompt.

Build these rules into your incident practice before an overnight failure forces the issue. Start by adding the custody fields to one existing handoff note and requiring a disposition for every agent run. The first time you find an unexplained SSH connection or an approval with no owner, you will have found a real gap rather than a theoretical one.

FAQ

What counts as an active AI agent session during a handoff?

Treat a live agent process as active until you can identify its process, session identifier, authority, current action, and stop method. A terminal tab that looks quiet can still hold an SSH control connection, a queued job, or a process waiting for approval. If the outgoing engineer cannot account for it, stop it and start a fresh run under the incoming engineer.

Should the next on-call engineer approve requests left pending by the previous engineer?

Do not transfer a pending approval by saying it is safe in chat. Record what the action will do, the exact target, the credential or authority involved, the expiry time, and the person who may approve it. If that record is missing, let the approval expire and rerun the request after review.

Can I transfer an agent session without sharing credentials?

Session ownership means responsibility for a running process and its consequences. Credential ownership means who can use a secret or authorize its use. Keep those separate: an incoming engineer may supervise a session without ever receiving a token, private key, or copied environment file.

When should an AI agent session be revoked instead of transferred?

The safest default is to revoke or stop the old session and launch a new one with a new approval boundary. Continue an existing process only when stopping it would interrupt a bounded, understood operation and the incoming engineer has reviewed its state. Convenience is not enough reason to preserve unknown authority overnight.

Can an SSH session remain active after the agent exits?

SSH multiplexing can leave a master connection alive after the command that opened it exits. Check for control sockets, running ssh processes, remote jobs, and forwarded ports before calling the session finished. The ssh_config manual documents that ControlPersist can retain the master connection, which is useful for speed but awkward during a shift change.

What should be in an AI agent handoff note?

A useful record names the agent process, workspace, current task, target systems, authority granted, pending approvals, expected next action, logs, expiry times, and recovery owner. It also states what the incoming engineer must not do, such as approving a production write or reusing a copied shell environment. Put timestamps beside anything that can expire.

What secrets should never appear in an on-call handoff?

Do not copy API tokens, SSH private keys, browser cookies, or credential files into a handoff document or chat thread. Share references, session identifiers, target names, and the path to approved evidence instead. The person taking over needs operational context, not portable secrets.

What if the previous on-call engineer is unreachable?

When the outgoing engineer becomes unreachable, the incoming engineer should first stop new external actions, preserve local and audit evidence, then determine whether the task caused a partial change. They should use normal incident escalation if the scope is unclear. Guessing what the first engineer intended is a poor recovery method.

Can autonomous coding agents safely run across a shift change?

Yes, provided the gateway keeps secrets out of the agent and gives the incoming engineer a way to review and revoke the run. A transfer should change the human authority over the session, not pass credentials through the agent. The audit record must survive even if the app or agent process crashes.

How do I verify an AI agent audit trail before taking over?

Verify the evidence from a write-once source rather than trusting copied log lines. For a hash-chained encrypted audit log, run its offline verifier and save the result with the handoff packet. A clean verification proves continuity of the recorded sequence, though it does not prove that an approved action was wise.

Sallyport

Sallyport runs API calls and SSH commands for your AI agent. The keys stay in a local vault on your Mac; you approve each run and every action lands in a sealed journal.

© 2026 Sallyport · Open source under Apache-2.0 · Oleg Sotnikov