[Claude Code 스킬] 헤드리스 모드(claude -p) — 대화창 없이 스크립트·CI에서 돌리기 | DAKER 커뮤니티
터미널에 뜨는 대화창은 Claude Code의 본체가 아니라 껍데기다. -p 플래그 하나면 그 껍데기를 벗기고, 같은 에이전트 루프를 셸 파이프라인 한 칸으로 쓸 수 있다.
무엇
claude -p "질문"(--print)는 대화형 TUI를 띄우지 않고 프롬프트 하나를 처리한 뒤 결과를 stdout에 찍고 종료한다. 도구·에이전트 루프·컨텍스트 관리는 대화형과 동일하고, 사라진 것은 화면과 사람뿐이다.
성공하면 종료 코드 0, 실패하면 0이 아닌 값을 돌려주므로 셸 스크립트가 if로 분기할 수 있다. 즉 Claude가 grep이나 jq처럼 다른 명령어들 사이에 끼어드는 하나의 유닉스 도구가 된다.
가장 큰 차이는 승인 주체다. 대화형에서는 권한 팝업을 사람이 눌렀지만, 헤드리스에는 누를 사람이 없다. 승인은 실행 전에 플래그로 미리 줘야 하고, 주지 않으면 도구를 쓰려는 순간 실패한다.
언제 쓰나
CI/CD 파이프라인 — PR diff 리뷰, 타이포 린터, 보안 점검처럼 사람이 앉아 있을 수 없는 자리
cron·스케줄러 — 매일 아침 변경 사항을 요약해 메일로 보내는 류의 반복 작업
빌드 스크립트 안 —
package.json의 스크립트 한 줄로 프로젝트 전용 린터 만들기파이프라인 중간 단계 — 로그를 stdin으로 흘려 넣고 설명을 파일로 받기
반대로 맞지 않는 자리도 분명하다. 실행 도중 사람의 판단이 필요한 작업(“이 테이블 지워도 될까요?”), 프로세스 재시작을 견뎌야 하는 장시간 에이전트, 여러 이슈를 동시에 처리하며 브랜치를 나눠 써야 하는 작업은 -p 대신 백그라운드 세션(--bg)이나 별도 오케스트레이션이 맞다. -p는 프롬프트 하나 들어가고 결과 하나 나오는 단발 프로세스다.
사용법
# 1) 가장 단순한 형태 — 물어보고 답만 받는다
claude -p "auth 모듈이 하는 일을 요약해줘"
# 2) 파이프로 넣고 파일로 받기 (stdin은 10MB 상한)
cat build-error.txt | claude -p '이 빌드 에러의 근본 원인만 간결히 설명' > output.txt
# 3) 스크립트가 파싱할 수 있게 JSON으로
claude -p "이 프로젝트를 요약해줘" --output-format json | jq -r '.result'--output-format은 결과를 무엇으로 받을지 정하는 스위치다. 세 값의 성격이 뚜렷이 다르다.
출력 모양까지 못 박고 싶다면 --json-schema로 스키마를 건네면 된다. 결과는 structured_output 필드에 스키마대로 담겨 온다.
claude -p "auth.py의 주요 함수 이름을 뽑아줘" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
| jq '.structured_output'CI에서 실제로 쓰는 형태는 아래에 가깝다. 브레이크를 먼저 달고 출발하는 셈이다.
claude --bare -p "$PROMPT" \
--allowedTools "Read,Grep,Bash(git diff *)" \
--permission-mode dontAsk \
--max-turns 40 \
--max-budget-usd 2 \
--output-format json > result.json 2> claude.err대화를 이어가야 한다면 첫 실행에서 session_id를 받아 두고 다음 호출에서 --resume으로 되짚는다. 같은 디렉터리에서 실행해야 세션을 찾는다.
session_id=$(claude -p "코드 리뷰 시작" --output-format json | jq -r '.session_id')
claude -p "이제 DB 쿼리에 집중해줘" --resume "$session_id"팁
1. CI에서는 --bare를 기본값처럼 붙인다. 훅·스킬·플러그인·MCP 서버·자동 메모리·CLAUDE.md 자동 탐색을 통째로 건너뛰어 시작이 빨라지고, 무엇보다 어느 기계에서 돌려도 같은 결과가 나온다. 동료의 ~/.claude에 있는 훅이나 프로젝트의 .mcp.json이 몰래 끼어들지 않기 때문이다. 다만 bare 모드는 OAuth·키체인을 읽지 않으므로 ANTHROPIC_API_KEY가 필요하다. 공식 문서는 이 모드를 스크립트·SDK 호출의 권장값으로, 그리고 향후 -p의 기본값이 될 예정이라고 밝히고 있다.
2. --allowedTools 패턴에서는 공백 한 칸이 보안 경계다. Bash(git diff *)는 git diff로 시작하는 명령을 허용하지만, 공백을 뺀 Bash(git diff*)는 git diff-index까지 함께 열어준다. 좁게 쓸수록 안전하다.
3. 진행 상황을 실시간으로 보고 싶으면 --output-format stream-json --verbose --include-partial-messages를 조합한다. 한 줄이 이벤트 하나이고, 마지막 한 줄은 항상 result 이벤트라 비용(total_cost_usd)과 세션 ID를 여기서 거둬들이면 된다.
4. -p 안에서도 스킬과 커스텀 커맨드는 살아 있다. 프롬프트 문자열에 /skill-name을 넣으면 Claude Code가 실행 전에 펼쳐 준다. 반면 /login처럼 터미널 UI 전용 커맨드는 쓸 수 없다.
5. 백그라운드 프로세스는 알아서 정리된다. -p 실행 중 Claude가 띄운 dev 서버 같은 백그라운드 Bash는 최종 결과 반환 뒤 약 5초의 유예를 두고 종료된다. 예전처럼 끝나지 않는 프로세스가 호출 전체를 붙잡고 있지 않는다.