Lifecycle hooks

Bob Shell 세션의 주요 시점에서 셸 명령을 자동으로 실행하여 활동을 기록하고, 컨텍스트를 주입하거나, 직접 작성한 로직으로 작업을 차단합니다.

Lifecycle hooks를 사용하면 Bob Shell 세션의 특정 시점에 셸 명령을 실행할 수 있습니다. 활동 로깅, 모델에 컨텍스트 주입, 작업 허용 또는 차단, 후속 자동화 시작 등을 Bob Shell을 수정하지 않고 구현할 수 있습니다.

Hooks 관리

/hooks를 실행하면 구성된 전역 및 워크스페이스 hooks를 모두 나열하는 대화 상자가 열립니다. 대화 상자에는 각 hook의 이벤트 유형, matcher, 범위, 상태 및 명령이 표시됩니다. 개별 hook을 켜거나 끌 수 있습니다. 디스크에서 hook 설정이 변경되면 목록이 자동으로 새로 고침됩니다.

참고:

조직의 모든 사용자에게 hooks를 적용하려면 EnforcedHooks를 참조하세요.

지원되는 hooks

Hook실행 시점차단 여부Stdout 동작
SessionStart세션 시작 시 1회아니요컨텍스트로 주입
UserPromptSubmit프롬프트를 제출할 때마다예 (exit 2)컨텍스트로 주입
PreToolUse일치하는 도구 실행 전예 (exit 2)무시됨
PostToolUse일치하는 도구 완료 후아니요무시됨
PreCompact컨텍스트 압축 시작 전예 (exit 2)무시됨
PostCompact컨텍스트 압축 완료 후아니요무시됨
Stop에이전트가 중지될 때아니요무시됨

설정

Hooks는 settings.json의 hooks 키 아래에 정의됩니다. Bob Shell은 두 위치에서 hooks를 병합합니다:

범위파일
전역 (모든 workspace)~/.bob/settings/settings.json
Workspace (현재 프로젝트).bob/settings.json

전역 hooks는 항상 실행됩니다. Workspace hooks는 전역 hooks 위에 병합되어 현재 프로젝트에만 적용됩니다.

중요:

Workspace hooks는 신뢰할 수 있는 폴더에서만 실행됩니다. 현재 폴더가 신뢰되지 않으면 .bob/settings.json 파일이 로드되지 않고 workspace hooks는 자동으로 건너뜁니다. ~/.bob/settings/settings.json의 전역 hooks는 폴더 신뢰 설정의 영향을 받지 않습니다.

설정 파일의 위치 및 로드 방법에 대한 자세한 내용은 Bob Shell 구성하기를 참조하세요.

Hook 스키마

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "^write_file$",
        "hooks": [
          {
            "type": "command",
            "command": "sh .bob/hooks/check.sh",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

설정 필드

필드타입기본값설명
type"command" | "https"(없음)필수. 핸들러 유형. 로컬 셸 명령을 실행하려면 command를, HTTP 엔드포인트로 이벤트를 보내려면 https를 사용하세요.
commandstring(없음)type이 command일 때 필수. 실행할 셸 명령. macOS와 Linux에서는 sh -c로, Windows에서는 cmd /c로 실행됩니다.
urlstring(없음)type이 https일 때 필수. hook 이벤트 페이로드를 전송할 HTTPS URL.
matcherstring(없음)선택. 도구 이름과 매칭할 regex (PreToolUse, PostToolUse에만 해당). 생략하면 모든 도구에 매칭됩니다.
timeoutnumber10Hook을 중지하기 전 초. 0으로 설정하면 타임아웃을 비활성화합니다.

Hook 참조

새 세션이 시작될 때 첫 번째 턴 전에 1회 실행됩니다.

stdin 스키마

{
  "session_id": "string",
  "cwd": "string",
  "hook_event_name": "string",
  "source": "startup | resume | compact"
}

페이로드 예시

{
  "session_id": "3f2a9c1e8b7d4f6a0e5c2b1d9a8f7e6c",
  "cwd": "/path/to/project",
  "hook_event_name": "SessionStart",
  "source": "startup"
}

Stdout: 추가 세션 정보로 모델의 컨텍스트에 기록됩니다.

차단: Exit 코드 2는 지원되지 않습니다. 세션은 항상 시작됩니다. 기타 비-제로 종료는 로그에 기록되고 무시됩니다.

프롬프트를 제출할 때마다 모델로 전송되기 전에 실행됩니다.

stdin 스키마

{
  "session_id": "string",
  "cwd": "string",
  "hook_event_name": "string",
  "prompt": "string"
}

페이로드 예시

{
  "session_id": "3f2a9c1e8b7d4f6a0e5c2b1d9a8f7e6c",
  "cwd": "/path/to/project",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Refactor the auth module"
}

Stdout: 프롬프트와 함께 모델의 컨텍스트에 기록됩니다.

차단: Exit 코드 2는 프롬프트 전송을 차단합니다. Bob Shell은 오류를 표시하고 프롬프트가 제출되지 않습니다.

일치하는 도구가 실행되기 전에 실행되어 작업을 검사하거나 차단할 기회를 줍니다.

stdin 스키마

{
  "session_id": "string",
  "cwd": "string",
  "hook_event_name": "string",
  "tool_name": "string",
  "tool_input": "object",
  "tool_use_id": "string"
}

페이로드 예시

{
  "session_id": "3f2a9c1e8b7d4f6a0e5c2b1d9a8f7e6c",
  "cwd": "/path/to/project",
  "hook_event_name": "PreToolUse",
  "tool_name": "write_file",
  "tool_input": {
    "path": "src/index.ts",
    "content": "..."
  },
  "tool_use_id": "toolu_01abc123"
}

Stdout: 무시됩니다.

차단: Exit 코드 2는 도구 실행을 방지합니다. Bob Shell은 도구가 차단되었다고 보고하고 세션을 계속합니다.

일치하는 도구가 완료된 후 성공 여부와 관계없이 실행됩니다.

stdin 스키마

{
  "session_id": "string",
  "cwd": "string",
  "hook_event_name": "string",
  "tool_name": "string",
  "tool_input": "object",
  "tool_response": "string",
  "tool_use_id": "string"
}

페이로드 예시

{
  "session_id": "3f2a9c1e8b7d4f6a0e5c2b1d9a8f7e6c",
  "cwd": "/path/to/project",
  "hook_event_name": "PostToolUse",
  "tool_name": "write_file",
  "tool_input": {
    "path": "src/index.ts",
    "content": "..."
  },
  "tool_response": "File written successfully",
  "tool_use_id": "toolu_01abc123"
}

Stdout: 무시됩니다.

차단: Exit 코드 2는 효과가 없습니다. 도구는 이미 실행되었습니다.

컨텍스트 압축이 시작되기 전에 실행되어 조건을 검사하거나 압축을 차단할 기회를 줍니다.

stdin 스키마

{
  "session_id": "string",
  "cwd": "string",
  "hook_event_name": "string",
  "trigger": "manual | auto",
  "custom_instructions": "string | null"
}

페이로드 예시

{
  "session_id": "3f2a9c1e8b7d4f6a0e5c2b1d9a8f7e6c",
  "cwd": "/path/to/project",
  "hook_event_name": "PreCompact",
  "trigger": "auto",
  "custom_instructions": null
}

Stdout: 무시됩니다.

차단: Exit 코드 2는 압축 진행을 차단합니다. Bob Shell은 압축이 차단되었다고 보고하고 세션을 계속합니다.

컨텍스트 압축이 완료된 후 실행됩니다.

stdin 스키마

{
  "session_id": "string",
  "cwd": "string",
  "hook_event_name": "string",
  "trigger": "manual | auto",
  "compact_summary": "string"
}

페이로드 예시

{
  "session_id": "3f2a9c1e8b7d4f6a0e5c2b1d9a8f7e6c",
  "cwd": "/path/to/project",
  "hook_event_name": "PostCompact",
  "trigger": "auto",
  "compact_summary": "..."
}

Stdout: 무시됩니다.

차단: Exit 코드 2는 효과가 없습니다. 압축은 이미 완료되었습니다.

에이전트가 중지될 때 마지막 턴 완료 후 실행됩니다.

stdin 스키마

{
  "session_id": "string",
  "cwd": "string",
  "hook_event_name": "string",
  "last_assistant_message": "string | null"
}

페이로드 예시

{
  "session_id": "3f2a9c1e8b7d4f6a0e5c2b1d9a8f7e6c",
  "cwd": "/path/to/project",
  "hook_event_name": "Stop",
  "last_assistant_message": "Done. The auth module is refactored."
}

Stdout: 무시됩니다.

차단: Exit 코드 2는 효과가 없습니다. 세션은 이미 종료되었습니다.

Exit 코드와 차단

Exit 코드동작적용 대상
0성공: hook이 문제 없이 실행됨모든 hooks
2차단: 현재 작업 중지UserPromptSubmit, PreToolUse, PreCompact
기타 비-제로비-차단 실패: 로그에 기록되고 무시됨모든 hooks
참고:

차단을 지원하는 것은 UserPromptSubmit, PreToolUse, PreCompact뿐입니다. SessionStart, PostToolUse, PostCompact, Stop에서의 Exit 코드 2는 비-차단 실패로 처리됩니다.

명령 세부 정보

  • 작업 디렉터리: 명령은 태스크 작업 디렉터리 (Bob이 작업 중인 폴더)에서 실행됩니다.
  • 기본 타임아웃: 10초. timeout 필드로 hook별로 재정의할 수 있습니다. timeout을 0으로 설정하면 타임아웃을 완전히 비활성화합니다.
  • Stderr: Bob Shell의 로그에 기록되지만 hook 결과에는 영향을 주지 않습니다.
  • Shell: macOS와 Linux에서는 sh -c로 명령이 실행됩니다.

시작하기

~/.bob/settings/settings.json에 있는 전역 설정 파일을 열거나 생성합니다.

사용할 hook의 hooks 키를 추가합니다. 아래 예시는 모든 write_file 호출 전에 스크립트를 실행합니다:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "^write_file$",
        "hooks": [
          {
            "type": "command",
            "command": "sh ~/.bob/hooks/log-write.sh"
          }
        ]
      }
    ]
  }
}

스크립트 파일을 생성합니다. 이 최소 스크립트는 들어오는 JSON 페이로드를 기록합니다:

#!/bin/sh
# ~/.bob/hooks/log-write.sh
cat >> ~/.bob/hooks/write-log.txt

Bob Shell 세션을 시작하고 일치하는 도구를 사용합니다. ~/.bob/hooks/write-log.txt를 확인하여 hook이 실행되고 페이로드가 기록되었는지 확인합니다.

예시

모든 hook 입력 로깅

디버깅을 위해 각 hook의 stdin을 파일에 기록합니다:

#!/bin/sh
# 타임스탬프와 함께 들어오는 JSON 페이로드 추가
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> ~/.bob/hooks/debug.log
cat >> ~/.bob/hooks/debug.log
echo "" >> ~/.bob/hooks/debug.log

임의의 hook 아래에 설정합니다:

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [{ "type": "command", "command": "sh ~/.bob/hooks/debug.sh" }]
      }
    ]
  }
}

세션 컨텍스트 주입

SessionStart hook에서 텍스트를 반환하여 모델의 컨텍스트에 추가합니다:

#!/bin/sh
# 모델이 사용할 프로젝트 메타데이터 출력
echo "Project: $(basename $PWD)"
echo "Git branch: $(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')"
echo "Node version: $(node --version 2>/dev/null || echo 'not installed')"

프롬프트 차단

UserPromptSubmit hook에서 Exit 코드 2로 종료하여 프롬프트 전송을 방지합니다:

#!/bin/sh
# "delete" 단어가 포함된 프롬프트 차단
PROMPT=$(cat | python3 -c "import sys,json; print(json.load(sys.stdin)['prompt'])")
case "$PROMPT" in
  *delete*|*DELETE*)
    echo "Prompt blocked: contains 'delete'" >&2
    exit 2
    ;;
esac

일치하는 도구 차단

PreToolUse hook에서 Exit 코드 2로 종료하여 특정 도구의 실행을 방지합니다:

#!/bin/sh
# src/ 디렉터리 외부 파일에 대한 write_file 작업 차단
PATH_VAL=$(cat | python3 -c "import sys,json; print(json.load(sys.stdin)['tool_input'].get('path',''))")
case "$PATH_VAL" in
  src/*) ;;
  *)
    echo "Blocked: writes outside src/ are not allowed" >&2
    exit 2
    ;;
esac

Stop에서 후속 자동화 실행

Stop을 사용하여 세션 종료 후 정리 또는 보고를 시작합니다:

#!/bin/sh
# 에이전트 완료 후 스테이징된 변경사항 커밋
cd "$PWD"
git diff --cached --quiet || git commit -m "chore: auto-commit from Bob Shell session"

HTTPS 엔드포인트로 hook 이벤트 보내기

핸들러 type을 https로 설정하여 외부 웹 서비스 또는 모니터링 도구로 이벤트 페이로드를 전송합니다:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "https",
            "url": "https://api.example.com/webhooks/bob-events",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

현재 제한 사항

다음 기능은 아직 사용할 수 없습니다:

  • command 및 https 이외의 hook 핸들러 타입: function hooks, 인라인 스크립트 hooks 등은 지원되지 않습니다.
  • 예약 hooks: hooks를 타이머 또는 외부 이벤트에 응답하여 실행되도록 설정할 수 없습니다.
  • 입력 재작성: hooks는 프롬프트나 도구 입력이 모델에 도달하기 전에 수정할 수 없습니다.
  • 샌드박스 실행: hooks는 사용자의 전체 권한으로 실행됩니다. 격리가 적용되지 않습니다.
  • 전용 hook 텔레메트리: hook 활동은 세션 분석에서 별도로 추적되지 않습니다.
  • 차단을 지원하지 않는 hooks에서의 차단: SessionStart, PostToolUse, PostCompact, Stop에서 Exit 코드 2는 효과가 없습니다.
이 주제는 어떤가요?