Architecture: Browy DevTools CLI internals
The DevTools CLI is a small, dependency-free plain JavaScript
implementation living in extension/panel.{html,js,css}. It mounts
inside the DevTools panel registered by extension/devtools.js.
For how to use it, see the DevTools CLI page. This page is for contributors curious about how it’s built.
| File | Role |
|---|---|
extension/devtools.html | Tiny shell that loads devtools.js |
extension/devtools.js | Calls chrome.devtools.panels.create('Browy', icon, 'panel.html') |
extension/panel.html | Toolbar + log + autocomplete listbox + textarea |
extension/panel.css | Styles modeled on the DevTools Console, light or dark to match your DevTools theme |
extension/panel.js | All behavior: REPL, slash commands, port glue |
The REPL loop
Section titled “The REPL loop”panel.js keeps a single <div id="log"> of “rows” (user / assistant /
tool / info / dim / ok / warn / err / banner). The textarea below is
the prompt. On Enter, the panel echoes your input as a row, then:
- If the input starts with
/, dispatch to the slash-command registry (COMMANDSarray near line 250 ofpanel.js). - In
/jsmode, evaluate the line in the inspected page withchrome.devtools.inspectedWindow.eval. - Otherwise, send
{type: 'chat.send', sessionId, text}over the port to the native host and streamchat.deltachunks into a single growing assistant row. Tool calls show up as cards that fill in whenchat.tool_resultarrives.
On Esc mid-flight, the panel posts {type: 'chat.cancel', sessionId}
to the host and shows a “cancel requested” warning row.
Slash-command registry
Section titled “Slash-command registry”Each command is a {name, help, run} triple:
const COMMANDS = [ { name: '/help', help: 'Show available commands', run: cmdHelp }, { name: '/clear', help: 'Clear the scrollback (Ctrl+L)', run: () => clearLog() }, { name: '/new', help: 'Start a new conversation', run: cmdReset }, { name: '/reset', help: 'Abandon this session and start fresh', run: cmdReset }, { name: '/model', help: 'Show current model + pick from list: /model [id]', run: cmdModel }, { name: '/login', help: 'Sign in to GitHub Copilot', run: cmdLogin }, // 16 more: /sessions, /copy, /version, /theme, /feedback, /url, /title, // /tabs, /eval, /js, /dom, /snapshot, /export, /cancel, /history, /exit];/? → /help and /models → /model are aliases handled at
dispatch time. New commands plug in by appending one entry.
Autocomplete
Section titled “Autocomplete”The listbox #ac shows matching COMMANDS entries as you type a
slash. Arrow keys move the selection, Tab / Enter accepts.
Implemented as a prefix match on name.
Model picker
Section titled “Model picker”/model with no argument fetches the model list from the host
({type: 'models.list'} → host calls the Copilot SDK’s listModels())
and renders each as a clickable row. Clicking a row sends
{type: 'models.set', id}, the same message /model <id> sends.
The toolbar’s #model badge updates on session.ready and
models.current.
History
Section titled “History”↑ steps back through past prompts when the cursor is on the first
line of the input, and ↓ steps forward when it’s on the last line.
Stored in-memory only. The panel page is rebuilt each time DevTools
is closed and reopened, so history lasts as long as that DevTools
window.
Per-target binding
Section titled “Per-target binding”Each DevTools panel inspects a single tab. The panel keeps its
sessionId in chrome.storage.local under
browy.dt.sessionId.<tabId> and binds the session to that tab with
inspectedTabId in session.start. Open DevTools on three tabs →
three separate conversations. They share one agent in the host, which
runs one turn at a time. Close and reopen DevTools on the same tab and
you’re back in the same conversation.
This is intentional: it makes the DevTools CLI a per-page tool, in the same way the inspector is per-page.
Why a separate panel.js?
Section titled “Why a separate panel.js?”We could have rendered the REPL in the side panel UI and called it “DevTools mode”. We didn’t, because:
- DevTools panels live alongside the inspector, network, and console, giving power users context they want next to the agent.
- The DevTools panel UI primitives (toolbar buttons, theming, host
shortcuts like
Ctrl+Lto clear) are subtly different from a regular side panel. Keeping them separate avoidsif (devtools)forks throughout the side-panel code. - It lets the two surfaces evolve independently: the side panel can stay friendly and chat-shaped; the DevTools CLI can grow more power-user features (REPL co-coding, attach to running session) without complicating the side panel.
Coming soon
Section titled “Coming soon”These items are tracked on the GitHub project board:
- REPL co-coding: explicit handoff syntax (
:edit,:continue) for pair-programming with the agent on a single file. - Attach to running session: debug view of an active side-panel agent.
See also
Section titled “See also”Browy updates by email
I'll write when there's a new version worth trying. Unsubscribe any time.
Rather get them on GitHub? Watch BrowyHQ/browy and choose Custom, then Releases.