CodeDocs Vault

12. Deep Dive — The /btw Command

/btw is one of the more clever features in Claude Code. It lets the user ask a quick side question without interrupting what the agent is doing. It is a useful study in how the codebase reuses primitives to build new user-facing features at low cost.

Shape

The flow

When the user types /btw <question>:

  1. The slash parser routes to commands/btw/btw.tsx:229-236:
export async function call(
  onDone: LocalJSXCommandOnDone,
  context: ProcessUserInputContext,
  args: string,
): Promise<React.ReactNode> {
  const question = args?.trim()
 
  if (!question) {
    onDone('Usage: /btw <your question>', { display: 'system' })
    return null
  }
  1. The main TUI renders a <BtwSideQuestion> React component (btw.tsx:36-181) as an overlay: spinner while fetching, scrollable markdown when the response arrives, dismiss with Space/Enter/Escape.

  2. Meanwhile the main agent loop keeps running in the background — it is not aborted, not paused.

  3. A separate, ephemeral forked agent is spawned via runForkedAgent() in utils/forkedAgent.ts. This is the same primitive used by memory extraction and the fork-subagent path.

The cached-param fork

The forked agent reuses the parent's cached prompt prefix. buildCacheSafeParams() (btw.tsx:208-227) builds a CacheSafeParams from the main thread's last request:

Because the cached-safe params match the parent byte-for-byte up to the boundary, the prompt cache hits and the side question is cheap.

The prompt the model actually sees

This is the most interesting bit. The user's question is wrapped in a <system-reminder> (sideQuestion.ts:61-78):

<system-reminder>This is a side question from the user. You must answer this question directly in a single response.

IMPORTANT CONTEXT:
- You are a separate, lightweight agent spawned to answer this one question
- The main agent is NOT interrupted - it continues working independently in the background
- You share the conversation context but are a completely separate instance
- Do NOT reference being interrupted or what you were "previously doing" - that framing is incorrect

CRITICAL CONSTRAINTS:
- You have NO tools available - you cannot read files, run commands, search, or take any actions
- This is a one-off response - there will be no follow-up turns
- You can ONLY provide information based on what you already know from the conversation context
- NEVER say things like "Let me try...", "I'll now...", "Let me check...", or promise to take any action
- If you don't know the answer, say so - do not offer to look it up or investigate

Simply answer the question with the information you have.</system-reminder>

${question}

Two things stand out:

Tool access

Zero. canUseTool returns { behavior: 'deny', reason: 'side_question' } for every tool (sideQuestion.ts:86-89). If the model tries a tool anyway, the call is caught and replaced with an error.

Budget

Rendering

The result is extracted from assistant content blocks via extractSideQuestionResponse() (sideQuestion.ts:125-155). The <BtwSideQuestion> component renders markdown with scroll keys, dismiss keys, and a character counter. It's purely client-side — the result never enters the main conversation history.

What this demonstrates