Skip to content
Development
Hook

Hooks

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

From plugin
code-forge
1623 skills58 agents11 hooks2 MCP
Install
$ npx -y skills add ggombee/code-forge --agent claude-code

Ships with code-forge. Installing the plugin gets these hooks.

What fires, and when

SessionStart

Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.

  • ${CLAUDE_PLUGIN_ROOT}/hooks/session-init.sh${CLAUDE_PLUGIN_ROOT}/hooks/bellows-log.sh

PostToolUse

  • MatchesEdit|Write|MultiEdit${CLAUDE_PLUGIN_ROOT}/hooks/lint-fix.sh
  • MatchesAgent|Skill${CLAUDE_PLUGIN_ROOT}/hooks/bellows-log.sh

PreToolUse

  • MatchesBash${CLAUDE_PLUGIN_ROOT}/hooks/guard.sh
  • MatchesWrite${CLAUDE_PLUGIN_ROOT}/hooks/write-guard.sh
  • MatchesWrite${CLAUDE_PLUGIN_ROOT}/hooks/skill-dedup.sh

Stop

  • ${CLAUDE_PLUGIN_ROOT}/hooks/quality-gate.sh

Notification

  • Matchespermission_prompt|idle_prompt${CLAUDE_PLUGIN_ROOT}/hooks/notify.sh

SubagentStop

  • ${CLAUDE_PLUGIN_ROOT}/hooks/subagent-stop.sh

PreCompact

  • ${CLAUDE_PLUGIN_ROOT}/hooks/pre-compact.sh

PostCompact

  • echo '[code-forge] compact 완료. notepad/state 복원 확인하세요.' >&2

PermissionRequest

  • ${CLAUDE_PLUGIN_ROOT}/hooks/permission-guard.sh

FileChanged

  • Matchespackage.json${CLAUDE_PLUGIN_ROOT}/hooks/package-changed.sh

UserPromptSubmit

Fires before Claude sees each prompt you send. A plugin can use it to inject context, so the same instruction reaches the model every turn instead of only at session start.

  • ${CLAUDE_PLUGIN_ROOT}/hooks/auto-flow-trigger.sh
Read hooks/hooks.json

Where it lives

  • hooks/auto-flow-trigger.shRunsGitHub
    Read the script
    #!/usr/bin/env bash
    # UserPromptSubmit hook — Foreman(작업 길안내) + 자연어 → flow CLI 강제 호출
    #
    # 블록 구성:
    #   C0. 직전 턴 마무리 제안 백스톱 — quality-gate가 route.json에 남긴 wrapup_hint를
    #       다음 프롬프트에서 1회 전달 (Stop 훅 stdout은 모델에 미도달 — 2026-06-12 판정)
    #   C1. Foreman — 작업성 발화 감지 시 /start·복잡도·effort 선택지 안내 (세션당 1회, 강제 아님)
    #   C2. 티켓 ID(PROJ-123 등) → flow tc select 강제 호출 (flow CLI 설치 시에만)
    #
    # INTEGRATION.md §4 자연어 매핑 회로 + FORGE_MASTERPLAN 2단계 (2026-06-12).
    # (2026-05-19 redesign G5 → 2026-06-12 Foreman 확장 — 전역 flow 가드를 C2로 강등,
    #  flow 미설치 환경에서도 C0/C1은 동작)
    #
    # 종료 코드:
    #   0 — 항상 0 (hook이 사용자 입력 자체를 막지 않음)
    # stdout — Claude에게 추가 컨텍스트로 주입
    #
    # set -e 주의 (must_fix 7): 분류용 grep/정규식은 매칭 실패가 정상 경로이므로
    # 전부 `|| true`/`|| echo ""` 가드 — 훅 침묵 사망 방지.
    
    set -e
    
    # stdin에서 prompt 읽기 (Claude Code 표준: JSON { "prompt": "...", "session_id": "..." })
    INPUT=$(cat 2>/dev/null || echo "")
    [ -z "$INPUT" ] && exit 0
    
    # prompt/session_id 추출 (jq 있으면 우선, 없으면 grep)
    if command -v jq >/dev/null 2>&1; then
      PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null || echo "")
      SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null || echo "")
    else
      PROMPT=$(echo "$INPUT" | grep -o '"prompt":[[:space:]]*"[^"]*"' 2>/dev/null \
        | sed 's/.*"prompt":[[:space:]]*"\(.*\)"/\1/' | head -1 || echo "")
      SESSION_ID=""
    fi
    [ -z "$PROMPT" ] && exit 0
    
    MARKER_DIR="$HOME/.code-forge"
    mkdir -p "$MARKER_DIR" 2>/dev/null || true
    TODAY=$(date +%Y%m%d)
    SID="${SESSION_ID:-nosid}"
    PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
    
    # ── C0. 직전 턴 마무리 제안 백스톱 (F3a 수신측) ──
    # quality-gate.sh(Stop)가 남긴 wrapup_hint는 모델에 직접 도달하지 않으므로
    # 다음 프롬프트에서 여기로 1회 전달. 2시간 지난 힌트는 무시 (세션 경계 오염 방지).
    WRAP_MARKER="$MARKER_DIR/foreman-$TODAY-$SID-f3a"
    ROUTE_FILE="$PROJECT_ROOT/.claude/state/route.json"
    if command -v jq >/dev/null 2>&1 && [ ! -f "$WRAP_MARKER" ] && [ -f "$ROUTE_FILE" ]; then
      HINT_TS=$(jq -r '.wrapup_hint.ts // empty' "$ROUTE_FILE" 2>/dev/null || echo "")
      if [ -n "$HINT_TS" ]; then
        HINT_EPOCH=$(date -j -u -f "%Y-%m-%dT%H:%M:%SZ" "$HINT_TS" +%s 2>/dev/null || echo 0)
        NOW_EPOCH=$(date -u +%s)
        if [ "$HINT_EPOCH" -gt 0 ] && [ $((NOW_EPOCH - HINT_EPOCH)) -lt 7200 ]; then
          touch "$WRAP_MARKER" 2>/dev/null || true
          echo "[code-forge foreman] 직전 턴: 변경 파일 있음 + progress.md 미갱신. 작업이 일단락된 상태면 progress 정리 또는 /handoff를 한 줄로 제안할 것 (세션당 1회 안내, 강제 아님)."
        fi
      fi
    fi
    
    # ── C1. Foreman — 작업성 발화 → /start·복잡도·effort 선택지 (세션당 1회) ──
    C1_MARKER="$MARKER_DIR/foreman-$TODAY-$SID-c1"
    case "$PROMPT" in
      /start*)
        # /start로 이미 정문 통과 — 이 세션의 안내를 소모해서, 진행 중간의
        # 추가 작업 발화("그리고 X도 추가해줘")에 "/start 할까요?"가 뜨는 모순 방지
        touch "$C1_MARKER" 2>/dev/null || true
        C1_ELIGIBLE=0 ;;
      /*) C1_ELIGIBLE=0 ;;  # 그 외 슬래시 명령 — 대상 아님 (안내 기회는 보존)
      *)  C1_ELIGIBLE=1 ;;
    esac
    # 진행 중 신호가 있으면 침묵 — 새 세션에서 이어가는 작업의 연속 발화("계속 진행해줘")에
    # 새 작업 안내가 뜨지 않게. 신호: plan.md 존재 또는 progress.md 1시간 내 갱신
    if [ "$C1_ELIGIBLE" -eq 1 ]; then
      if [ -f "$PROJECT_ROOT/.claude/temp/plan.md" ]; then
        C1_ELIGIBLE=0
      elif [ -f "$PROJECT_ROOT/.claude/state/progress.md" ]; then
        P_MTIME=$(stat -f %m "$PROJECT_ROOT/.claude/state/progress.md" 2>/dev/null \
          || stat -c %Y "$PROJECT_ROOT/.claude/state/progress.md" 2>/dev/null || echo 0)
        [ $(( $(date +%s) - P_MTIME )) -lt 3600 ] && C1_ELIGIBLE=0
      fi
    fi
    if [ "$C1_ELIGIBLE" -eq 1 ] && [ ! -f "$C1_MARKER" ] && [ "${#PROMPT}" -ge 10 ]; then
      if echo "$PROMPT" | grep -qiE '(만들|구현|추가|수정해|수정하|고쳐|고치|리팩토|개선해|개선하|작성해|작성하|생성해|연동|적용해|마이그레|구축|개발해|시작하|시작해|진행해|붙여|implement|build|create|add|refactor|fix)' 2>/dev/null; then
        touch "$C1_MARKER" 2>/dev/null || true
        cat <<'FOREMAN_EOF'
    [code-forge foreman] 작업성 발화 감지 (세션당 1회 안내, 강제 아님)
    이 발화가 실제 코드 작업 요청이면, 착수 전에 사용자에게 다음 선택지를 한 번 제시할 것:
      ① /start로 정식 진행 (분석→구현→검증→커밋, progress 기록)
      ② 그냥 진행 — 단, 복잡도 판단(LOW/MED/HIGH)과 권장 effort(low/medium/high/xhigh)를 한 줄로 명시
    질문/단답/논의성 발화, 또는 직전까지 진행 중이던 작업의 연속 발화(추가 요청·수정 지시)로
    판단되면 제안을 생략하고 기존 맥락 안에서 이어갈 것 — 새 작업으로 시작하지 말 것.
    FOREMAN_EOF
      fi
    fi
    
    # ── C2. 티켓 ID → flow tc select (flow CLI 설치 시에만 — 기존 G5 회로, 동작 무변경) ──
    command -v flow >/dev/null 2>&1 || exit 0
    
    # 티켓 ID 정규식 (대문자 알파벳 + 하이픈 + 숫자 1자리 이상)
    # 음성 친화 (2026-06-08 G9c): case-insensitive + 공백 fallback
    #   예: PROJ-123, proj-123, PROJ 123, Proj 123 (Whisper dictation 결과 변동 흡수)
    TICKET_RAW=$(echo "$PROMPT" | grep -oiE '\b[A-Z]{2,}[[:space:]-][0-9]+\b' 2>/dev/null | head -1 || echo "")
    [ -z "$TICKET_RAW" ] && exit 0
    
    # normalize: 공백 → 하이픈, 소문자 → 대문자
    TICKET=$(echo "$TICKET_RAW" | tr ' ' '-' | tr 'a-z' 'A-Z')
    
    # 모델명 오탐 제외 (2026-06-14): "gpt 4" / "claude 3" / "llama 3" 등은 티켓이 아니라 모델명.
    # G9c 음성 정규식이 \b[A-Z]{2,}[ -][0-9]+\b 로 이들을 잡아 flow tc select를 잘못 호출하던 잠복 지뢰
    # (flow 활성 시 발화). 알려진 모델 prefix면 정규화하지 말고 통째로 스킵.
    TICKET_PREFIX="${TICKET%%-*}"
    case "$TICKET_PREFIX" in
      GPT|GPT4O|CLAUDE|LLAMA|GEMINI|OPUS|SONNET|HAIKU|FABLE|MISTRAL|QWEN|DEEPSEEK|GROK|O1|O3|O4)
        exit 0 ;;
    esac
    
    # 영향 TC 자동 조회 (실패해도 사용자 작업은 방해하지 않음)
    echo "[code-forge auto-flow-trigger] 티켓 '$TICKET' 감지 → flow tc select 자동 호출"
    if flow tc select "$TICKET" --json 2>/dev/null; then
      :
    else
      echo "[code-forge auto-flow-trigger] flow tc select '$TICKET' 실패 또는 미적용 프로젝트 — skip"
    fi
    
    exit 0
    
  • hooks/bellows-log.shRunsGitHub
    Read the script
    #!/bin/bash
    # Bellows — 에이전트/스킬 사용 로깅
    # PostToolUse에서 실행. Agent, Skill 도구 호출을 usage.jsonl에 기록.
    # v2: session_id + model + duration_ms + success 필드 추가 (forge-glow L3 연동)
    
    TOOL_NAME="${CLAUDE_TOOL_NAME:-}"
    TOOL_INPUT="${CLAUDE_TOOL_INPUT:-}"
    TOOL_RESPONSE="${CLAUDE_TOOL_RESPONSE:-}"
    
    # Agent 또는 Skill 호출만 기록
    if [[ "$TOOL_NAME" != "Agent" && "$TOOL_NAME" != "Skill" ]]; then
      exit 0
    fi
    
    LOG_DIR="$HOME/.code-forge"
    LOG_FILE="$LOG_DIR/usage.jsonl"
    mkdir -p "$LOG_DIR"
    
    TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
    PROJECT_DIR="${CLAUDE_CWD:-$(pwd)}"
    PROJECT_NAME=$(basename "$PROJECT_DIR")
    SESSION_ID="${CLAUDE_SESSION_ID:-unknown}"
    MODEL="${CLAUDE_MODEL:-unknown}"
    
    # 소스 판별
    SOURCE="plugin"
    if [[ "$TOOL_NAME" == "Agent" ]]; then
      _AGENT_NAME=$(echo "$TOOL_INPUT" | grep -o '"subagent_type"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"//')
      if [[ "$_AGENT_NAME" == "${PROJECT_NAME}-"* ]]; then
        SOURCE="local"
      fi
    fi
    
    # duration 근사 (이전 Bellows 호출과의 간격)
    SESSION_MARKER="$LOG_DIR/.session-start-${SESSION_ID}"
    DURATION_MS=0
    if [[ -f "$SESSION_MARKER" ]]; then
      LAST=$(cat "$SESSION_MARKER" 2>/dev/null || echo "")
      if [[ -n "$LAST" ]]; then
        NOW_SEC=$(date +%s)
        DURATION_MS=$(( (NOW_SEC - LAST) * 1000 ))
      fi
    fi
    date +%s > "$SESSION_MARKER"
    
    # success 판단 (TOOL_RESPONSE에 "error"가 없으면 true로 가정)
    SUCCESS="true"
    if [[ -n "$TOOL_RESPONSE" ]] && echo "$TOOL_RESPONSE" | grep -qiE '"(is_?error|error)"[[:space:]]*:[[:space:]]*true'; then
      SUCCESS="false"
    fi
    
    # JSON 이스케이프 헬퍼
    esc() {
      printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g' | tr -d '\n'
    }
    
    if [[ "$TOOL_NAME" == "Agent" ]]; then
      AGENT_TYPE=$(echo "$TOOL_INPUT" | grep -o '"subagent_type"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"subagent_type"[[:space:]]*:[[:space:]]*"//' | sed 's/"//')
      AGENT_DESC=$(echo "$TOOL_INPUT" | grep -o '"description"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"description"[[:space:]]*:[[:space:]]*"//' | sed 's/"//')
      ENTRY="{\"ts\":\"$TIMESTAMP\",\"sid\":\"$(esc "$SESSION_ID")\",\"type\":\"agent\",\"name\":\"$(esc "${AGENT_TYPE:-general-purpose}")\",\"desc\":\"$(esc "${AGENT_DESC:-}")\",\"model\":\"$(esc "$MODEL")\",\"duration_ms\":$DURATION_MS,\"success\":$SUCCESS,\"source\":\"$SOURCE\",\"project\":\"$(esc "$PROJECT_NAME")\"}"
    elif [[ "$TOOL_NAME" == "Skill" ]]; then
      SKILL_NAME=$(echo "$TOOL_INPUT" | grep -o '"skill"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"skill"[[:space:]]*:[[:space:]]*"//' | sed 's/"//')
      ENTRY="{\"ts\":\"$TIMESTAMP\",\"sid\":\"$(esc "$SESSION_ID")\",\"type\":\"skill\",\"name\":\"$(esc "${SKILL_NAME:-unknown}")\",\"model\":\"$(esc "$MODEL")\",\"duration_ms\":$DURATION_MS,\"success\":$SUCCESS,\"source\":\"$SOURCE\",\"project\":\"$(esc "$PROJECT_NAME")\"}"
    fi
    
    echo "$ENTRY" >> "$LOG_FILE"
    
    # usage.jsonl 30일 GC (성능상 매 호출 아닌 확률적 — 100회 중 1회)
    if [ $(( RANDOM % 100 )) -eq 0 ]; then
      CUTOFF=$(date -u -v-30d +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u -d '30 days ago' +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null)
      if [ -n "$CUTOFF" ]; then
        awk -v c="$CUTOFF" 'match($0, /"ts":"([^"]+)"/, a) { if (a[1] >= c) print }' "$LOG_FILE" > "$LOG_FILE.tmp" 2>/dev/null && mv "$LOG_FILE.tmp" "$LOG_FILE"
      fi
    fi
    
    exit 0
    
  • hooks/guard.shRunsGitHub
    Read the script
    #!/bin/bash
    # guard.sh — Bash 실행 전 위험 명령 차단
    # PreToolUse hook (Bash)
    
    # stdin JSON 파싱 (Claude Code hooks는 stdin으로 JSON 전달)
    INPUT=$(cat)
    COMMAND=$(echo "$INPUT" | python3 -c "
    import sys, json
    try:
        d = json.load(sys.stdin)
        print(d.get('tool_input', {}).get('command', ''))
    except:
        print('')
    " 2>/dev/null)
    
    # 폴백: 환경변수 방식 (구버전 호환)
    if [ -z "$COMMAND" ]; then
      COMMAND="${TOOL_INPUT_COMMAND:-}"
    fi
    if [ -z "$COMMAND" ] && [ -n "$TOOL_INPUT" ]; then
      COMMAND=$(echo "$TOOL_INPUT" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"command"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
    fi
    [ -z "$COMMAND" ] && exit 0
    
    if echo "$COMMAND" | grep -qE 'git\s+add\s+(-A|--all|\.)(\s|$)'; then
      echo "BLOCKED: 'git add .' / 'git add -A' 금지. 파일을 명시적으로 지정하세요." && exit 2
    fi
    if echo "$COMMAND" | grep -qE 'git\s+push\s+.*(--force|--force-with-lease|-f)(\s|$)'; then
      echo "BLOCKED: force push 금지." && exit 2
    fi
    if echo "$COMMAND" | grep -qE 'git\s+commit\s+.*--no-verify'; then
      echo "BLOCKED: '--no-verify' 금지." && exit 2
    fi
    if echo "$COMMAND" | grep -qE 'git\s+stash\s+(drop|clear)'; then
      echo "BLOCKED: 'git stash drop/clear' 금지." && exit 2
    fi
    if echo "$COMMAND" | grep -qE '(yarn|npm|pnpm)\s+publish'; then
      echo "BLOCKED: 패키지 배포 금지." && exit 2
    fi
    if echo "$COMMAND" | grep -qE 'rm\s+(-rf|-fr)\s+(/|~|\$HOME)(\s|$)'; then
      echo "BLOCKED: 루트/홈 삭제 금지." && exit 2
    fi
    if echo "$COMMAND" | grep -qiE 'DROP\s+(TABLE|DATABASE)'; then
      echo "BLOCKED: DROP TABLE/DATABASE 금지." && exit 2
    fi
    if echo "$COMMAND" | grep -qE 'git\s+reset\s+--hard'; then
      echo "BLOCKED: 'git reset --hard' 금지." && exit 2
    fi
    if echo "$COMMAND" | grep -qE 'git\s+(checkout|restore)\s+\.(\s|$)'; then
      echo "BLOCKED: 모든 변경사항 되돌리기 금지." && exit 2
    fi
    exit 0
    
  • hooks/lint-fix.shRunsGitHub
    Read the script
    #!/bin/bash
    # lint-fix.sh — Edit/Write/MultiEdit 후 자동 ESLint --fix + Prettier
    # PostToolUse hook (Edit|Write|MultiEdit)
    
    FILE_PATH="${TOOL_INPUT_FILE_PATH:-}"
    if [ -z "$FILE_PATH" ] && [ -n "$TOOL_INPUT" ]; then
      FILE_PATH=$(echo "$TOOL_INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
    fi
    [ -z "$FILE_PATH" ] && exit 0
    
    case "$FILE_PATH" in
      *.js|*.ts|*.jsx|*.tsx|*.vue|*.css|*.scss|*.json) ;;
      *) exit 0 ;;
    esac
    
    [ -f "$FILE_PATH" ] || exit 0
    
    PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
    
    ESLINT_BIN=""
    if [ -f "$PROJECT_ROOT/node_modules/.bin/eslint" ]; then
      ESLINT_BIN="$PROJECT_ROOT/node_modules/.bin/eslint"
    elif command -v npx &>/dev/null; then
      for cfg in .eslintrc.js .eslintrc.json .eslintrc.cjs .eslintrc.yml .eslintrc.yaml eslint.config.js eslint.config.mjs eslint.config.ts; do
        [ -f "$PROJECT_ROOT/$cfg" ] && ESLINT_BIN="npx eslint" && break
      done
    fi
    
    if [ -n "$ESLINT_BIN" ]; then
      $ESLINT_BIN --fix --quiet "$FILE_PATH" 2>/dev/null
      REMAINING=$($ESLINT_BIN --quiet "$FILE_PATH" 2>&1)
      [ -n "$REMAINING" ] && echo "$REMAINING" | head -10 >&2
    fi
    
    PRETTIER_BIN=""
    if [ -f "$PROJECT_ROOT/node_modules/.bin/prettier" ]; then
      PRETTIER_BIN="$PROJECT_ROOT/node_modules/.bin/prettier"
    elif command -v npx &>/dev/null; then
      for cfg in .prettierrc .prettierrc.js .prettierrc.json .prettierrc.yml prettier.config.js prettier.config.cjs; do
        [ -f "$PROJECT_ROOT/$cfg" ] && PRETTIER_BIN="npx prettier" && break
      done
    fi
    
    [ -n "$PRETTIER_BIN" ] && $PRETTIER_BIN --write --log-level=silent "$FILE_PATH" 2>/dev/null
    
    exit 0
    
  • hooks/notify.shRunsGitHub
    Read the script
    #!/bin/bash
    # Claude Code - 사용자 입력 필요 시 Mac 알림
    # Claude Code의 Notification 훅에서 자동 호출됨
    
    TITLE="Claude Code"
    MESSAGE="${CLAUDE_NOTIFICATION_TITLE:-확인이 필요합니다}"
    
    # terminal-notifier를 사용한 배너 알림 (macOS 15 Sequoia 호환)
    NOTIFIER=$(command -v terminal-notifier || echo "/opt/homebrew/bin/terminal-notifier")
    "$NOTIFIER" -title "$TITLE" -message "$MESSAGE" -sound Glass
    
    # 터미널 벨 소리 (터미널 포커스 없을 때 추가 알림)
    echo -e "\a"
    
  • hooks/package-changed.shRunsGitHub
    Read the script
    #!/bin/bash
    # package-changed.sh — package.json 변경 감지
    # FileChanged hook
    
    INPUT=$(cat)
    FILE=$(echo "$INPUT" | python3 -c "
    import sys, json
    try:
        d = json.load(sys.stdin)
        print(d.get('file', ''))
    except:
        print('')
    " 2>/dev/null)
    
    echo "[FileChanged] $FILE 변경 감지"
    echo "의존성 변경이 있을 수 있습니다. 필요시 yarn install을 실행하세요."
    exit 0
    
  • hooks/permission-guard.shRunsGitHub
  • hooks/pre-compact.shRunsGitHub
  • hooks/quality-gate.shRunsGitHub
  • hooks/scope-type-check.shGitHub
  • hooks/session-init.shRunsGitHub
  • hooks/skill-dedup.shRunsGitHub
  • hooks/subagent-stop.shRunsGitHub
  • hooks/write-guard.shRunsGitHub

All 14 scripts are listed above. The source is inlined for 6 of them, starting with whatever hooks.json actually runs. See all of them in the repo.

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 withcode-forge

설치하면 Claude Code가 더 잘 동작합니다. 전문 에이전트, 슬래시 스킬, 스택 모듈을 제공하는 Claude Code 플러그인. 검증된 사고모델(GROUND→APPLY→VERIFY→ADAPT)이 모든 작업의 품질을 일관되게 유지합니다. (에이전트/스킬 개수는 디스크가 진실 — ls agents/.md | wc -l, ls skills//SKILL.md | wc -l) 현재 상태: 개인 GitHub 운영 중 (마켓플레이스 배포 4.10.0).

Get the whole plugin