Auto‑color your iTerm2 tabs by project (with zsh)
I’ve been having a lot of Claude Code terminal windows open and more than once typed into the wrong one. I wan’ted to color code each project for quick visual feedback. Next step is to maybe get around to syncing VS Code’s border color to match my Iterm2 tab color. Yeah, I guess I could use the integrated VS Code terminal, but I never got used to it.
If you juggle multiple repos at once, coloring each iTerm2 tab to match the project’s primary color makes context‑switching painless. This guide shows a tiny, shell‑only solution that automatically tints the tab/title bar when you cd
into a project and resets it when you leave. Optional add‑ons let you tint the terminal background too, and even pull colors from Tailwind.
What you’ll build
- Auto‑tinted tabs: drop a
.iterm-color
file (a hex like#7e3af2
) in a repo’s root directory; whenever your shell is inside that repo (or any subfolder), the tab turns that color. - Automatic reset:
cd ..
out of the project tree and the tab goes back to your default profile color. - Optional: also tint the terminal’s text‑area background.
Requirements
- iTerm2 on macOS (tab coloring works on recent builds)
- zsh (the default macOS shell)
- No plugins required (works fine with oh‑my‑zsh/prezto, etc.)
Tip: If you use tmux, test the color change outside tmux first. Some tmux setups filter non‑standard escape sequences.
1) Quick sanity check: can iTerm2 tint tabs?
Run this once in a fresh iTerm2 tab. Your tab should turn red:
# Pure red tab chrome (top bar)
echo -e "\033]6;1;bg;red;brightness;255\a\033]6;1;bg;green;brightness;0\a\033]6;1;bg;blue;brightness;0\a"
If nothing happens, make sure you are actually in iTerm2 (not Terminal.app) and on a recent version.
2) Add the auto‑tint hook to ~/.zshrc
Paste this entire block into your ~/.zshrc
, then source ~/.zshrc
.
# ---------------------------------------------------------------------
# Auto‑color iTerm2 tab chrome based on nearest .iterm-color file
# ---------------------------------------------------------------------
autoload -Uz add-zsh-hook
# Find the closest .iterm-color by walking up from $PWD to /
_iterm_find_color_file() {
local dir=$PWD
while [[ $dir != "/" ]]; do
[[ -f "$dir/.iterm-color" ]] && { echo "$dir/.iterm-color"; return 0; }
dir=${dir:h} # zsh dirname shorthand
done
return 1
}
# Apply either the project color (if found) or reset to profile default
_iterm_apply_tab_color() {
local cfg=$(_iterm_find_color_file) || true
if [[ -n $cfg ]]; then
# Read first non-empty line, strip leading '#'
local hex
hex=$(grep -Eo '[#]?[0-9A-Fa-f]{6}' "$cfg" | head -n1)
hex=${hex#\#}
[[ ${#hex} -ne 6 ]] && return 0
local r=$((16#${hex[1,2]}))
local g=$((16#${hex[3,4]}))
local b=$((16#${hex[5,6]}))
# iTerm2 OSC 6; set tab/title-bar background by RGB channel (0–255)
printf '\033]6;1;bg;red;brightness;%d\a' $r
printf '\033]6;1;bg;green;brightness;%d\a' $g
printf '\033]6;1;bg;blue;brightness;%d\a' $b
else
# Reset tab/title-bar to your profile default
printf '\033]6;1;bg;*;default\a'
fi
}
# Run after every directory change, and once on startup
add-zsh-hook chpwd _iterm_apply_tab_color
_iterm_apply_tab_color
# ---------------------------------------------------------------------
How it works
- Every time you
cd
,_iterm_apply_tab_color
looks for.iterm-color
up the directory tree. - If found, it parses the hex, converts it to three 0–255 channels, and emits iTerm2’s tab‑color escape sequences.
- If not found, it sends a single reset escape sequence so the tab color returns to your profile default.
3) Mark projects with a color
Inside each repo (or at the monorepo root), create a .iterm-color
file containing a single hex color:
echo "#22c55e" > ~/code/my-api/.iterm-color # green
Now:
cd ~/code/my-api # tab turns green
cd ~/ # tab resets to default
Inheritance: The color applies to all subfolders until you leave the project tree.
Optional: also tint the text‑area background
If you want the terminal canvas (not just the tab) to match the project color, add this one line inside _iterm_apply_tab_color
right after the three RGB writes:
# Also tint the terminal background (session‑local)
printf '\033]1337;SetColors=bg=%s\a' "$hex"
To reset when leaving a project, add a matching reset in the else
branch:
# Reset terminal background to profile default
printf '\033]1337;SetColors=bg=default\a'
This uses iTerm2’s proprietary
OSC 1337;SetColors
escape. It affects only the current session/pane.
Optional: pull the color from Tailwind
If your projects define a primary
color in tailwind.config.{js,cjs}
, you can auto‑derive .iterm-color
with a tiny Node helper.
- Create
scripts/iterm-primary.js
in the repo:
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const tryPaths = ["tailwind.config.js", "tailwind.config.cjs"].map(p =>
path.join(process.cwd(), p)
);
const cfgPath = tryPaths.find(fs.existsSync);
let hex = null;
if (cfgPath) {
const cfg = require(cfgPath);
const colors =
(cfg.theme && (cfg.theme.extend?.colors || cfg.theme.colors)) || {};
const primary = colors.primary;
if (typeof primary === "string") hex = primary;
else if (primary && typeof primary.DEFAULT === "string")
hex = primary.DEFAULT;
}
console.log((hex || "#2563eb").replace("#", ""));
- Generate the
.iterm-color
automatically:
node scripts/iterm-primary.js | awk '{print "#"$0}' > .iterm-color
Drop that into your build or a pre‑commit hook if you want the file kept in sync.
Troubleshooting
-
Tab doesn’t change at all → Re‑run the sanity check (Step 1). Make sure you’re in iTerm2, not Terminal.app. Try a brand‑new window.
-
Hook not firing → Add a quick debug line right after
add-zsh-hook
:iterm_tab_debug() { echo "[iterm] chpwd in $PWD"; } add-zsh-hook chpwd iterm_tab_debug
cd
around; if you don’t see the message, ensure you’re actually runningzsh
(echo $ZSH_VERSION
). If you use a framework, keep the hook after its init line in~/.zshrc
. -
Inside tmux → If the color works in a plain iTerm2 tab but not inside tmux, your tmux config may be filtering these escape sequences. Test outside tmux or consult tmux passthrough options for your version.
-
Malformed
.iterm-color
→ Must be a 6‑digit hex. Shorthand like#f60
won’t parse; use#ff6600
. -
Border color → iTerm2’s window border color isn’t themeable; only thickness on/off can be toggled in Preferences.
Extras & notes
- The amount of top‑bar fill depends on your iTerm2 Theme (Minimal/Compact vs Light/Dark).
- You can keep a palette of favorite hexes in a cheatsheet dotfile and copy them into
.iterm-color
per project. - Because this is all shell‑side, it plays nicely with any prompt (Starship, pure, powerlevel10k, etc.).
Recap
- Confirm tab tinting works in your iTerm2 build.
- Add the zsh hook that emits tab‑color escape codes.
- Drop a
.iterm-color
file with a hex in any repo you want tinted. - (Optional) Tint the terminal background too.
That’s it — now every project gets an at‑a‑glance color, and your brain gets fewer context switches.