claude-borders
v0.2.0
Published
A distinct, colored window border for every Claude Code session, so you never lose track of which terminal is which.
Maintainers
Readme
borders
A distinct, colored window border for every Claude Code session — so you never lose track of which terminal is which.
Run several Claude Code sessions at once and they all look identical. borders gives each one its own color and paints it as a frame around that terminal window. Glance at your screen and you instantly know which window is which.
npx claude-bordersThat's the whole install. Open a new Claude Code session and it gets a border.
What it does
- Watches Claude Code sessions start and end (via Claude's own
SessionStart/SessionEndhooks). - Assigns each session a color and draws a colored frame around the terminal window.
- By default uses no-repeat rotation: every concurrent session gets a different color; the color is freed when the session ends. Prefer one stable color per repo instead? Set
"mode": "project"— same project, same color, every day. - Pulses the frame when a session needs you — a permission prompt or Claude waiting for input makes that window's border gently pulse until you focus it (Claude's
Notificationhook). With many sessions open, the one that wants attention finds you. - Several sessions in one window (tabs, nested claudes) render as nested rings — newest on the outside — on a single overlay, so every session stays visible and nothing flickers.
- Fully customizable: your own palette, border width, and assignment strategy.
It does not touch your Claude Code status line, your prompt, or your terminal tabs. Just the window border.
Platform support — honestly
| Platform | What you get |
|---|---|
| Windows 11 / 10 + Windows Terminal (and conhost, Alacritty, WezTerm) | A real colored frame drawn around the window, any width. ✅ The full experience. |
| macOS / Linux / WSL, inside tmux | Colored tmux pane borders for the session. ✅ |
| macOS / Linux, not in tmux | Nothing yet — there is no portable OS API to color a terminal window border. Run inside tmux, or use it on Windows. |
Windows Terminal note: Windows Terminal draws its own title bar (that's where the tabs live), so it ignores the OS title-bar color. That's why
bordersdraws a frame overlay instead — the frame is your visual, and it works regardless.
Install
npx claude-borders # install (default)
# or, globally:
npm i -g claude-borders && borders installThe installer:
- Copies a small, dependency-free runtime to
~/.claude/borders/. - Creates
~/.claude/borders/config.json(only if you don't have one). - Merges three hooks (
SessionStart,SessionEnd,Notification) into~/.claude/settings.jsonwithout touching anything else in that file (a one-time backup is saved assettings.json.borders-backup). It refuses to write if it can't parse your settings.
Re-running install is always safe — it's idempotent and also how you upgrade.
Uninstall
borders uninstall # remove the hooks, stop overlays, reset colored windows
borders uninstall --purge # also delete ~/.claude/borders and your configYour settings.json returns to exactly its previous shape (the hooks we added are removed; anything else you had is untouched).
Commands
| Command | What it does |
|---|---|
| borders / borders install | Install or upgrade (idempotent). |
| borders status | Show which session currently owns which color. |
| borders set <#hex \| 0-9> | Recolor the current terminal now (great via !borders set 3 inside a session). |
| borders demo | Preview the palette and draw a sample frame on this window. |
| borders attention | Pulse the active session frames — see what a needs-attention pulse looks like. |
| borders reset | Clear a stuck color in the current terminal (recovery). |
| borders doctor | Diagnose the install. |
| borders uninstall [--purge] | Remove borders. |
Configuration
Edit ~/.claude/borders/config.json:
{
"mode": "rotate",
"palette": [
"#E06C75", "#61AFEF", "#98C379", "#E5C07B", "#C678DD",
"#56B6C2", "#D19A66", "#7F9CF5", "#F472B6", "#34D399"
],
"border": { "style": "frame", "width": 3, "radius": 8, "placement": "outside", "titlebar": true, "maxRings": 4 },
"attention": { "enabled": true, "timeoutSec": 30 },
"win32": { "hostAllowlist": ["WindowsTerminal.exe", "conhost.exe", "alacritty.exe", "wezterm-gui.exe"] },
"tmux": { "border": true, "lines": "heavy" },
"advanced": { "debug": false, "staleHours": 24, "psTimeoutMs": 8000 }
}palette— your colors, as hex. Add or remove as many as you like.mode— how a color is chosen:rotate(default) — next free color; concurrent sessions never share.hash— deterministic from the session id (same session → same color across resumes; colors can repeat).project— deterministic from the working directory (one color per project).
border.width— frame thickness in pixels (Windows).border.radius— corner radius in pixels (default8, matching Windows 11 windows).0for square corners. Drawn with anti-aliasing.border.placement—outside(default; a ring around the window, not covering any content) orinside(overlaps the window's outer edge). Maximized windows automatically use a square inside border, since an outside ring would fall off-screen.border.style—frame(the overlay, any width, Win 10 & 11) orsystem(native 1px DWM border, Win 11).border.titlebar— also try to color the OS title bar (works on some terminals; ignored by Windows Terminal — see note above). When several sessions share a window, the newest session's color wins the title bar.border.maxRings— how many nested session rings one window may show (default4).attention.enabled— pulse a session's ring when it needs your input (defaulttrue).attention.timeoutSec— stop pulsing after this long if you never focus the window (default30). Focusing the window stops it immediately.tmux.lines—single/double/heavy(heavy & double need tmux ≥ 3.4).
Look changes (width, radius, placement, maxRings, titlebar) apply to open frames within a moment — the background helper re-reads the config live. mode and palette apply to the next session that starts; use borders set to recolor an open one now.
Troubleshooting
The frame didn't appear when I opened a session (Windows).
Run borders doctor to confirm the install. Then test the visual directly with borders demo — a sample frame should flash around the window. If the demo works but new sessions don't get a frame automatically, your node may not be on PATH for hooks; re-run borders install (it records the right invocation) and check borders doctor again.
A window stayed colored after I closed a session / crashed.
The background helper notices a dead Claude process within a few seconds and drops its frame automatically. If something still looks stuck, run borders reset in that terminal; colors also auto-expire after staleHours (default 24h), and the frame disappears on its own when the window closes.
Multiple tabs in one Windows Terminal window.
Each session in the window gets its own ring on the shared frame — the newest session is the outer ring, older ones nest inside (up to border.maxRings). The title-bar color follows the newest session. For one clean border per session, use separate windows.
The frame doesn't show in Task View / Alt+Tab (the 3-finger swipe-up overview).
Expected, not a bug. Task View and Alt+Tab show a separate per-window thumbnail of each app — DWM hands them only that one window's own rendered surface. The frame is a separate, click-through overlay window that sits on top of the terminal on the live desktop; its pixels are never part of the terminal's own surface, so they can't appear in the terminal's thumbnail. (Putting them there would require modifying or injecting into the terminal itself, which borders deliberately never does.) The frame is a live-desktop visual — that's where you read and switch between sessions — and it's fully visible there.
tmux borders aren't showing.
tmux only draws pane borders when a window is split. Also, heavy/double line styles need tmux ≥ 3.4.
Windows 10. The frame works. The native DWM title-bar color does not (Windows 11 only) — but Windows Terminal ignores that anyway, so you lose nothing.
Turn on logging.
Set "debug": true under advanced in the config; diagnostics go to ~/.claude/borders/debug.log. Hooks never print to your screen or into Claude's context.
How it works (and safety)
borders registers three Claude Code hooks. On session start, a tiny Node script claims a color, finds your terminal window, and records the pairing in a small state file. A single background helper (one hidden process for all your sessions) reads that file and draws an anti-aliased, click-through frame around each window — exactly one overlay per window, so colors can never fight — following it as you move or resize (it listens for OS window events, so it costs ~nothing while idle). On session end, the hook removes the claim and the helper drops that frame; it also drops frames whose Claude process died without saying goodbye. When no windows remain, the helper exits on its own.
The helper has to outlive the hook that starts it (Claude runs hooks in a short-lived job), so it's launched via a Windows scheduled task — created at install, removed at uninstall, and visible in Task Scheduler as borders-daemon. Everything is local: no network, no telemetry. Hooks always exit cleanly, so a borders problem can never break your Claude Code session.
Changelog
0.2.0
- Sessions sharing one window now draw as nested rings on a single overlay (newest outside) — fixes the frame blinking between colors when a forked/second session started in the same terminal.
- Attention pulse: the border pulses when a session is waiting on you (permission prompt / idle), via Claude's
Notificationhook. Stops when you focus the window.borders attentionto preview. - The background helper now owns the title-bar color (no more start/stop flashes), reaps sessions whose Claude process died within seconds, and tracks windows via OS events instead of polling (near-zero idle CPU).
borders setoverrides now survive resume/compaction; uninstall reliably stops the helper even if its heartbeat file is gone.
0.1.0
- First release: per-session colored window frames on Windows, tmux pane borders on macOS/Linux/WSL, no-repeat rotation,
rotate/hash/projectmodes, custom palette and width.
License
MIT
