Created
March 2, 2026 21:20
-
-
Save leonjang88/1874086da13a8d99bce8c51e94630500 to your computer and use it in GitHub Desktop.
Claude Code (cc) tmux session management commands for .bashrc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Claude Code (cc) Commands for .bashrc | |
| # Quick tmux-based session management for Claude Code | |
| # Context directories | |
| _CC_HA="$HOME/pezbox/infra/homeAssistant" | |
| _CC_HW="$HOME/pezbox/hiveworth" | |
| _CC_RS="$HOME/pezbox/redfin-scraper" | |
| # Resolve context name to directory | |
| _cc_dir() { | |
| case "$1" in | |
| ha) echo "$_CC_HA" ;; | |
| hw) echo "$_CC_HW" ;; | |
| rs) echo "$_CC_RS" ;; | |
| pb) echo "$HOME/pezbox" ;; | |
| *) echo "$HOME/pezbox" ;; | |
| esac | |
| } | |
| # Resolve context name to session prefix | |
| _cc_prefix() { | |
| case "$1" in | |
| ha) echo "cc-ha" ;; | |
| hw) echo "cc-hw" ;; | |
| rs) echo "cc-rs" ;; | |
| pb) echo "cc-pezbox" ;; | |
| *) echo "cc-pezbox" ;; | |
| esac | |
| } | |
| # Create a new tmux session, send claude into it, attach | |
| _cc_new_session() { | |
| local session_name="$1" | |
| local work_dir="$2" | |
| local cmd="$3" | |
| tmux new-session -d -s "$session_name" -c "$work_dir" | |
| tmux send-keys -t "$session_name" "$cmd" Enter | |
| tmux attach -t "$session_name" | |
| } | |
| # Picker for multiple sessions | |
| _cc_pick_session() { | |
| local sessions="$1" | |
| echo "Active Claude sessions:" >&2 | |
| echo "$sessions" | nl >&2 | |
| echo -n "Which session? (number): " >&2 | |
| read choice </dev/tty | |
| echo "$sessions" | sed -n "${choice}p" | |
| } | |
| # Pick a project and resume into it | |
| _cc_pick_project_and_resume() { | |
| echo "Available projects:" >&2 | |
| echo " 1) ha - Home Assistant ($_CC_HA)" >&2 | |
| echo " 2) hw - Hiveworth ($_CC_HW)" >&2 | |
| echo " 3) rs - Redfin Scraper ($_CC_RS)" >&2 | |
| echo " 4) pb - Pezbox ($HOME/pezbox)" >&2 | |
| echo " 5) current - Current directory ($PWD)" >&2 | |
| echo "" >&2 | |
| echo -n "Which project? (number): " >&2 | |
| read choice </dev/tty | |
| local ctx work_dir prefix | |
| case "$choice" in | |
| 1) ctx="ha"; work_dir="$_CC_HA"; prefix="cc-ha" ;; | |
| 2) ctx="hw"; work_dir="$_CC_HW"; prefix="cc-hw" ;; | |
| 3) ctx="rs"; work_dir="$_CC_RS"; prefix="cc-rs" ;; | |
| 4) ctx="pb"; work_dir="$HOME/pezbox"; prefix="cc-pezbox" ;; | |
| 5) ctx="current"; work_dir="$PWD"; prefix="cc-$(basename "$PWD")" ;; | |
| *) echo "Invalid selection"; return 1 ;; | |
| esac | |
| local session_name="${prefix}-$(date +%m%d-%I%M%p | tr '[:upper:]' '[:lower:]')" | |
| local cmd="claude --dangerously-skip-permissions --continue" | |
| echo "Starting new session in $work_dir..." | |
| _cc_new_session "$session_name" "$work_dir" "$cmd" | |
| } | |
| # Switch to a different project within the current tmux session | |
| _cc_switch_project_in_session() { | |
| echo "Switch to project:" >&2 | |
| echo " 1) ha - Home Assistant" >&2 | |
| echo " 2) hw - Hiveworth" >&2 | |
| echo " 3) rs - Redfin Scraper" >&2 | |
| echo " 4) pb - Pezbox" >&2 | |
| echo " 5) current - Stay in current directory" >&2 | |
| echo "" >&2 | |
| echo -n "Which project? (number): " >&2 | |
| read choice </dev/tty | |
| local work_dir | |
| case "$choice" in | |
| 1) work_dir="$_CC_HA" ;; | |
| 2) work_dir="$_CC_HW" ;; | |
| 3) work_dir="$_CC_RS" ;; | |
| 4) work_dir="$HOME/pezbox" ;; | |
| 5) work_dir="$PWD" ;; | |
| *) echo "Invalid selection"; return 1 ;; | |
| esac | |
| echo "Switching to $work_dir..." | |
| cd "$work_dir" | |
| claude --dangerously-skip-permissions --continue | |
| } | |
| # cc [context] — new Claude Code session | |
| cc() { | |
| # cc clear [all|context|session-name] | |
| if [ "$1" = "clear" ]; then | |
| local sessions | |
| # No arg: interactive picker | |
| if [ -z "$2" ]; then | |
| sessions=$(tmux ls 2>/dev/null | grep "^cc-" | cut -d: -f1) | |
| if [ -z "$sessions" ]; then | |
| echo "No Claude Code sessions found." | |
| return | |
| fi | |
| echo "Select session(s) to kill:" >&2 | |
| echo "$sessions" | nl >&2 | |
| echo "" >&2 | |
| echo "Enter number(s) separated by spaces (or 'all' for all):" >&2 | |
| read choices </dev/tty | |
| if [ "$choices" = "all" ]; then | |
| echo "🔥 Killing ALL Claude Code sessions" | |
| echo "$sessions" | xargs -I {} tmux kill-session -t {} | |
| else | |
| for choice in $choices; do | |
| local selected | |
| selected=$(echo "$sessions" | sed -n "${choice}p") | |
| if [ -n "$selected" ]; then | |
| echo "Killing $selected" | |
| tmux kill-session -t "$selected" | |
| fi | |
| done | |
| fi | |
| echo "Done." | |
| return | |
| fi | |
| # cc clear all - nuclear mode | |
| if [ "$2" = "all" ]; then | |
| sessions=$(tmux ls 2>/dev/null | grep "^cc-" | cut -d: -f1) | |
| if [ -z "$sessions" ]; then | |
| echo "No Claude Code sessions found." | |
| else | |
| echo "🔥 Nuclear clear - killing ALL Claude Code sessions:" | |
| echo "$sessions" | |
| echo "$sessions" | xargs -I {} tmux kill-session -t {} | |
| echo "Done." | |
| fi | |
| return | |
| fi | |
| # Check if it's a full session name | |
| if tmux has-session -t "$2" 2>/dev/null; then | |
| echo "Killing session: $2" | |
| tmux kill-session -t "$2" | |
| echo "Done." | |
| return | |
| fi | |
| # Otherwise treat as context prefix | |
| local prefix | |
| prefix=$(_cc_prefix "$2") | |
| sessions=$(tmux ls 2>/dev/null | grep "^${prefix}" | cut -d: -f1) | |
| if [ -z "$sessions" ]; then | |
| echo "No sessions matching '${prefix}' or '$2' found." | |
| else | |
| echo "Killing ${prefix} sessions:" | |
| echo "$sessions" | |
| echo "$sessions" | xargs -I {} tmux kill-session -t {} | |
| echo "Done." | |
| fi | |
| return | |
| fi | |
| local ctx="$1" | |
| local work_dir | |
| work_dir=$(_cc_dir "$ctx") | |
| local prefix | |
| prefix=$(_cc_prefix "$ctx") | |
| local cmd="claude --dangerously-skip-permissions" | |
| if [ -n "$TMUX" ]; then | |
| cd "$work_dir" && eval "$cmd" | |
| else | |
| local session_name="${prefix}-$(date +%m%d-%I%M%p | tr '[:upper:]' '[:lower:]')" | |
| _cc_new_session "$session_name" "$work_dir" "$cmd" | |
| fi | |
| } | |
| # ccs — quick Claude session switcher (for use within tmux) | |
| ccs() { | |
| if [ -z "$TMUX" ]; then | |
| echo "Not in a tmux session. Use ccr instead." >&2 | |
| return 1 | |
| fi | |
| # Show resume menu directly | |
| claude --dangerously-skip-permissions --resume | |
| } | |
| # ccr — resume any Claude Code session (shows all projects) | |
| ccr() { | |
| local cmd="claude --dangerously-skip-permissions --continue" | |
| # If already in tmux, handle session switching differently | |
| if [ -n "$TMUX" ]; then | |
| if ! tty -s; then | |
| echo "❌ You're already in a tmux session but have no TTY (probably inside Claude)." >&2 | |
| echo " Exit this session first (exit or Ctrl-D), then run ccr from your terminal." >&2 | |
| return 1 | |
| fi | |
| # Find ALL Claude Code sessions | |
| local sessions | |
| sessions=$(tmux ls 2>/dev/null | grep "^cc-" | cut -d: -f1) | |
| if [ -z "$sessions" ]; then | |
| echo "No other Claude sessions found. Continue in current session." >&2 | |
| eval "$cmd" | |
| return | |
| fi | |
| # Show current session and available options | |
| echo "Current session: $(tmux display-message -p '#S')" >&2 | |
| echo "" >&2 | |
| echo "Available Claude sessions:" >&2 | |
| local i=1 | |
| while IFS= read -r session; do | |
| echo " $i) $session" >&2 | |
| i=$((i+1)) | |
| done <<< "$sessions" | |
| echo " c) Continue in current directory" >&2 | |
| echo " n) New project" >&2 | |
| echo -n "Choice: " >&2 | |
| read choice </dev/tty | |
| if [ "$choice" = "c" ]; then | |
| eval "$cmd" | |
| return | |
| elif [ "$choice" = "n" ]; then | |
| _cc_switch_project_in_session | |
| return | |
| elif [[ "$choice" =~ ^[0-9]+$ ]]; then | |
| local selected_session=$(echo "$sessions" | sed -n "${choice}p") | |
| if [ -n "$selected_session" ]; then | |
| echo "Switching to session: $selected_session" | |
| tmux switch-client -t "$selected_session" | |
| else | |
| echo "Invalid selection" | |
| fi | |
| return | |
| else | |
| echo "Invalid selection" | |
| return | |
| fi | |
| fi | |
| # Find ALL Claude Code sessions across all projects | |
| local sessions | |
| sessions=$(tmux ls 2>/dev/null | grep "^cc-" | cut -d: -f1) | |
| if [ -z "$sessions" ]; then | |
| # No sessions exist - start a new one in current dir or pezbox | |
| local work_dir="${PWD}" | |
| if [[ ! "$PWD" =~ pezbox ]]; then | |
| work_dir="$HOME/pezbox" | |
| fi | |
| local session_name="cc-pezbox-$(date +%m%d-%I%M%p | tr '[:upper:]' '[:lower:]')" | |
| echo "No Claude sessions found. Starting new session..." | |
| _cc_new_session "$session_name" "$work_dir" "$cmd" | |
| elif [ "$(echo "$sessions" | wc -l)" -eq 1 ]; then | |
| # Only one session - ask if they want to attach or start new | |
| echo "Found 1 session: $sessions" >&2 | |
| echo "" >&2 | |
| echo " 1) Attach to existing session" >&2 | |
| echo " 2) Resume into another project" >&2 | |
| echo -n "Choice: " >&2 | |
| read choice </dev/tty | |
| if [ "$choice" = "1" ]; then | |
| tmux attach -t "$sessions" | |
| elif [ "$choice" = "2" ]; then | |
| _cc_pick_project_and_resume | |
| else | |
| echo "Invalid selection" | |
| fi | |
| else | |
| # Multiple sessions - show picker with ALL of them + new project option | |
| echo "All Claude sessions:" >&2 | |
| echo "$sessions" | nl >&2 | |
| local total=$(echo "$sessions" | wc -l) | |
| local next=$((total + 1)) | |
| echo " $next) Resume into another project" >&2 | |
| echo "" >&2 | |
| echo -n "Which session? (number): " >&2 | |
| read choice </dev/tty | |
| if [ "$choice" = "$next" ]; then | |
| _cc_pick_project_and_resume | |
| else | |
| local selected | |
| selected=$(echo "$sessions" | sed -n "${choice}p") | |
| if [ -n "$selected" ]; then | |
| tmux attach -t "$selected" | |
| else | |
| echo "Invalid selection" | |
| fi | |
| fi | |
| fi | |
| } | |
| # ============================================ | |
| # BONUS: ccrename skill (use as /ccrename in Claude) | |
| # ============================================ | |
| # | |
| # This skill analyzes recent work in the conversation and renames | |
| # the tmux session with a descriptive summary. | |
| # | |
| # Usage in Claude Code: /ccrename | |
| # | |
| # The skill will: | |
| # 1. Analyze the conversation history | |
| # 2. Generate a short descriptive name | |
| # 3. Rename the tmux session to: cc-[project]-[description] | |
| # | |
| # Example renames: | |
| # cc-ha-0302-0345pm → cc-ha-fix-hvac-sensors | |
| # cc-rs-0302-0400pm → cc-rs-add-rental-pipeline | |
| # | |
| # ============================================ | |
| # Manual version for bash (if you want to rename from terminal) | |
| ccrename() { | |
| if [ -z "$TMUX" ]; then | |
| echo "Not in a tmux session." | |
| return 1 | |
| fi | |
| local current=$(tmux display-message -p '#S') | |
| echo "Current session: $current" | |
| echo -n "New name: " | |
| read new_name </dev/tty | |
| if [ -n "$new_name" ]; then | |
| tmux rename-session "$new_name" | |
| echo "Renamed to: $new_name" | |
| fi | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment