Session lifecycle
How CompozyOS creates, activates, stops, and classifies one durable runtime session.
A session is the runtime object CompozyOS manages. It ties together:
- one logical agent session, which can bind an ACP-compatible agent subprocess when a prompt runs
- one workspace boundary
- one per-session SQLite event store
- one permission policy
- one durable CompozyOS session ID
That CompozyOS session ID identifies one durable lifecycle and its retained record.
State machine
Rendering diagram…
| State | Meaning | Valid live transition |
|---|---|---|
starting | A prompt to a stopped session is restoring the ACP process and durable provider history. | starting -> active |
active | CompozyOS has durably allocated the session ID, prepared its storage, and accepts prompts. Before the first prompt, its runtime is unbound; after binding, it can emit ACP events. | active -> stopping |
stopping | CompozyOS has accepted a stop request and is draining the session toward a stopped state. | stopping -> stopped |
stopped | Final metadata is written and the recorder is closed. Reads remain available. A normal prompt can restore an eligible stopped public session; a terminal process_exit remains read-only history and must be forked into a new session. | stopped -> starting |
Creating a session
Create a new session from the CLI:
compozy session new \
--agent general \
--cwd "$PWD" \
--name code-reviewCreate the same session over HTTP:
curl -X POST http://localhost:2123/api/sessions \
-H "Content-Type: application/json" \
-d '{
"agent_name": "general",
"name": "code-review",
"workspace_path": "/absolute/path/to/repo"
}'name is optional for user sessions. With roles.auto_title.enabled = true, CompozyOS starts one bounded
title pass after the first assistant response is persisted, then stores a successful title in
session metadata and the catalog. An explicit name always wins any race. If generation is disabled
or fails, the session remains unnamed; daemon-managed session types are never eligible. Configure
the title pass agent, provider, model, reasoning, and fallback routes under [roles.auto_title].
The request must include exactly one of:
workspace: a registered workspace name or IDworkspace_path: an absolute filesystem path
Behind that request, CompozyOS:
- Resolves the workspace and agent definition.
- Creates
~/.compozy/sessions/<session-id>/. - Opens
events.dbfor the session. - Persists the catalog row and session metadata.
- Activates the logical session with
runtime.status: "unbound". - Returns HTTP/UDS
201 Createdwithstate: "active"and no ACP process or ACP session ID.
Creation never accepts a prompt or runtime selector. It only creates the durable logical session. The agent definition supplies the defaults that the first prompt can use, but CompozyOS does not launch ACP or negotiate provider options until that prompt arrives.
Creation provenance
A session created from inside another session records that origin in its lineage:
compozy__session_create(native tool) links the calling session automatically. The link is server-derived from the bound caller, never a tool input, and is recorded only when the new session lands in the caller's workspace.compozy session new --parent <session-id>andparent_session_idonPOST /api/sessionslink explicitly. The parent must exist in the target workspace; it does not need to be active.- An HTTP/UDS create carrying validated agent identity headers and no explicit parent infers the caller's session as the parent.
Provenance sets lineage.parent_session_id, inherits root_session_id from the parent's tree, and
computes spawn_depth server-side. The session stays type: "user" with no TTL, auto-stop, spawn
budget, or permission narrowing — governed children come only from
safe spawn. Query the hierarchy with the catalog filters parent=<id>
(direct children) and root=<id> (the whole tree, root included), exposed as
compozy session list --parent/--root and on compozy__session_list.
Running an active session
Once a session is active, a prompt supplies an immutable runtime snapshot. The first prompt binds
the logical session to that runtime; later prompts can choose a different snapshot:
compozy session prompt sess-1234 "Review the current changes and report correctness risks." \
--provider cursor \
--model grok-4.6 \
--reasoning-effort high \
--speed fastcurl -N -X POST http://localhost:2123/api/workspaces/ws_alpha/sessions/sess-1234/prompt \
-H "Content-Type: application/json" \
-d '{
"message": "Review the current changes and report correctness risks.",
"message_id": "msg_1234",
"idempotency_key": "idem_1234",
"runtime": {
"provider": "cursor",
"model": "grok-4.6",
"reasoning_effort": "high",
"speed": "fast"
}
}'Pass other advertised select and boolean options with repeatable typed flags. For example, Cursor's Opus 5 variants can expose a Thinking toggle:
compozy session prompt sess-1234 "Review with extended thinking." \
--provider cursor \
--model claude-opus-5 \
--reasoning-effort high \
--speed fast \
--acp-toggle thinking=trueUse --acp-option id=value for selects and --acp-toggle id=true|false for booleans. HTTP and UDS
send the same data as runtime.acp_options, with exactly one of value_id or bool_value per entry.
Two operational details matter here:
message_ididentifies the authored transcript row, whileidempotency_keyidentifies the submission. Keep both values and reuse them together only when retrying the exact same request.runtimeis a prompt-bound snapshot ofprovider,model,reasoning_effort,speed, and typed ACP options. The accepted snapshot is retained with the turn and is not rewritten by later runtime changes.- If a snapshot keeps the same provider, CompozyOS configures the existing ACP session in place when the provider exposes the needed live options. A provider or harness change replaces the process and replays the canonical stored transcript into the replacement ACP session.
- A Cursor model, Reasoning, Fast, or Thinking change resolves a different private launch alias and atomically replaces the process. Public session data continues to expose only the logical model ID.
- CompozyOS records
user_messageonly after runtime binding or reconfiguration succeeds. If binding, replacement, or its rollback fails, the authored message is not persisted as a user turn. - One session processes one prompt turn at a time. Stop logic waits for in-flight prompt setup to finish before it asks the ACP driver to stop the subprocess.
- Long-running prompts stay healthy through runtime activity supervision. CompozyOS updates
activity.last_activity_aton real ACP events and metadata-only waiting heartbeats, then emits lower-frequencyruntime_progressevents. Only actual work evidence prevents silence supervision. - CompozyOS also maintains a separate metadata-only session health
record (
state,health,attachable,eligible_for_wake). Activity supervision feeds health, but the two are distinct authorities — supervision owns timers and persisted progress events, health is consumed byHEARTBEAT.mdwake decisions and thecompozy session health|status|inspectsurfaces.
When the provider disconnects during a prompt
CompozyOS persists each accepted agent event before forwarding it. If the ACP subprocess disconnects after sending part of an answer, the stored assistant chunks remain in events and transcript reads. The daemon then makes three automatic recovery attempts with 1, 2, and 4 second delays. While this is running, session reads expose:
runtime.status: "recovering"runtime.transition: "automatic_recovery"runtime.generationand structuredruntime.recoveryattempt timing- durable
runtime_recovery_started,runtime_recovery_succeeded, andruntime_recovery_exhaustedevents
The replacement process first tries ACP session/load. When that is unavailable, CompozyOS rebuilds
context from the durable transcript. It then replays the interrupted turn with its original turn ID;
the authored user message is not inserted again. A successful replacement continues the same prompt
stream. Viewer disconnects remain detached from execution and do not stop recovery.
Only exhausted recovery emits one terminal error and stops the runtime. A JSONL prompt writes that
error and exits nonzero; compozy__session_prompt returns tool_backend_failed. Inspect the session
before continuing:
compozy session status sess-1234 -o json
compozy session events sess-1234 --last 20 -o jsonAutomatic replay can repeat a tool or external side effect whose completion was not persisted before the disconnect. CompozyOS supplies retained results to the replacement runtime, but cannot prove an external mutation did not complete. Inspect the external system before manually repeating the work.
Selecting the next runtime
Persist next-prompt runtime intent without starting or reconfiguring ACP:
compozy session runtime set sess-1234 \
--provider cursor \
--model claude-opus-5 \
--reasoning-effort high \
--speed fast \
--acp-toggle thinking=trueSession reads expose runtime.selected, runtime.selection_revision, and runtime.effective.
selected survives stops and daemon restarts; effective describes the runtime already applied to
the current process. Runtime fields resolve from provider/project and agent defaults, then durable
selected, then the prompt snapshot. Each higher layer replaces only the fields or option IDs it sets.
HTTP and UDS use PUT /api/workspaces/:workspace/sessions/:id/runtime with the complete runtime
and current expected_revision. Clear the selection with
DELETE /api/workspaces/:workspace/sessions/:id/runtime?expected_revision=<revision>. A stale
revision returns 409; read the session again before deciding what to save.
Workspace knowledge on live turns
Put workspace-owned reference material under <workspace>/knowledge/ as Markdown files. Before an
accepted user, Network, or synthetic turn reaches the agent, CompozyOS reopens that tree and adds a
bounded <workspace-knowledge-snapshot> to the prompt. The snapshot carries the current file bytes,
workspace-relative paths, a revision digest, and omission metadata when a safety limit is reached.
CompozyOS reads regular .md files only and does not follow symbolic links. The read stays inside the
session workspace. A file change does not wake a session by itself; the next eligible turn receives
the new snapshot. This includes task, task-creator, and Heartbeat wakes, so an active worker does not
need a second operator prompt to observe a knowledge change.
The snapshot is prompt context, not durable CompozyOS memory. Use the memory system when the information must be curated, searched, or retained across workspaces and sessions.
Busy input modes
An active session still processes one prompt turn at a time, but CompozyOS accepts explicit busy-input
modes so operators and agents do not have to guess what happens when a prompt is already running.
session.busy_input.default_mode defaults to steer; session.busy_input.queue_cap bounds
the persisted queue.
The Web composer is available for active and eligible stopped user, system, coordinator, and
spawned sessions. While one of these sessions is busy, the Web controls can queue a prompt, steer
or interrupt the current turn, or stop generation. These are turn-level controls: daemon-managed
sessions still do not expose user-session lifecycle actions such as rename, clear, attach, delete,
or stop session. Dream and hidden maintenance sessions remain read-only in the Web session view.
| Mode | CLI | HTTP shape | Result |
|---|---|---|---|
queue | compozy session prompt <id> "<text>" --queue | POST /api/workspaces/:workspace/sessions/:id/prompt with {"mode":"queue","message":"...","message_id":"msg_queue_1234","idempotency_key":"idem_queue_1234","runtime":{...}} | Persists the input and runtime snapshot in FIFO order. The result reports status: "queued", delivery: "after_turn", queue ID, position, and generation. |
interrupt | compozy session prompt <id> "<text>" --interrupt --expected-turn-id turn_1234 | POST /api/workspaces/:workspace/sessions/:id/prompt with {"mode":"interrupt","expected_turn_id":"turn_1234","message":"...","message_id":"msg_interrupt_1234","idempotency_key":"idem_interrupt_1234","runtime":{...}} | Resolves an omitted fence or validates an explicit fence, advances the queue generation, and returns status: "interrupting" with delivery: "interrupt_then_prompt". |
steer | compozy session prompt <id> "<text>" --steer --expected-turn-id turn_1234 | POST /api/workspaces/:workspace/sessions/:id/steer with {"text":"...","message_id":"msg_steer_1234","idempotency_key":"idem_steer_1234","expected_turn_id":"turn_1234"} | Injects into the live turn when supported; otherwise records an interrupt fallback. Reports disposition and steer_delivery. |
The prompt response is authoritative. Use disposition and steer_delivery to inspect the outcome;
transcript markers retain history but are not a second action result channel.
See Session control plane for delivery outcomes, automatic fences, and exact retries.
Managing queued input
Use the queue entry ID from a queued result or from session input list. The daemon owns the list, so
read it again after each mutation instead of keeping a client-side queue.
compozy session input list sess-1234
compozy session input edit sess-1234 queue_entry_1234 "Run the focused test first."
compozy session input steer sess-1234 queue_entry_1234 "Prefer the smaller patch." \
--expected-turn-id turn_1234
compozy session input cancel sess-1234 queue_entry_1234edit and steer author a replacement message_id and idempotency_key; provide both original
values together only to retry the exact same mutation. steer requires --expected-turn-id, which
rejects a request that targets an older turn. HTTP and UDS expose the same daemon-owned operations:
| Operation | Endpoint |
|---|---|
| List | GET /api/workspaces/:workspace/sessions/:id/prompt/queue |
| Edit | PUT /api/workspaces/:workspace/sessions/:id/prompt/queue/:queue_entry_id |
| Promote to steer | POST /api/workspaces/:workspace/sessions/:id/prompt/queue/:queue_entry_id/steer with expected_turn_id |
| Cancel | DELETE /api/workspaces/:workspace/sessions/:id/prompt/queue/:queue_entry_id |
Use POST /api/workspaces/:workspace/sessions/:id/prompt/cancel to stop the current turn without a
replacement. Use prompt mode interrupt or steer with expected_turn_id when replacement text must
run next. Every busy-input transition writes transcript marker evidence for recap, replay, and audit.
Queue and interrupt preserve the runtime snapshot accepted with their replacement input. A queued prompt therefore runs with the selected provider, model, reasoning effort, and speed even if a later prompt changes the session binding first.
Both interrupt and steer submit only the explicit replacement text. They never salvage, reuse, or
combine the canceled authored prompt. The expected turn fence rejects stale actions before they can
affect a newer turn.
Runtime activity supervision
Supervision inspects every live session, including idle sessions. Any fresh work signal keeps the session alive: agent progress, a verified running tool, an active child, a recently reconciled Loop run, a held task lease, or a scheduled wait with a future deadline. Opening a session, subscribing to its events, and provider-wait heartbeats do not renew work evidence.
Inspect supervision.work_signals, supervision.sources, and supervision.quiet_warning
with compozy session status <id> -o json, the session resource, or compozy__session_describe.
Signals are rebuilt from their owners after restart. They are not persisted as keep-alive flags.
Expired evidence stops counting as work. A stale tool, stopping child, or Loop raises attention;
a source inspection error is unknown, raises attention, and prevents an automatic inactivity stop
until the source can be inspected again.
After session.supervision.quiet_after of observed silence (default 30m), CompozyOS records
one session.supervision_warning and shows it in the open session. Continued silence for
session.supervision.stop_grace (default 10m) requests the normal stop ladder with cause
inactivity. session.supervision_stopped records verified termination. Persisted stop metadata
uses stop_reason: "timeout" and stop_detail: "inactivity". New work clears the warning and
cancels the pending automatic stop. quiet_after = "0" disables both actions;
stop_grace = "0" keeps the warning but disables automatic stop.
Event waits without an authored expiry receive the effective admission horizon, normally 168h.
Existing expiryless waits use their original creation time and pinned configuration when upgraded.
An expired wait follows the existing attention path instead of keeping a session alive forever.
runtime_progress remains a periodic progress projection. Metadata-only activity heartbeats and
progress projections do not themselves prove fresh work. Explicit prompt/session wall-clock budgets
remain opt-in controls separate from silence supervision.
Rewinding a conversation
Rewind an idle user session when you want to retry from an earlier prompt without creating another
CompozyOS session. The selected durable user message and every later active event are removed from the
active transcript. CompozyOS returns the selected text as draft_text, keeps the same session ID, and
starts a fresh ACP context from the retained prefix.
compozy session rewind sess-1234 \
--message-id msg_1234The CLI reads the current transcript fences immediately before the request. Scripts retrying one
known request can pass all three --expected-* flags together with the original idempotency key.
HTTP and UDS use POST /api/workspaces/:workspace_id/sessions/:session_id/rewind and require those
same fences.
An identical idempotency_key retry returns the original result. A stale fence, busy session, queued
input, pending approval, or daemon-managed session returns 409 without cutting the transcript.
Rewind changes the conversation only. It does not undo file changes, tool effects, network actions, saved memory, or external provider actions. Removed events remain archived for audit:
compozy session events sess-1234 --archive archived
compozy session history sess-1234 --archive allThe Web action appears on durable user messages. It requires an empty composer, confirms the same
side-effect boundary, reloads the daemon-owned transcript, and places draft_text in the composer.
Stopping a session
Request a stop immediately, or wait for its verified result:
compozy session stop sess-1234
compozy session stop sess-1234 --wait -o jsonThe default command returns the updated session resource. --wait returns the stop outcome:
state, verified, escalated, stop_cause, phase, and stopped_after. A verified result has
state: "stopped" and verified: true. If process exit cannot be verified after the final kill,
the outcome keeps state: "stopping", verified: false, and attention: "stop_verification_failed". The diagnostic also persists on the session resource with the nonterminal needs-attention badge, so reconnecting does not lose the retry action. A verified retry clears it. Compact session status exposes lifecycle_state, verified, escalated, and attention; its existing state field retains the health-state vocabulary.
Inspect the process diagnostics and retry the stop; do not treat that outcome as termination.
HTTP and UDS share the same operation:
curl -X POST http://localhost:2123/api/workspaces/ws_alpha/sessions/sess-1234/stop \
-H 'Content-Type: application/json' -d '{"wait":false}'wait:false returns 202 with status: "stopping". wait:true returns 200 with the settled stop
outcome, including the unverified attention branch. An already stopped session returns 200 without
starting another operation. Closing the requesting client does not abandon an accepted stop.
The governed native tool compozy__session_stop accepts the same wait choice and outcome fields.
Its existing approval and same-workspace, non-self target rules still apply.
For compatibility through v0.4, HTTP/UDS requests that omit wait retain synchronous 204 responses
with a migration warning. Native calls that omit wait retain the previous synchronous result and
include deprecation. Send an explicit boolean; implicit synchronous requests are removed in v0.5.0.
The stop path moves active -> stopping, requests cooperative cancellation, then escalates to
process stop and group kill when necessary. session.stop.cooperative_grace configures the first
phase (default 10s); force and kill verification each have a five-second budget. PID and start-time
identity must prove process exit before terminal state is published. Session reads expose verified
and the durable escalated flag. Turn cancellation uses the same ladder but preserves the logical
session and rebinds a replacement process when escalation killed the previous one.
Stopping preserves the session directory, catalog row, metadata, events, and selected runtime. It ends attach eligibility. A later normal prompt restores the provider history and continues under the same CompozyOS session ID; attach, queue, steer, interrupt, and other control operations do not restart it.
Archiving a stopped session
Archive a stopped session when it should leave the default catalog but its history must remain:
compozy session archive sess-1234The matching HTTP and UDS operation is:
curl -X POST http://localhost:2123/api/workspaces/ws_alpha/sessions/sess-1234/archiveArchive is catalog metadata, separate from the session lifecycle state. Only a stopped session can
be archived. Its metadata, events, ledger, runtime selection, and direct read operations remain
available. Attach, prompt, and resume operations are rejected while it is archived.
Restore the session to the default catalog before restarting it:
compozy session unarchive sess-1234The matching HTTP and UDS endpoint ends in /unarchive. Unarchiving preserves the stopped state, so
a later normal prompt can restart the same logical session. Use removal only when the complete
session record should be deleted.
Timeout behavior
CompozyOS has separate timeout concepts:
| Timeout | What it protects |
|---|---|
session.limits.timeout | Optional wall-clock session limit. 0s disables it. |
session.supervision.quiet_after | Observed silence before one warning; zero disables silence actions. |
session.supervision.stop_grace | Continued silence after the warning before the standard stop ladder. |
session.supervision.prompt_deadline | Optional total prompt budget; zero disables it. |
session.supervision.timeout_cancel_grace | Grace after explicit prompt-budget cancellation. |
session.stop.cooperative_grace | Cooperative phase of the stop ladder, followed by bounded forced/kill phases. |
| Session lifecycle timeout | Recorder close and final cleanup work during stop. |
A session may run indefinitely while fresh work exists and no explicit wall-clock budget is set.
Stop reasons
The session manager currently emits these persisted stop classifications:
| Stop reason | When CompozyOS uses it |
|---|---|
completed | The agent finished normally. |
user_canceled | A normal user stop request. |
max_iterations | A user stop request carried max_iterations detail. |
loop_detected | A user stop request carried loop_detected detail. |
budget_exceeded | A user stop request carried budget_exceeded detail. |
timeout | An explicit runtime budget expired, or silence supervision completed its warning/grace path (stop_detail: inactivity). |
error | Start or stop failed, or ACP reported a transport failure and the subprocess then exited successfully with code 0. |
agent_crashed | The subprocess exited with a non-zero code, a signal, or a wait error; also used when CompozyOS repairs stale active/stopping metadata after a daemon crash. |
hook_stopped | A required lifecycle hook denied continuation. |
shutdown | The daemon shut the session down. |
Inspect the current session state and stop classification at any time:
compozy session status sess-1234Removing persisted history
Remove a session only when its durable history is no longer needed:
compozy session remove sess-1234curl -X DELETE http://localhost:2123/api/workspaces/ws_alpha/sessions/sess-1234Removal stops an active session first, deletes its durable catalog row and session directory, and emits a workspace-scoped catalog deletion signal. After a successful removal, later status or detail reads return session not found. If deletion fails before the directory is removed, CompozyOS preserves or restores catalog truth instead of reporting a partially deleted session.
Failure diagnostics
Stop reasons answer "why did the CompozyOS session stop?" Failure diagnostics answer "what kind of
lifecycle failure did CompozyOS classify, and what evidence is available?" When a lifecycle failure occurs,
CompozyOS persists a failure object with:
kind: stable machine-readable failure kindsummary: bounded redacted diagnostic textcrash_bundle_path: path to a redacted crash bundle when CompozyOS captured one
The same failure object is exposed through session status, session list JSON, session SSE terminal
events, and compozy status.
compozy session status sess-1234 -o json | jq '.session.failure'Current failure kinds are:
| Failure kind | Meaning |
|---|---|
startup_failure | CompozyOS could not finish preparing, launching, or initializing the provider. |
handshake_failure | The subprocess launched but ACP initialization did not complete. |
load_session_failure | An internal daemon-owned provider reload path failed. This is not resume attach. |
protocol_failure | ACP returned a structured protocol/request error outside a prompt-specific path. |
prompt_failure | ACP prompt submission or prompt streaming failed. |
cancellation | The operation was canceled by user action or context cancellation. |
permission_failure | A lifecycle hook or permission boundary denied continuation. |
process_exit | The provider subprocess exited unexpectedly or returned a wait error. |
transport_failure | The ACP stdio transport closed or failed while CompozyOS expected protocol traffic. |
timeout | Runtime supervision or lifecycle timeout expired. |
unknown_failure | CompozyOS had an error but no more specific kind was available. |
Crash bundles are written under ~/.compozy/logs/crash-bundles/ by default. They are JSON documents
with schema compozy.session_crash_bundle.v2, session identity, provider identity, failure kind,
process metadata, error text, and captured stderr when available. Completed process metadata also
includes exit_code and the terminating signal when the operating system exposes them. Bundle
contents are bounded and redacted before they are written, and files are created with owner-only
permissions.
Crash classification and transcript repair
CompozyOS repairs stale persisted metadata the next time it reads a session after an unclean daemon exit. That classification keeps status, list, history, and repair consistent after a crash:
- stale
activebecomesstoppedwithagent_crashed,process_exit, and detaildaemon crashed while session active - stale
stoppingbecomesstoppedwithagent_crashed,process_exit, and detailstop did not complete - stale
startingbecomesstoppedwitherror,startup_failure, and detailstart did not complete
During daemon boot, CompozyOS also inspects stopped sessions whose stop reason is agent_crashed or
error. If the final persisted turn was interrupted, CompozyOS appends repair events to terminalize the
transcript: dangling tool calls receive interrupted tool results, then the turn receives a terminal
error event. The repair is append-only; CompozyOS does not truncate, delete, or resequence session events.
Operators and agents can inspect or run the same append-only transcript repair explicitly:
compozy session repair <session-id> --dry-run
compozy session repair <session-id>What gets persisted
Every session owns a directory under ~/.compozy/sessions/<session-id>/:
meta.json: durable session metadata such as state, workspace, session CWD, stop reason, failure diagnostics, and ACP session IDevents.db: persisted event, token usage, and hook-run history
That durable store supports live resume attach, event replay, deterministic recap, and approval audit. Attach requires a live, attachable session; the other reads remain useful after terminal stop.
Session types
CompozyOS records why a session exists:
| Type | Meaning |
|---|---|
user | Normal interactive work created by a person or client. |
dream | Background memory consolidation work. |
system | Internal CompozyOS-managed work. |
coordinator | Managed autonomy coordinator for workspace-scoped coordinated task runs. |
spawned | Child session created by an agent through safe spawn. |
Dream sessions are special for permissions: they always start with approve-all.
Coordinator sessions are root lineage rows. They are created only after executable coordinated work is enqueued, not when a task is merely created. Spawned sessions record parent, root, depth, role, TTL, and permission metadata so CompozyOS can reap children when their TTL expires or their parent stops.
System sessions created for a Loop Goal record the session that started the Loop as creation provenance when one is available. That relationship groups the Goal under its origin in session views, but it does not make the Goal a safe-spawn child: it has no inherited spawn permissions, TTL, child cap, or parent-stop behavior. Deleting the origin keeps the Goal session and its recorded lineage; views show it as a root when the recorded parent is no longer available.
Next steps
- Use Resume Attach and Replay when you need to attach to an eligible live session or reconstruct prior work from durable reads.
- Use Event Streaming when you need the exact stored and streamed session record.
- Use Runtime Autonomy for coordinator, task lease, and safe-spawn behavior.
- Use Permissions when you need to control or approve agent actions.