The panel should match kitty's font, but extension pages can't reach system
fonts by name — CSP blocks `local()` — so the TTFs ship in the repo:
fonts/JBMono-Regular.ttf 2.5MB weight 400
fonts/JBMono-Bold.ttf 2.5MB weight 700
Copied from /usr/share/fonts/TTF/JetBrainsMonoNerdFontMono-{Regular,Bold}.ttf.
Heavy, but it's local-only — the panel never downloads them.
`@font-face` in sidepanel.html, fallback chain kept (ui-monospace, SF Mono,
Menlo, monospace). Line-height 1.4 -> 1.5 for JBMono's taller glyphs.
The Nerd Font variant means nerd-font glyphs leaking out of the pane render
properly instead of as boxes.
No `web_accessible_resources` needed: the side panel is an extension page on the
same chrome-extension:// origin, so bundled files are directly reachable. That
key is only for files injected into web pages.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CC Sidepanel
A Brave/Chrome MV3 side-panel extension that puts a live Claude Code seat in your browser sidebar — type in the sidebar, it lands in the real terminal pane. Two-way.
Built by Monica (bridge + extension skeleton), parser and styling pass by Selene, 2026-09-11.
Pieces
bridge.py— a localhost HTTP shim on:8988. Browser extensions can't reach a unix socket, so this proxies JSON toinjectd.py's socket at/tmp/injectd.sock(ops:seats,screen,inject). CORS is locked to onechrome-extension://origin — no wildcard.extension/— MV3 side panel. Polls/screenevery 1.5s, parses the raw kitty pane into typed blocks (user / assistant / tool / thinking / live-heartbeat / meta), and sends text back via/inject.
Dependencies / pre-reqs
injectd.pyis house infrastructure, not part of this repo. The bridge expects the socket/tmp/injectd.sockto already exist (created by injectd, which runs separately and is shared by every seat).- The extension ID is deliberately not in the code.
bridge.pyreadsCCSIDEPANEL_EXT_IDfrom the environment and refuses to start if it's unset (no silent fallback).
Setup
-
Load the extension unpacked from
extension/atbrave://extensions. -
Copy its ID from the
brave://extensionspage. -
Create the env file:
cp cc-sidepanel.env.example /etc/cc-sidepanel.env # fill in CCSIDEPANEL_EXT_ID=<your-id> -
Start/restart the bridge:
systemctl restart cc-sidepanel-bridge # unit: /etc/systemd/system/cc-sidepanel-bridge.serviceThe systemd unit runs as
juxtapoand reads config viaEnvironmentFile=/etc/cc-sidepanel.env— both files live outside the repo (documented here, not committed).
Gotcha: reloading = new ID
Reloading the extension from a different path gives it a new ID, and the panel gets CORS-blocked with no visible error. If the panel stops working after a reload, copy the new ID, update /etc/cc-sidepanel.env, and restart the unit.
License
House project — MIT.