Skip to main content
자체 호스팅 환경은 Team 및 Enterprise 플랜에서 공개 베타 상태입니다. 가용성 및 제한사항에서 활성화 경로를 확인할 수 있습니다. 이 페이지는 CI 테스트 레시피입니다. 설정은 빠른 시작을, 프로덕션 배포 레시피는 프로덕션에 배포를 참조하세요.
자체 호스팅 환경에서 Claude Code 클라우드 세션은 사용자가 빌드하고 유지 관리하는 러너 이미지에서 실행됩니다. 새 이미지를 프로덕션 환경에 배포하기 전에 스크립트에서 테스트 환경에 대해 전체 세션을 실행합니다. 세션을 생성하고, Claude의 응답을 읽고, 후속 메시지를 보내고, 그 응답도 읽습니다. 이것이 러너 이미지, git 액세스 및 모든 사용자 정의 도구를 검증한 후 변경 사항을 승격하기 전에 수행하는 CI 스모크 테스트의 형태입니다. 이 레시피는 사용자가 이미 환경과 러너를 설정했으며, CI 작업이 테스트 스크립트와 동일한 호스트에서 러너 프로세스를 시작한다고 가정합니다. 이는 새 러너 이미지를 테스트하기 위한 자연스러운 설정입니다. 러너에 설치한 Stop 훅은 각 턴의 최종 응답을 로컬 파일에 기록하고, 스크립트는 그곳에서 읽으므로 Anthropic API에 대한 유일한 호출은 두 디스패치 자체입니다. 테스트 러너가 별도의 인프라에 있는 경우 원격 테스트 러너를 참조하세요.

테스트 러너에 캡처 훅 설치

읽기 작업은 Claude Code Stop 훅을 통해 작동합니다. Claude가 턴을 완료하면 훅은 최종 어시스턴트 메시지를 stdin JSON의 last_assistant_message로 받고 $E2E_REPLY_DIR/<session_id>.txt에 추가합니다. commit-nudge Stop 훅과 동일한 방식으로 러너 호스트의 ~/.claude/에 설치합니다. 러너는 모든 세션에 이를 시드합니다.

훅 파일 저장

러너 호스트에 아래 두 파일을 저장합니다:
  • 설정 블록: 러너 호스트의 ~/.claude/settings.json에 병합
  • 스크립트: 러너 호스트의 ~/.claude/hooks/e2e-stop-hook-capture.sh로 저장하고 실행 가능하게 설정

러너를 시작하기 전에

훅이 의존하는 두 가지:
  • 러너를 시작하기 전에 설치합니다. 러너는 시작 시 ~/.claude/를 한 번 스냅샷하므로, 실행 중인 러너에 추가된 훅은 재시작 후에만 적용됩니다.
  • 러너 프로세스에 E2E_REPLY_DIR을 내보냅니다. 훅은 변수가 설정되지 않았거나 디렉토리가 없을 때 작동하지 않으므로, systemd 단위, pod 사양 또는 CI 단계와 같이 러너를 시작하는 곳에서 설정합니다. 아래 테스트 스크립트도 이를 필요로 합니다.
이 훅은 테스트 환경을 제공하는 러너에만 설치합니다. E2E_REPLY_DIR이 존재할 때마다 모든 세션의 최종 응답을 디스크에 기록합니다. 이는 일회용 CI 러너에서는 무해하지만 변수가 실수로 설정될 수 있는 프로덕션 환경 러너 이미지로 옮기는 것은 좋지 않습니다.

테스트 루프 실행

--environment--ref 디스패치 플래그는 스크립트를 실행하는 머신(러너 자체와 동일한 수준)에서 Claude Code v2.1.224 이상이 필요합니다. 훅이 설치되고 이 호스트에서 러너가 시작된 상태에서 테스트 스크립트는:
  1. claude -p "<prompt>" --environment <environment-id> --output-format json으로 테스트 환경에서 세션을 생성합니다. origin 원격에서 저장소를 자동 감지할 수 있도록 git 체크아웃에서 실행합니다. 선택적 --ref <branch>는 로컬 HEAD 대신 명명된 ref를 기반으로 세션의 체크아웃을 설정합니다. 명령은 세션을 생성하고, session_id를 포함하는 한 줄의 JSON을 인쇄하고, Claude의 응답을 기다리지 않고 종료합니다.
  2. 러너의 Stop 훅이 턴을 완료한 후 $E2E_REPLY_DIR/<session_id>.txt에 기록된 응답이 나타날 때까지 기다립니다.
  3. claude -p "<message>" --cloud <session_id> --output-format json으로 후속 메시지를 보냅니다(실행 중인 세션에 후속 메시지 보내기 참조). 이는 기존 세션에 사용자 이벤트를 게시하고 종료합니다.
  4. 2단계와 동일한 방식으로 후속 응답을 기다립니다.

--environment 디스패치 동작

Claude Code는 세션을 생성하고, 세션 ID와 링크를 인쇄하고, 종료합니다. 플래그는 remote.defaultEnvironmentId 설정보다 우선합니다. --output-format stream-json을 지원하지 않으며, --resume, --continue, --teleport, --session-id 또는 --init-only와 같이 세션을 재개, 연결 또는 사전 구성하는 플래그와 결합할 수 없습니다. --cloud는 세션 ID 또는 URL과 함께 거부되며, 설명을 포함하는 비대화형 실행에서도 거부됩니다. 단순 --cloud는 없는 것으로 처리됩니다. 터미널에서 위치 프롬프트 대신 --cloud 설명으로 작업을 전달할 수 있습니다.

예제 스크립트

아래 스크립트는 $CLAUDE_TEST_ENVIRONMENT_ID에 대해 전체 루프를 실행합니다. 이는 테스트 환경의 ccpool_... ID이며, 관리 페이지의 환경 상세 대화상자에 표시되거나 환경 생성 호출에서 반환됩니다. 각 응답의 센티널 구문을 어설션합니다. 캡처 훅이 설치되고 E2E_REPLY_DIR이 내보내진 이 호스트에서 러너를 시작한 후, 작업하려는 저장소의 git 체크아웃에서 실행합니다.
TURN1/TURN2 프롬프트와 EXPECT1/EXPECT2 센티널을 사용자 정의 MCP 도구 중 하나를 실행하도록 Claude에 요청하고 출력을 어설션하는 등 설정을 실행하는 것으로 바꿉니다.

원격 테스트 러너

테스트 러너가 CI 작업이 파일 시스템을 공유할 수 없는 지속적인 Kubernetes 플릿과 같은 별도의 인프라에 있는 경우, Stop 훅의 파일 쓰기를 드라이버가 수신 대기하는 엔드포인트로의 POST로 바꿉니다:
드라이버 측에서는 POST를 수락하고 테스트가 요청할 때까지 응답을 보유하는 모든 것을 실행합니다. 예를 들어 CI 작업 내부의 작은 HTTP 리스너 또는 이미 실행 중인 웹훅 수신기입니다. 훅은 인프라에서 실행되므로 엔드포인트는 러너에서만 도달 가능하면 됩니다.

CI에서 인증

claude -p ... --environmentclaude -p ... --cloud 모두 claude.ai OAuth 토큰으로 인증합니다. sk-ant-xxxxx와 같은 API 키는 두 호출 모두에서 허용되지 않습니다. 두 가지 방법으로 CI에서 토큰을 사용할 수 있습니다.

장기 CI 호스트

스크립트를 실행하는 머신에서 자동화용 전용 사용자 계정을 사용하여 claude auth login을 한 번 대화형으로 실행합니다. Claude Code는 macOS의 OS 키체인에 토큰을 저장하거나, Linux 및 Windows의 ~/.claude/.credentials.json에 저장합니다. 키체인을 쓸 수 없는 macOS 호스트(예: SSH 세션에서 로그인 키체인이 잠긴 경우)에서 Claude Code는 토큰을 ~/.claude/.credentials.json에도 저장합니다. 자격증명 관리를 참조하세요. CLI는 각 호출 시 단기 액세스 토큰을 자동으로 새로 고치지만, 기본 새로 고침 토큰 부여는 초기 로그인으로부터 30일로 제한되므로, 해당 호스트에서 30일마다 claude auth login을 대화형으로 다시 실행합니다.

임시 CI 러너

현재 이에 대한 장기 CI 토큰이 없습니다. 원격 세션 제어를 부여하는 범위인 user:sessions:claude_code는 서버 측에서 30일로 제한되므로, 1년 추론 전용 토큰을 발급하는 claude setup-token은 이를 포함하지 않습니다. 환경 시크릿도 허용되지 않습니다. 러너가 환경에 등록하도록만 승인하고 세션을 생성하지는 않기 때문입니다. 임시 러너에 저장된 로그인을 프로비저닝하려면 CLAUDE_CODE_OAUTH_REFRESH_TOKENCLAUDE_CODE_OAUTH_SCOPES를 설정하여 claude auth login이 브라우저 없이 토큰을 교환하도록 합니다. 새로 고침 부여에 동일한 30일 상한이 적용됩니다. 인간 계정에 바인딩되지 않은 머신 ID 경로가 필요한 경우 Anthropic 계정 팀에 문의하세요.

전용 테스트 환경 생성

환경을 프로그래밍 방식으로 생성 및 삭제하여 각 CI 실행이 깨끗한 환경을 얻도록 합니다. CI 작업이 시작하는 러너가 새 환경에 등록됩니다. 아래의 생성 및 삭제 호출은 claude.ai의 클라우드 환경 관리 페이지에서 사용하는 동일한 엔드포인트이며, anthropic-beta: ccr-byoc-2025-07-29 헤더가 필요합니다.

관리자 토큰 발급

$ADMIN_TOKEN은 Owner 역할을 보유하는 계정의 claude.ai OAuth 액세스 토큰이며, CI에서 인증과 동일한 방식으로 발급됩니다:
  • 발급: Owner 역할을 보유하는 계정으로 claude auth login을 실행한 후, 장기 CI 호스트에서 Claude Code가 저장한 위치에서 현재 액세스 토큰을 읽습니다.
  • 각 실행마다 새로 읽기: CLI가 액세스 토큰을 회전하고, 동일한 30일 새로 고침 부여 상한이 적용되므로, 복사본을 저장하지 마세요.
  • stdin을 통해 전달: 예제처럼 토큰이 curl의 인수 목록이나 빌드 로그에 남지 않도록 합니다.

환경 생성

응답을 에코하지 않고 캡처합니다. pool_secret은 환경에 러너를 등록할 수 있는 장기 자격증명이므로, 마스킹된 CI 시크릿으로 저장하고 환경 ID만 인쇄합니다. 토큰을 프로세스 목록에서 제외하는 -H @- 형식은 curl 7.55 이상이 필요합니다. 이전 curl은 @-를 리터럴 헤더로 취급하고 인증 없이 요청을 보냅니다.
Owner가 조직에 대해 자체 호스팅 환경 허용을 켤 때까지, 호출은 403 permission_error로 실패하며 self-hosted runners are disabled by your organization's policy를 읽습니다. 이 호스트에서 SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET=$ENVIRONMENT_SECRET으로 러너를 시작합니다. 캡처 훅 설치에 따라 캡처 훅과 E2E_REPLY_DIR을 추가한 후 테스트 스크립트를 실행합니다.

환경 삭제

실행이 완료되면 환경을 삭제하여 각 CI 실행이 깨끗하게 시작되도록 합니다: