Skip to content

sperelson/tmux-setup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tmux-powerkit Custom Plugins

Custom tmux-powerkit plugins for the tmux status bar.

Plugins

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

Files

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

Installation

1. Copy the plugins

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

2. Copy the status line script

cp statusline.sh ~/.claude/statusline.sh
chmod +x ~/.claude/statusline.sh

3. Enable in tmux.conf

Add the plugins to your @powerkit_plugins list in ~/.tmux.conf:

set -g @powerkit_plugins "group(datetime,cpuas,ram),claude_code,git"

Note: Use cpuas instead of cpu and ram instead of memory for accurate Apple Silicon readings.

4. Ensure Claude Code statusLine is configured

In ~/.claude/settings.json, the statusLine entry should exist:

{
  "statusLine": {
    "type": "command",
    "command": "input=$(cat); echo \"$(echo \"$input\" | ~/.claude/statusline.sh)\""
  }
}

5. Reload tmux

prefix + r

Or from the terminal:

tmux source-file ~/.tmux.conf

CPU Apple Silicon Plugin

A drop-in replacement for the built-in cpu plugin that provides accurate CPU readings on Apple Silicon macOS.

Why not the built-in cpu plugin?

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.

How it calculates

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.

Settings

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 "󰻠"

Health coloring (via powerkit theme)

  • ok: Usage below 70%
  • warning: Usage 70-90%
  • error: Usage above 90%

RAM Plugin

A drop-in replacement for the built-in memory plugin that provides accurate memory readings on Apple Silicon macOS (Tahoe+).

Why not the built-in memory plugin?

The built-in memory plugin has two accuracy problems on Apple Silicon:

  1. memory_pressure reports a coarse "free percentage" that doesn't match Activity Monitor
  2. vm_stat fallback only counts active + wired pages, ignoring compressor-occupied pages — a significant category on Apple Silicon where memory compression is aggressive

How it calculates

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

Settings

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 "󰍛"

Health coloring (via powerkit theme)

  • ok: Usage below 75%
  • warning: Usage 75-90%
  • error: Usage above 90%

Claude Code Plugin

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.

How it works

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
    }
  }
}

Data flow

  1. Claude Code pipes JSON to statusline.sh via the statusLine setting
  2. statusline.sh extracts both rate limit percentages and writes them to /tmp/claude-code-ctx
  3. claude_code.sh (powerkit plugin) reads /tmp/claude-code-ctx and renders the values

Changes made to statusline.sh

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

Display

The plugin renders as: <icon> XX%/XX% (5h usage / 7d usage)

Icons (based on 5-hour window percentage)

Range Icon
0-5% 󱚣
5-40% 󱜙
40-60% 󰚩
60-80% 󱚝
80-95% 󱚟
95%+ 󱚡

Health coloring (via powerkit theme)

  • 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"

Notes

  • 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"


tmux Pane Control Skill

A Claude Code skill that lets Claude control tmux panes — create splits, send commands, and capture output — directly from a conversation.

Files

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

Installation

Copy the skill to your Claude skills directory:

cp -r tmux-panes ~/.claude/skills/tmux-panes

Claude will pick it up automatically — invoke it by asking Claude to run something in a tmux pane.

How it works

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.


tmux-resurrect Bug Fixes

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

Fix 1: Tilde Expansion in restore.sh

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"; then

This matches the existing fix already present in new_window().

Fix 2: Stdin Consumption Corrupts Save Data — save.sh + restore.sh

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" ]; then

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


Useful Shell Aliases

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"

About

My custom tmux setup on Mac with some Claude Code integrations and other improvements

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages