Skip to main content

3. What is truly advanced about a unified runtime host and App Server?

3.1 The most valuable part of “unified across ends” is a unified contract

A basic design might have the CLI, IDE, and desktop each implement its own loop. When you add “continue after approval,” every end needs a code change, and the state semantics easily diverge. The idea of a shared runtime is: the client sends structured intent, the host owns the tasks and execution, and then pushes the event stream back to the client. The same tool start, tool end, awaiting approval, completed, and failed can be represented in a single set of state semantics. App Server provides bidirectional communication and protocol primitives such as threads, turns, and items. The official description says it can be used for rich-client integration and supports the CLI connecting to a remote host. This supports “a reusable host interface,” but does not prove that all products run only one OS process, or that all threads share one JavaScript heap. Official App Server documentation
Note: different SDKs do not define “turn” identically. Do not conflate Codex’s product turn, one model API response, and a single model step within the loop.

3.2 How does a request complete end to end?

Protocol messages follow JSON-RPC style, and App Server omits the jsonrpc field on the wire. Requests have an id; notifications do not; reverse approval requests also have an id. So you cannot write “treat the first line of JSON read as the current request’s result.”
The last two are only protocol illustrations; this probe did not send them. See the full runnable client in the appendix app_server_client.py, which only performs initialization and verifies a real stdio handshake.

3.3 Why distinguish request ID, thread ID, turn ID, call ID, and cell ID?

These concepts are related but not interchangeable. IDs generated by the server should be passed through unchanged; a business-layer extra revision is for recording requirement changes and should not impersonate a protocol field.

3.4 Benefits and costs of a unified host

“One session, one process” is not an architectural original sin. For untrusted code, stronger isolation has value. Choosing Rust, Bun, Node, or Python itself does not prove whether task scheduling and state recovery are well designed. Engineering-wise, a shared host should at minimum have: per-thread permission and state isolation, global and per-thread concurrency limits, bounded queues, output backpressure, cancellation propagation, disconnect recovery, and version negotiation. Unified implementation does not mean giving up isolation.

3.5 Remote connections and version drift

Localhost example from the official docs:
“CLI connects to App Server” and “App Server connects to Code Mode Host” are two different connections. The former is the product control protocol; the latter is the code-execution host protocol. This time we also found a real docs/source divergence: the online App Server docs still show --code-mode-host wss://...; in the pinned source, CodeModeHostTransport::Grpc and URL validation accept http/https. This article therefore does not provide a remote Code Mode deployment command claimed to be cross-version portable. You should use the schema, help output, and matching source generated by the version you actually deploy. Remote exposure also needs authentication and transport protection configured, and experimental interfaces cannot be automatically assumed to be production commitments. Pinned source: host transport config

3.6 Interview answer

I understand the core of a unified Runtime Host is extracting the agent’s execution semantics out of the client and supporting multiple frontends with a stable task protocol. The benefit is consistent behavior for sessions, tools, approvals, and events; the cost is that a shared host must supply isolation, backpressure, recovery, and version compatibility. I do not judge architecture quality by process count or implementation language.

4. Agent GUI: it looks like an interface, but it is really a projection of runtime state

Screenshots praise UI/UX, but what really deserves discussion in an interview is “how the interface lets the user know what is happening, and what they can still control.” This section is engineering design based on an event-driven system; it does not claim to reproduce closed-source desktop code.

4.1 What underlying support does a good interface need?

You cannot rely only on a frontend timer to fake “reading file” or “almost done.” Otherwise, after a backend failure, the UI may still show success.

4.2 Why do you need a reducer?

Below is a custom teaching event protocol, not Codex fields. A reducer turns events into UI state so that “handling events” and “drawing the interface” are separated:
This assumes the server provides an ordered event stream; if a sequence gap is found, you should catch up or refresh the snapshot rather than use lastSeq to mask the missing events. Multi-thread events also need to be split by thread/turn. Do not map teaching event sequence numbers directly onto fields that every App Server notification carries. Reconnection can use a “snapshot + events after the snapshot cursor” pattern, ensuring the snapshot and the cursor come from the same consistency boundary. Otherwise, events are lost between reading the snapshot and subscribing. Whether a specific product supports event replay depends on the corresponding protocol; you cannot infer the implementation from the UI appearing to recover.

4.3 The three most important interaction distinctions

  1. Request accepted ≠ work finished: Is the RPC return a start acknowledgment or a completion result?
  2. Tool completed ≠ task succeeded: A test command exiting does not mean the exit code was zero; a zero exit code does not mean acceptance requirements are covered.
  3. New requirement enqueued ≠ new requirement applied: Steering must show the actual state, not claim “already adjusted” the moment the send button is pressed.