Files
2025-11-30 08:56:13 +08:00

13 KiB

name, description
name description
tmux-task-runner Run build processes, test suites, deployments, and development servers in monitored tmux sessions with persistent logging. Use when executing long-running tasks that need background execution with real-time monitoring, or when running commands like npm build, pytest, deployment scripts, or dev servers that should continue running while you work on other tasks.

Tmux Long-Running Task Skill

Overview

This skill provides a robust solution for running long-running tasks in tmux sessions, offering superior flexibility compared to standard background process execution. It enables:

  • Detached execution: Tasks run in isolated tmux sessions
  • Real-time monitoring: Capture and analyze logs via tmux capture-pane
  • Developer control: Attach to sessions for interactive debugging
  • Persistent logging: All output saved to timestamped log files (configurable via LOG_DIR)
  • Status metadata: Exit codes, timings, and environment details saved for later review
  • Session management: List, monitor, summarize, and clean up active sessions

Critical Workflow

When a user requests execution of a long-running task (builds, tests, deployments, servers, etc.):

  1. Detect task type: Identify if the task is long-running (>30s expected duration)
  2. Create session: Generate unique session name (e.g., task-build-1729519263)
  3. Execute in tmux: Run command in detached tmux session with logging
  4. Monitor output: Use tmux capture-pane to read session output
  5. Report status: Inform user of session name, log/status file locations, and monitoring options
  6. Provide access: Give user commands to tail logs, use the tail helper, or attach to the session

CRITICAL: Always check if tmux is installed before proceeding. If not found, inform the user to install it first.

How It Works

  1. User requests a long-running task execution
  2. Skill creates a tmux session with descriptive name
  3. Task runs in a detached session with output captured to a timestamped log in ${LOG_DIR:-/tmp}
  4. Skill records status metadata (exit code, timings, command, overrides) in ${STATUS_DIR:-/tmp}
  5. User can monitor via log tailing, the built-in tail helper, the status summary, or by attaching
  6. Session persists until task completes or user kills it

Setup Instructions

Ensure tmux is installed on your system:

# macOS
brew install tmux

# Ubuntu/Debian
sudo apt-get install tmux

# Fedora/RHEL
sudo dnf install tmux

Verify installation:

tmux -V

Execution Pattern

Step 1: Validate tmux availability

// Check if tmux is installed
const { execSync } = require('child_process');

try {
  execSync('which tmux', { stdio: 'pipe' });
} catch (error) {
  throw new Error('tmux is not installed. Please install it first.');
}

Step 2: Prepare session metadata

# Generate unique session name and resolve directories
SESSION_NAME="task-${TASK_TYPE}-$(date +%s)"
LOG_DIR="${LOG_DIR:-/tmp}"
STATUS_DIR="${STATUS_DIR:-/tmp}"
LOG_FILE="$LOG_DIR/${SESSION_NAME}.log"
STATUS_FILE="$STATUS_DIR/${SESSION_NAME}.status"

# Optional overrides
WORKDIR="${WORKDIR:-$PWD}"                 # run command from a different folder
ENV_OVERRIDES=("NODE_ENV=ci" "DEBUG=1")    # repeatable KEY=VALUE pairs
NOTIFY=1                                   # enable desktop notifications if available

Step 3: Launch tmux session with logging and status tracking

tmux new-session -d -s "$SESSION_NAME" -c "$WORKDIR" bash -lc '
  set -o pipefail

  # Export requested environment overrides
  export NODE_ENV=ci DEBUG=1

  START_EPOCH=$(date +%s)
  START_ISO=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

  your-command-here 2>&1 | tee "'"$LOG_FILE"'"
  exit_code=${PIPESTATUS[0]}

  END_EPOCH=$(date +%s)
  END_ISO=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
  DURATION=$((END_EPOCH - START_EPOCH))

  {
    printf "exit_code=%q\n" "$exit_code"
    printf "command=%q\n" "your-command-here"
    printf "started_at_iso=%q\n" "$START_ISO"
    printf "finished_at_iso=%q\n" "$END_ISO"
    printf "duration_seconds=%q\n" "$DURATION"
    printf "log_file=%q\n" "'"$LOG_FILE"'"
    printf "workdir=%q\n" "'"$WORKDIR"'"
    printf "env_vars=%q\n" "NODE_ENV=ci; DEBUG=1"
  } > "'"$STATUS_FILE"'"

  if [ '"$NOTIFY"' -eq 1 ]; then
    message="[$SESSION_NAME] "
    if [ "$exit_code" -eq 0 ]; then
      message+="completed successfully"
    else
      message+="failed (exit $exit_code)"
    fi
    command -v notify-send >/dev/null 2>&1 && notify-send "tmux-task-runner" "$message"
  fi

  exit "$exit_code"
'

Step 4: Provide monitoring and summary commands

# Tail the log file directly
tail -f "$LOG_FILE"

# Poll output without attaching
./run.sh tail "$SESSION_NAME" --interval 5 --lines 80

# Summarize session metadata (exit status, duration, timestamps)
./run.sh status "$SESSION_NAME"

# Attach to the session (interactive)
tmux attach-session -t "$SESSION_NAME"

Common Patterns

Build Tasks

./run.sh run build "npm run build"
# Monitor tail:   ./run.sh tail task-build-... --interval 5
# Summarize:      ./run.sh status task-build-...

Test Suites

./run.sh run test --env NODE_ENV=ci "npm test -- --coverage"

Development Server

./run.sh run server --workdir ./services/web "npm run dev"

Deployment Scripts

./run.sh run deploy --notify "./deploy.sh production"

Run Script Enhancements

Working Directory Overrides

  • Use --workdir <path> to run the command from a different directory without wrapping the command in cd ... &&.
  • The script attempts to use tmux new-session -c when available and falls back to an inline cd if necessary.

Environment Variable Injection

  • Repeatable --env KEY=VALUE flags export additional environment variables for the task.
  • Variable names are validated to prevent invalid shell identifiers.

Completion Notifications

  • --notify triggers a best-effort desktop notification (notify-send, osascript, or terminal-notifier) when the job ends.
  • Notifications include the session name and whether the command succeeded.

Status Metadata and Summaries

  • Each run writes a status file to ${STATUS_DIR:-/tmp} containing exit code, timestamps, duration, command, workdir, and env overrides.
  • ./run.sh status lists recent runs; ./run.sh status <session> prints detailed metadata and the latest log lines.
  • Status files enable tooling to expose job history without attaching to tmux directly.

Tail Helper

  • ./run.sh tail <session> [--interval N] [--lines M] polls tmux capture-pane on a timer for lightweight monitoring.
  • Falls back to the log file if the session has already exited.

Configurable Directories and Pruning

  • Override LOG_DIR and STATUS_DIR to store artifacts outside /tmp.
  • PRUNE_RETENTION_DAYS (default 7) automatically removes stale log/status files.
  • STATUS_SUMMARY_LIMIT, TAIL_DEFAULT_LINES, and TAIL_DEFAULT_INTERVAL tune command defaults without editing the script.

Session Management

List Active Sessions

# List all tmux sessions
tmux list-sessions

# List only task sessions
tmux list-sessions 2>/dev/null | grep "^task-" || echo "No active task sessions"

Monitor Session Output

# Capture last 100 lines
tmux capture-pane -t SESSION_NAME -p -S -100

# Capture entire scrollback buffer
tmux capture-pane -t SESSION_NAME -p -S -

# Save to file
tmux capture-pane -t SESSION_NAME -p -S - > session-capture.txt

Kill Sessions

# Kill specific session
tmux kill-session -t SESSION_NAME

# Kill all task sessions
tmux list-sessions -F "#{session_name}" | grep "^task-" | xargs -I {} tmux kill-session -t {}

Helper Script Example

Create a reusable helper for common operations:

#!/bin/bash
# tmux-task.sh - Tmux task runner helper

run_task() {
  local task_type=$1
  shift
  local command="$@"

  local session="task-${task_type}-$(date +%s)"
  local logfile="/tmp/${session}.log"

  # Create session
  tmux new-session -d -s "$session" "$command 2>&1 | tee $logfile"

  # Output info
  echo "✓ Task started in session: $session"
  echo "  Log file: $logfile"
  echo ""
  echo "Monitoring commands:"
  echo "  tail -f $logfile              # Follow log output"
  echo "  tmux attach-session -t $session   # Attach to session"
  echo "  tmux kill-session -t $session     # Stop task"
}

check_session() {
  local session=$1

  if tmux has-session -t "$session" 2>/dev/null; then
    echo "Session '$session' is running"
    echo ""
    echo "Recent output:"
    tmux capture-pane -t "$session" -p -S -20
  else
    echo "Session '$session' has completed or doesn't exist"
  fi
}

list_tasks() {
  echo "Active task sessions:"
  tmux list-sessions 2>/dev/null | grep "^task-" || echo "  No active tasks"
}

# Usage example
case "$1" in
  run)
    run_task "$2" "${@:3}"
    ;;
  check)
    check_session "$2"
    ;;
  list)
    list_tasks
    ;;
  *)
    echo "Usage: $0 {run|check|list} [args...]"
    exit 1
esac

Tips

  • CRITICAL: Always use unique session names to avoid conflicts
  • CRITICAL: Include timestamps in session names for easy identification
  • CRITICAL: Always provide log file paths to users for monitoring
  • Use descriptive task type prefixes (build, test, deploy, server, etc.)
  • Use LOG_DIR (defaults to /tmp) to avoid cluttering project directories
  • Use tmux capture-pane -p -S -100 to get reasonable output chunks
  • For very long output, save to file instead of displaying inline
  • Remind users they can attach to sessions for interactive debugging
  • Clean up completed sessions periodically to avoid clutter

Troubleshooting

Problem: "session not found" error

  • Solution: Session may have completed. Check if process finished in log file.

Problem: Unable to capture pane output

  • Solution: Ensure session name is correct: tmux list-sessions

Problem: Log file not updating

  • Solution: Verify command includes 2>&1 | tee $LOG_FILE for proper output capture

Problem: tmux not found

  • Solution: Install tmux using system package manager (brew, apt, dnf, etc.)

Problem: Session already exists

  • Solution: Use unique names with timestamps or kill existing session first

Example Usage

User: "Run the full test suite in the background and let me monitor it"

Claude: I'll run your test suite in a tmux session so you can monitor it easily.

./run.sh run test --env NODE_ENV=ci "npm test -- --runInBand"

Your tests are now running in the background. Here's how to monitor:

Monitor the logs:

./run.sh tail task-test-1729519263 --interval 5 --lines 80
# or tail -f "$LOG_DIR"/task-test-1729519263.log

Attach to the session:

tmux attach-session -t task-test-1729519263

(Press Ctrl+b then d to detach without stopping the tests)

Check current status summary:

./run.sh status task-test-1729519263

The summary includes exit code, duration, timestamps, workdir, and environment overrides once the command finishes.


Advanced Features

Multi-Pane Monitoring

Run multiple related tasks in split panes:

SESSION="task-multiview-$(date +%s)"

# Create session with first task
tmux new-session -d -s "$SESSION" "npm run build"

# Split horizontally and run tests
tmux split-window -h -t "$SESSION" "npm test"

# Split first pane vertically for logs
tmux select-pane -t 0
tmux split-window -v -t "$SESSION" "tail -f /tmp/app.log"

echo "Multi-pane session created: $SESSION"
echo "Attach with: tmux attach-session -t $SESSION"

Persistent Sessions

Configure tmux to save sessions across reboots (requires tmux-resurrect plugin):

# Install tmux plugin manager (TPM)
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

# Add to ~/.tmux.conf
echo "set -g @plugin 'tmux-plugins/tmux-resurrect'" >> ~/.tmux.conf
echo "run '~/.tmux/plugins/tpm/tpm'" >> ~/.tmux.conf

Integration with CI/CD

Use tmux sessions for local CI/CD simulation:

SESSION="task-ci-$(date +%s)"
LOG="/tmp/${SESSION}.log"

tmux new-session -d -s "$SESSION" bash -c "
  echo '=== Linting ===' && npm run lint &&
  echo '=== Testing ===' && npm test &&
  echo '=== Building ===' && npm run build &&
  echo '=== CI Complete ===' || echo '=== CI Failed ==='
" 2>&1 | tee $LOG

Best Practices

  1. Always provide monitoring commands to users after starting a session
  2. Use descriptive task types in session names (build, test, deploy, etc.)
  3. Capture initial output after starting to confirm task began successfully
  4. Use LOG_DIR (defaults to /tmp) to keep project directories clean
  5. Include cleanup instructions for when tasks complete
  6. Check session status before attempting operations
  7. Provide both tail and attach options for different monitoring preferences
  8. Use tee for logging to enable both file and real-time capture