From PTY to Agent Session: How Orca Knows What Is Happening
Orca’s agent session is the running relationship among a CLI agent, a terminal, and a worktree—not just a tab with a spinner. This chapter follows that relationship through launch, work, questions, completion, exit, restart, and restore. It also explains how terminal output and provider hooks become status evidence, and why Orca sometimes shows a workspace without claiming that the underlying process is still alive. That distinction is what makes a multi-agent dashboard useful instead of merely animated.
A session is a process with a visible lifecycle
A worktree is a place on disk. A terminal tab is a surface through which a shell or process communicates. An agent session is the process-specific layer that connects the two: one recognized CLI agent running in one terminal in one worktree. The distinction matters because each object can have a different lifecycle. A worktree may remain after its agent exits. A terminal can host a plain shell that Orca does not recognize as an agent. An agent process can continue while its visible window is closed.
Orca starts a supported agent in the selected worktree and tracks the session as it changes. The normal path begins with launch, when the CLI is spawned with its working directory and provider-specific configuration. During work, the terminal receives output and the agent may emit status hooks or terminal title signals. If the agent asks for permission or information, the session becomes waiting or blocked rather than simply idle. When the agent reports that its turn is complete, Orca can surface a done state and notify the operator. If the process exits, a restart control can start the same agent again in the same worktree.
These states answer different operational questions. “Working” means the system has evidence of active agent work. “Waiting” means progress depends on a human response. “Done” means the agent has reached a completion boundary; it does not mean the code has passed review. “Idle” describes a quiet session that has not recently reported completion. “Blocked” or “failed” tells the operator that progress cannot continue normally. Keeping the vocabulary separate prevents a dashboard from turning every non-spinning state into “finished.”
The terminal is therefore more than a place to display text. Orca’s runtime consumes the bytes arriving from the PTY, retains a bounded tail and transcript view, watches for agent status signals, and publishes terminal data to its viewers. A user can search the scrollback, copy context, or open links, while the same stream can update the status attached to the worktree. The agent remains the source of the work; the terminal is the observable channel through which the runtime can connect process behavior to a workspace.
The lifecycle has two persistence layers. The first is the agent process and its PTY. Orca’s terminal daemon owns local PTYs separately from the main/runtime process that owns RPC, Git, worktree metadata, persistence, and control-plane services. When the desktop application closes in a normal way, the UI can detach from the daemon while the agent continues. Reopening Orca can then reattach to the process and restore the worktree, tabs, splits, scrollback, and focused view.
That behavior is deliberately narrower than “the session always survives.” The daemon depends on the host. A reboot, hard power failure, operating-system event, or daemon crash ends the running agent processes even if Orca can restore the layout and the last persisted scrollback. A supervisor can also define a boundary that is stronger than process detachment: in the documented combined systemd setup, stopping the service kills the daemon and the PTYs in its cgroup. An update or restart that preserves the daemon is therefore different from a service stop that tears down the entire process group.
This distinction helps explain why the same worktree can look familiar after a failure while requiring a new agent process. The directory and branch are durable Git objects. The pane arrangement and some terminal history are persisted UI state. The live process is a host resource. A restart reuses the first two layers but cannot retroactively preserve an in-flight command that the host has already killed.
It also explains why Orca tracks an agent rather than inferring everything from whether a terminal exists. A terminal tab can be open at a shell prompt after its agent has exited. A process can be alive while the UI is temporarily detached. A worktree can contain partial edits even after the process that made them is gone. The session layer joins these facts: it records which agent was launched, which terminal and worktree it belongs to, what state was last observed, and whether the same surface can be restarted or reattached.
The join is not perfect for every provider. Some agents expose explicit hooks for turn boundaries and questions; others provide only recognizable terminal titles or output patterns. Orca can launch a broad set of CLIs, but deeper status, usage, account, and history integration varies. That is why a common dashboard should be read as a normalized view of available evidence, not as a claim that every provider has the same internal lifecycle. When no agent is recognized, the absence of an indicator is itself meaningful: Orca is showing a shell, not silently inventing agent state.
Status is evidence, and evidence can age
Orca receives agent state through several channels because different agents expose different signals. Provider hooks can report explicit lifecycle events. OSC status payloads can arrive inside PTY bytes. Terminal titles offer another, weaker observation. Launch-time information can seed an initial row, and structured agent sessions can publish a projection from a journal even when there is no traditional PTY. The product can present a common set of working, waiting, blocked, and done states, but the evidence behind those states is not identical.
In practice, these signals are observations of different strength and scope. A hook may say that an agent submitted a turn or is asking a question. A status payload embedded in terminal output can update quickly, but it is still a snapshot of what the PTY received. A title can be a useful fallback for a provider that does not expose hooks, yet a title does not necessarily identify why the process is quiet. Structured chat journals provide durable conversation evidence, but their projection into a worktree row is not the same as a live process signal. Treating all signals as interchangeable would make the interface look simpler while making its conclusions less reliable.
The difference between a hook and a title is consequential. A provider hook is designed to report an agent event, while a title can be delayed, truncated, or changed by an intermediate shell. Orca’s status pipeline keeps provider identity, worktree attribution, terminal joins, state history, prompts, tool previews, and assistant-message previews with the row so a reader can see more than a color. It also bounds these fields and the number of retained history entries. Bounded state is not merely a performance optimization: it prevents a noisy or malformed agent from turning one status row into unbounded memory or transport load.
Structured sessions add a useful case. A chat-oriented session can have a durable journal and a host-owned status projection without owning a PTY of its own. The host publishes that projection into the same status path used by other readers, while the journal remains the durable truth for the structured conversation. This lets the CLI, mobile view, and worktree listing find the session without pretending that a chat projection is a terminal transcript. When the host closes or relinquishes the structured session, the corresponding row must be removed; otherwise a dashboard could show a permanently working agent that no longer exists.
The current architecture is moving toward one source of status per execution host. Hook events, OSC observations, relayed inputs, and structured-session summaries converge on the host’s status store. The desktop sidebar, worktree ps, mobile, and the agent dashboard then project views from that store rather than independently inventing the meaning of a row. This removes one class of contradiction: a dismissal or certified exit can remove the same status everywhere. The repository’s engineering record is careful, however, to distinguish the landed host-store consolidation from later renderer-side unification and shared rollup work. One canonical host store does not mean every client implementation has already become identical.
The ownership rule matters more than the storage format. The execution host is the only side that can directly observe its process, so it should decide which observations are accepted and how they relate to a pane or terminal. A client can acknowledge a notification, hide a quiet row, or mirror a snapshot, but it should not write its guess back as execution truth. This prevents a disconnected laptop or phone from overwriting a host’s later evidence. It also makes cleanup coherent: a certified process exit or an explicit dismissal can remove the same row instead of leaving a second retained copy visible elsewhere.
Freshness is the harder problem. A status row can be delivered now even though its evidence was observed earlier. A relay may replay a previous observation after reconnect. A persisted row may describe what was true before the application stopped receiving events. Orca therefore separates the clock that orders delivery from the clock that measures the age of evidence. A replay should arrive in the right order without becoming falsely new merely because the network delivered it again.
Hydration is consequently conservative. When Orca reads a persisted non-done row after a restart, it marks that row as restored but unconfirmed. The row can help rebuild the interface and reconnect provider identity, yet it is not treated as live truth until fresh evidence arrives. This is an important design choice because absence of a new event is ambiguous: the agent may still be working, the hook receiver may have been unavailable, or the process may have died while no one was listening. The interface is allowed to remember; it is not allowed to turn memory into proof.
The same principle applies when status is mirrored to another client. A phone or paired desktop may receive a snapshot from a host and display it later. If the mirror used only the host’s timestamp, clock skew could make old evidence appear permanently fresh or make new evidence decay immediately. A local receipt time gives the replica a way to measure how long it has gone without hearing from the authority. The host remains the owner of execution state; the client owns only its presentation and its knowledge of when the last evidence arrived locally.
This architecture also limits how much status work the runtime must do. It does not need every reader to poll every terminal and independently rescan every history. The host can publish changes when evidence arrives, while bounded caches and periodic reconciliation cover changes made outside the application. The repository’s worktree-scan measurements describe this same trade-off: cheap fingerprints can reduce unnecessary Git subprocesses while a scheduled reconciliation preserves a limit on how long some external change remains undiscovered. Responsiveness is achieved by budgeting observation, not by claiming continuous omniscience.
This is why a disconnected workspace should not automatically be rendered as failed. A missing status update can mean a quiet agent, a lost transport, a stale restored row, or a process that really exited. Orca’s later fleet projections make this uncertainty explicit for supervised workers, but the same reasoning is already present in session status: the system should preserve the difference between what it observed and what it cannot currently observe.
The operator can use that evidence model in practical ways. A working row with a recent provider signal deserves attention differently from a restored row with no fresh event. A waiting row calls for a response, not a restart. A done row calls for diff review, not immediate merge. A red or blocked row calls for diagnosis, and the diagnosis should begin by asking whether the problem is the agent, the setup, the terminal, the runtime, or the connection. Status makes those questions discoverable; it does not answer all of them automatically.
The result is a deliberately modest promise. Orca can make many sessions visible at once, preserve their context across an ordinary application close, and expose evidence from several agent protocols through one interface. It cannot guarantee that every provider reports the same signals, that every restored process survived, or that a quiet remote connection means the work ended. The value of the status layer is precisely that it can represent those distinctions instead of hiding them behind a single success color.
With worktrees separating the files and sessions making process state visible, a three-agent race becomes something an operator can inspect rather than merely start. But visibility still leaves a decision: which attempt deserves to move toward delivery, and what evidence is missing before that choice is safe? The next synthesis brings isolation, session evidence, and human selection together before the review loop begins.