Skip to content
Development
Hook

Hooks

What claudetop runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
claudetop
2125 commands3 hooks
Install
> /plugin marketplace add liorwn/claudetop
> /plugin install claudetop@claudetop

Ships with claudetop. Installing the plugin gets these hooks.

Where it lives

  • hooks/claudetop-prompt.shGitHub
    Read the script
    #!/bin/bash
    # claudetop-prompt.sh — Sets iTerm2 background to black when user submits
    # Writes directly to TTY + updates state file
    
    [ -n "${CLAUDETOP_ITERM:-}" ] || exit 0
    
    TTY_MAP="$HOME/.claude/claudetop-iterm-ttys"
    SESSION_ID="${ITERM_SESSION_ID:-}"
    
    # If no ITERM_SESSION_ID in env, find it from parent process TTY
    if [ -z "$SESSION_ID" ] && [ -f "$TTY_MAP" ]; then
      PARENT_TTY=$(ps -p $PPID -o tty= 2>/dev/null | tr -d ' ')
      if [ -n "$PARENT_TTY" ]; then
        PARENT_TTY="/dev/${PARENT_TTY}"
        SESSION_ID=$(grep "=${PARENT_TTY}$" "$TTY_MAP" 2>/dev/null | head -1 | cut -d= -f1)
      fi
    fi
    
    [ -n "$SESSION_ID" ] || exit 0
    
    # Write directly to TTY for instant black
    if [ -f "$TTY_MAP" ]; then
      MY_TTY=$(grep "^${SESSION_ID}=" "$TTY_MAP" 2>/dev/null | tail -1 | cut -d= -f2-)
      if [ -n "$MY_TTY" ] && [ -w "$MY_TTY" ]; then
        printf "\033]1337;SetColors=bg=000000\007" > "$MY_TTY"
      fi
    fi
    
    # Update state file
    STATE_FILE="$HOME/.claude/claudetop-iterm-state.${SESSION_ID}"
    [ -f "$STATE_FILE" ] || exit 0
    if grep -q "^bgcolor=" "$STATE_FILE" 2>/dev/null; then
      sed -i "" "s/^bgcolor=.*/bgcolor=000000/" "$STATE_FILE"
    else
      echo "bgcolor=000000" >> "$STATE_FILE"
    fi
    sed -i "" "s/^timestamp=.*/timestamp=$(date +%s)/" "$STATE_FILE"
    
  • hooks/claudetop-stop.shGitHub
    Read the script
    #!/bin/bash
    # claudetop-stop.sh — no-op, bgcolor is handled by the watcher's idle detection
    # Kept for future use if needed.
    exit 0
    
  • hooks/session-end.shGitHub
    Read the script
    #!/bin/bash
    # session-end.sh — Claude Code SessionEnd hook
    # Appends one JSONL record per session to ~/.claude/claudetop-history.jsonl
    #
    # Register in ~/.claude/settings.json:
    #   "hooks": { "SessionEnd": [{ "type": "command", "command": "/path/to/session-end.sh" }] }
    
    set -euo pipefail
    
    HISTORY_FILE="$HOME/.claude/claudetop-history.jsonl"
    JSON=$(cat)
    
    # Detect git branch from project directory
    PROJECT_DIR=$(echo "$JSON" | jq -r '.workspace.project_dir // .cwd // ""')
    GIT_BRANCH=""
    if [ -n "$PROJECT_DIR" ] && [ -d "$PROJECT_DIR/.git" ]; then
      GIT_BRANCH=$(git -C "$PROJECT_DIR" rev-parse --abbrev-ref HEAD 2>/dev/null) || true
    fi
    
    jq -c \
      --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
      --arg tag "${CLAUDETOP_TAG:-}" \
      --arg branch "$GIT_BRANCH" \
      '{
        timestamp:       $timestamp,
        session_id:      (.session_id // ""),
        project:         ((.workspace.project_dir // .cwd // "") | split("/") | last),
        project_dir:     (.workspace.project_dir // .cwd // ""),
        model:           (.model.id // ""),
        duration_ms:     (.cost.total_duration_ms // 0),
        cost_usd:        (.cost.total_cost_usd // 0),
        input_tokens:    (.context_window.total_input_tokens // 0),
        output_tokens:   (.context_window.total_output_tokens // 0),
        lines_added:     (.cost.total_lines_added // 0),
        lines_removed:   (.cost.total_lines_removed // 0),
        context_used_pct:(.context_window.used_percentage // 0),
        tag:             $tag,
        branch:          $branch
      }' <<< "$JSON" >> "$HISTORY_FILE"
    
    # Signal THIS session's watcher to reset terminal and exit
    # Find session ID via ITERM_SESSION_ID or parent TTY
    SESSION_ID="${ITERM_SESSION_ID:-}"
    TTY_MAP="$HOME/.claude/claudetop-iterm-ttys"
    if [ -z "$SESSION_ID" ] && [ -f "$TTY_MAP" ]; then
      PARENT_TTY=$(ps -p $PPID -o tty= 2>/dev/null | tr -d ' ')
      if [ -n "$PARENT_TTY" ] && [ "$PARENT_TTY" != "??" ]; then
        SESSION_ID=$(grep "=/dev/${PARENT_TTY}$" "$TTY_MAP" 2>/dev/null | head -1 | cut -d= -f1)
      fi
    fi
    if [ -n "$SESSION_ID" ]; then
      sf="$HOME/.claude/claudetop-iterm-state.${SESSION_ID}"
      [ -f "$sf" ] && {
        echo "iterm_session=${SESSION_ID}"
        echo "timestamp=$(date +%s)"
        echo "status=ended"
        echo "bgcolor=default"
        echo "modes=all"
      } > "$sf"
    fi
    

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

Ships withclaudetop

htop for your Claude Code sessions — real-time cost, cache efficiency, model comparison, and smart alerts

Get the whole plugin
Stats
211
Stars
10
Forks
Maintained
Maintenance
Shell
Language
MIT
License
1mo ago
Last commit
4mo ago
Created

Repo: liorwn/claudetop