A multi-agent comparison layer on top of workmux. Run several coding agents on one prompt in an isolated tmux grid, then review, score, and merge the best β all from a few keystrokes.
ββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ
β claude β
8 β codex β
9 β opencode β
6 β β one prompt, N agents, scored
β β β β
ββββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ€
β wtcp (prefix, then) Ctrl-P pick Β· Ctrl-X drop Β· Ctrl-S send-all Β· Ctrl-R review
βββββββββββββββββββββββββββββββββββββββββββββββ
workmux already does the hard part: one command gives you a git worktree, a
tmux window, and a coding agent running in it, plus a clean merge that folds
the branch back and tears the worktree down. wtcp does not reimplement any of
that β every worktree, branch, agent launch, status icon, and merge below is
workmux doing its job. wtcp is the layer that runs N of them against the
same prompt and helps you choose:
| Layer | Owns |
|---|---|
| workmux | worktrees + branches, tmux windows, launching/prompting each agent, agent status tracking, merge / remove / base + main branch policy |
| wtcp | one prompt β N agents at once, joining their panes into a scored grid, an LLM judge that ranks them head-to-head, and one keystroke to merge the winner and drop the rest |
So everything you know about workmux keeps working, and anything workmux
configures (main_branch, base_branch, agent profiles, hooks) is policy wtcp
follows rather than overrides. If you also drive workmux by hand in the same
repo, read
Using wtcp alongside plain workmux β wtcp
deliberately keeps to its own lane there.
If you don't use workmux yet, start there. wtcp only pays off once running one agent in a worktree is already routine for you.
workmux β the engine wtcp drives, not an
optional integration. Install and set it up first, alongside tmux, git,
jq, and curl (usually preinstalled or one brew/apt away):
brew install raine/workmux/workmux # macOS / Linuxbrew
workmux setup # once: installs the agent status hooksworkmux setup is not optional decoration β the grid's live π€/π¬/β
pane
badges are read straight out of workmux's per-agent state files, so without the
hooks the borders stay blank. wtcp doctor tells you if they're missing.
Agent CLIs β install and log in to the ones you want to compare; neither
workmux nor wtcp authenticates them, they only launch them. An "agent" here is a
workmux agent name: the builtins workmux knows (claude, codex, opencode,
gemini) or any profile in your ~/.config/workmux/config.yaml. Others (e.g.
agy / Antigravity) are auto-configured by wtcp.
A judge LLM endpoint β required only for wtcp score. Use any
OpenAI-compatible /chat/completions endpoint you already run, local or hosted.
Set COCKPIT_JUDGE_URL and usually COCKPIT_JUDGE_MODEL (see
LLM endpoint). On macOS, branch naming can use on-device Apple
Intelligence without a judge endpoint.
git clone https://github.com/puritysb/worktree-cockpit
cd worktree-cockpit
./install.sh # symlinks `wtcp` onto your PATH; builds the FM helper on macOSThen create a config file:
mkdir -p ~/.config/wtcp
cp wtcp.config.example ~/.config/wtcp/config
$EDITOR ~/.config/wtcp/configAt minimum, set COCKPIT_AGENTS to workmux agent names whose CLIs are installed
and logged in on your machine. Set the judge endpoint fields when you want
wtcp score.
Run wtcp from the repository you want agents to edit, inside tmux β the same
place you'd run workmux add:
cd /path/to/your/git-repo
tmux new -s wtcp
wtcp doctor # tmux, workmux config fit, deps, configured agents
wtcp agents codex claude # use only agents installed + logged in on this machine
wtcp start "add a CONTRIBUTING.md"wtcp start is workmux add repeated once per agent β same worktrees, same
branches, same prompt injection β with the resulting panes gathered into one
grid instead of scattered across windows.
Once the grid opens, review the panes. If a judge endpoint is configured, use
prefix Ctrl-R to open the review menu: run the LLM judge, merge the scored
winner in one step (wtcp merge β no menu, it reads the judge's π/top score),
pick a winner from a menu, view any agent's full diff, show the detailed
report, or copy the last result. You can also focus any pane and use
prefix Ctrl-P to pick it yourself. If the round was analysis-only (the winner has no code diff), picking
keeps that agent as a live session instead of merging, so you can continue
the conversation β see
Analysis rounds.
wtcp score calls an OpenAI-compatible /chat/completions endpoint. wtcp does
not ship a model or assume a provider. Configure the endpoint you actually use:
COCKPIT_JUDGE_URL="http://localhost:<port>/v1/chat/completions"
COCKPIT_JUDGE_MODEL="<model-name>"
COCKPIT_JUDGE_AUTH=""For hosted APIs, set COCKPIT_JUDGE_AUTH to the full Authorization header
value, for example Bearer .... For local servers that do not require auth,
leave it empty. Leave COCKPIT_JUDGE_MODEL empty only if your endpoint supplies
a default model server-side; most OpenAI-compatible servers require a model.
Branch naming can reuse the same endpoint/model/auth. On macOS the default
COCKPIT_NAMER=fm tries Apple Intelligence first; without that, or with
COCKPIT_NAMER=off, wtcp falls back to an ASCII slug of the prompt.
If wtcp score shows "no judgment β is the judge LLM running?", check the URL,
model name, auth header, and that the server is running.
Inside a git repo, inside a tmux session:
wtcp agents # show the compare set (default: claude codex opencode)
wtcp agents claude codex opencode agy # set it (persists to ~/.config/wtcp/config)
wtcp start "add a CONTRIBUTING.md" # branch each agent + broadcast + build the gridThe grid installs its keybindings automatically. In the grid, with your tmux prefix then:
| Key | Action |
|---|---|
Ctrl-P |
pick focused pane as winner β auto-commit + merge into the workmux main branch, drop the rest. A winner with no code changes is kept as a live session instead (see Analysis rounds) |
Ctrl-K |
keep the focused agent's live session (own window, no merge), drop the other agents and the grid |
Ctrl-X |
drop just the focused pane (grid re-tiles) |
Ctrl-S |
send a follow-up instruction to every agent; arrows/backspace edit with Readline, Ctrl-C cancels |
Ctrl-F |
fork: type a prompt in a popup β new multi-agent round branched from the focused agent's work |
Ctrl-R |
review menu: run the judge (normal or fresh), merge/pick the winner, keep a session, view diff, show or copy the report |
z |
fullscreen the focused agent (again to return) Β· arrows move between agents |
[ |
scroll/copy a pane (mouse wheel scrolls; drag to select copies to the clipboard; Ctrl-U/Ctrl-D page, y/Enter copy, q exits) |
Clicking any pane (focused or not) selects it; the mouse wheel scrolls the pane under the cursor β agents that handle the mouse themselves get the wheel events directly, other panes scroll tmux history.
Each agent pane's border also shows a live status straight from workmux:
π€ while the agent is working, π¬ when it's waiting for input, β
when
it's done. workmux's own window-name status icons can't survive the grid
(the agent windows are joined into it), so wtcp reads workmux's per-pane
state files (the same source the sidebar/dashboard use) and re-stamps the
icon on each border. This requires workmux's agent status hooks to be
installed β run workmux setup once (covers claude/codex/opencode/...).
Tune or disable the watcher with COCKPIT_STATUS* (see Configuration).
wtcp pick and wtcp merge also pass workmux merge strategies through:
wtcp pick <name> --squash, --rebase, or --into <branch> (stacked
branches) work exactly like workmux merge's flags.
Use Ctrl + the letter β the Ctrl variants pass through the Korean IME.
Other commands: wtcp send "...", wtcp merge (merge the judge's winner
in one shot β reads the scored π/top-β
pane, then runs the normal pick
machinery), wtcp keep [name] (keep one agent's live session, drop the rest β
no merge), wtcp fork "..." (new round from a pane's WIP), wtcp winner
(menu to pick the scored winner and merge it),
wtcp diff [name] (an agent's full diff vs the round base in a popup β the
focused pane's agent, or a menu; rendered with delta
when installed), wtcp show (last judge report), wtcp copy (copy last judge
report), wtcp abandon (discard the current grid without merging), wtcp grid,
wtcp list, wtcp clean (this round's worktrees; --all for every workmux
worktree in the repo), wtcp doctor (environment check). Run wtcp help
for the full list. See
Using wtcp alongside plain workmux when
you also drive workmux by hand.
| Command | Effect |
|---|---|
wtcp start |
creates one worktree/branch per configured agent and opens the grid |
wtcp pick |
commits the focused winner if needed; with code changes merges it, removes the other round worktrees, and closes the grid; without code changes keeps the winner as a live session (like wtcp keep) |
wtcp keep |
moves one agent's pane into its own window (worktree + running agent survive, nothing merged), removes the other agents' worktrees, closes the grid |
wtcp drop |
removes only the focused agent's worktree/pane |
wtcp fork |
commits the focused pane's WIP as a base and starts another round from it |
wtcp abandon |
removes the current grid's worktrees without merging anything |
wtcp clean |
removes this round's worktrees and closes wtcp grid windows (kept sessions included); worktrees you created with plain workmux add are left alone |
wtcp clean --all |
removes every workmux worktree in the repo, uncommitted changes and all β asks for confirmation first |
wtcp drives workmux, so both read the same config and can share a repo and a tmux session. wtcp keeps to its own lane:
- Destructive commands are scoped.
wtcp clean,pick,keep, andabandononly touch worktrees wtcp created for the round. Usewtcp clean --all(which confirms first) for the repo-wide sweep β that one does remove worktrees you made yourself.wtcp listis a plain passthrough toworkmux list, so it still shows everything. - Your workmux agent entries are never overwritten. wtcp writes launch
commands into
~/.config/workmux/config.yamlfor agents it manages, marking them# wtcp-managed, and backs the file up toconfig.yaml.wtcp-bakbefore its first change. An entry you wrote by hand β especially a multi-linetype:/command:/args:/env:block β is left exactly as-is, and wtcp tells you that itsCOCKPIT_AGENT_*_CMD/_MODELfor that name is being ignored. To hand an entry over to wtcp, delete it or append# wtcp-managed. - Branch policy comes from workmux. At round launch wtcp resolves the base
ref to an immutable commit SHA, passes that SHA as workmux's explicit
--base, and stores the same SHA for judging. A branch moving while agents work therefore cannot pollute their diffs, and abase_branch:in your workmux config can't make launch and scoring disagree. Where wtcp has to guess a base it uses yourmain_branchbefore falling back tomain/master. - Starting a round inside another worktree. This is allowed, but
workmux mergealways targetsmain_branchβ so the winner would land on main rather than the branch you're on. wtcp warns when the round starts and then makeswtcp pickask for an explicit--into <branch>instead of merging somewhere you didn't mean. - During a round, use wtcp's commands. Agent panes are joined into the grid
window, so workmux's
send/capture/runcan no longer find them by window name;wtcp sendand the in-grid keys are the equivalents.workmux dashboard/sidebarkeep working β they read the per-pane state files, which is also where the grid's π€/π¬/β icons come from. wtcp doctorreports the fit. It prints yourmain_branch,base_branch, and flags settings wtcp can't follow β a customwindow_prefix/worktree_prefix(the grid silently never assembles), a custompanes:/windows:layout (wtcp grids only the first pane of each agent window), and which agent entries are yours versus wtcp's.
One thing wtcp does not survive: a tmux server restart. Round state lives in
tmux window options, so workmux resurrect brings the worktrees' windows back
but not the grid β score/pick/diff won't work in it. Merge or keep what you
want before restarting tmux; otherwise re-run the round, or wtcp clean --all
to clear the leftovers.
Not every round produces code. When you ask the agents to analyze, review, or answer a question, the "result" is the conversation in the winning pane β there is nothing to merge, but you usually want to continue working with that agent.
That's what keep does (prefix Ctrl-K on the focused pane, the review
menu's Keep a session, or wtcp keep [name]):
- the kept agent's pane moves to its own tmux window β the worktree and the running agent session (full conversation context) survive;
- the other agents' worktrees are removed and the grid closes;
- nothing is merged.
wtcp pick chooses automatically based on the diff: a winner with code
changes is merged as usual; a winner with no code changes vs the round
base is kept as a live session instead. So you can always score with
prefix Ctrl-R and pick the winner β wtcp does the right thing for both kinds
of rounds.
Continuing from a kept session. Type follow-ups directly in the kept pane β
it's the same agent, same conversation. When a follow-up deserves another
multi-agent comparison, press prefix Ctrl-F (fork): type the new prompt in
the popup and a fresh grid launches, with every agent branched from the kept
agent's work. Rounds can alternate naturally: fan out β keep one β continue β
fan out again.
Tip: before forking from an analysis-only session, ask the kept agent to write its findings to a file (e.g.
NOTES.md).wtcp forkauto-commits the worktree's WIP, so the new round's agents all start with those findings β otherwise the analysis exists only in the kept pane's scrollback.
When you're done with a kept session, prefix Ctrl-X (drop) removes its
worktree and closes the window.
Run wtcp doctor first β it reports tmux version, the live mouse/mode-keys
state, whether you're in a nested tmux, the configured agents (and whether their
CLIs are on PATH), and missing dependencies.
Mouse, per-pane scroll, or the in-grid keys don't work (works on one machine
but not another): the quickest fix is to detach tmux (prefix d) and re-run
wtcp start (or just wtcp setup). wtcp sets mouse on and the keybindings
as server-global options, but a long-lived tmux session can leave the terminal's
mouse-reporting state stale β detaching re-initializes it. Also check:
- Nested tmux (local tmux β ssh β remote tmux, or tmux-in-tmux): the outer
tmux eats mouse clicks/wheel so they never reach the inner one. Connect from a
bare terminal (no outer tmux) instead.
wtcp doctorflags likely nesting. - Terminal mouse reporting: the emulator must forward mouse events. In iTerm2,
settings aren't synced across machines β compare Settings β Pointer and the
iTerm2 version on both. Don't use iTerm2's
tmux -CCintegration (different mouse model); launch plaintmux. - Old tmux (< 2.1) uses
mode-mouseinstead ofmouse on;wtcp setupfalls back to it automatically, but upgrading tmux is better.
The grid doesn't build / panes are missing β usually an agent failed to
launch. On timeout wtcp start prints a per-agent launched/MISSING table and
asks whether to keep what did launch (default β slow worktree hooks may just
need more time; raise COCKPIT_LAUNCH_TIMEOUT) or clean the round's
worktrees. Make sure every name in COCKPIT_AGENTS is an installed,
authenticated CLI (and, for custom agents, defined in
~/.config/workmux/config.yaml). A too-small terminal window can also fail
joins ("pane too small") β make the window bigger.
A merge conflict during wtcp pick keeps the whole round intact β nothing
is removed. wtcp detects where the conflict landed (mid-merge in the main
worktree, mid-rebase in the winner's worktree, or β with current workmux β
nowhere, with a prompt to rebase the winner's worktree onto the base) and prints
the matching resolve/retry steps.
wtcp score sends all agents to the configured judge LLM in one call so
it compares them head-to-head: it scores each 0β10 with a reason relative to the
others and names a winner. The judge sees the full instruction timeline: the
initial prompt plus any wtcp send / Ctrl-S follow-ups. Later follow-ups refine
or supersede earlier instructions when they conflict, and every score reflects
the agent's current final state at the moment you run wtcp score.
It evaluates both evidence vs the round's immutable base SHA and terminal
output. Each candidate's evidence starts with git status --short, the complete
changed-file list and numstat, static imports from changed tests, and explicit
truncation counts. Patch excerpts then receive a file-balanced budget, with new
test files prioritized, so one large early diff cannot hide every later file.
For code tasks, visible implementation evidence is the source of truth while
output supports tests run, claims, and analysis. Explicitly omitted content is
uncertain rather than evidence that a matching terminal claim is false.
For test-heavy work, the judge treats a green pass count as a gate rather than a quality score. It is instructed to prefer verified coverage deltas and to check whether tests import and exercise real product modules instead of rewarding synthetic/self-fulfilling fixtures or surface keywords. For analysis, review, debugging, planning, or research tasks with empty diffs, terminal output remains the primary evidence. The popup shows a short bullet report; each pane border gets its score. It falls back to independent scoring if comparison can't parse.
Every score uses one canonical, additive rubric:
| Dimension | Points | What it measures |
|---|---|---|
| Task | 0β4 | Explicit requirements fulfilled correctly at the right layer |
| Grounding | 0β3 | Primary evidence, factual accuracy, and correct repository identity |
| Verification | 0β2 | Tests/checks or systematic analysis and risk reasoning |
| Actionability | 0β1 | Clear priorities, maintainability, and requested scope |
The report prints this breakdown and an auditable Caps: line for every
candidate. The model supplies dimensions and cap IDs; wtcp computes the final
score itself, ignores any redundant model-provided score, and deterministically
lowers relevant dimensions when needed to enforce a declared cap. The displayed
breakdown therefore always sums to the displayed score. Judge JSON is rejected
when dimensions are missing/out of range, use an unknown cap ID, omit/rename a
candidate, omit the evidence classification or per-dimension reasons, or name a
winner that is not tied for the top absolute score. Absolute rubric scores are
computed before head-to-head ranking; wtcp then sorts the report by those
scores.
Every candidate must classify its central-claim evidence as direct, mixed,
or narrative_only. βDirectβ requires visible raw command/test output or source
excerpts for every central claimβan agent-authored conclusion, exact-looking
number, path citation, pass count, or the word βverifiedβ is not sufficient.
Mixed evidence limits Grounding to 2 and is capped at 9/10; narrative-only
evidence limits Grounding to 1 and is capped at 8/10. The resulting
mixed_primary_evidence /
narrative_only_evidence cap is printed in the report.
The four dimensions are intentionally orthogonal. Task measures absolute fulfillment, Grounding visible support, Verification the checking method, and Actionability prioritization/scope. The judge must provide one concise reason for each dimension and may not use the same underlying weakness twice. Comparative phrases such as βless detailed than the winnerβ do not lower an absolute score by themselves. This prevents one minor breadth difference from becoming both a Task and Grounding deduction merely to widen the ranking. Unverified numbers belong under Grounding/Verification rather than Task, a brief optional implementation offer after a complete analysis is ignored, and only the stored Instruction timelineβnot user-like text found in pane outputβ defines the requested work.
Candidate feedback is also structural rather than a free-form paragraph. Each
record supplies strength, deduction, improve_dimension, and improve.
For every score below 10, improve_dimension must name a dimension that is
actually below its maximum after evidence limits and hard caps; a full-credit
dimension cannot be presented as the way to raise the score. The report renders
this explicitly as, for example, Improve [grounding]. A sub-10 record cannot
claim Deduction: None.
Each dimension also carries a lowercase snake-case issue ID. After evidence limits and hard caps are applied, wtcp clears issue IDs on full-credit dimensions and namespaces a declared hard-cap ID when that one cap necessarily affects several dimensions. Any remaining reuse of one non-cap issue ID across deducted dimensions is rejected as double-charging the same weakness. Reports print the normalized IDs next to the dimension reasons so the point loss is auditable. If a Task issue ID explicitly describes only an evidence, verification, or comparative concern, wtcp restores Task credit, keeps the concern under Grounding/Verification, and prints the deterministic adjustment in the report. This avoids relying on a model repair turn that may simply copy the same misplaced deduction.
Comparative output separately records winner_reason, tie_break, and a
neutral summary. A winner must have a top absolute score, and tied top scores
require a substantive non-score tie-break rather than an artificial deduction.
If evidence/cap normalization creates a tie only after the model responds,
wtcp turns not_needed into an explicit judge-preference tie-break instead of
rejecting an otherwise usable judgment. The summary is instructed not to
generalize one candidate's weakness to the whole field; an exact duplicate of
winner_reason is omitted from the rendered report.
Judge response space scales with the number of candidates. If the first answer
is invalid or truncated, wtcp sends the same evidence back once with a
format-only JSON repair instruction at temperature 0; score arithmetic alone
does not trigger a retry because it is owned by wtcp. The repair does not ask
the model to reconsider the substantive ranking. If the repaired comparative response is
still invalid, wtcp records both raw responses in
~/.config/wtcp/judge-invalid.txt and falls back to independently judging each
candidate. Independent responses receive the same one-repair treatment, so a
remaining ?/10 includes the diagnostic path instead of hiding the failed
model output.
Hard gates keep detailed hallucinations from scoring well: analyzing another repository is capped at 2/10 with Grounding 0; fabricated or directly contradicted central evidence and wrong-layer/nonfunctional core work are capped at 4/10; a missing major explicit requirement is capped at 6/10; and a material unresolved fact conflict that blocks verification is capped at 8/10. A 10 is exceptional and requires direct evidence for every central claim, full credit in every independent dimension, and correct repository identity.
To make those gates enforceable, every evidence manifest identifies the canonical repository and package, worktree and HEAD, tracked/test-file counts, and the complete top-level tracked structure. A response that describes another product or relies on central path namespaces absent from that profile receives no credit for its apparent detail, test counts, or pass rate.
After scoring, wtcp merge merges the winner's branch without any menu: it
reads the π-marked pane (or the highest β
score when there is no trophy) and
runs the same pick machinery β merge when the winner has code changes, keep the
session when it doesn't. The winner menu (prefix Ctrl-R) remains for choosing
a different agent than the judge's pick.
You can score repeatedly during a multi-turn round. Previous scores are shown to
the judge only as context for improvement/regression; the judge is instructed to
grade the current evidence, not to preserve an earlier ranking. The judge sees as
much context as fits its window β the instruction timeline, manifest plus
balanced patch excerpts, and each agent's pane scrollback, budgeted by the
*_CHARS vars below. Complete manifests and a minimum new-test excerpt may
slightly exceed the nominal evidence target rather than being silently omitted.
Change evidence and terminal output share one per-agent pool: unused diff space
automatically flows to the terminal, which prevents read-only analysis rounds
from wasting half their context. Terminal output that still exceeds the pool is
packaged as explicit head + tail excerpts with total/delivered counts instead of
silently keeping only the tail.
Use wtcp score --fresh (also available in the Ctrl-R menu) after correcting
an evaluation setup problem or whenever prior scores might anchor the next
decision. It reuses the current round and evidence but omits all previous judge
labels/reasons, so restarting the agents is unnecessary.
The report keeps structural labels in English, but writes each agent's
reason/summary content in the same language as your prompt. Judge bullets are
kept concise and include an Improve: bullet when points were deducted. The
prompt explicitly tells the judge not to reward or penalize language choice
unless your task requires a specific language.
It also shows a Judge model: line naming the model the endpoint actually used.
wtcp copy copies the last report from ~/.config/wtcp/judge.txt to the system
clipboard (pbcopy, wl-copy, or xclip).
COCKPIT_AGENTS entries are workmux agent names and must be unique because they
become branch/worktree suffixes. To compare the same CLI with different
models, give each variant an alias and set its model β wtcp launches the
alias's base CLI with --model:
Aliases are not inferred from their names. For example, codex-glm does not
select GLM by itself; it must have a matching COCKPIT_AGENT_CODEX_GLM_MODEL,
COCKPIT_AGENT_CODEX_GLM_CMD, or named profile in
~/.config/workmux/config.yaml. If none is set, wtcp refuses the alias and tells
you which profile names or model settings are available. It will not silently run
codex-glm with the default Codex model.
# claude vs claude: which model handles this prompt better?
COCKPIT_AGENTS="claude-fable claude-opus claude-sonnet"
COCKPIT_AGENT_CLAUDE_FABLE_MODEL="fable"
COCKPIT_AGENT_CLAUDE_OPUS_MODEL="opus"
COCKPIT_AGENT_CLAUDE_SONNET_MODEL="sonnet"COCKPIT_AGENT_<ALIAS>_MODEL accepts anything the CLI's --model flag accepts
(an alias like opus, or a full model id). It works for any alias whose kind is
a real CLI that takes --model β codex and opencode switch models the same way:
COCKPIT_AGENT_CODEX_GPT5_MODEL="gpt-5" # -> codex --model gpt-5
COCKPIT_AGENT_OPENCODE_GLM_MODEL="zai-coding-plan/glm-5.2" # -> opencode --model <provider>/<model>(opencode takes provider/model β use the provider id from your opencode
config.) wtcp doctor prints the exact command each alias will launch and the
installed CLIs / workmux profiles detected on the current machine.
When no model is set for a plain agent such as claude or codex, wtcp uses
COCKPIT_AGENT_<KIND>_DEFAULT_MODEL or COCKPIT_AGENT_DEFAULT_MODEL. The
built-in default for claude is sonnet. For codex, wtcp reads the model
from ~/.codex/config.toml and otherwise lets the Codex CLI use its own
default. opencode has no built-in default because its provider/model names
are local to your opencode config. Aliases still require an explicit _MODEL,
_CMD, or workmux profile so unsupported model combinations fail with guidance
instead of launching the wrong model.
For anything --model can't express β a different backend behind the same
CLI, extra flags, env vars β set COCKPIT_AGENT_<ALIAS>_CMD with the full
command instead (it wins over _MODEL). That is how you attach GLM (or any
Anthropic-compatible endpoint) to Claude Code and race it against the stock
models:
COCKPIT_AGENTS="claude-fable claude-glm opencode-glm"
COCKPIT_AGENT_CLAUDE_FABLE_MODEL="fable"
# Claude Code CLI pointed at Zhipu's GLM endpoint (any Anthropic-compatible API works):
COCKPIT_AGENT_CLAUDE_GLM_CMD="env ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic ANTHROPIC_AUTH_TOKEN=sk-... ANTHROPIC_MODEL=glm-5.2 claude"
# ...and the same model through opencode, for a same-model different-CLI race:
COCKPIT_AGENT_OPENCODE_GLM_KIND="opencode"
COCKPIT_AGENT_OPENCODE_GLM_MODEL="zai-coding-plan/glm-5.2"All variants run side by side in the grid, get scored by the judge like any other agents, and the winner merges the same way.
Aliases starting with claude-, codex-, opencode-, or agy- inherit the
right trust-store handling and COCKPIT_TRUST launch flags. For other names,
set COCKPIT_AGENT_<ALIAS>_KIND, for example
COCKPIT_AGENT_MY_ALIAS_KIND="codex" (the kind is also the CLI that _MODEL
aliases launch).
agy-* names do not select Gemini models automatically. Plain agy uses
wtcp's prompt-loading wrapper for the default agy CLI. If you want
agy-gemini (or any other agy-*) to be a distinct backend, define it as a
real workmux profile or set COCKPIT_AGENT_AGY_GEMINI_CMD. Older wtcp versions
could leave aliases like agy-gemini: ~/.config/wtcp/agy-wm; wtcp doctor
reports those as stale generic wrappers, not usable backend profiles.
The compare set is capped at 6 agents. Panes are arranged: 2β1Γ2, 3β1Γ3,
4β2Γ2, 5β2Γ3 (one blank bottom-right), 6β2Γ3.
All settings live in ~/.config/wtcp/config (sourced shell vars). See
wtcp.config.example. Key ones:
| Var | Default | Meaning |
|---|---|---|
COCKPIT_AGENTS |
claude codex opencode |
agents compared by wtcp start (max 6) |
COCKPIT_JUDGE_URL |
(empty) | OpenAI-compatible /chat/completions endpoint for wtcp score |
COCKPIT_JUDGE_MODEL |
(empty) | model name sent to the judge endpoint, if required |
COCKPIT_JUDGE_AUTH |
(empty) | Authorization header for hosted endpoints, e.g. Bearer sk-... (namer reuses it) |
COCKPIT_JUDGE_OUTPUT_CHARS |
16000 |
target per-agent terminal evidence budget; unused diff space is added |
COCKPIT_JUDGE_DIFF_CHARS |
16000 |
target per-agent manifest + balanced patch evidence budget |
COCKPIT_JUDGE_COMPARE_CHARS |
48000 |
target total comparative evidence budget (split between agent evidence and terminal output) |
COCKPIT_PROMPT_LOG_CHARS |
12000 |
instruction timeline budget for initial prompt + follow-ups |
COCKPIT_JUDGE_TIMEOUT |
120 |
seconds per judge request |
COCKPIT_LAUNCH_TIMEOUT |
0 |
seconds to wait for agent windows; 0 auto-scales for slow cold worktree hooks |
COCKPIT_STATUS |
1 |
live π€/π¬/β
status on grid pane borders, read from workmux's per-pane state (0 disables) |
COCKPIT_STATUS_INTERVAL |
3 |
status poll interval (seconds) |
COCKPIT_POPUP_WIDTH / COCKPIT_POPUP_HEIGHT |
92% / 85% |
tmux popup size for judge details |
COCKPIT_POPUP_DIM / COCKPIT_POPUP_DIM_STYLE |
1 / fg=colour244,bg=colour235 |
dim pane styles behind popups; tmux has no true blur/backdrop |
COCKPIT_NAMER |
fm |
branch naming: fm (Apple Intelligence) / mlx / off |
COCKPIT_NAMER_URL / COCKPIT_NAMER_MODEL |
judge settings | optional separate endpoint/model for branch naming |
COCKPIT_NO_INTERACTIVE_MENUS |
0 |
1 = never auto-open the winner menu after scoring (headless runs) |
COCKPIT_TRUST |
0 |
opt-in: skip the per-agent folder-trust dialog + auto-approve tool use so new projects auto-start (edits the agents' trust stores + global workmux config) |
COCKPIT_CLAUDE_CMD / COCKPIT_CODEX_CMD |
(see below) | override how claude/codex launch under COCKPIT_TRUST |
COCKPIT_AGENT_DEFAULT_MODEL |
(empty) | fallback model for plain agents whose kind has no specific default |
COCKPIT_AGENT_CLAUDE_DEFAULT_MODEL |
sonnet |
default model for plain claude |
COCKPIT_AGENT_CODEX_DEFAULT_MODEL |
~/.codex/config.toml model |
default model for plain codex; empty falls back to Codex CLI's own default |
COCKPIT_AGENT_OPENCODE_DEFAULT_MODEL |
(empty) | optional opencode default, usually provider/model from your opencode config |
COCKPIT_AGENT_<ALIAS>_CMD |
(empty) | full command for a custom/variant agent alias (env vars, backends, extra flags; wins over _MODEL) |
COCKPIT_AGENT_<ALIAS>_MODEL |
(empty) | model for an alias: launches the alias kind's CLI with --model <value> |
COCKPIT_AGENT_<ALIAS>_KIND |
inferred | base kind for alias trust handling and the CLI _MODEL launches (claude, codex, opencode, agy, etc.) |
Raise the *_CHARS budgets for a bigger-context judge model; lower them for a
small local one (char β β
βΒΌ token, so keep the total under the model's window).
By default, agents show their "Do you trust this folder?" prompt on a new
project β confirm once and that repo auto-starts thereafter. COCKPIT_TRUST=1
makes even the first round start unattended by doing two things before the round:
- Pre-seeding each agent's folder-trust store so the trust dialog is skipped
(claude β
~/.claude.json, codex β~/.codex/config.toml). agy is left to a one-time manual accept β its store lives under~/.gemini. - Launching agents in an unattended permission mode so they don't pause on
every tool prompt: claude in
--permission-mode auto(not full bypass), codex with--dangerously-bypass-approvals-and-sandbox. Override either withCOCKPIT_CLAUDE_CMD/COCKPIT_CODEX_CMD.
This edits the agents' trust stores and the global workmux config, so it is off by default. Enable it only for repositories you trust.