One Runtime, Many Ways to Reach It
Codewhale’s architecture answers a specific problem: how can a terminal session, a headless command, a worker roster, and a local application interface all perform agent work without quietly developing different meanings of approval, failure, or completion? This chapter maps those surfaces by responsibility. The useful result is not a component inventory, but a way to tell who launches work, who selects a worker, who orders the work, who executes it, and who observes the result.
The repository’s architectural direction is to make one Runtime the durable execution substrate. The interactive TUI remains the live end-user surface and owns the actual turn loop and tool execution path. Other surfaces are launchers, selectors, coordinators, or observers over that substrate. Some compatibility paths are still converging, so this is both a current boundary and a design rule: do not infer that every workspace crate is already an independent runtime merely because its name suggests one.
The same work from different surfaces
The TUI is the surface most people meet first. It accepts a prompt, displays streamed output, presents approval decisions, and renders tool activity in a terminal. A TUI turn is interactive and in-process, but that does not make it a special kind of agent. It still uses the Runtime’s model client, tool policy, execution path, and lifecycle decisions.
The headless codewhale exec path answers a different practical need. A script, CI job, or another local supervisor can submit a task without opening the terminal interface. It emits a structured stream rather than relying on screen output, and it can run the same broad tool-backed loop. The absence of terminal chrome changes how the work is presented, not the basic question of what authority the worker receives or how its terminal state is recorded.
The Runtime API serves applications that need more than a one-shot answer. The local app-server can expose HTTP/SSE, JSON-RPC over stdio, or a Unix-socket transport, while the embedded browser and mobile surfaces provide local control experiences. These clients can create or resume threads, start and steer turns, interrupt work, follow replayable events, resolve approvals, and inspect usage. They are meant to consume lifecycle-aware data rather than scrape a TUI transcript.
That distinction matters when an application reconnects. A screen scraper may see that text stopped appearing and guess that a task finished. A Runtime-aware client can read a turn status, follow an event sequence, inspect pending approvals, and distinguish a completed turn from an interrupted one. The client is not asked to reconstruct authority from presentation. The Runtime exposes the state and decisions that matter.
The local API boundary is deliberately modest. It binds to loopback by default and uses a Runtime token for authenticated mutation and thread data. It does not provide a hosted relay, custody of provider keys, TLS, or user isolation. A local browser or mobile page is therefore a convenience surface for the same machine, not evidence that Codewhale has become a remotely hosted control plane. Exposing such a service to a public network would require a stronger transport and identity boundary than the current API supplies.
The four surfaces can therefore show the same work without being identical interfaces. The TUI is optimized for a person watching a turn. exec is optimized for a script or worker process. The API is optimized for an application that needs durable lifecycle operations. Their relationship is not “four agents competing for the task.” It is “four ways to reach or observe one authority-bearing runtime.”
Who launches, who selects, who executes
Codewhale’s public vocabulary becomes much easier once each noun answers a different question.
Runtime answers: where and how does authorized work execute? It owns the process or worker lifecycle, provider route, workspace and project boundary, tools, approvals, sandbox choice, leases, retries, logs, and terminal state. It is the layer that must make a model response consequential. If a selected worker cannot run within the effective authority envelope, Runtime fails closed rather than silently replacing that worker with a more convenient one.
Fleet answers: who is eligible and which member is selected? A Fleet is a local-first roster. A member has a stable identity, an optional name, a semantic role such as explore or implement, and an exact provider/model route or an explicit inherited route. Fleet can select a member deterministically by identity, role, name, or route. It does not decide whether that member may read a path, use a secret, open a network connection, or bypass approval. Those are Runtime policy inputs applied after selection.
This separation prevents a subtle but important failure mode. Suppose a roster contains a reviewer pinned to one model and an implementer pinned to another. If the implementer cannot run inside the current workspace or policy envelope, Codewhale must report that incompatibility. It must not quietly select the reviewer because the reviewer happens to be available. Identity selection and authority enforcement must remain separate so that a receipt still tells the truth about who was chosen.
Workflow answers: in what order should work happen? It can express phases, branches, loops, gates, budgets, and fan-in. A Workflow is a coordination document, not a hidden shell script. Its JavaScript or TypeScript authoring surface is intentionally restricted to a compile-only declaration subset: the workflow VM does not get a filesystem, shell, network, environment, imports, clock, or randomness. Real work is performed by Runtime workers under the ordinary authority and approval rules.
Lane answers: which one running Workflow instance is being observed? It gives a durable running identity to a Workflow execution. That makes a distinction between a plan for work and a particular run of that plan. A Workflow can be inspected or rerun as an ordering definition; a Lane represents the current lifecycle of one execution. This is useful when a person needs to interrupt, inspect, or resume work without confusing a reusable plan with a live process.
The same division appears in the shared control-plane contract. A slash command and a CLI verb should agree on the operation identifier, target, persistence scope, read-versus-write authority, retry behavior, and receipt shape. If /fleet status and codewhale fleet status mean different things, a person cannot transfer knowledge between the terminal and a script safely. A shared descriptor table is therefore more than a convenience: it is a guard against surface drift.
The diagram is intentionally asymmetric. Fleet and Workflow point toward Runtime because they supply selection and ordering inputs. TUI and exec are ways to launch or observe it. The model client supplies inference, but it does not own the lifecycle. Events and receipts flow out of Runtime because observation should come from the same state transitions that govern execution.
Why one substrate matters
The strongest reason to consolidate execution is not elegance. It is failure behavior.
A detached child that loses a provider connection should not become a mysterious failed paragraph while an equivalent durable worker retries, preserves a checkpoint, and exposes a continuation handle. If the same assignment has different retry or receipt semantics depending on whether it was launched from agent, Fleet, or exec, the operator cannot tell whether a failure belongs to the task, the provider, the transport, or the launcher. One lifecycle gives those cases a common vocabulary.
The same is true for authority. A background worker should not gain broader filesystem or network access merely because it was started by a Workflow instead of the parent turn. A Fleet profile may identify a model and role, but it must not smuggle in trust mode, secret access, or a sandbox exemption. The Runtime intersects a child’s requested posture with the live parent or standalone execution envelope. Delegation can move work; it cannot widen authority.
Durability also changes what “done” means. A TUI turn can end when the model produces a final response, but a durable run may still have child workers, queued phases, verifier gates, or artifacts to settle. Runtime-owned records let a supervisor see whether a worker is running, interrupted, failed, or completed. Workflow and Fleet can then use those records for fan-in rather than treating dispatch as completion.
There is a performance reason as well. The project’s runtime notes distinguish a compact lifecycle stream from a child’s full transcript. A parent should receive a bounded worker summary and lifecycle events, not every internal message from every child. The execution work can remain rich while the orchestrating UI remains readable. When durable work runs out of process, the heavy construction and recovery state also move away from the interactive terminal, reducing the chance that fan-out makes the TUI unresponsive.
These benefits depend on keeping the boundary honest. The architecture documentation says the split into workspace crates is incremental and that the TUI runtime remains the live source of truth. It also describes some sub-agent behavior as a compatibility path while it converges on the durable Runtime lifecycle. The right conclusion is not that the design is already perfectly unified. It is that the project has chosen a test for new features: does a new surface launch and observe the one Runtime, or does it invent a second execution path?
Choosing a surface without inventing semantics
For a person exploring a repository, the TUI is the natural surface because it exposes the interaction, approvals, and work state directly. For a repeatable script or CI job, exec is more appropriate because structured output can be consumed without terminal rendering. For an editor, browser, or local supervisor that needs to resume, steer, interrupt, or replay a turn, the Runtime API is the stronger fit.
Fleet and Workflow are not replacements for those choices. They become useful when the work needs stable worker identities, multiple roles, ordered phases, durable retries, or deterministic fan-in. A small change does not become better merely because it is split into workers. The smallest sufficient surface is usually the safest one: keep tightly coupled work in the parent turn, use a focused child when separation helps, and reserve Workflow for work whose order, gates, or recovery must be explicit.
A restart scenario makes the difference concrete. An interactive process may disappear while a turn is in progress; a durable Runtime record can mark the in-flight work interrupted rather than letting a caller infer success from silence. A headless worker can preserve a checkpoint or retry a transient provider failure, while the parent receives a bounded lifecycle event instead of an unbounded child transcript. The point is not that every failure is recoverable. The point is that the same lifecycle vocabulary gives the operator a place to look and a reason to distinguish transport failure, task failure, cancellation, and incomplete work.
The boundary also matters when policy changes during a run. A Fleet member can be selected from a saved route, but the Runtime still checks whether that route fits the current workspace and authority envelope. If it does not, the run fails closed; it does not search the roster for a substitute. This is a deliberate inconvenience. Silent substitution would make a successful receipt less truthful because the model, provider, or role that actually performed the work would differ from the one the operator chose.
Observation is part of the architecture, not a decoration placed on top. The Runtime API’s thread and event model lets a client reconnect to a known cursor, inspect pending approvals, and ask for an interrupt without pretending that a new prompt is equivalent to a control operation. The TUI, a script, and a browser can render different views, but they should be able to refer to the same turn, worker, or run. That shared identity is what makes an event useful after the original screen is gone.
The same principle explains why the project is cautious about surfaces that are not fully implemented. A browser control page may omit file-change or restore controls until the Runtime publishes an explicit contract for them. A compatibility command may retain an older name without becoming a new model-facing capability. A crate may contain a future or transitional subsystem without proving that the live TUI executes through it. The architecture is strongest when it reports these distinctions instead of smoothing them into a single feature list.
There is a maintenance cost to this approach. Every new launch surface must preserve route identity, permission behavior, cancellation semantics, event ordering, and receipt meaning. Every new orchestration layer must remain unable to bypass the Runtime’s tool and sandbox policy. Every integration must decide whether it needs a live stream, a durable record, or a one-shot result. Those constraints slow down shortcuts, but they also prevent a local convenience path from becoming an unreviewed second authority system.
The practical judgment is therefore architectural rather than brand-specific. When two surfaces appear to do the same thing, ask whether they share the same authority, lifecycle, and evidence model. If they do, the difference is likely presentation or launch context. If they do not, a hidden second runtime may be forming—and with it, a second definition of what approval, failure, and completion mean.
The next step is to open that shared substrate and watch it operate. Once the boundaries among TUI, exec, Fleet, Workflow, Lane, Runtime, and the model client are clear, the central question becomes temporal: what happens inside one selected Runtime after a user submits a task and before Codewhale can honestly say the work is done?