You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For any web browsing task, use the `wmux browser` commands so the user can watch in the browser panel. Do NOT use Playwright, Firecrawl, or WebSearch — they open invisible windows the user cannot see. If the user explicitly asks for one of those tools, use it.
For any web browsing task, use the wmux browser commands so the user can watch in the browser panel. Do NOT use Playwright, Firecrawl, or WebSearch — they open invisible windows the user cannot see.
Because the file is global, it loads in every session on the machine — not only the ones inside wmux. Claude Code Desktop, a plain terminal, a headless or scheduled run, CI, an SSH session: all of them read ~/.claude/CLAUDE.md. In those sessions the opening sentence is false, and the instruction that follows is unfollowable — wmux may not even be on PATH, and if wmux is not running the CLI cannot reach the pipe.
What actually happens
Observed on v0.46.0 (Windows 11), 2026-08-12. A Claude Code Desktop session — no wmux process running at all — read the block, believed it, and tried to drive wmux browser for a web task while explicitly avoiding WebSearch. It burned several turns on a tool that could not work before noticing the contradiction and falling back. The failure mode is quiet: the agent is not confused about the task, it is confidently following instructions that were true somewhere else.
The instruction is unusually load-bearing for a false premise, because it does not merely offerwmux browser — it removes the alternative. An agent that believes it has no other web tool has no obvious reason to go looking for one.
Worth noting this is not limited to Claude Code: the same text lands in OpenCode's global AGENTS.md and, since #148, in Kiro's global steering directory, which Kiro CLI loads unconditionally for every workspace.
Root cause
The claim is treated as a write-time fact when it is really a read-time one.
ensureClaudeContext() runs when wmux starts, and at that instant "wmux is running" is true — so the sentence is accurate about the moment it is written:
// No CLAUDE.md yet — create with just the wmux block
fs.writeFileSync(claudeMdPath,wmuxBlock,'utf-8');
console.log('[wmux] Created ~/.claude/CLAUDE.md with wmux context');
return;
}
But the file it writes is then read by every future session on the machine, arbitrarily later, most of which have no relationship to that wmux instance. Nothing re-evaluates the claim at the point where it is consumed, and nothing can: the writer has no way to know who will read the file or where from.
Why this is awkward to fix, and what I'd like your call on
I can see three shapes and they trade off differently against decisions you have already made deliberately, so I would rather ask than guess.
1. Make the block self-checking (my preference). Keep the global file, but stop asserting presence as fact. Open with a cheap verification step (wmux ping) and say what to do in both outcomes — use wmux browser when it answers, fall back to the agent's native web tools when it does not.
It fixes all three agents with one edit, because all three share the one content file.
It respects the "one source of truth, no per-agent drift" rule you set out in kiro-context.ts.
No new machinery, no install-time behaviour change, no consent-model change.
Cost: a few lines of prose, and it spends a subprocess call on first web use.
2. Stop writing to the global file. Cleanest in principle, largest change — and I think parts of it are already ruled out by decisions you have made:
Per-session env injection does not address the reported case at all. The sessions that get this wrong are exactly the ones wmux did not spawn, so there is no shell of ours to inject into.
That leaves dropping global context entirely, which costs the discoverability the current design is clearly buying.
3. Make the content conditional at generation time. I don't think this can work, for the reason in the root-cause section: the condition is read-time. wmux would be baking "wmux is running" into a file read by sessions that start hours later, and the answer can differ per reader. It would still be wrong for the desktop-app case, which is the one that actually bit.
So my read is that 1 is the only option that fixes the reported failure without giving up something you chose on purpose — but you own the discoverability/verbosity trade-off here, and if you would rather go a different way I'm happy to implement whichever you pick.
Aside
wmux ping is a good probe for option 1 specifically: it is answered before the auth gate in handleV1, so it needs no pipe token, and it fails fast when nothing is listening.
Happy to open the PR once you've picked a direction. If you want option 1, I'd keep the diff to resources/claude-instructions.md plus a test pinning that the block never asserts wmux's presence unconditionally.
Summary
wmux writes its auto-managed block into three global agent-context files:
~/.claude/CLAUDE.mdensureClaudeContext()~/.config/opencode/AGENTS.mdensureOpencodeContext()~/.kiro/steering/wmux.mdensureKiroContext()All three receive the same file,
resources/claude-instructions.md, byte-for-byte. It opens with:wmux/resources/claude-instructions.md
Lines 3 to 5 in fae21a5
and then, on the strength of that claim, forbids the agent's own web tooling:
wmux/resources/claude-instructions.md
Line 9 in fae21a5
Because the file is global, it loads in every session on the machine — not only the ones inside wmux. Claude Code Desktop, a plain terminal, a headless or scheduled run, CI, an SSH session: all of them read
~/.claude/CLAUDE.md. In those sessions the opening sentence is false, and the instruction that follows is unfollowable —wmuxmay not even be onPATH, and if wmux is not running the CLI cannot reach the pipe.What actually happens
Observed on v0.46.0 (Windows 11), 2026-08-12. A Claude Code Desktop session — no wmux process running at all — read the block, believed it, and tried to drive
wmux browserfor a web task while explicitly avoidingWebSearch. It burned several turns on a tool that could not work before noticing the contradiction and falling back. The failure mode is quiet: the agent is not confused about the task, it is confidently following instructions that were true somewhere else.The instruction is unusually load-bearing for a false premise, because it does not merely offer
wmux browser— it removes the alternative. An agent that believes it has no other web tool has no obvious reason to go looking for one.Worth noting this is not limited to Claude Code: the same text lands in OpenCode's global
AGENTS.mdand, since #148, in Kiro's global steering directory, which Kiro CLI loads unconditionally for every workspace.Root cause
The claim is treated as a write-time fact when it is really a read-time one.
ensureClaudeContext()runs when wmux starts, and at that instant "wmux is running" is true — so the sentence is accurate about the moment it is written:wmux/src/main/claude-context.ts
Lines 32 to 54 in fae21a5
But the file it writes is then read by every future session on the machine, arbitrarily later, most of which have no relationship to that wmux instance. Nothing re-evaluates the claim at the point where it is consumed, and nothing can: the writer has no way to know who will read the file or where from.
Why this is awkward to fix, and what I'd like your call on
I can see three shapes and they trade off differently against decisions you have already made deliberately, so I would rather ask than guess.
1. Make the block self-checking (my preference). Keep the global file, but stop asserting presence as fact. Open with a cheap verification step (
wmux ping) and say what to do in both outcomes — usewmux browserwhen it answers, fall back to the agent's native web tools when it does not.kiro-context.ts.2. Stop writing to the global file. Cleanest in principle, largest change — and I think parts of it are already ruled out by decisions you have made:
kiro-context.ts).3. Make the content conditional at generation time. I don't think this can work, for the reason in the root-cause section: the condition is read-time. wmux would be baking "wmux is running" into a file read by sessions that start hours later, and the answer can differ per reader. It would still be wrong for the desktop-app case, which is the one that actually bit.
So my read is that 1 is the only option that fixes the reported failure without giving up something you chose on purpose — but you own the discoverability/verbosity trade-off here, and if you would rather go a different way I'm happy to implement whichever you pick.
Aside
wmux pingis a good probe for option 1 specifically: it is answered before the auth gate inhandleV1, so it needs no pipe token, and it fails fast when nothing is listening.wmux/src/main/pipe-server.ts
Lines 152 to 160 in fae21a5
Happy to open the PR once you've picked a direction. If you want option 1, I'd keep the diff to
resources/claude-instructions.mdplus a test pinning that the block never asserts wmux's presence unconditionally.