Hear your git context. Every repo has a voice. Every branch has a melody.
A CLI synthesizer that generates deterministic musical phrases from git branch names. Each repository gets its own harmonic identity — key, scale, timbre, pad shape — while each branch gets its own melodic identity — pattern, rhythm, envelope. Same inputs always produce the same sound.
Comes with a built-in interactive step sequencer featuring 10 classic drum breaks, a chromatic piano keyboard, and 7 synth presets inspired by jungle/liquid DnB hardware (Roland Juno-106, JP-8000, Korg M1).
Ever lose track of which terminal is on which branch? Now you can hear it.
One repo might be A# Lydian with a Swell pad shape. Another lands on E Mixolydian with a Pulse. Branches within each repo share that harmonic character but diverge in melody, rhythm, swing, and envelope — so main and feature/auth in the same repo sound like siblings, while the same branch in a different repo sounds like a stranger.
The result is ethereal, spaceship-like tones that ring out and overlap — inspired by the pad sounds of 90s jungle and liquid drum & bass.
curl -sSL https://raw.githubusercontent.com/rmzi/branch-tone/main/install.sh | shThen register the Claude Code plugin:
branch-tone init # User scope (all projects)
branch-tone init --scope project # Project scope (team-shared)Or manually:
cargo install --git https://github.com/rmzi/branch-tone
branch-tone initbranch-tone # Play tone for current branch
branch-tone feature/auth # Specific branch
branch-tone --dry-run # Show parameters without playing🎵 Repo: my-project | Branch: feature/auth [Arpeggio]
Key: E Mixolydian | Octave: 1.5x | Shape: Swell
Timbre: harmonic=0.13, 3rd=0.11
Notes: ["494Hz", "881Hz", "623Hz"]
Pattern: #4 | Envelope: Soft | Swing: 30%
Stagger: [0.00, 0.02, 0.06, 0.06, 0.12]
Spread: 0.92 | Duration: 600ms
# Sound modes
branch-tone --pad # Warm subtractive chord
branch-tone --chorus # BBD-style detuned layers
branch-tone --tremolo # Volume wobble
branch-tone --bulldozer # Layered pad (70%) + arp shimmer (30%)
branch-tone --spooky # Thin sines, dark filter, eerie resonance
# Parameters
branch-tone --steps 5 # 5-note phrase (default: 3)
branch-tone --reverse # Descending instead of ascending
branch-tone -d 800 -v 0.5 # Duration (ms) and volume (0.0–1.0)
branch-tone --repo my-project # Explicit repo name| Variable | Default | Effect |
|---|---|---|
BRANCH_TONE_VOLUME |
1.0 |
Global volume multiplier |
BRANCH_TONE_TEMPO |
1.0 |
Global duration multiplier |
A real-time drum machine and piano keyboard that uses your repo's harmonic identity as its scale.
branch-tone player # Amen break at native BPM
branch-tone player --pattern 3 # Apache break
branch-tone player --bpm 140 # Custom BPM branch-tone player --- Amen @ 136 BPM --- [PLAYING]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
K ● · · · ● · · ● · · ● · · · · ·
S · · · · ● · · · · · ● · · ○ · ·
H ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
O · · · · · · · · · · · · · · · ·
▲
Piano: Oct 0 | Synth: Iceman | Shape: Swell
W E T Y U O P
A S D F G H J K L [A# Lydian]
[enter] toggle [i] ghost [</>] move [^/v] row
[1-0] pattern [+/-] BPM [space] play/pause [q] quit
[A-L] piano [r] record [z/x/c/v] rec K/S/H/O
[[\]] octave [,/.] synth [;/'] pad shape [tab] sustain
Drum grid — 16 steps, 4 rows (Kick, Snare, Hi-hat, Open hat). Toggle full hits (●) and ghost notes (○) with velocity cycling.
10 classic breaks:
| # | Break | Native BPM |
|---|---|---|
| 0 | Amen | 136 |
| 1 | Think | 120 |
| 2 | Funky Drummer | 115 |
| 3 | Apache | 107 |
| 4 | Skull Snaps | 105 |
| 5 | One Drop | 75 |
| 6 | Steppers | 140 |
| 7 | Rockers | 130 |
| 8 | Dancehall | 100 |
| 9 | Two-Step | 138 |
Piano keyboard — chromatic keys mapped to your repo's scale. A–L for natural notes, W/E/T/Y/U/O/P for accidentals.
7 synth presets:
| Preset | Voices | Character |
|---|---|---|
| Juno | 3 | Classic warm BBD chorus |
| Supersaw | 7 | Massive JP-8000 detune |
| Iceman | 5 | LTJ Bukem liquid pad |
| M1 | 3 | Clean digital PCM |
| Bulldozer | 5 | Heavy filtered saw |
| Raw | 1 | Pure unprocessed sawtooth |
6 pad shapes — Swell, Cascade, Bloom, Pulse, Drift, Stab — each hashed per-repo so the same project always sounds the same.
Record mode — press r to arm, then z/x/c/v to live-record kick/snare/hat/open during playback.
Repo and branch are hashed separately with SHA-256, contributing independently to the final sound:
SHA-256 SHA-256
┌──────────┐ ─────────► ┌─────────────────┐ ─────────► ┌─────────────────┐
│ repo name│ │ Harmonic identity│ │ Melodic identity │
└──────────┘ │ │ ┌────────┐ │ │
│ Root note (C–B) │ │ branch │ │ Arpeggio pattern│
│ Scale type │ │ name │ │ Swing timing │
│ Octave register │ └────────┘ │ Envelope shape │
│ Timbre blend │ │ Chorus detune │
│ Pad shape │ │ Interval spread │
└─────────────────┘ │ Stagger offsets │
└─────────────────┘
Same repo + branch = same hashes = same sound. Every time. When used as Claude Code hooks, a per-event seed rotates the pattern, pad shape, and hit type — so each event sounds distinct while preserving the repo/branch identity.
The audio engine is a from-scratch soft synth written in Rust:
- Oscillators — Sawtooth-dominant with sine blend, 3–7 detuned voices per note with per-voice phase spreading
- Filter — 24dB/oct Butterworth LPF (cascaded biquads) with envelope-driven cutoff sweep and resonance control
- Reverb — Schroeder reverb: 4 comb filters + 2 allpass filters for depth and space
- Chorus — BBD-style delay modulation with phase-inverted L/R LFO (90° offset) for stereo width
- Dub delay — Tape-style echo with wow/flutter, filtered feedback, and gradual decay
- Drums — Fully synthesized: kick (sine pitch sweep 150→50Hz + click), snare (sine body + noise burst), rimshot (click + resonant ring), hi-hats (noise + metallic sines at 6/8/10kHz)
- Single hits — Short percussive events use a single drum hit (repo-deterministic type) with fast ~125ms decay
- Envelopes — 4 shapes (Punchy, Soft, Pluck, Swell) with exponential decay and note overlap for ethereal ringing
branch-tone initOne command registers hooks for 10 Claude Code events in ~/.claude/settings.json. Each event gets a distinct sound that varies by repo and branch — you can tell which event fired and which project you're in:
| Group | Events | Sound | Duration |
|---|---|---|---|
| Session | SessionStart |
Pad + chorus + dub | 2s |
SessionEnd |
Pad + tremolo + dub | 2s | |
| Rhythm | Stop |
Single drum hit | 300ms |
UserPromptSubmit |
Single drum hit (different type) | 250ms | |
| Alerts | PermissionRequest |
Pad + tremolo + dub + reverse | 1.5s |
Notification |
Pad + chorus + tremolo | 1.2s | |
| Ambient | SubagentStart, SubagentStop |
Randomized pad | 500ms |
PreCompact |
Pad + chorus + echo | 1.1s | |
| Waiting | TeammateIdle |
Clean gentle ping | 600ms |
Every event uses a unique event seed that rotates the note pattern, pad envelope shape, and drum hit type — so SessionStart and SessionEnd play different melodies in the same key, Stop and UserPromptSubmit use different percussive hits, and alerts each have their own character. The actual content (which notes, which hit type) still varies by repo+branch.
Run branch-tone test in any repo to preview all hook sounds.
Add to ~/.zshrc for audio feedback when switching worktrees:
function wt() {
local selection=$(git worktree list 2>/dev/null | \
awk '{path=$1; branch=$NF; gsub(/\[|\]/, "", branch); n=split(path, parts, "/"); dir=parts[n]; printf "%-20s %-30s %s\n", branch, dir, path}' | \
fzf --height 40% --reverse)
if [[ -n "$selection" ]]; then
local dir=$(echo "$selection" | awk '{print $NF}')
local branch=$(echo "$selection" | awk '{print $1}')
command -v branch-tone &>/dev/null && (cd "$dir" && branch-tone "$branch") &>/dev/null &
cd "$dir"
fi
}./scripts/demo.sh # Scan current directory for git repos
./scripts/demo.sh /path/to/repos # Scan a specific directory
./scripts/demo.sh --all # Include worktreescargo build # Debug build
cargo run -- main # Run with args
cargo run -- player # Step sequencer
cargo build --release # Optimized build
cargo test # 57 tests| Layer | Technology |
|---|---|
| Language | Rust 2024 edition |
| Audio | CPAL (Cross-Platform Audio Library) |
| Hashing | SHA-256 (two-layer: repo + branch) |
| CLI | Clap with derive macros |
| Terminal | Crossterm for the step sequencer |
| Synthesis | Saw/sine oscillators, Butterworth LPF, Schroeder reverb, BBD chorus, tape delay |
| Scales | 10 types across 12 chromatic roots |
The synthesis is modeled after the pad sounds of 90s jungle and liquid drum & bass — hardware like the Roland Juno-106 (BBD chorus), Roland JP-8000 (Supersaw), Roland JD-800 (the "Iceman" patch from LTJ Bukem's productions), and Korg M1 (PCM pads). The synth presets in the step sequencer are named after these references.
See docs/sound-design.md for the full synthesis research, frequency tables, hardware references, and Camelot key mappings.
MIT