claude-borders
v0.1.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.
- 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 two hooks 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 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 },
"win32": { "hostAllowlist": ["WindowsTerminal.exe", "conhost.exe", "alacritty.exe", "wezterm-gui.exe"] },
"tmux": { "border": true, "lines": "heavy" },
"advanced": { "debug": false, "staleHours": 24, "psTimeoutMs": 8000, "pollMs": 90 }
}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).tmux.lines—single/double/heavy(heavy & double need tmux ≥ 3.4).
Changes apply to the next session that starts. Use borders set to recolor an open one.
Troubleshooting
The frame didn't appear when I opened a session (Windows).
Run borders doctor to confirm the install. Then test the visual directly: in the terminal, run borders set 2 — a frame should appear. If set 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.
A window stayed colored after I closed a session / crashed.
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. A window frame is per window, so tabs in the same window share it. For distinct per-session borders, use separate windows. (Each new window gets its own color.)
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 two 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, following it as you move or resize. On session end, the hook removes the claim and the helper drops that frame; 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.
License
MIT
