Skip to content

Releases: tdody/switchboard

v0.2.0 — Layouts, broadcast, and a perf pass

Choose a tag to compare

@tdody tdody released this 07 Jun 00:56
d64d7df

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 localStorage by 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 in localStorage.

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/send per 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.py defines Template / TemplateWindow models with two built-ins (web-project, agent-grid) and loads user templates from ~/.switchboard/templates/*.json.
  • ${VAR} substitution across session, window name / cwd / cmd; the modal collects values per template, the backend substitutes at instantiation time, and unknown vars pass through unchanged.
  • GET /api/templates returns lightweight summaries; POST /api/templates/instantiate creates the session and starts each window's command.

Pane history search (⌘⇧F)

  • GET /api/search?q=<term>&lines=500 fans the per-pane capture + grep out via asyncio.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 expose clear.
  • Live activity timers — Xm ago spans tick at 1Hz via a dedicated AgoSpan leaf 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_pane output 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/state response deduped so unchanged windows keep their object references.
    • WindowCard memo upgraded with prUrl + a content-aware preview check.
    • xterm stream rewriter gets a fast-path for chunks with no truecolor background.
    • OSC 4 theme packets precomputed at module load.
    • Terminal-modal fit() debounced via rAF instead of an 80 ms setTimeout.
    • 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-modal now 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 #282c34 inline background on .term-body so 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.py fixed by neutralizing the prewarm-scrape daemon in conftest.

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, gh for 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.sh

No 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

Choose a tag to compare

@tdody tdody released this 31 May 02:01
e5d97e1

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.

Kanban dashboard

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 #N chips 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, gh for 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_open client fixture against the claude_usage prewarm 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 checkout inside a pane lights up the dashboard in the next poll.

Full changelog: https://github.com/tdody/switchboard/commits/v0.1.0