Claude Code 공식문서 리뷰-Build with Claude Code[6] : Run Claude Code programmatically
- -
안녕하세요! 갓대희입니다.
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 로그에서 민감한 정보가 노출되지 않는지 확인하자.
- -p 플래그: 대화형 UI 없이 결과만 출력하는 비대화형 모드
- 활용: CI/CD 파이프라인, 스크립트, 자동화 워크플로우
- 출력 형식: text, json, stream-json, json-schema 지원
사용자 입력 없이 스크립트나 자동화에서 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) |
'AI > Claude Code Doc(공식문서) 번역본' 카테고리의 다른 글
당신이 좋아할만한 콘텐츠
-
Claude Code 공식문서 리뷰-Build with Claude Code[8] : Troubleshooting 2025.12.29
-
Claude Code 공식문서 리뷰-Build with Claude Code[7] : Connect Claude Code to tools via MCP 2025.12.28
-
Claude Code 공식문서 리뷰-Build with Claude Code[5] : Output styles 2025.12.28
-
Claude Code 공식문서 리뷰-Build with Claude Code[4] : Agent Skills 2025.12.28
소중한 공감 감사합니다