bug(commands): /btw and /background sent as chat text when typed mid-turn — missing from busy-path slash intercept allowlist
#6,597 opened on Jul 29, 2026
Repository metrics
- Stars
- (17,368 stars)
- PR merge metrics
- (Avg merge 14h 31m) (314 merged PRs in 30d)
Description
Summary
/btw and /background work correctly when the agent is idle, but typing them while a turn is running sends them through as chat text instead of executing the intended command. Since their primary value is exactly mid-task (/btw for a quick side lookup, /background for parallel work), that's the case that's broken.
Steps to reproduce
- Start a long-running agent task.
- While it's running (
S.busy), type/btw what is the capital of Franceand press Enter. - Instead of an ephemeral side-question bubble, the raw text
"/btw what is the capital of France"gets steered into the active agent, or queued, or causes an interrupt — depending ondefaultMessageMode. - Repeat with
/background. Same misrouting.
(When idle, both commands execute correctly — the bug is busy-only.)
Root cause
Both commands are registered client-side (static/commands.js:29-30 → cmdBtw, cmdBackground, both noEcho:true) and intercepted correctly on the idle send path at static/messages.js:1428. But when the composer submits while S.busy is true, the code returns early at the busy block (messages.js:1356-1376), before reaching the idle intercept.
The busy block has its own narrow allowlist of commands that bypass defaultMessageMode routing:
// static/messages.js:1368
if(_pc&&['steer','interrupt','queue','terminal','goal','yolo'].includes(_pc.name)){
btw and background are not in this list, so they fall through to defaultMessageMode behaviour and get treated as plain chat text.
Why both handlers are safe to call mid-turn
Both cmdBtw (commands.js:1727-1741) and cmdBackground (commands.js:1742-1755) are fully self-contained:
- They only read
S.session.session_id— they do not readS.busy,S.activeStreamId, or any agent-running state. - They call their own dedicated API endpoints (
POST /api/btw,POST /api/background). - They connect to independent SSE streams / polling loops that do not share or interfere with the main session's active stream.
- The
/btwanswer renders in a dedicated ephemeral bubble (.msg-row-btw), not the main message list. - The
/backgroundresult surfaces via a composer badge + polling, then appends a_background-tagged message.
Previous precedent — Issue #4117
The same bug was reported for /yolo, fixed in v0.51.393 by adding yolo to this same allowlist (#4117). /btw and /background were simply overlooked.
Suggested fix
One-line addition in static/messages.js:1368:
// Current:
if(_pc&&['steer','interrupt','queue','terminal','goal','yolo'].includes(_pc.name)){
// Should be:
if(_pc&&['steer','interrupt','queue','terminal','goal','yolo','btw','background'].includes(_pc.name)){
Front-end only. No backend changes needed.
Scope
- Repo:
nesquena/hermes-webui - File:
static/messages.js(~L1368) - Risk: low — one-line allowlist addition; both handlers are idempotent and session-scoped