새소식

300x250
AI/Claude Code Doc(공식문서) 번역본

Claude Code 공식문서 리뷰-Build with Claude Code[6] : Run Claude Code programmatically

  • -
728x90

안녕하세요! 갓대희입니다. 
Claude Code Docs 공식 문서 >> Build with Claude Code 섹션의 내용 중 [Run Claude Code programmatically]를 살펴 보려고 합니다.
https://code.claude.com/docs/en/headless

Run Claude Code programmatically - Claude Code Docs

Use the Agent SDK to run Claude Code programmatically from the CLI, Python, or TypeScript.

code.claude.com

 
이 카테고리의 글은 편하게 공식 문서 위주의 내용을 눈으로 쭉 살펴 보고 넘어가는 목적을 갖고 시작 하게 되었습니다.
저도 초심으로 돌아가 기초적읜 글을 살펴보다보니, 지금와서 클로드에서 강조 하고자 하는 원칙이 어떤건지 되돌아볼 수 있는 계기가 되기도 하는 것 같아, 다른 분들도 꼭 한번 눈으로라도 이해 하고 넘어가는것이 좋다고 생각하여 공식 문서의 내용을 억지로 리뷰해보게 되었습니다. 

 

 

보안 주의사항

--allowedTools 사용 시 승인된 도구들이 사용자 확인 없이 자동 실행된다. 신뢰할 수 없는 입력이나 프롬프트로 실행할 때는 특히 주의가 필요하다. 모든 CI 로그에서 민감한 정보가 노출되지 않는지 확인하자.
Headless 모드 (비대화형 실행)

  • -p 플래그: 대화형 UI 없이 결과만 출력하는 비대화형 모드
  • 활용: CI/CD 파이프라인, 스크립트, 자동화 워크플로우
  • 출력 형식: text, json, stream-json, json-schema 지원
용어 설명: Headless 모드
사용자 입력 없이 스크립트나 자동화에서 Claude Code를 실행하는 모드다. -p (또는 --print) 플래그로 활성화한다.

 

빠른 시작 (5분)

초보자 팁
Headless 모드는 대화형 UI 없이 Claude Code를 실행한다. CI/CD 파이프라인, 스크립트, 자동화에 필수다.

Step 1: 기본 실행

가장 간단한 형태의 Headless 실행:

claude -p "현재 디렉토리의 구조를 설명해"

ex) slack bot Project 설명

 

Step 2: 도구 권한 부여

파일 읽기/쓰기가 필요한 경우:

claude -p "README.md를 읽고 요약해" --allowedTools "Read"

ex)

 

Step 3: JSON 출력

파싱 가능한 구조화된 출력:

claude -p "이 프로젝트를 분석해" --output-format json

ex) 

{
  "type": "result",
  "subtype": "success",
  "is_error": false,
  "duration_ms": 105970,
  "duration_api_ms": 136936,
  "num_turns": 2,
  "result": "## 프로젝트 분석 결과\n\n### 개요\n\n**eslackbot**은 Google Gemini LLM과 Slack을 통합하여 AWS Lambda에 배포하는 교육용 프로젝트입니다. 사용자가 Slack에서 봇을 멘션하면 AI 응답을 생성합니다.\n\n### 핵심 아키텍처\n\n```\nSlack Event → Dispatcher Lambda → Worker Lambda → Gemini API → Slack 응답\n             (3초 내 200 OK)     (비동기 호출)    (실제 처리)\n```\n\n**Dispatcher-Worker 패턴**을 사용하여 Slack의 3초 타임아웃 제약을 해결합니다.\n\n### 기술 스택\n\n| 구분 | 기술 |\n|------|------|\n| 언어 | Python 3.12+ |\n| 패키지 관리 | UV |\n| 웹 프레임워크 | FastAPI (로컬) |\n| LLM | Google Gemini (`gemini-2.5-flash-lite`) |\n| 배포 | AWS Lambda, Docker, ECR |\n| Slack | `slack-sdk` |\n\n### 디렉토리 구조\n\n```\ncore/           # 공유 유틸리티 (config, slack, gemini 클라이언트)\ndispatcher/     # Dispatcher Lambda 핸들러\nworker/         # Worker Lambda 핸들러\nserver/         # FastAPI 서버 (로컬 개발용)\ntests/          # pytest 테스트 (121+ 테스트)\n```\n\n### 주요 보안 기능\n\n- **HMAC-SHA256 서명 검증** (리플레이 공격 방지)\n- **프롬프트 인젝션 방어** (패턴 기반 필터링)\n- **Rate Limiting** (slowapi, 60 req/min per IP)\n- **사용자 ID 해싱** (로깅 시 개인정보 보호)\n- **pip-audit** (의존성 취약점 스캔)\n\n### 배포 방식\n\n```bash\n# 로컬 개발\nuv run uvicorn server.main:app --reload\n\n# AWS Lambda 배포\nmake all           # Dispatcher + Worker 전체 배포\nmake dispatcher    # Dispatcher만\nmake worker        # Worker만\n```\n\n### 주요 파일\n\n| 파일 | 역할 |\n|------|------|\n| `core/config.py` | 환경변수, Docker Secrets 로딩 |\n| `core/slack_utils.py` | 서명 검증, 이벤트 파싱 |\n| `core/gemini_client.py` | Gemini API 래퍼 (재시도 로직 포함) |\n| `dispatcher/handler.py` | Lambda 진입점, Worker 비동기 호출 |\n| `worker/handler.py` | LLM 처리, Slack 응답 전송 |\n\n### 상태\n\n- **테스트**: 121+ 테스트 케이스\n- **문서화**: AGENTS.md, prd.md 등 상세 문서\n- **프로덕션 준비**: Docker Swarm, Secrets 관리, 롤링 업데이트 지원\n\n---\n\n잘 설계된 프로젝트로, Serverless LLM 통합의 교과서적 구현입니다. 추가로 궁금한 부분이 있으면 말씀해주세요.",
  "session_id": "ed9b9e5d-e04e-498b-bade-217a70262e0f",
  "total_cost_usd": 0.44793109999999997,
  "usage": {
    "input_tokens": 16,
    "cache_creation_input_tokens": 25757,
    "cache_read_input_tokens": 73723,
    "output_tokens": 1460,
    "server_tool_use": {
      "web_search_requests": 0,
      "web_fetch_requests": 0
    },
    "service_tier": "standard",
    "cache_creation": {
      "ephemeral_1h_input_tokens": 0,
      "ephemeral_5m_input_tokens": 25757
    }
  },
  "modelUsage": {
    "claude-haiku-4-5-20251001": {
      "inputTokens": 9818,
      "outputTokens": 6955,
      "cacheReadInputTokens": 623371,
      "cacheCreationInputTokens": 69291,
      "webSearchRequests": 0,
      "costUSD": 0.19354385,
      "contextWindow": 200000
    },
    "claude-opus-4-5-20251101": {
      "inputTokens": 26,
      "outputTokens": 1809,
      "cacheReadInputTokens": 96102,
      "cacheCreationInputTokens": 25757,
      "webSearchRequests": 0,
      "costUSD": 0.25438725,
      "contextWindow": 200000
    }
  },
  "permission_denials": [
    {
      "tool_name": "Bash",
      "tool_use_id": "toolu_01X8fUjQRmqqqKjgwbtTedx5",
      "tool_input": {
        "command": "wc -l /Users/gdh/work/workspace/ai/slackBot/tests/test_*.py",
        "description": "Count lines in test files"
      }
    }
  ],
  "uuid": "f72e26f5-d9ad-48af-8f7e-6da564833d40"
}

 

 

Step 4: 파이프 입력

다른 명령의 출력을 Claude에 전달:

git diff | claude -p "이 변경사항을 리뷰해"

 

Step 5: 세션 유지

이전 대화를 이어서 계속:

claude -p "코드 리뷰 시작" --output-format json
claude -p "이어서 보안 이슈도 확인해" --continue

 

출력 형식

--output-format으로 응답 형식을 제어한다:

형식 설명 용도
text (기본) 텍스트만 출력 사람이 읽는 용도
json 완료 후 전체 JSON 결과 파싱, 세션 ID 추출
stream-json 줄바꿈 구분 JSON 스트림 실시간 진행 상황 모니터링

 

JSON 응답 구조

--output-format json 사용 시 반환되는 구조:

{
  "type": "result",
  "subtype": "success",
  "is_error": false,
  "session_id": "abc123-...",
  "result": "Claude의 응답 텍스트",
  "duration_ms": 1234,
  "duration_api_ms": 1200,
  "num_turns": 1,
  "cost_usd": 0.002
}

 

jq로 결과 파싱

JSON 출력에서 특정 필드만 추출:

# 텍스트 결과만 추출
claude -p "코드 요약해" --output-format json | jq -r '.result'

# 세션 ID 저장
session_id=$(claude -p "분석 시작" --output-format json | jq -r '.session_id')
echo "세션 ID: $session_id"

# 비용 확인
claude -p "테스트 분석" --output-format json | jq '.cost_usd'

 

JSON 스키마로 구조화된 출력

--json-schema로 응답을 특정 형식으로 강제할 수 있다:

# 커밋 분석을 구조화된 JSON으로 받기
claude -p "최근 커밋을 분석해" \
  --output-format json \
  --json-schema '{
    "type": "object",
    "properties": {
      "summary": {"type": "string"},
      "risk_level": {"type": "string", "enum": ["low", "medium", "high"]},
      "suggestions": {"type": "array", "items": {"type": "string"}}
    },
    "required": ["summary", "risk_level"]
  }' \
  --allowedTools "Bash(git:*)"
실전 팁
--json-schema는 AI 응답을 파싱해야 하는 자동화 파이프라인에서 유용하다. 응답 형식이 일관되게 보장된다.

 

도구 자동 승인

--allowedTools로 권한 프롬프트를 건너뛴다:

claude -p "테스트 실행하고 실패하면 수정해" \
  --allowedTools "Bash,Read,Edit"

 

세분화된 권한 패턴

도구 범위를 세밀하게 제어할 수 있다:

패턴 설명 예시
Tool 도구 전체 허용 Read - 모든 파일 읽기
Bash(cmd:*) 특정 명령으로 시작하는 것만 Bash(git:*) - git 명령만
Bash(cmd:sub:*) 특정 서브커맨드까지 제한 Bash(git:diff:*) - git diff만
mcp__server__tool MCP 서버 도구 mcp__memory__store

 

실전 예시: 안전한 커밋 생성

# git 관련 명령만 허용
claude -p "스테이징된 변경사항을 보고 커밋 메시지를 작성해" \
  --allowedTools "Bash(git:diff:*),Bash(git:log:*),Bash(git:status:*),Bash(git:commit:*)"
주의
Bash를 전체 허용하면 모든 셸 명령이 실행될 수 있다. 가능하면 Bash(cmd:*) 패턴으로 범위를 제한하자.

 

파이프 입력 처리

stdin으로 다른 명령의 출력을 Claude에 전달할 수 있다:

기본 파이프

# git diff 결과를 리뷰
git diff | claude -p "이 변경사항을 리뷰해"

# 로그 파일 분석
cat error.log | claude -p "이 에러들의 패턴을 분석해"

# PR diff를 보안 관점에서 검토
gh pr diff 123 | claude -p "보안 취약점을 찾아"

 

시스템 프롬프트와 결합

# 보안 전문가 역할로 코드 리뷰
gh pr diff "$PR_NUMBER" | claude -p "이 PR을 리뷰해" \
  --append-system-prompt "당신은 보안 엔지니어입니다. 취약점에 집중하세요." \
  --output-format json

 

실전 예시: PR 리뷰 자동화

#!/bin/bash
PR_NUMBER=$1

# PR diff를 가져와서 분석
gh pr diff "$PR_NUMBER" | claude -p \
  "이 PR의 변경사항을 분석해. 버그, 보안 이슈, 개선점을 찾아." \
  --output-format json \
  | jq -r '.result' > review.md

# 결과를 PR에 코멘트로 추가
gh pr comment "$PR_NUMBER" --body-file review.md

 

시스템 프롬프트 커스터마이징

Claude의 기본 동작을 조정하는 두 가지 옵션:

옵션 동작 사용 시점
--append-system-prompt 기본 프롬프트에 추가 역할/관점 추가 (권장)
--system-prompt 기본 프롬프트 완전 대체 완전히 다른 동작 필요 시
# 추가 지침 (기본 동작 유지)
claude -p "이 코드를 리뷰해" \
  --append-system-prompt "모든 응답을 한국어로 작성하세요."

# 완전히 새로운 역할 (기본 동작 대체)
claude -p "테스트 케이스를 생성해" \
  --system-prompt "당신은 QA 엔지니어입니다. 엣지 케이스에 집중하세요."
실전 팁
대부분의 경우 --append-system-prompt가 더 낫다. 기본 동작(파일 읽기, 코드 분석 등)을 유지하면서 추가 지침만 제공하기 때문이다.

ex) claude -p "이 코드를 리뷰해" --append-system-prompt "모든 응답을 한국어로 작성하세요."

 

세션 관리

여러 요청에 걸쳐 컨텍스트를 유지할 수 있다:

 

--continue: 마지막 대화 계속

# 첫 번째 요청
claude -p "이 코드베이스의 성능 문제를 검토해"

# 가장 최근 대화 계속
claude -p "이제 데이터베이스 쿼리에 집중해" --continue
claude -p "발견된 모든 문제의 요약을 생성해" --continue

 

--resume: 특정 세션 재개

# 세션 ID 저장
session_id=$(claude -p "리뷰 시작" --output-format json | jq -r '.session_id')

# 나중에 해당 세션 재개
claude -p "그 리뷰 계속해" --resume "$session_id"
실전 팁
CI/CD에서 여러 단계의 작업을 수행할 때 --continue--resume을 활용하면 컨텍스트를 유지하면서 효율적으로 작업할 수 있다.

 

조건부 실행

종료 코드를 활용한 조건부 로직:

#!/bin/bash

# 분석 수행 후 조건부 처리
if claude -p "보안 취약점이 있는지 확인해" --output-format json | jq -e '.result | test("취약점")' > /dev/null; then
    echo "보안 이슈 발견! 빌드 중단"
    exit 1
else
    echo "보안 검사 통과"
fi

 

MCP 도구와 결합

# MCP 도구를 포함한 자동화
claude -p "데이터베이스에서 최근 에러 로그를 분석해" \
  --allowedTools "mcp__postgres__query,Read" \
  --output-format json

 

주요 옵션 요약

옵션 설명
-p, --print 비대화형(Headless) 모드 활성화
--output-format 출력 형식 (text, json, stream-json)
--json-schema 응답을 특정 JSON 스키마로 강제
--allowedTools 도구 자동 승인 (쉼표 구분)
--append-system-prompt 기본 시스템 프롬프트에 추가
--system-prompt 시스템 프롬프트 완전 대체
--continue 마지막 대화 계속
--resume 특정 세션 ID로 대화 재개
--max-turns 최대 대화 턴 수 제한
참고
슬래시 명령 (/commit, /review 등)은 대화형 모드 전용이다. Headless 모드에서는 설명적인 프롬프트를 사용한다.

 

CLI vs Agent SDK

복잡한 통합이 필요한 경우 Agent SDK(Python/TypeScript)가 더 적합할 수 있다:

사용 사례 권장
간단한 스크립트, CI/CD CLI (claude -p)
커스텀 도구, 세밀한 제어 Agent SDK (Python/TypeScript)
애플리케이션 내 통합 Agent SDK (Python/TypeScript)
멀티 에이전트 워크플로우 Agent SDK (Python/TypeScript)

 

300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.

💡 AI 관련 질문이 있나요? 눌러보세요!