Custom tmux-powerkit plugins for the tmux status bar.
| Plugin | Description |
|---|---|
| Claude Code | Displays Claude Code rate limit usage (5h/7d) |
| CPU AS | Accurate CPU usage for Apple Silicon macOS |
| RAM | Accurate memory usage for Apple Silicon macOS |
| File | Description |
|---|---|
claude_code.sh |
Claude Code rate limit plugin |
cpuas.sh |
Accurate CPU usage plugin (replaces built-in cpu) |
ram.sh |
Accurate RAM usage plugin (replaces built-in memory) |
statusline.sh |
Claude Code status line script (bridges data to the plugin) |
.tmux.conf |
Full tmux configuration with all plugins enabled |
tmux-panes/ |
Claude Code skill for controlling tmux panes from Claude |
cp claude_code.sh ~/.tmux/plugins/tmux-powerkit/src/plugins/claude_code.sh
cp cpuas.sh ~/.tmux/plugins/tmux-powerkit/src/plugins/cpuas.sh
cp ram.sh ~/.tmux/plugins/tmux-powerkit/src/plugins/ram.shcp statusline.sh ~/.claude/statusline.sh
chmod +x ~/.claude/statusline.shAdd the plugins to your @powerkit_plugins list in ~/.tmux.conf:
set -g @powerkit_plugins "group(datetime,cpuas,ram),claude_code,git"Note: Use
cpuasinstead ofcpuandraminstead ofmemoryfor accurate Apple Silicon readings.
In ~/.claude/settings.json, the statusLine entry should exist:
{
"statusLine": {
"type": "command",
"command": "input=$(cat); echo \"$(echo \"$input\" | ~/.claude/statusline.sh)\""
}
}prefix + r
Or from the terminal:
tmux source-file ~/.tmux.confA drop-in replacement for the built-in cpu plugin that provides accurate CPU readings on Apple Silicon macOS.
The built-in cpu plugin uses top -l 1 on macOS, which returns the cumulative-since-boot CPU average — not a live snapshot. This inflates readings significantly, often showing 2x the actual load compared to Activity Monitor.
The cpuas plugin uses iostat -c 2 -w 1 and discards the first sample (cumulative). The second sample is a true 1-second delta of user + system time, matching Activity Monitor.
On Linux it uses /proc/stat delta calculations between refresh cycles.
All settings use the @powerkit_plugin_cpuas_ prefix in .tmux.conf:
# Health thresholds (controls powerkit theme coloring)
set -g @powerkit_plugin_cpuas_warning_threshold "70"
set -g @powerkit_plugin_cpuas_critical_threshold "90"
# Custom icon (Nerd Font glyph)
set -g @powerkit_plugin_cpuas_icon ""- ok: Usage below 70%
- warning: Usage 70-90%
- error: Usage above 90%
A drop-in replacement for the built-in memory plugin that provides accurate memory readings on Apple Silicon macOS (Tahoe+).
The built-in memory plugin has two accuracy problems on Apple Silicon:
memory_pressurereports a coarse "free percentage" that doesn't match Activity Monitorvm_statfallback only counts active + wired pages, ignoring compressor-occupied pages — a significant category on Apple Silicon where memory compression is aggressive
The ram plugin matches Activity Monitor's "Memory Used" breakdown:
| Component | Source (vm_stat) |
|---|---|
| App Memory | Anonymous pages - Purgeable pages |
| Wired | Pages wired down |
| Compressed | Pages occupied by compressor |
| Used | App + Wired + Compressed |
All settings use the @powerkit_plugin_ram_ prefix in .tmux.conf:
# Display format: "percent" (default), "usage" (used/total), or "used" (used only)
set -g @powerkit_plugin_ram_format "percent" # e.g. 54%
set -g @powerkit_plugin_ram_format "usage" # e.g. 17.3G/32.0G
set -g @powerkit_plugin_ram_format "used" # e.g. 17.3G
# Health thresholds (controls powerkit theme coloring)
set -g @powerkit_plugin_ram_warning_threshold "75"
set -g @powerkit_plugin_ram_critical_threshold "90"
# Custom icon (Nerd Font glyph)
set -g @powerkit_plugin_ram_icon ""- ok: Usage below 75%
- warning: Usage 75-90%
- error: Usage above 90%
Displays Claude Code rate limit usage in the tmux status bar. Shows two percentages: 5-hour window usage / 7-day reset usage, with a dynamic icon that changes based on the 5-hour rate limit level.
Claude Code pipes JSON to the statusLine command on each update. The JSON includes rate limit data:
{
"rate_limits": {
"five_hour": {
"used_percentage": 23,
"resets_at": 1738425600
},
"seven_day": {
"used_percentage": 41,
"resets_at": 1738857600
}
}
}- Claude Code pipes JSON to
statusline.shvia thestatusLinesetting statusline.shextracts both rate limit percentages and writes them to/tmp/claude-code-ctxclaude_code.sh(powerkit plugin) reads/tmp/claude-code-ctxand renders the values
The following lines were added to extract rate limit data and write it to a temp file:
# Extract rate limit percentages for tmux-powerkit plugin
five_h=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // ""' | cut -d. -f1)
seven_d=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // ""' | cut -d. -f1)
# Export for tmux-powerkit claude_code plugin
printf '%s %s\n' "${five_h:-}" "${seven_d:-}" > /tmp/claude-code-ctx 2>/dev/nullThe plugin renders as: <icon> XX%/XX% (5h usage / 7d usage)
| Range | Icon |
|---|---|
| 0-5% | |
| 5-40% | |
| 40-60% | |
| 60-80% | |
| 80-95% | |
| 95%+ | |
- ok: 5h usage below 40%
- warning: 5h usage 40-60%
- error: 5h usage above 60%
Thresholds are configurable in .tmux.conf:
set -g @powerkit_plugin_claude_code_warning_threshold "40"
set -g @powerkit_plugin_claude_code_critical_threshold "60"- Rate limit data is only available for Claude Pro/Max subscribers
- Data only appears after the first API response in a Claude Code session
- The plugin hides automatically when the data file is stale (default: 10 minutes)
- Stale timeout is configurable:
set -g @powerkit_plugin_claude_code_stale_seconds "600"
A Claude Code skill that lets Claude control tmux panes — create splits, send commands, and capture output — directly from a conversation.
| File | Description |
|---|---|
tmux-panes/SKILL.md |
Full skill documentation (loaded by Claude when invoked) |
tmux-panes/scripts/pane-send.sh |
Send a command to a pane and wait for completion via sentinel |
tmux-panes/scripts/pane-capture.sh |
Capture N lines of scrollback from a pane |
Copy the skill to your Claude skills directory:
cp -r tmux-panes ~/.claude/skills/tmux-panesClaude will pick it up automatically — invoke it by asking Claude to run something in a tmux pane.
pane-send.sh appends a unique sentinel string after the command, then polls the pane's scrollback until the sentinel appears. This reliably detects when a command has finished without requiring any shell integration or modification to the target pane.
pane-capture.sh is a thin wrapper around tmux capture-pane -S -N for reading pane output without sending a command.
Two bugs in tmux-resurrect cause panes to lose their working directories on restore. All fixes go in ~/.tmux/plugins/tmux-resurrect/scripts/. Reapply after any tmux-resurrect plugin update (prefix + U).
The new_window() function expands ~ to $HOME, but new_session() and new_pane() do not.
Fix: In both new_session() and new_pane(), find the line local pane_id="${session_name}:${window_number}.${pane_index}" and add the tilde expansion line directly after it, before the if statement. The result should look like this in both functions:
local pane_id="${session_name}:${window_number}.${pane_index}"
dir="${dir/#\~/$HOME}"
if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; thenThis matches the existing fix already present in new_window().
The dump_panes() function in save.sh pipes raw pane data through a while read loop. Inside the loop, pane_full_command spawns subprocesses that inherit the pipe's stdin. When these subprocesses inadvertently read from stdin, they steal bytes from the pipe, causing the next read to get shifted fields — the dir field is lost and pane_active (a 0 or 1) lands in its place.
This particularly affects panes where Claude Code (or similar long-running TUI programs) was recently exited — 54 of 205 tested save files were corrupted this way.
Fix 2a — save.sh: In the dump_panes() function, find the pane_full_command call and redirect stdin to /dev/null:
# Find this line:
full_command="$(pane_full_command $pane_pid)"
# Replace with:
full_command="$(pane_full_command $pane_pid </dev/null)"Fix 2b — restore.sh: In the restore_pane() function, add a fallback that recovers the directory from pane_title when the dir field is corrupt. Find these two consecutive lines:
dir="$(remove_first_char "$dir")"
pane_full_command="$(remove_first_char "$pane_full_command")"And insert the fallback block directly after them, before the if [ "$session_name" == "0" ] check:
dir="$(remove_first_char "$dir")"
pane_full_command="$(remove_first_char "$pane_full_command")"
# If dir is not an absolute path (corrupted save), try pane_title as fallback
if [ -z "$dir" ] || [ "${dir:0:1}" != "/" ]; then
local fallback_dir="$(remove_first_char "$pane_title")"
if [ "${fallback_dir:0:1}" = "/" ]; then
dir="$fallback_dir"
fi
fi
if [ "$session_name" == "0" ]; thenThis works because when the save corrupts, the shell's pane title (set by zsh's precmd to :/path/to/dir) still contains the correct working directory.
Add these to your ~/.zshrc for convenient tmux management:
# Smart attach: reattach to existing session, or start a new one and restore via tmux-resurrect
alias mux='tmux attach 2>/dev/null || { tmux new-session -d && tmux run-shell ~/.tmux/plugins/tmux-resurrect/scripts/restore.sh && tmux attach; }'
# List all tmux sessions
alias tls="tmux ls"
# Kill the tmux server (all sessions)
alias tk="tmux kill-server"