Harnesses
Harnesses
A harness is an AI coding agent mechabedo drives. Seven of them run here: Claude Code, Codex, OpenCode, Qwen Code, Hermes, maki, and mechabedo's own coding agent.
They differ in who made them, which models they can reach and what their tools are called. They do not differ in how you read them. Every one speaks the Agent Client Protocol, so one conversation view, one permission prompt and one queue serve all seven.
Why they all look the same
ACP is a small vocabulary of updates an agent sends while it works: text, reasoning, a tool call with its input and its diff, a plan, a request for permission, and what the turn cost. mechabedo renders that vocabulary and nothing else.
Drawing the diagram…
Nothing about a conversation is reconstructed. What you read is what the agent actually sent.
Who is its own agent, and who needs an adapter
Two of the seven have no ACP mode of their own, so a separate program speaks it on their behalf. That program is a prerequisite: without it, that harness opens no session at all.
| Harness | How it speaks ACP | Needs |
|---|---|---|
| OpenCode | opencode acp | Nothing |
| Qwen Code | qwen --acp | Nothing |
| Hermes | hermes acp | Nothing |
| maki | maki acp | Nothing |
| mechabedo | mechabedo acp | Nothing |
| Claude Code | @agentclientprotocol/claude-agent-acp | The adapter |
| Codex | @agentclientprotocol/codex-acp | The adapter |
Adapters are installed for you
Settings, Bootstrap installs both adapters as part of either recommended set. You do not normally meet this distinction; you meet it when a harness tile wears an install badge.
Two kinds, and what the kind decides
The kind is about process lifecycle, not about the conversation.
| Kind | Harnesses | What runs |
|---|---|---|
server | OpenCode | One long-lived opencode serve per workspace, on a private loopback port, proxied by mechabedo |
cli | The other six | No resident process. A workspace is ready as soon as its binary is |
An OpenCode workspace therefore runs two processes doing different jobs: the server the workspace is proxied to, and one opencode acp per session.
The requirement gate
Picking a harness that cannot open a session sends you to the install rather than failing later.
Drawing the diagram…
Every surface that picks a harness runs this check before anything is created: the Home launcher, the workbench's deep links, the Refinery's run form, the conventions panel, and the chat's own open_session and launch_agent tools. A tool call that hits the gate comes back with the package to install and the harnesses that are ready, and creates nothing.
A real terminal, as well
Every harness also runs under a real pseudo-terminal. Type /cli in the prompt box, or press t, and it takes the workbench's main pane in place of the conversation. That path gives you the harness's own interface, keystroke for keystroke, for the times you want to drive it yourself.
The two paths do not replace each other. A session is a native ACP session or it does not open; the terminal is beside it, not underneath it.
Sessions nobody asked mechabedo to start
A harness you launched in a terminal of your own is still found. mechabedo scans the process table and joins what it finds with the token meter and the transcript archive, so a claude you started by hand appears on the Home dashboard with its rate and its archive rows.
What each one brings
The differences that actually reach you are the model catalog and the effort levels.
| Harness | Model comes from | Effort |
|---|---|---|
| Claude Code | The Agent SDK's own list, including the [1m] long-context spellings | Five levels, resolved against what the chosen model offers |
| Codex | CODEX_CONFIG at spawn, and a live config option afterwards | model_reasoning_effort |
| OpenCode | Its provider catalog | The current model's own variant keys, which may be two names rather than five |
| Qwen Code | A spawn argument, for every session that process opens | A per-session settings file |
| Hermes | session/set_model, which rebuilds its agent | A profile key |
| maki | provider/model, parsed before the session opens | None. maki has no effort option |
| mechabedo | Your gateway's catalog | The five, straight through |
You do not pick from these lists by hand. A loadout names the harness, the model and the effort together, and it is the only thing that does.
maki wants a qualified id
maki parses provider/model before the session opens, so a bare model id exits its agent with a parse error. mechabedo refuses such a loadout at the point every launch path goes through, and the message names the field.
Configuring one
Settings, Harnesses shows what mechabedo needs to run each harness: the binary it resolved, the variable that overrides it, the arguments and the environment.
What the harness itself is configured with - its providers, its models, its own settings - is a file of its own, which mechabedo neither writes nor parses. Each card names it on a Configuration row, and clicking it opens the file in BedoIDE on the folder it sits in.
| Harness | File |
|---|---|
| Codex | ~/.codex/config.toml |
| Claude Code | ~/.claude/settings.json |
| OpenCode | ~/.config/opencode/opencode.json |
| Qwen Code | ~/.qwen/settings.json |
| maki | ~/.maki/providers.toml |
| Hermes | ~/.hermes/config.yaml |
Each of those moves if you point its own variable somewhere else - CODEX_HOME, CLAUDE_CONFIG_DIR, QWEN_HOME, HERMES_HOME, OPENCODE_CONFIG
- and mechabedo follows the variable rather than the default. A file the harness has not written yet is marked
not written yet, and opening it puts you in the folder it belongs in.
Claude Code's card on the bootstrap page also carries three switches mechabedo applies itself rather than writing into that file: thinking summaries, claude.ai connectors, and Subagent sessions. Connectors are off by default, so the Claude Code sessions mechabedo starts skip the connectors on your claude.ai account, and so skip the notice about the ones that still need authorizing. Turn the switch on to load them.
Subagent sessions are on by default. Each subagent a Claude Code session spawns then streams as a read-only session of its own, below its parent in the rail, and its permission questions are asked on the parent. Off, its tool calls appear inside the parent's conversation instead. The switch applies to sessions opened after it changes.
On Linux the same card offers a pkill guard. Claude Code runs each command as bash -c with the command in that shell's own arguments, so a pkill -f whose pattern matches the command kills the shell running it, and the command stops with Exit code 144. The guard is a file in ~/.claude that makes pkill and pgrep skip their own parent processes, named as CLAUDE_ENV_FILE in ~/.claude/settings.json, so your terminal sessions get it too. If CLAUDE_ENV_FILE already names a file of your own, the card leaves it alone and shows the two lines to add to it.
The guard cannot reach a pkill run over ssh, a ps | grep | kill, or another harness's shell, so every session on every machine is also told to write such a pattern with one letter in quoted brackets, pkill -f 'lo[o]p'. It still matches the process, and no longer matches the shell carrying it.
The same button is on Settings, Loadouts, under each harness's models section, where it answers the other half of the question: what that harness can actually run.
Moving a running session to another model
/model on the workbench prompt line, between turns. A busy session refuses, because a switch landing mid-turn would attribute a turn on screen to a model that did not write it.
The effort is re-resolved against the new model's own list, and the context window is dropped, because the window belonged to the model that named it.
Adding your own
Adding a harness is a spec: what its binary is called, how it is spawned, how it speaks ACP, and how a model and an effort reach it. That is developer work rather than configuration; the shape of it is in the project's own HARNESSES.md.