Repository navigation
Releases: tdody/switchboard
Release list
v0.2.0 — Layouts, broadcast, and a perf pass
Switchboard v0.2 — new layouts and filter primitives for the kanban, broadcast in the command palette, full-text search across pane scrollback, session templates, the bulk of an external security audit closed out, and a batch of perf work.
Highlights
New layouts & filter ergonomics
- Grid view — every pane on screen at once, grouped by session.
- List view — dense single-column rundown.
- Layout suggestion chip — header hint nudges you toward the layout that fits your current pane count.
- Pinned windows — pin button in the card foot promotes a card to the top of its column with an accent border and header badge, and keeps it visible even when the active filter would normally hide it. Persisted in
localStorageby pane id. - Saved filter presets — chip-bar in the subhead saves the current
(status, kind, query)filter under a name and lets you recall or delete it in one click. Persisted inlocalStorage.
Command palette: broadcast mode
- Open the palette with multiple target panes and it switches to broadcast mode: amber pill in the header, one chip per target with an inline X to prune before sending, footer reads target: N panes. Submit iterates
POST /api/sendper remaining target; per-target errors are swallowed so one bad pane doesn't abort the rest. - NeedsStrip gains a Broadcast button (visible when there are ≥2 pending panes) that opens the palette pre-loaded with the pending list as targets.
Session templates
services/templates.pydefinesTemplate/TemplateWindowmodels with two built-ins (web-project,agent-grid) and loads user templates from~/.switchboard/templates/*.json.${VAR}substitution acrosssession, windowname/cwd/cmd; the modal collects values per template, the backend substitutes at instantiation time, and unknown vars pass through unchanged.GET /api/templatesreturns lightweight summaries;POST /api/templates/instantiatecreates the session and starts each window's command.
Pane history search (⌘⇧F)
GET /api/search?q=<term>&lines=500fans the per-pane capture + grep out viaasyncio.gather(asyncio.to_thread(...)). Case-insensitive substring match on ANSI-stripped lines; returns pane id, session, window name + index, 1-based line number, and 3 lines of context per match. Capped at 50 matches per pane and 5,000 lines per pane; empty query returns 400.- New
<SearchModal>opened via⌘⇧F/Ctrl+Shift+F(also from inside inputs). Live search-as-you-type with a 200 ms debounce and an AbortController on every keystroke.
Cards that do more
- Per-kind quick actions — agent cards expose
y/n/Ctrl-C; shell cards exposeclear. - Live activity timers — Xm ago spans tick at 1Hz via a dedicated
AgoSpanleaf component. - Needs-strip dismiss persistence — dismissals stored as a per-pane id set in
sessionStorage, so they survive reloads in the same tab.
Security audit
A full external audit landed; every finding is now closed:
- 5 high-severity auth findings fixed.
- 9 medium-severity findings fixed.
- 6 low-severity findings closed out.
Performance
- Backend
parse_paneoutput cached keyed by(lines-hash, cwd).pane.capture_pane()cached under modal-open polling so the modal and the kanban poll can share the capture.- libtmux calls in the WS recv loop offloaded via
asyncio.to_thread. - Branch cache TTL 2→5s, PR cache TTL 30→60s.
- Frontend
/api/stateresponse deduped so unchanged windows keep their object references.WindowCardmemo upgraded withprUrl+ a content-aware preview check.xtermstream rewriter gets a fast-path for chunks with no truecolor background.- OSC 4 theme packets precomputed at module load.
- Terminal-modal
fit()debounced viarAFinstead of an 80 mssetTimeout. - Cached pane preview painted at modal mount; replaced on the first snapshot.
- New
useSetting(key)selector hook lets the terminal modal subscribe to a single settings key instead of the whole object. - Favicon and title effects merged into one.
Bug fixes
.rename-modalnow has the same chrome as the other modals (panel background, border, radius, drop shadow, rise animation). It was previously transparent — invisible in dark mode by accident, and unreadable in light mode.- Removed the hardcoded
#282c34inline background on.term-bodyso the theme-aware CSS rule (added in the original theme work) wins. Fixes the light/high-contrast terminal modal where the body sandwiched the xterm viewport between light chrome and a dark padding band. - Size button now scales modal height in lockstep with width.
- CI flake in
test_open.pyfixed by neutralizing the prewarm-scrape daemon inconftest.
Docs
- Wordmark banner + install/python/license badges replace the centered logo + heading on the README.
- New Contributing and Reporting a security issue sections; tightened Layout.
Requirements
Unchanged from v0.1.0:
- Backend: Python ≥ 3.11,
tmux,uv(FastAPI + pydantic-settings). - Frontend: Node ≥ 20 (Vite + React 19, xterm.js).
- Optional: an editor on the IDE allowlist for path-click open,
ghfor PR / CI chip enrichment.
Upgrading from v0.1.0
git fetch --tags
git checkout v0.2.0
cd backend && uv sync && cd ..
cd frontend && npm install && cd ..
./scripts/dev.shNo config migrations. Pins and saved filter presets persist in localStorage and start empty; needs-strip dismissals live in sessionStorage and clear on tab close.
Full changelog: v0.1.0...v0.2.0
v0.1.0 — Initial public release
First public cut of Switchboard — a live browser dashboard for tmux sessions, purpose-built for watching a swarm of Claude Code agents without the tab-fight.
Highlights
Kanban dashboard
- Sessions become columns, every tmux window becomes a card; status colors call out idle / running / waiting / failed at a glance.
- Drag to reorder columns and tiles within a column.
- Sticky header with quick session / window creation.
Live terminal modal
- xterm.js bridged over WebSocket with auto-reconnect on transient drops.
- Robust input — bracketed paste, buffered text, image paste from the clipboard.
- Modal header chips: branch, PR #, CI rollup, zoom controls.
- Interactive prompts (menu / y-n / press-enter) rendered as a click-or-keyboard overlay over the terminal.
- Kill / rename / new-window controls without leaving the modal.
Claude Code awareness
- Detects spinner with elapsed, recap of the last assistant line, branch + PR + CI, and pending-input across menu / y-n / press-enter / free-form question shapes.
- Per-pane context-window percent and per-session cost surfaced inline.
- Rolling-window Claude usage pill with plan-% scraping.
Notifications & glance-ability
- Native browser notifications when any agent flips to waiting; favicon dot mirrors the state.
- Status legend explains every color and glyph.
Discoverability
- ⌘K command palette — send keys to the focused pane from anywhere, with localStorage-backed recents.
?shortcuts sheet.- First-run interactive tour, replayable from Settings.
- In-app Docs tab with architecture diagrams.
- ✨ Auto-rename — Anthropic Haiku suggests a window name for every pane in a session, with per-row preview / edit / skip before applying.
Editor & GitHub linkifiers
- Clickable file paths in pane output open in your configured IDE; ⚙️ Settings picks from probed-and-installed editors.
- Clickable
PR #Nchips open the GitHub PR in a new tab.
Themes & accessibility
- Four themes: dark / light / high-contrast / phosphor.
- Every interactive surface, including the xterm.js 256-color palette, clears WCAG AA contrast — wired up to a CI audit .
Requirements
- Backend: Python ≥ 3.11,
tmux,uv(FastAPI + pydantic-settings). - Frontend: Node ≥ 20 (Vite + React 19, xterm.js).
- Optional: an editor on the IDE allowlist (
code,cursor, …) for path-click open,ghfor PR / CI chip enrichment.
Quickstart
```bash
cd backend && uv sync && cd ..
cd frontend && npm install && cd ..
git config core.hooksPath scripts/hooks # one-time
./scripts/dev.sh # backend :8765, frontend :5173
```
Then open http://localhost:5173. Full instructions, env vars, and a seeded-tmux dev script in the README.
Notable bug fixes baked into this cut
- Reject typed numbered lists as menu prompts so the prompt overlay no longer pops up mid-typing (#69).
- Stabilize the
test_openclientfixture against theclaude_usageprewarm thread to eliminate the CI race seen on #68 (#68). - Free-form question detection picks up "let me know", "awaiting your …", and the modern ⏺ assistant marker.
- Per-agent context % survives the brain-emoji status bar across Claude Code builds.
- Branch cache TTL dropped to 2 s so a
git checkoutinside a pane lights up the dashboard in the next poll.
Full changelog: https://github.com/tdody/switchboard/commits/v0.1.0
