pi: /btw side-chat
• 275 words • 2 min • updated
Problem statement: mid-task, I want to ask the LLM agent a quick tangential question — “will this change cause downtime?” — without polluting the main agent thread.
Claude Code has /btw1 for exactly this.
pi doesn’t, but
patriceckhart/pi-btw does, as an
extension. It opens a side-chat overlay: the LLM gets to see the full main
thread context and answers, but nothing is written back to the conversation
history.
The upstream extension imports the pre-fork @mariozechner/* package names,
which are now deprecated. As such, I use
earendil-works/pi. Rather than trust a
diff I hadn’t read, I reimplemented it against the current API, and
cross-checked against the bundled examples/extensions/summarize.ts (the
canonical example for calling the model from an extension):
import { complete } from "@earendil-works/pi-ai/compat";
import type { ExtensionAPI, SessionEntry } from "@earendil-works/pi-coding-agent";
import { convertToLlm, getMarkdownTheme } from "@earendil-works/pi-coding-agent";
// ...inside the /btw command handler, once at entry:
const branch = ctx.sessionManager.getBranch();
const mainMessages = branch
.filter((entry): entry is SessionEntry & { type: "message" } => entry.type === "message")
.map((entry) => entry.message);
const mainLlmMessages = convertToLlm(mainMessages); // frozen snapshot
const systemPrompt = ctx.getSystemPrompt();
// ...per question, the side-chat calls the model directly:
const response = await complete(
ctx.model!,
{ systemPrompt, messages: [...mainLlmMessages, ...btwLlmMessages] },
{ apiKey: auth.apiKey, headers: auth.headers, env: auth.env, signal },
);The key move is what’s missing: the handler never calls pi.sendMessage()
or appends anything. It reads the branch once, talks to the model in an
ctx.ui.custom()
overlay, and returns. The main session is untouched, so the next real prompt
doesn’t pay for any of it.
Added to ~/.pi/agent/extensions/btw.ts.
🤖 Drafted with /bloggify.