Live agent sessions
Overlord can connect a running agent session to its mission. This live connection is separate from the mission protocol: the protocol records attach, progress, questions, and delivery; the agent-session connection handles activity, time-bounded decisions, and instructions while the harness is running.
The three live paths
Section titled “The three live paths”Agent harness │ ├─ observe ──► activity events in Overlord (never blocks) ├─ decide ◄── allow or deny while a hook waits (bounded wait) └─ inject ◄── instruction for this live session (delivery varies by harness)- Observe reduces native events on the execution target before sending them. Tool inputs, outputs, file contents, environment variables, and transcript paths are not uploaded. A prompt is the deliberate exception because the activity feed exists to show it; secret redaction still runs first.
- Decide creates a short-lived request when the harness can pause for an answer. A callback
never advertises an answer window beyond the time it can actually wait; Overlord reserves 20%
of the native timeout for fallback. Many callback harnesses therefore allow only tens of
seconds even though Overlord’s general away-user policy permits a longer window. If Overlord,
the network, or the waiter fails, Overlord emits no answer and returns control to the harness.
Pi is different and is described below. A held decision renders in the mission panel as one of
four request kinds — a plain allow/deny permission, a blocking question, a choice
among fixed options, or a retry intent — depending on what the harness asked for. Only
question and choice requests can currently be answered remotely, and only when the
mission’s objective has a live Latch terminal session Overlord can reach
(
AgentRequestDto.delivery.mode === 'latch'); a permission or retry request always falls back to the harness’s own native prompt or policy. - Inject sends an instruction to a specific live session. The result is honest about what the harness proved: Delivered, Queued (turn boundary), Queued (next turn), or Unsupported. An instruction already emitted to a harness is never automatically retried.
Why a session channel exists
Section titled “Why a session channel exists”When wired up, the channel is created before the agent process starts, so startup events have somewhere authorized to land before the mission protocol attaches. Its credential is scoped to one channel and stored hash-only by the server. It cannot read mission context or act as a human, and a normal user token cannot impersonate an adapter.
runner/manual launch └─ creates channel + one-time credential └─ starts harness └─ protocol attach binds channel to agent sessionAs the caution above notes, this creation step is not currently called from either launch path, so a launched session today runs without a channel — the diagram describes the intended shape, not current behavior. The native harness session id is only a correlation label in any case. Neither it nor the checkout path grants access. This matters when several missions, worktrees, or agents are active on the same machine.
Answering a held question
Section titled “Answering a held question”Use ovld requests to list a decision that a live adapter has already opened, then answer it
with the request ID and revision shown. Only question and choice requests are
answerable this way, and only while ovld requests reports a latch delivery mode for that
request; a request reporting read_only (no reachable Latch session) cannot be answered
remotely — resolve it in the native harness instead. The static capability catalog is
diagnostic evidence; it does not manufacture a request when the live harness never opened one.
Sending an arbitrary instruction into a running session (ovld inputs send) and the mission
panel’s session-instructions control are retired along with the session channel above; the
backend now rejects both with session_controls_gone. ovld inputs list still reads historical
rows for a mission but cannot be used to queue a new one.
Conflicts with hooks outside Overlord
Section titled “Conflicts with hooks outside Overlord”Overlord installs hooks additively and preserves existing configuration, but two valid hooks can still conflict because the harness decides ordering, timeout, and response composition.
Two hooks answer the same decision
Section titled “Two hooks answer the same decision”An external policy hook may auto-allow, deny, or rewrite a request while Overlord is holding the same callback for a human. Depending on the harness, first response, last response, or a merged response may win. Do not run two decision owners for the same native event unless that harness’s composition rule is documented and tested.
Permission event ├─ Overlord hook ── waits for remote answer └─ team hook ── auto-allows immediately ▲ effective winner is harness-specificFor Codex, do not combine the hook adapter with an experimental app-server decision subscriber; select one integration shape. For Cursor, avoid routing Claude-shaped permission output into Cursor’s flat decision contract.
A hook changes failure behavior
Section titled “A hook changes failure behavior”Overlord’s decision callbacks fail toward native behavior: no response means the harness shows
its normal prompt or follows its normal policy. Settings such as Cursor’s failClosed can turn a
script error into a denial and invert that guarantee. Leave fail-closed behavior off for the
Overlord hook and apply mandatory policy in a separate, deliberately tested control.
Pi has no native permission prompt. Its optional decision interceptor therefore fails toward running the tool. It is disabled unless both workspace policy and project opt-in enable it; do not enable it without accepting the named fail-open deadline. Current builds do not expose those gates in Settings, so normal connector setup leaves Pi decisions disabled.
Timeouts stack
Section titled “Timeouts stack”Each callback, wrapper shell, and hook manager may impose a timeout. The shortest timeout wins. If another hook consumes most of the budget, an Overlord card can disappear just before it is answered. Keep unrelated observational hooks non-blocking and set decision timeouts from one policy owner.
Duplicate observation and side effects
Section titled “Duplicate observation and side effects”Overlord reduces each connector callback through that connector’s compiled codec. Only an exact
normalized file.edited path can enter the objective/session ledger; read-only callbacks are
silent, and mutation-capable callbacks without a usable path record unavailable hook health.
Duplicate hook registrations can still run arbitrary external commands twice, so remove duplicate
registrations even though ledger synchronization itself is idempotent.
Shared configuration namespaces
Section titled “Shared configuration namespaces”Some harnesses read compatibility configuration belonging to another harness. Cursor may read Claude hook configuration in addition to Cursor’s own file, which can make a Claude callback run inside a Cursor session. Keep connector installations current, avoid copying generated hook blocks between harnesses, and inspect both configurations when a hook fires twice.
Stdout is part of the decision protocol
Section titled “Stdout is part of the decision protocol”A decision hook’s stdout is machine-readable native response data. Debug echo output, shell
banners, or a wrapper that combines stderr with stdout can corrupt the response. Send custom
diagnostics to stderr, redact them, and keep them bounded. Overlord itself stays silent on every
failure-to-decide path.
Diagnose a live session
Section titled “Diagnose a live session”ovld doctorovld agent-session capabilities <agent> --jsonovld doctor detects missing or stale managed connector files. The capabilities command is
offline and shows what is fixture-proven, unsupported, not implemented, or still unverified.
After an Overlord upgrade, refresh the connector with ovld agent-setup <agent>.
Given the caution at the top of this page, expect OVERLORD_SESSION_CHANNEL_ID to be absent
from every launched session’s environment today — that reflects the current, unwired state of
launch, not a misconfigured connector.
Related: Agents and connectors · Data boundaries · Troubleshooting
