From Terminal Process to Visible Agent

Munder Difflin's second problem is more specific than “how do we display several agents?” It must show what a real provider CLI actually printed while also explaining what that process is doing at a meaningful lifecycle boundary. This chapter follows that split through the terminal plane, the event plane, the main process, and the office floor. The goal is a trustworthy mental model: an avatar is not an interpretation floating above the terminal, but a view assembled from different signals with different owners and different failure modes.

Raw terminal output is evidence, but not state

A coding agent is still a terminal process. It produces prompts, tool output, warnings, permission requests, stack traces, and provider-specific interface details. Munder Difflin keeps a terminal view because those bytes are the closest thing the operator has to the session as it actually happened. A compact status label may say that an agent is working; the terminal can show what it asked for, what command it ran, whether a test failed, or whether it is waiting for a choice the status label did not anticipate.

That authenticity has a cost. Terminal output is a stream designed for a human or a terminal emulator, not a stable machine-readable description of state. The same text can be formatted differently across providers or terminal modes. A word such as “working” may be printed as part of an ordinary response, while a tool call may be hidden behind a provider's interface. Parsing every byte to infer the current operation would make the visual floor depend on fragile guesses about presentation.

The terminal plane therefore answers a narrow but important question: what did the process emit, and what can the operator inspect directly? It does not, by itself, answer whether a tool invocation has begun, whether a provider has reached a safe idle boundary, or whether an operator control should deny the next action. For those questions, Munder Difflin needs another channel.

Structured events provide the boundaries the stream cannot

The event plane receives lifecycle information through provider hooks or bridges. A hook can identify that a prompt was submitted, a tool is about to run, a tool has returned, a notification needs attention, a session has stopped, or a status signal has reported current context occupancy. The exact contract depends on the provider, but the important property is structure: the application receives an event with fields it can validate and route rather than trying to rediscover meaning from screen decoration.

In the current implementation, provider hook shims send newline-delimited JSON to a Unix-domain socket owned by the Electron main process. The hook server places a size limit on an incoming frame, parses it, records session and transcript information when available, and validates the event before forwarding it to the renderer. That path is intentionally local. It is a small bridge between a provider's lifecycle and the harness's control plane, not a public web endpoint.

The event is also more than a notification for the avatar. At the PreToolUse boundary, the main process can consult operator control state and return an immediate denial for a paused or gated tool. A halt can stop the agent cleanly at a hook boundary. A steering message or standing goal can be added to an eligible provider response without pretending that the user typed it into the terminal. Repeated tool calls and error signals feed the circuit-breaker policy. Status-line context accounting can be forwarded to the floor so Michael sees which workers have room for a large task.

These actions reveal why timing matters. An event is useful because it arrives at a boundary where a decision can still affect the next step. A raw terminal line that says a tool failed may be valuable evidence, but it comes after the fact. A structured pre-tool event can deny the call before it runs. Conversely, a hook response is not a replacement for the terminal: it can say that a call was attempted without showing the exact provider output that followed.

The main process is the crossing point

The Electron main process owns the privileged crossing between these channels. It manages PTYs, receives hook traffic, starts and stops hive services, and handles filesystem and Git operations exposed to the interface. The renderer communicates through a typed preload bridge rather than receiving unrestricted Node access. In the window configuration, Chromium's renderer sandbox remains active, context isolation is enabled, and Node integration is disabled. This arrangement gives the floor access to the state it needs without making the visual layer the owner of every local capability.

That ownership split is easy to miss because the user sees one application. A terminal panel, an avatar, a task card, and a control button may all refer to the same worker, but they do not write to the same state in the same way. PTY bytes belong to the process stream. Hook payloads belong to the event path. Decisions about filesystem and Git access belong to main-side handlers. The renderer asks for views and actions through the bridge; it does not become a second unrestricted process supervisor.

The benefit is not merely security in the abstract. It gives the application a place to reconcile signals. A hook can identify a session, update the agent's observed state, and trigger a UI event while the terminal stream continues independently. A missing hook should not erase the terminal evidence. A renderer window that is being rebuilt should not become the sole owner of the hive's durable routing. Keeping those responsibilities apart makes partial failure visible instead of turning it into one indistinguishable blank state.

One turn, two signal paths

sequenceDiagram participant H as Human participant P as Agent CLI / PTY participant B as Hook bridge participant M as Main process participant R as Renderer H->>P: Submit prompt through terminal or command bar P-->>R: Raw PTY bytes for terminal view P->>B: Lifecycle hook payload B->>M: JSON over local Unix socket M->>M: Validate, record session/context, apply control policy M-->>R: Hook event and avatar/status update R-->>H: Floor view plus selected terminal P-->>R: More raw output P->>B: Tool result or stop/notification event B->>M: Structured boundary M-->>R: Working, blocked, idle, or completion state

The sequence shows why the planes should converge in the main process instead of being collapsed into one parser. The human can submit through a command surface, but the provider CLI remains the process that interprets and executes the prompt. Its raw output reaches the terminal view. Its hook bridge reports boundaries to the main process. The main process decides what can be forwarded, denied, or enriched, and the renderer turns those results into a floor state the operator can scan.

A failure in one path has a different meaning from a failure in the other. If the PTY is alive but no hook arrives, the user may still see output, but the avatar can become stale and guarded delivery may not know when the agent is safe to wake. If hooks arrive but the terminal view is broken, the floor may show a worker as active while the operator cannot inspect the underlying exchange. If the renderer is temporarily unavailable, the main process can still own local services and durable hive state, but the user loses the immediate visual explanation. The architecture is valuable partly because it lets these failures be named separately.

From event to floor state

The office floor translates structured events into an operator-facing language. A prompt submission wakes an avatar. A tool boundary moves it toward a station associated with file work, a terminal command, a web action, a task update, or another provider integration. A completed tool result can return it toward its desk. A notification that means the agent is waiting for the user can raise a mailbox or a desktop notice. A closed terminal can become a ghost and later leave the active floor. These mappings are not claims that the avatar has intentions; they are a compact display of observed process conditions.

The design system makes the same point through its status rules. “Working,” “thinking,” “waiting,” “blocked,” “success,” and “ghost” have distinct meanings, and status is supposed to be communicated through color, icon, and position rather than color alone. Reduced-motion behavior can replace walking with an immediate state change. The floor is therefore a summary view with accessibility and uncertainty requirements, not a replacement for the selected terminal or the underlying event record.

This distinction matters when an avatar appears to be thinking. The implementation can know that a provider is moving through a hook-driven lifecycle or that a PTY is producing output, but it cannot infer the quality of the reasoning from movement. Likewise, a worker sitting at a desk may mean that a turn ended, not that its result is correct. The floor answers “where in the operating cycle is this process?” It does not answer “should I trust the code it produced?” That judgment still requires the terminal, files, tests, task record, or human review.

Provider bridges make visibility conditional

A common interface does not create identical lifecycle semantics across providers. Claude-style providers can receive settings and hook configuration in a direct path. Other CLIs need translated hooks, a per-agent configuration directory, a plugin, or a loopback proxy that synthesizes the same kind of event for the harness. Some providers can safely receive inbox work at an idle boundary; others cannot expose enough state to prevent a message from being typed into a busy or uncertain interface. In those cases, Munder Difflin uses a terminal handoff or bounces the message to Michael rather than treating the provider as fully equivalent.

This is a crucial qualification on the office metaphor. Two avatars may occupy the same floor and show similar colors while their event coverage differs. One provider may report a native stop event; another may depend on a bridge whose runtime behavior has not been proven with a live key. A proxy may fail to bind and deliberately let the CLI run in a degraded mode without synthesized hive events. The product's source and changelog distinguish reviewed wiring from runtime verification. A reader should do the same.

The visible model can also become stale for ordinary operational reasons: a hook process may exit, a socket may be unavailable, a provider may change its event contract, or the renderer may miss a state update. The raw terminal remains a useful fallback, but it is not a full substitute for lifecycle events. Conversely, a healthy-looking avatar cannot prove that a provider's output was delivered, that a message reached its recipient, or that a task has been integrated. Munder Difflin's architecture makes those questions inspectable; it does not answer them automatically.

The floor is a view over a control boundary

The two-plane design also clarifies what “autonomy with a leash” means in concrete terms. The agent process owns the provider conversation and executes tools within its configured environment. The main process owns the socket, control decisions, and privileged bridges. The renderer presents the state and gives the operator a way to pause, steer, gate, or inspect. A hook can be denied at the right boundary, but a slow human approval remains a native provider permission flow. A terminal notification can say that the worker needs attention, but the application should not silently type around a prompt the person is answering.

This arrangement keeps the human relationship visible in the UI. Michael can route routine work, but the floor is also a place where the operator can select a worker, read the live terminal, and intervene. The event plane gives the application enough structure to coordinate; the terminal plane keeps the provider process accountable to direct inspection. Neither channel is the authority on its own. Their convergence is what lets Munder Difflin be both a control room and a window onto actual agent work.

The remaining difficulty is now clear. Seeing several agents is not the same as giving them a reliable shared context. Once the floor can tell the operator that work is happening, the system needs a substrate that can carry a request from one process to another, preserve what happened, and recover when a recipient is busy or absent. That is the role of the hive.

References