Claude Code Hook으로 quota 전환 자동화하기

Claude Code의 SessionStart hook을 활용하여 여러 quota 간 전환을 자동화하는 방법을 정리합니다.

Claude Code를 여러 quota로 사용하는 경우가 있습니다. 예를 들면 다음과 같습니다.

  • Max plan을 2개를 구독해서 번갈아 가면서 쓰는 경우

  • 같은 이메일 계정에 여러 organization이 연결되어 각각 별도의 quota가 있는 경우

  • Team plan과 Enterprise plan을 동시에 구독하는 경우

이런 상황에서 한쪽 quota가 소진되었을 때 다른 쪽으로 전환해서 쓸 수 있습니다.

문제는 quota A가 소진되어 quota B로 전환한 뒤, quota A가 초기화되는 시점에 다시 돌아오는 걸 잊기 쉽다는 것입니다. Claude Code의 Hook 기능을 활용하면 이 전환을 자동화할 수 있습니다.

구현 목표

  1. Quota A가 소진되면, 초기화 예정 시간을 기록한다.

  2. /logout 후 quota B로 로그인하여 계속 작업한다.

  3. 초기화 시간이 지난 뒤 새 세션을 시작하거나 `/clear`를 하면, 자동으로 quota B의 credentials를 제거하여 quota A로 재로그인을 유도한다.

Claude Code에게 구현 요청

아래와 같은 프롬프트로 Claude Code에게 구현을 요청했습니다.

Claude Code를 quota A, quota B 두 개로 쓰고 있어. Quota A가 소진되면 초기화 예정 시간을 기록하고 quota B로 전환해서 쓰다가, 초기화 시간이 지난 후 새 세션이나 /clear 시 자동으로 quota B를 logout해서 quota A로 복귀하고 싶어. SessionStart hook으로 구현해줘.

Claude Code는 이 요청을 두 개의 스크립트와 `settings.json`의 hook 설정으로 구현했습니다.

생성된 코드 분석

초기화 시간 기록 스크립트

~/.claude/scripts/record-quota-reset.sh 는 quota A의 초기화 예정 시간을 기록하는 스크립트입니다.

record-quota-reset.sh
#!/bin/bash
# Record when quota A resets so the hook can switch back from quota B
# Usage: record-quota-reset.sh "2026-03-29 09:00"
#        record-quota-reset.sh 4h    (4 hours from now)
#        record-quota-reset.sh 30m   (30 minutes from now)

RESET_FILE="$HOME/.claude/quota-switch-reset-time"

if [ -z "$1" ]; then
    echo "Usage: $0 <datetime or duration>"
    echo "  Examples:"
    echo "    $0 '2026-03-29 09:00'   # absolute time"
    echo "    $0 4h                    # 4 hours from now"
    echo "    $0 30m                   # 30 minutes from now"
    exit 1
fi

INPUT="$1"

# Parse duration format (e.g., 4h, 30m)
if [[ "$INPUT" =~ ^([0-9]+)h$ ]]; then
    HOURS="${BASH_REMATCH[1]}"
    RESET_EPOCH=$(date -d "+${HOURS} hours" +%s)
    RESET_DISPLAY=$(date -d "+${HOURS} hours" "+%Y-%m-%d %H:%M:%S")
elif [[ "$INPUT" =~ ^([0-9]+)m$ ]]; then
    MINS="${BASH_REMATCH[1]}"
    RESET_EPOCH=$(date -d "+${MINS} minutes" +%s)
    RESET_DISPLAY=$(date -d "+${MINS} minutes" "+%Y-%m-%d %H:%M:%S")
else
    # Absolute datetime
    RESET_EPOCH=$(date -d "$INPUT" +%s 2>/dev/null)
    if [ $? -ne 0 ]; then
        echo "Error: Cannot parse datetime '$INPUT'"
        exit 1
    fi
    RESET_DISPLAY=$(date -d "$INPUT" "+%Y-%m-%d %H:%M:%S")
fi

echo "$RESET_EPOCH" > "$RESET_FILE"
echo "Quota A reset time recorded: $RESET_DISPLAY"
echo "Saved to: $RESET_FILE"
echo ""
echo "Now run /logout in Claude Code and log in with quota B."
echo "When the reset time arrives, the next session start or /clear will auto-logout quota B."

절대 시간("2026-03-29 09:00")과 상대 시간(4h, 30m) 두 가지 형식을 지원합니다. 내부적으로는 Unix epoch 타임스탬프로 변환하여 ~/.claude/quota-switch-reset-time 파일에 저장합니다.

자동 전환 hook 스크립트

~/.claude/scripts/check-quota-switch.sh 는 SessionStart hook에서 실행되는 스크립트입니다.

check-quota-switch.sh
#!/bin/bash
# SessionStart hook: check if quota A has reset
# If so, remove credentials to force re-login with quota A

RESET_FILE="$HOME/.claude/quota-switch-reset-time"
CRED_FILE="$HOME/.claude/.credentials.json"

# No reset time recorded, nothing to do
if [ ! -f "$RESET_FILE" ]; then
    exit 0
fi

RESET_EPOCH=$(cat "$RESET_FILE")
NOW_EPOCH=$(date +%s)

if [ "$NOW_EPOCH" -ge "$RESET_EPOCH" ]; then
    # Time to switch back to quota A
    RESET_DISPLAY=$(date -d "@$RESET_EPOCH" "+%Y-%m-%d %H:%M:%S")

    # Backup quota B credentials and remove current credentials
    if [ -f "$CRED_FILE" ]; then
        cp "$CRED_FILE" "$HOME/.claude/.credentials.quota-b.bak"
        rm -f "$CRED_FILE"
    fi

    # Remove reset time file
    rm -f "$RESET_FILE"

    # Exit with code 2 to block session and show message
    echo "Quota A has reset (reset time: $RESET_DISPLAY)." >&2
    echo "Quota B credentials have been removed." >&2
    echo "Please restart Claude Code to log in with quota A." >&2
    exit 2
fi

# Not yet time to switch
exit 0

이 스크립트의 핵심 동작은 다음과 같습니다.

  • 기록된 초기화 시간 파일이 없으면 `exit 0`으로 아무 동작 없이 종료합니다. 평소에는 hook이 세션 시작을 방해하지 않습니다.

  • 현재 시간이 초기화 시간 이상이면 전환을 실행합니다.

  • ~/.claude/.credentials.json~/.claude/.credentials.quota-b.bak 으로 백업한 후 삭제합니다. Credentials 파일이 없으면 Claude Code가 다음 시작 시 로그인을 요청합니다.

  • `exit 2`로 세션을 블로킹하고 stderr로 안내 메시지를 출력합니다. Claude Code hook에서 exit code 2는 세션 진행을 차단하고 stderr 메시지를 사용자에게 보여주는 약속된 규칙입니다.

settings.json hook 설정

~/.claude/settings.jsonSessionStart hook을 등록합니다.

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/.claude/scripts/check-quota-switch.sh"
          }
        ]
      },
      {
        "matcher": "clear",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/.claude/scripts/check-quota-switch.sh"
          }
        ]
      }
    ]
  }
}

SessionStart 이벤트는 matcher 로 세션이 시작된 원인을 구분할 수 있습니다. startup 은 새 세션 시작, clear/clear 명령 실행 시 발생합니다. 두 경우 모두 같은 스크립트를 실행하도록 설정했습니다.

사용 방법

1단계: quota A 소진 시 초기화 시간 기록

Quota A가 소진되면 Claude Code에게 초기화 예정 시간을 알려줍니다. Claude Code가 record-quota-reset.sh 스크립트를 실행하여 시간을 기록합니다.

quota A가 다 됐어. 4시간 후에 초기화돼.

Claude Code는 이 요청을 받아 다음과 같이 스크립트를 실행합니다.

~/.claude/scripts/record-quota-reset.sh 4h

물론 터미널에서 직접 스크립트를 실행할 수도 있습니다.

# 절대 시간
~/.claude/scripts/record-quota-reset.sh "2026-03-29 09:00"

# 상대 시간
~/.claude/scripts/record-quota-reset.sh 4h
~/.claude/scripts/record-quota-reset.sh 30m

2단계: quota B로 전환

Claude Code에서 /logout 을 실행한 후 quota B 계정으로 재로그인합니다.

3단계: 자동 복귀

기록한 초기화 시간이 지난 후에 Claude Code를 새로 시작하거나 `/clear`를 실행하면 hook이 동작합니다. Quota B의 credentials가 자동으로 제거되고, Claude Code를 재시작하면 quota A로 로그인할 수 있습니다.

초기화 시간 기록의 자동화 가능성

현재 1단계(초기화 시간 기록)는 사용자가 직접 시간을 알려줘야 합니다. Pro plan이나 Max plan의 경우 quota 소진 시 Claude Code가 초기화 예정 시간을 메시지로 안내하는데, 이 메시지를 hook으로 캡처할 수 있다면 record-quota-reset.sh 실행까지 자동화할 수 있습니다.

이를 확인하기 위해 진단용 hook을 설정하여 quota 소진 시 어떤 이벤트 데이터가 전달되는지 로깅할 수 있습니다.

log-hook-event.sh
#!/bin/bash
# Diagnostic hook: log all event data received via stdin

LOG_FILE="$HOME/.claude/hook-events.log"
INPUT=$(cat)

echo "=== $(date '+%Y-%m-%d %H:%M:%S') ===" >> "$LOG_FILE"
echo "$INPUT" | jq . >> "$LOG_FILE" 2>/dev/null || echo "$INPUT" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"

exit 0

이 스크립트를 Notification, Stop, StopFailure 이벤트에 hook으로 등록합니다.

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/.claude/scripts/log-hook-event.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/.claude/scripts/log-hook-event.sh"
          }
        ]
      }
    ],
    "StopFailure": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/.claude/scripts/log-hook-event.sh"
          }
        ]
      }
    ]
  }
}

Quota가 소진되면 ~/.claude/hook-events.log 에 이벤트 데이터가 기록됩니다. 이 로그를 Claude Code에게 보여주며 자동화 스크립트 작성을 요청하면 됩니다.

hook-events.log 내용 보여줘. quota 소진 시 자동으로 record-quota-reset.sh가 실행되도록 hook을 만들어줘.

로그에 초기화 시간 정보가 포함되어 있다면 파싱하여 `record-quota-reset.sh`를 자동 실행하는 hook을 만들 수 있습니다. 포함되어 있지 않다면 이 단계의 자동화는 불가능하며, 사용자가 직접 초기화 시간을 입력해야 합니다.

한계

  • credentials 파일 의존: ~/.claude/.credentials.json 파일을 직접 조작하는 방식이므로, Claude Code의 내부 인증 구조가 변경되면 동작하지 않을 수 있습니다.

  • 완전 자동 로그인은 불가: Credentials 제거 후 재시작 시 로그인 화면이 나타나지만, quota A 계정을 자동으로 선택해주지는 않습니다. 사용자가 직접 quota A 계정으로 로그인해야 합니다.

  • 세션 중간 전환은 지원하지 않음: SessionStart hook은 새 세션 시작이나 /clear 시에만 동작합니다. 세션 중간에 초기화 시간이 지나더라도 현재 세션에서는 전환이 일어나지 않습니다. 매 프롬프트마다 체크하는 방식(UserPromptSubmit hook)도 가능하지만, 세션 중간에 credentials가 제거되면 진행 중인 작업과 컨텍스트가 유실되므로 권장하지 않습니다.

macOS에서의 차이점

Claude Code는 실행 환경의 OS를 인식합니다. macOS에서 같은 요청을 하면 date 명령어 부분이 BSD 문법으로 생성됩니다. 주요 차이는 다음과 같습니다.

용도 Linux (GNU date) macOS (BSD date)

상대 시간 (4시간 후)

date -d "+4 hours" +%s

date -v+4H +%s

절대 시간 파싱

date -d "2026-03-29 09:00" +%s

date -j -f "%Y-%m-%d %H:%M" "2026-03-29 09:00" +%s

epoch → 표시 형식

date -d "@$EPOCH" "+%Y-%m-%d %H:%M:%S"

date -r $EPOCH "+%Y-%m-%d %H:%M:%S"

Claude Code의 '/model opusplan’과 showClearContextOnPlanAccept 옵션 Go 코드에 품질 도구 적용하기