자동화 대상은 “어려운 일”이 아니라 “판정이 쉬운 일”입니다
자동화할 업무를 고를 때 난이도부터 보면 대개 실패합니다. 기준은 다른 데 있습니다. 결과가 맞았는지 5초 안에 판정할 수 있는가. 커밋 메시지 초안은 읽으면 바로 압니다. 빌드 에러 원인 요약도 그렇습니다. 반대로 시장 분석이나 전략 제안은 결과가 그럴듯해 보여서 검증에 30분이 걸립니다. 그런 작업은 대화창에서 사람이 옆에 붙어 있는 게 맞습니다.
| 업무 | 판정 시간 | 어디서 돌릴까 |
|---|---|---|
| 변경분에서 오타·깨진 링크 찾기 | 즉시 | 스크립트 |
| 에러 로그에서 원인 한 줄 요약 | 즉시 | 스크립트 |
| 회의록에서 결정사항만 추출 | 짧음 | 스크립트 |
| 코드 리뷰(보안 관점) | 중간 | 스크립트 + 사람 확인 |
| 기획안 작성, 우선순위 판단 | 길다 | 대화창 |
여기서 ‘스크립트’라고 적은 것들은 전부 클로드를 사람처럼 대하지 않고 명령줄 도구처럼 쓰는 작업입니다. 입력을 파이프로 넣고, 출력을 파일이나 다음 명령으로 넘기는 방식입니다.
시작은 -p 한 글자입니다
Claude Code는 기본적으로 대화형 세션을 띄우지만, -p(또는 --print)를 붙이면 대답을 출력하고 바로 종료합니다. 설치된 버전에서 도움말을 그대로 확인하면 이렇게 적혀 있습니다.
$ claude --version
2.1.271 (Claude Code)
$ claude --help
-p, --print Print response and exit (useful for pipes)

이 모드는 표준 입력을 읽습니다. 그래서 다른 명령의 출력을 그대로 넘길 수 있습니다. 공식 문서가 드는 예시가 가장 직관적입니다.
cat build-error.txt | claude -p '이 빌드 에러의 근본 원인만 간단히 설명해줘' > output.txt
파이프로 넣는 입력에는 상한이 있습니다. 10MB를 넘기면 명령이 오류와 함께 0이 아닌 상태 코드로 끝납니다. 큰 파일은 파이프 대신 경로를 알려주고 읽게 하는 편이 맞습니다.
그냥 -p로 실행하면 대화형 세션과 똑같은 맥락을 불러옵니다. 작업 폴더와 ~/.claude의 훅, 스킬, 서브에이전트, MCP 서버, CLAUDE.md까지 전부입니다. 내 컴퓨터에서는 편하지만 CI에서는 재현성이 깨집니다. --bare는 이 자동 탐색을 건너뛰어 어느 기계에서 돌려도 같은 결과가 나오게 합니다. 대신 인증은 구독 로그인이 아니라 ANTHROPIC_API_KEY만 씁니다. 공식 문서는 스크립트와 SDK 호출에는 --bare를 권장하며, 향후 -p의 기본값이 될 예정이라고 밝히고 있습니다.
사람이 읽을 답이 아니라 프로그램이 읽을 데이터를 받습니다
자동화의 갈림길은 출력 형식입니다. 텍스트를 받으면 결국 사람이 읽어야 하고, JSON을 받으면 다음 단계가 자동으로 이어집니다. --output-format은 세 가지를 지원합니다. 기본 text, 한 덩어리로 받는 json, 줄 단위로 흘려받는 stream-json입니다.
실제로 이 사이트 저장소에서 --output-format json을 실행해 받은 응답에 어떤 필드가 들어 있는지만 추려보면 이렇습니다. 값은 자리표시로 두었습니다.
{
"type": "result", "subtype": ..., "is_error": ...,
"result": ..., // 답 본문 또는 실패 메시지
"session_id": ..., "num_turns": ...,
"duration_ms": ..., "duration_api_ms": ...,
"total_cost_usd": 0,
"usage": { "input_tokens": 0, "output_tokens": 0,
"cache_read_input_tokens": ... },
"permission_denials": [...], "modelUsage": { ... }
}
실무에서 바로 쓰게 되는 필드는 네 개입니다. result(답 본문), is_error(성공 여부 분기), session_id(이어서 질문할 때), total_cost_usd(호출별 비용 기록). 특히 마지막 값은 대시보드를 열지 않고도 스크립트가 스스로 지출을 남길 수 있게 해줍니다. 다만 공식 문서는 이 수치가 클라이언트 측 추정치이며 실제 청구와 다를 수 있다고 명시합니다. 사내 정산 근거로 쓰기보다 추세 감시용으로 쓰는 게 맞습니다.
답의 형태까지 고정하고 싶다면 한 걸음 더 갈 수 있습니다. --json-schema에 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'
여기서 주의할 점이 하나 있습니다. 스키마에 "format": "email" 같은 키워드를 써도 Claude Code는 이를 주석으로만 취급하고 강제하지 않습니다. 이메일 형식 검증은 받아온 뒤 직접 해야 합니다.
사람이 없는 시간에 돌리려면 권한을 먼저 잠급니다
자동화에서 가장 흔한 실패는 모델이 답을 못 하는 게 아니라 승인 프롬프트 앞에서 멈춰 서는 것입니다. 새벽 3시에 실행된 작업이 “이 명령을 실행할까요?”에서 대기하고 있으면 그 작업은 없는 것과 같습니다.
-p 실행은 모든 요금제에서 수동(Manual) 모드로 시작합니다. 그래서 원하는 모드를 명시적으로 넘겨야 합니다.
| 설정 | 동작 | 쓰는 상황 |
|---|---|---|
| --allowedTools "Read,Edit" | 지정한 도구만 프롬프트 없이 허용 | 범위가 뚜렷한 단일 작업 |
| --permission-mode dontAsk | 물어봐야 할 건 전부 거부하고 진행 | 잠가둔 CI 실행 |
| --permission-mode acceptEdits | 파일 쓰기와 mkdir·mv 같은 기본 명령 자동 승인 | 린트 수정 같은 편집 작업 |
| --permission-prompts none | 승인 요청을 기다리지 않고 거부한 뒤 계속 | 응답할 사람이 아예 없는 예약 작업 |

도구 이름만 나열하는 대신 명령 단위로 좁힐 수도 있습니다. 공식 문서의 커밋 예시가 이 문법을 잘 보여줍니다.
claude -p "스테이징된 변경을 보고 적절한 커밋을 만들어줘" \
--allowedTools "Bash(git diff *),Bash(git log *),
Bash(git status *),Bash(git commit *)"
괄호 안 * 앞의 공백 한 칸이 의미를 바꿉니다. Bash(git diff *)는 git diff로 시작하는 명령을 허용하지만, 공백을 뺀 Bash(git diff*)는 git diff-index 같은 다른 명령까지 함께 열어버립니다. 권한 규칙을 손으로 적을 때 가장 놓치기 쉬운 지점입니다.
모드별 세부 규칙과 settings.json에서의 deny·ask·allow 우선순위는 Claude Code 권한 설정 글에 따로 정리해 두었습니다.
예약 실행에서 제일 먼저 터지는 건 모델이 아니라 인증입니다
여기가 직접 부딪혀 본 지점입니다. 로그인 자격이 없는 환경에서 -p를 실행하면 명령은 정상적으로 돌아가고, JSON도 정상적으로 나옵니다. 문제는 그 JSON의 내용입니다.
{ "is_error": true,
"subtype": "success",
"terminal_reason": "api_error",
"result": "Not logged in · Please run /login",
"num_turns": 1, "duration_ms": 92 }
이 응답에서 읽어야 할 것은 세 가지입니다. 첫째, subtype은 여전히 "success"입니다. 이 필드만 보고 성공 여부를 판단하는 스크립트는 실패를 성공으로 기록합니다. 둘째, 실제 판정 기준은 is_error와 terminal_reason입니다. 셋째, /login은 터미널 대화 세션에서만 동작하는 명령이라 -p 모드 안에서는 해결할 방법이 없습니다.
정리하면 무인 실행 환경에서는 로그인 세션에 기대지 말고 --bare와 ANTHROPIC_API_KEY 조합으로 고정하는 편이 안정적입니다. 실행 후에는 텍스트 결과만 보지 말고 상태를 분기해야 합니다.
out=$(claude --bare -p "$PROMPT" --allowedTools "Read" --output-format json)
if [ "$(echo "$out" | jq -r '.is_error')" = "true" ]; then
echo "실패: $(echo "$out" | jq -r '.result')" >&2; exit 1
fi
echo "$out" | jq -r '.result'
참고로 잘못된 플래그를 넘긴 경우는 이와 다르게 처리됩니다. 실행이 시작되기도 전에 표준 오류로 에러를 내고, 성공 시 종료 코드 0, 실패 시 0이 아닌 코드로 끝납니다. 즉 플래그 오타는 종료 코드로, 실행 중 실패는 stdout의 JSON으로 잡는다고 기억하면 됩니다.
오늘 바로 붙일 수 있는 작업 세 개
거창한 파이프라인보다 하루에 몇 번씩 반복하는 작업부터 옮기는 쪽이 오래 갑니다.
① 커밋 전 오타 린터변경분을 파이프로 넘기면 파일을 읽을 권한조차 필요 없습니다. package.json의 스크립트로 등록해 두고 npm run lint:claude로 부릅니다. 공식 문서가 이 형태를 예시로 제시합니다.
② 실패한 빌드 로그 요약CI가 실패하면 로그 마지막 200줄만 잘라 넘기고, 결과를 알림 메시지로 보냅니다. 이건 판정이 즉시 되는 대표적인 작업입니다.
③ 보안 관점 PR 리뷰--append-system-prompt로 역할만 덧붙이면 기본 동작을 유지한 채 관점을 바꿀 수 있습니다.
gh pr diff "$1" | claude -p \
--append-system-prompt "당신은 보안 엔지니어입니다. 취약점 관점에서 검토하세요." \
--output-format json
세 작업 모두 공통점이 있습니다. 입력이 파이프로 들어가고, 출력이 짧고, 틀렸는지 바로 보입니다. 반대로 “우리 서비스 개선점을 정리해줘” 같은 작업을 크론에 걸면, 매일 아침 검토해야 할 문서가 한 장씩 쌓이기만 합니다.
여러 작업을 순서대로 이어야 한다면 세션을 이어붙일 수 있습니다. 세션 ID를 받아 두고 --resume으로 넘기는 방식입니다.
session_id=$(claude -p "리뷰 시작" --output-format json | jq -r '.session_id')
claude -p "이제 DB 쿼리만 집중해서 봐줘" --resume "$session_id"
멈추는 법을 먼저 정해둡니다
무인 실행에서 의외로 중요한 건 시작이 아니라 종료 조건입니다. 알아두면 좋은 동작이 몇 가지 있습니다.
| 상황 | Claude Code의 동작 |
|---|---|
| SIGTERM으로 중단 | 종료 코드 143, 진행 중이던 턴은 결과 없이 미완으로 남음 |
| 백그라운드 Bash 작업이 남음 | 최종 결과 반환 후 약 5초 뒤 종료 |
| 백그라운드 서브에이전트가 남음 | 작업이 끝날 때까지 대기, 연속 대기 10분에서 상한 |
| 스트리밍 출력을 느리게 읽음 | 큐가 빠질 때까지 대기, 최대 30초 |
예약 작업에는 별도의 타임아웃을 씌우는 게 안전합니다. 10분 상한은 서브에이전트가 멈췄을 때의 방어선이지, 작업 전체의 실행 시간 제한이 아니기 때문입니다.
흔한 실수
subtype만 보고 성공 판정인증 실패에서도 subtype은 success로 옵니다. is_error를 봐야 합니다.
내 컴퓨터에서만 되는 스크립트--bare 없이 쓰면 내 ~/.claude 설정과 프로젝트 훅이 함께 로드됩니다. 동료 기계에서는 다르게 동작합니다.
권한 규칙의 공백 누락Bash(git diff*)는 의도보다 넓게 열립니다. * 앞 공백을 확인하세요.
비용 필드를 청구액으로 오해total_cost_usd는 클라이언트 추정치입니다. 실제 청구와 차이가 날 수 있습니다.
판정이 오래 걸리는 업무를 크론에검토가 밀리면 자동화가 아니라 숙제가 됩니다. 판정 5초 규칙으로 걸러내세요.
자주 묻는 질문
구독 요금제로도 스크립트 자동화가 되나요?
-p만 쓰는 경우에는 로그인된 세션의 자격을 그대로 사용합니다. 다만 --bare를 붙이면 OAuth와 키체인을 읽지 않으므로 ANTHROPIC_API_KEY가 필요합니다. 재현성이 중요한 CI라면 API 키 쪽으로 가는 게 관리가 쉽습니다.
스킬이나 커스텀 명령도 -p에서 쓸 수 있나요?
프롬프트 문자열 안에 /스킬이름을 넣으면 실행 전에 확장됩니다. 다만 /login처럼 터미널 화면에서만 동작하는 내장 명령은 쓸 수 없습니다. 스킬과 서브에이전트의 차이는 별도 글에 정리했습니다.
n8n 같은 자동화 도구와 무엇이 다른가요?
역할이 다릅니다. n8n은 여러 서비스를 연결하고 일정·재시도·분기를 관리하는 오케스트레이션 쪽이고, claude -p는 그 흐름 안에서 판단이 필요한 한 단계를 처리하는 도구입니다. 둘을 붙여 쓰는 구성이 가장 흔합니다.
설치 버전(v2.1.271), --help 출력, --output-format json 응답 필드와 인증 실패 응답은 2026년 9월 17일 로컬에서 직접 실행해 확인했습니다. 권한 모드·--bare·종료 동작·입력 상한 등 실행으로 재현하지 않은 사양은 Anthropic 공식 문서의 헤드리스 모드 문서를 근거로 했습니다.