A client is a product, and how it runs is not configuration
Current names. ADR 0013 renamed a trial's trace to its transcript. The decision itself stands.
Every client returns one trace, and the same graders score it. Nothing in grading or reporting branches on a client's name. What differs from client to client is how MST runs it, and part of that reaches the eval config:
- An option changes the product.
chatgptwithclientOptions.surface: "codex"tests the Codex surface of the desktop app, not ChatGPT. Its name also collides with thecodexclient, which is the Codex CLI, and the two Codex products need names that tell them apart. - A setting chooses what the OS already decides.
coworktakesclientOptions.computerUseProvider: "anthropic-computer-use" | "linux-desktop", but each OS supports only one of them. The coordinator fills in its own OS's value when it reads the config, so a run from macOS with--env dockercan send the macOS value to a Linux worker.linux-desktopisn't Computer Use and has no provider. - One idea has several names. The desktop action budget is
computerUseMaxActionson Cowork and on ChatGPT for macOS, andnativeMaxActionson ChatGPT for Linux. The defaulttimeoutis none formst, 180 s for Claude Code, 300 s for Codex and ChatGPT, and 900 s for Cowork. Some options are accepted and never used:pluginDir,pluginMcpUrl,apiTokenandserveronclaude-code, and a fixedprovideroncoworkandchatgpt. - Each client applies its own rules around a trial. Deadlines, the check that servers are ready, reset after a failure, failure diagnosis and secret redaction are written once per client. Stored results drop answers and tool outputs from traces, but ChatGPT's conversation history stays in its client telemetry.
- Nothing lists the clients. The only list MST prints is the error for an unknown client. The docs table doesn't say which OS, credentials or setup command each client needs.
- Some names say how, not what.
mstnames the tool, not what the client is: a model alone with the servers' tools. The code calls the per-OS mechanism a driver, controller, runtime, platform, backend and adapter. Recorded identities mixopenai.chatgpt.agent.desktop-app.macoswithlinux-desktop.
Decision
-
A client is one product that a person would name. The built-in clients are:
Client What it is apiThe model alone, through its provider's API, with the servers' tools (was mst)claude-codeThe Claude Code CLI coworkClaude Desktop in Cowork mode codex-cliThe Codex CLI (was codex)chatgptThe ChatGPT desktop app codex-appThe Codex surface of the desktop app (was chatgptwithsurface: "codex")No option changes which product a client is.
mst,codex, andsurfaceonchatgpt, fail validation and name their replacement, as the client names ADR 0002 replaced do. The two Codex products are named for what they are,codex-cliandcodex-app, so neither name is the bare product name that could mean the other. -
How a client runs follows from the client and the OS of the machine that runs the trial. It is not configuration. On macOS,
cowork,chatgptandcodex-appuse Computer Use, withcomputerUseModelas its planner. On Linux they use the accessibility (AT-SPI) automation, which has no planner.computerUseProvideris removed. The machine that runs the trial decides, not the coordinator. A trial records the environment and OS it ran on, so its result says how it ran. MST adds no term for this: a client, a model and an environment describe a trial. In code, a client's per-OS parts are<client>/macos.tsand<client>/linux.ts. -
MST owns the rules around a trial, the same for every client. Shared timeout enforcement and reset retry timings remain follow-ups, as recorded below.
timeoutmeans one thing: the time from the prompt to the trace, without app setup. Each client's definition states its default.- Dataset loading rejects empty or whitespace-only inputs for every client, including run-only plugins, before opening a client or submitting any trial. Valid prompt text is preserved exactly, without trimming. Direct native-session calls retain their blank-input guard before submission.
- One readiness check runs before the first trial: each server connects and lists at least one tool.
- One reset and diagnosis policy applies to a client that keeps an app open across trials.
- One redaction pass covers everything MST stores, client telemetry included.
- How a trial ended follows ADR 0010.
-
One contract for every client, built-ins included. A
ClientDefinitionhas a name, a description, its requirements (OS, credentials, setup command), an options schema, andrun,open, or both. Run-only clients need no change; MST wraps a one-shot session when needed.openreceives fixed client options, model, servers and environment. Its session hasrun,reset, optionaldiagnose, andclose. Each trial supplies its identity and prompt, and returns its result pluscontinue,reset, orstop. A session can list servers that resolve only after opening; MST checks them then. Different fixed settings use separate sessions. MST calls these operations under the rules above. Built-in clients use no private layer: the external-client capability pipeline and the simulation result shape thatmstandclaude-codeconvert through are removed. -
One idea has one option name, and a config that can't run fails when it loads. The shared names are
timeout,maxActions,reasoningEffort(one list of values) andappVersion. An option that a client can't use fails validation. So does a case override that a client can't honor, such as a differentmodelper case in one desktop batch. -
mst clientslists the clients from their definitions. For each one it shows what it is, the OS it needs, its credentials, its setup command, and its options with their defaults.showprints the same information for one client. Both JSON forms include the options schema:defaultfor a literal value,x-defaultDescriptionfor a dynamic default or omission semantics. Runtime fallbacks and schema annotations share their values; listing does not fill in missing options. The docs tables are generated from the same schemas. -
A known environment OS is checked at eval load. Each variant and case client's
requirements.osmust allow the executing machine's OS forlocal, Linux for built-indocker, or a plugin environment's declaredos: 'macos' | 'linux'. The environment field is optional. Unknown or mixed environments leave it out, and MST does not guess. Validation opens no machines and does not compute per-OS option defaults.
Consequences
- The eval config changes before 2.0.
mstbecomesapi,codexbecomescodex-cli,chatgptwithsurface: "codex"becomescodex-app,computerUseProvidergoes, and the option names above change. Each earlier name fails validation and names its replacement, and the migration guide lists them. - A stored run keeps the client names it was written with. Readers treat
mstasapi,codexascodex-cli, andchatgptwith the Codex surface ascodex-app. - Plugin clients that implement
runBatchmove toopen(). A plugin client with onlyrunneeds no definition change. Its datasets now reject whitespace-only inputs too; a blank later case cannot be discovered after earlier cases have already run. - Code goes: the capability pipeline in
src/evals/externalClient/(about 1,100 lines, used only by ChatGPT), the simulation result shape, andexternalClient/builtins/macosDesktop.ts, which nothing uses. ChatGPT's own steps move into its client. Native trace readers move out ofexternalClient/. - Some differences stay, because the products differ. Computer Use on macOS has a planner model and its cost; the Linux automation has neither. Results show which one ran.
CONTEXT.mdchanges with the renames, not before them.- It ships as separate pull requests:
mst clientsand the generated table; the renames and option changes; the MST-owned trial rules, with redaction first; then the contract change and the removals.
Implementation status
Local and worker collection now use the shared session loop. Built-in and plugin clients may implement run, open, or both; collection prefers open, and run-only clients remain unchanged. The client extension's runBatch and the desktop wrappers are removed. Declared-server readiness runs before opening, and Cowork's preparation-dependent readiness runs after opening. Reset retries, diagnosis deadlines, leases and cleanup policy remain unchanged.
File, plugin and in-memory datasets reject blank inputs before any client opens or trial runs, for all clients; valid prompt text is unchanged. The canonical dataset input schema owns this rule, with no client validation hook.
Cowork, ChatGPT and Codex app now have concrete macos.ts and linux.ts entry points, selected from the product and worker OS when the batch opens. The platform selectors are removed. The native helpers, app transactions and turn bodies remain shared. New results omit driver identities, including driver on Linux receipts; readers retain old fields without rewriting stored runs.
The option/default catalogue and known-environment OS checks are implemented, including case clients and optional plugin environment OS metadata. The contract and removal sequence is complete, and this ADR is accepted.
Deferred work
Shared timeout enforcement and reset retry timings remain deferred. Existing client deadlines, reset retries and diagnosis limits are unchanged. Preserving ChatGPT's typed planner failure cause and replacing vercel-sdk / anthropic-api in the connection-policy error also remain separate work.
Verification
The sequence was checked with unit tests, CLI use cases, mocked desktop sessions and local MCP servers. Live Linux Cowork execution was not tested.