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

