Worktree Color Sync is a macOS-first Rust daemon that syncs visual context to your active git worktree.
This MVP includes:
- Ghostty terminal color sync (tab-specific, based on TTY)
- Cursor workspace titlebar tint sync (
.vscode/settings.json) - Deterministic, collision-aware color assignment for active worktrees
- Built-in high-contrast palette with 24 default slots
- Local daemon + CLI (
daemon,notify,status,current,doctor)
When juggling multiple worktrees, it is easy to run commands in the wrong one. This tool makes context visible through color.
Prerequisites:
jq(required for Cursor integration) - install viabrew install jq
Build the release binary:
cargo build --release -p worktree-syncInstall to your PATH:
cp target/release/worktree-sync ~/.local/bin/worktree-syncMake sure ~/.local/bin is in your PATH. If not, add to your ~/.zshrc:
export PATH="$HOME/.local/bin:$PATH"To update: Rebuild and copy again:
cargo build --release -p worktree-sync && cp target/release/worktree-sync ~/.local/bin/worktree-sync- Start daemon:
worktree-sync daemon- Add shell hook to your
~/.zshrc:
echo 'source /path/to/worktree-color-sync/shell/hook.zsh' >> ~/.zshrcThen reload your shell: source ~/.zshrc
- In Ghostty, each tab/session sends updates using a zsh hook with:
terminal_id = $(tty)(tab-specific)- notification when entering a git root (worktree/repo root)
- notification when leaving git-root context so terminal resets to defaults
- transition detection so repeated prompts do not spam updates
- Check health:
worktree-sync status
worktree-sync doctor --terminal-id "$(tty)"worktree-sync daemon
worktree-sync notify --terminal-id /dev/ttys012 --cwd /path/to/repo-or-worktree
worktree-sync status
worktree-sync current --terminal-id /dev/ttys012
worktree-sync doctor --terminal-id /dev/ttys012
worktree-sync cycle-color --worktree-path /path/to/worktreeDon't like the assigned color? Use cycle-color to generate a new random color:
# From within the worktree directory
worktree-sync cycle-color
# Or specify the path explicitly
worktree-sync cycle-color --worktree-path /path/to/worktreeRun it repeatedly until you find a color you like. Each run generates a new random color and immediately updates all terminals and Cursor windows for that worktree.
The zsh hook defines a cursor shell function for worktree ergonomics:
cursor(no args): opens the current git root in a new Cursor window- if currently inside a git checkout, it normalizes to the worktree/project root
- before launching Cursor, it sends
worktree-sync notifyso terminal and workspace settings stay aligned - if args are provided, it preserves them and adds
--new-windowunless you already passed-n/--new-windowor-r/--reuse-window
Examples:
cursor # opens current git root in new window
cursor . # opens cwd in new window
cursor -r . # explicitly reuse existing window
cursor --new-window . # explicit new windowDefault config path is optional. You can run with defaults or pass:
worktree-sync --config ~/.config/worktree-sync/config.toml daemonExample config:
config/worktree-sync.toml.example
notifyevent resolves worktree via:git rev-parse --show-toplevelgit rev-parse --git-common-dirgit worktree list --porcelain
- Worktree identity key is
repo_root + worktree_path. - Color allocator is deterministic, preserves persisted assignments to disk, and reuses the same worktree color across leave/re-enter cycles.
- Built-in palette size is
24, so up to 24 worktrees can hold unique palette colors before fallback generation (unlessstrict_palette = true). - Ghostty update behavior is context-aware per tab TTY:
- in worktree context: writes OSC 11 (background) + OSC 10 (foreground)
- outside worktree context: writes OSC reset sequences (110/111/112) to restore terminal defaults
- Cursor update merges managed titlebar keys into
.vscode/settings.json, and sets integrated terminal defaults:terminal.integrated.cwd = ${workspaceFolder}terminal.integrated.splitCwd = initial
After installation, verify everything works:
# Navigate to a git repo - should get a color
cd ~/github/some-repo
# Open new Ghostty tab (Cmd+T) - should inherit same color
# Try from subdirectory - should still work
cd ~/github/some-repo/subdirectorycd ~/github/your-worktree
worktree-sync cycle-color
# Cursor titlebar should change immediately
# New Ghostty tabs should get the new color
# Run again to get a different colorcd /tmp # non-git directory
worktree-sync cycle-color
# Should show error with link to git documentationworktree-sync status # Check daemon
worktree-sync current --terminal-id "$(tty)" # Current terminal color
worktree-sync doctor --terminal-id "$(tty)" # Health checkcargo fmt --all
cargo check --workspace
cargo test --workspaceMVP scope: Terminal + Cursor only. Browser integration is intentionally excluded.Platform: Designed for macOS and Ghostty + Cursor workflows.Ghostty behavior: Tab-specific updates rely on OSC support (OSC 11 + OSC 10) and TTY accessibility; behavior can vary by terminal/version and theme settings.Fallback: If tab-specific TTY update fails, daemon writes a global Ghostty fallback config snippet at:~/.config/ghostty/worktree-sync-global.conf- You must manually include this file in your Ghostty config if you want fallback to apply.
Shell hook requirement: To get tab-specific behavior, use$(tty)asterminal_id(not window/resource path).Root-transition trigger: Current hook updates on entering roots and leaving root context.Cursor wrapper: The hook defines a shell function namedcursor; if you need the raw binary, usecommand cursor ....Cursor settings: This tool writes to workspace-local.vscode/settings.jsonand may create the file.Terminal defaults: Workspace terminal cwd/split behavior is set to project-root oriented defaults.Color capacity: Built-in default palette supports24unique color slots. Above that, deterministic fallback colors are generated unlessstrict_palette = true(then allocation errors once full).Security: The daemon trusts local socket clients on your user account. Do not expose the socket path to other users.No warranty: This is open source software provided "as is".
License: MIT (LICENSE)
cargo fmt --all
cargo check --workspace
cargo test --workspaceCurrent tested commands during implementation:
cargo check --workspacecargo test --workspace
