Skip to content

aulorbe/worktree-color-sync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Worktree Color Sync (beta)

Worktree Color Sync is a macOS-first Rust daemon that syncs visual context to your active git worktree.

Worktree Color Sync example

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)

Why

When juggling multiple worktrees, it is easy to run commands in the wrong one. This tool makes context visible through color.

Install / Build

Prerequisites:

  • jq (required for Cursor integration) - install via brew install jq

Build the release binary:

cargo build --release -p worktree-sync

Install to your PATH:

cp target/release/worktree-sync ~/.local/bin/worktree-sync

Make 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

Quick Start

  1. Start daemon:
worktree-sync daemon
  1. Add shell hook to your ~/.zshrc:
echo 'source /path/to/worktree-color-sync/shell/hook.zsh' >> ~/.zshrc

Then reload your shell: source ~/.zshrc

  1. 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
  1. Check health:
worktree-sync status
worktree-sync doctor --terminal-id "$(tty)"

CLI

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/worktree

Changing a Worktree's Color

Don'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/worktree

Run 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.

Cursor Workflow (New Window)

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 notify so terminal and workspace settings stay aligned
  • if args are provided, it preserves them and adds --new-window unless you already passed -n/--new-window or -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 window

Configuration

Default config path is optional. You can run with defaults or pass:

worktree-sync --config ~/.config/worktree-sync/config.toml daemon

Example config:

  • config/worktree-sync.toml.example

How It Works

  • notify event resolves worktree via:
    • git rev-parse --show-toplevel
    • git rev-parse --git-common-dir
    • git 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 (unless strict_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

Testing

After installation, verify everything works:

1. Basic Functionality

# 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/subdirectory

2. Cycle Color

cd ~/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 color

3. Error Handling

cd /tmp  # non-git directory
worktree-sync cycle-color
# Should show error with link to git documentation

4. Status Commands

worktree-sync status                       # Check daemon
worktree-sync current --terminal-id "$(tty)"  # Current terminal color
worktree-sync doctor --terminal-id "$(tty)"   # Health check

Development

cargo fmt --all
cargo check --workspace
cargo test --workspace

Known Constraints and Disclaimers

  • MVP 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) as terminal_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 named cursor; if you need the raw binary, use command cursor ....
  • Cursor settings: This tool writes to workspace-local .vscode/settings.json and may create the file.
  • Terminal defaults: Workspace terminal cwd/split behavior is set to project-root oriented defaults.
  • Color capacity: Built-in default palette supports 24 unique color slots. Above that, deterministic fallback colors are generated unless strict_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".

Open Source

License: MIT (LICENSE)

Development

cargo fmt --all
cargo check --workspace
cargo test --workspace

Current tested commands during implementation:

  • cargo check --workspace
  • cargo test --workspace

About

Worktree Color Sync (MVP): sync Ghostty and Cursor colors by active git worktree

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors