Claude Code 비대화형 모드 (claude -p) 사용
상세 flag·gotcha의 SSOT는 flag-matrix.md와 gotchas.md이며, 본문은 선택 기준과 성공 계약만 요약한다. 설정 키워드 검색으로 시작하지 말고 의사결정 트리와 성공 계약부터 읽는다 — 이미 문서화된 사실을 시행착오로 재발견한 세션이 다수였다.
작성 기준
- 확인 날짜: 2026-07-10
- 확인 버전: Claude Code v2.1.206
- 재검증:
claude --version && claude --help && claude -p --help - 개별 항목에
재확인: <날짜>, <버전>스탬프가 붙어 있으면 그 스탬프가 위 헤더보다 우선한다 (헤더는 문서 전체를 일괄 재확인한 시점이고, 개별 스탬프는 그 항목만 최신 버전으로 재실측한 시점이다). 2.1.233 런타임 관측 항목의 재검증 명령은echo "ok" | claude -p --model haiku --output-format json이며, 각 항목이 요구하는 추가 플래그는 해당 항목에 함께 적는다. - 버전 warn 시 최소 재검증 세트: 위 help diff + 실행 smoke 3종 (① json 성공 경로 wire shape ② 성공 계약 판정식 ③ help diff에서 변경이 의심되는 개별 항목 — 각 항목이 명시한 호출 형태 그대로). 전면 재확인 없이 헤더만 올리지 않는다.
print 모드는 workspace trust dialog를 생략하고 invalid settings를 조용히 무시할 수 있다 (2.1.206 help). 자동화 전에는 settings를 별도 검증한다.
범위
| 포함 | 제외 |
|------|------|
| claude -p 비대화형 실행 | 대화형 TUI 사용법 |
| --output-format json 파싱 | Claude Code hooks/plugins 설정 |
| harness 셀프테스트 (T1~T8) | Codex CLI 실행 → using-codex-exec |
| SSH 경유 크로스머신 실행 | Codex settings/skill projection (repo 정책/검증 스크립트 참조) |
| 숨겨진 동작 | Python/TS SDK (별도 스킬 분리 대상) |
| 세션 체이닝 (--resume) | |
의사결정 트리
claude -p 실행이 필요한가?
│
├─ 도구 실행이 필요한가?
│ ├─ YES
│ │ 도구를 제한할 필요가 있나?
│ │ ├─ YES, 정밀 allowlist → --allowed-tools "Bash,Read" (stdin 필수!)
│ │ │ ⚠️ --dangerously-skip-permissions와 함께 쓰면 제한 무효
│ │ │ ⚠️ Bash 패턴은 따옴표·공백 민감 (gotchas #36·#46) — 스킬 실행엔 부적합할 수 있음
│ │ ├─ YES, 위험 도구만 차단 → --permission-mode dontAsk + deny 규칙 (hooks·deny 존중)
│ │ │ 또는 --dangerously-skip-permissions + --disallowedTools Write,Edit
│ │ └─ NO → --dangerously-skip-permissions 추가 (전면 우회 아님 — carve-out은 gotchas #43)
│ └─ NO → 기본 실행 (권한 플래그 불필요)
│
├─ 출력을 프로그래밍적으로 파싱할 필요가 있나?
│ ├─ YES → --output-format json (가변 길이 이벤트 스트림 — 이벤트 수는 런마다 다름, 2.1.233 실측)
│ │ 배열/객체를 정규화한 뒤 type=result 탐색 (후행 비-JSON 라인 내성 필수)
│ │ 또는 --output-format stream-json (JSONL; wire shape 재검증 미수행)
│ └─ NO → 기본 text 출력
│
├─ harness 인벤토리를 검증하고 싶다면?
│ └─ --output-format json → init 이벤트 파싱
│ → references/harness-testing.md T1 참조
│
├─ 원격 머신에서 실행해야 한다면?
│ └─ echo "prompt" | ssh host 'claude -p ...'
│ ⚠️ alias 사용 불가, stdin pipe 필수
│ → references/patterns.md 패턴 5 참조
│
├─ 이전 세션을 이어가야 한다면?
│ └─ --resume SESSION_ID
│ → references/patterns.md 패턴 4 참조
│
└─ 결과를 파일에 저장해야 한다면?
└─ shell redirect: > result.txt
⚠️ --output-file / -o 플래그 존재하지 않음
빠른 참조
| 상황 | 명령 |
|------|------|
| 단순 질의 | echo "prompt" \| claude -p |
| 도구 실행 | echo "prompt" \| claude -p --dangerously-skip-permissions |
| harness 인벤토리 | echo "ok" \| claude -p --output-format json → init 파싱 |
| 세션 이어가기 | echo "prompt" \| claude -p --resume SESSION_ID |
| 원격 실행 | echo "prompt" \| ssh host 'claude -p ...' |
| 결과 저장 | echo "prompt" \| claude -p > result.txt |
| 모델 선택 | echo "prompt" \| claude -p --model sonnet |
| 시스템 프롬프트 추가 | echo "prompt" \| claude -p --append-system-prompt "..." |
핵심 Gotchas
<values...>variadic flag 뒤 인라인 프롬프트가 flag 값으로 소비됨:--allowed-tools,--disallowed-tools등은 stdin으로 prompt 전달--max-turns 1은 도구 실행 불가 — 최소 2턴 필요 (v2.1.202 실측; 2.1.206 재검증 미수행 — help에는 없지만 parser 수용 확인)- exit code나
subtype=success하나만으로 성공 판정 금지: exit + subtype/is_error + 기대 산출물 + 진척 delta 확인 --cwd,--output-file플래그 없음:cd dir && claude -p, shell redirect> file사용- SSH alias 미로드: non-login shell에서
calias 사용 불가 →claudefull path 필수 --append-system-prompt는 append — 기존 시스템 프롬프트를 override하지 못함 (v2.1.202 실측; 2.1.206 재검증 미수행)--tools ""로 빌트인을 비활성화해도 MCP는 남음 — MCP 비활성화는 별도 조치 필요 (v2.1.202 실측; 2.1.206 재검증 미수행)- 플러그인 스킬 인식은 설치 시점에 고정 — 캐시 수정·symlink·브랜치 변경 대신 stdin 주입 또는 재설치 (v2.1.202 실측; 2.1.206 재검증 미수행)
- 커스텀 환경변수는 명시적으로 전달 —
.env는 자동 로드되지 않으므로VAR=val claude -p사용 (v2.1.202 실측; 2.1.206 재검증 미수행) - piped stdin 상한은 10MB (공식 headless 문서 계약) — 발사 전
wc -c게이트로 자르고, 초과분은 파일에 쓰고 경로를 프롬프트에서 참조한다 (gotchas #40)
전체 목록: references/gotchas.md
셸 transport 계약
- stdout, stderr, 업무 산출물을 분리 보관한다. JSON parser 앞
2>&1은 stderr를 섞어 파싱을 깨뜨린다. - pipeline은
set -o pipefail을 사용한다. zsh에서 Claude 자체 exit가 필요하면 pipeline 직후claude_rc=$pipestatus[2]로 보존한다. | head,| tail, 뒤이은; echo $?는 원래 exit를 가릴 수 있으므로 판정 경로에서 제외한다.
호출 상한 (Bash tool 경유)
Claude Code 하네스의 Bash tool로 claude -p를 발사할 때는 하네스 상한이 실질 상한이다.
수치·계약의 SoT는 using-codex-exec execution-contracts.md "foreground/background 상한 불일치" 절이다
(그 절이 명시하듯 claude -p headless에 공통 적용). 이 절은 수치를 복제하지 않는다 — 규칙만 적는다.
- 안쪽 예산(wrapper·SSH
timeout등)이 하네스 상한보다 길면 하네스 timeout이 먼저 발화한다 (반대로 안쪽이 더 짧으면 그쪽이 먼저 발화한다). timeout 파라미터에 상한 초과값을 줘도 거부되지 않지만 실효 상한은 하네스 최대치로 클램프된다. - 상한 도달의 처리와 그때의 결과 회수 계약은 하네스 버전에 따라 갈린다 — background 자동 전환이면 작업이 완주하고 완료 알림이 오지만, 프로세스 종료면 알림이 없고 이미 파일로 영속화된 산출물만 남는다. 두 동작의 관측·회수 계약 표와 재현 절차는 using-codex-exec execution-contracts.md의 같은 절이 정본이다. 어느 쪽이든 foreground 응답은 그 시점에 끊기므로 결과는 stdout이 아니라 파일로 받는다.
- 동일 응답에서 여러 foreground Bash 호출을 발사해도 병렬이 아니라 직렬 실행된다
(재확인: 2026-08-15, v2.1.233 — 3초 작업 4개가 0.0→3.0, 3.1→6.1, 6.2→9.2, 9.3→12.3초로
순차. 재현: 한 응답에서 시작·종료 시각을 파일에 기록하는 짧은 CPU 작업 4개를 foreground로
발사하고 시작 시각의 분산을 본다 — 모델 호출 0). fan-out 예산은 합산해야 하며, 실제 병렬은
run_in_background: true뿐이다. - 수 분 이상 걸릴 수 있는 호출은 Bash tool
run_in_background: true로 발사한다. 완료 알림의 exit code는 claude가 아니라 래핑 셸의 최종 rc다 —rc 캡처 → .rc 파일 영속화 → exit $rc로 끝낸다 (using-codex-exec execution-contracts.md "background 발사의 rc 계약"과 동일 규약; 꼬리 echo/cat을 두면 전건 실패도 completed로 통지된다). - foreground
sleep은 하네스가 차단한다 (Blocked: sleep ...실측) — 대기는 Monitor until-loop 또는 run_in_background 완료 알림으로 한다. - Bash tool 호출 사이에 셸 변수·함수·
trap EXIT는 소멸한다 — 경로·상태는 파일로 영속화한다. - 하네스 timeout으로 잘린 호출은 명령 말미의 in-band 계약 검사(
_EC=$?; ...후속 라인)까지 함께 사라진다 — 판정은 별도 호출(out-of-band)로 재확인한다. - 용어 구분 3종: CLI 플래그
--background/--bg(background agent 시작) ≠ Bash toolrun_in_background파라미터 ≠ 하네스의 foreground→background 자동 전환(foreground 상한 도달이 트리거). 자동 전환되면 stdout 직수신 전제가 깨지므로 결과는 항상 파일로 받는다. 단 자동 전환 자체는 실패가 아니다 — 그 경로에서는 작업이 계속되고 완료 알림이 온다 (종료 경로와의 차이는 위 SoT 표 참조).
성공 계약
claude -p --output-format json 완료는 다음 조건을 모두 만족해야 한다.
- process exit가 0이다.
type=result이벤트가 있고subtype=success,is_error=false다. 보조 축 (2.1.233 실측 — 같은 result 이벤트에서 무료로 얻는다):terminal_reason이completed가 아니면 비정상 종료,permission_denials가 비어 있지 않으면 exit 0이어도 도구가 차단된 것이다 (gotchas #3의 프로그래밍적 탐지 — "도구 거부는 exit로 못 잡는다" 갭을 이 필드가 메운다).- 파일 생성을 요구한 작업은
test -s "$RESULT"를 통과하고 기대 완료 표식이 있다 — 단 이 판정은 종료 후에만 한다. json 출력은 완료 시 일괄 기록이라 실행 중 0바이트는 실패 신호가 아니다 (gotchas #48). - 반복 pass는 직전 결과 대비 새 finding·수정·판정 같은 진척 delta가 있다.
성공 경로의 이벤트 스트림은 가변 길이다 (2.1.233 실측: 같은 버전·같은 플래그·같은 모델에서도
thinking_tokens 이벤트 수에 따라 런마다 다름 — 특정 이벤트 개수를 기대하는 파서 금지).
help는 json (single result), 공식 문서는 result 필드를 가진 단일 객체를 예시하지만 실측
런타임은 top-level 배열이다 — 어느 쪽도 가정하지 말고 배열/객체를 정규화한 뒤 type=result를
찾는 파서가 유일 경로다. stdout 말미에 비-JSON 경고 라인이 간헐 혼입되므로(MCP 구성 의존,
2.1.233 실측) 파서는 첫 JSON 문서만 취하되, 그래도 파싱이 실패하면 raw를 조용히 흘리지 말고
non-zero로 죽어야 한다. 반대로 auth 실패 경로는 subtype:success, is_error:true, exit 1도
가능했다. 산출물 0개인데 success인 실전 사례가 있으므로 진척 없는 pass가 연속되면 circuit
breaker로 중단한다. child에게 같은 collector/fan-out을 다시 생성시키지 않는다.
SSH 크로스머신 요약
# ✅ 유일한 안정 패턴: stdin pipe
echo "hostname 실행 결과만 출력해" | ssh minipc 'claude -p --dangerously-skip-permissions'
# ❌ 피해야 할 패턴: 3중 중첩 quote
ssh minipc 'zsh -li -c "c -p \"...\""' # → unmatched quote
- SSH non-login shell에서 alias 미로드 →
claudefull path 필수 - 3중 중첩 quote 지옥 → 파일 기반 stdin pipe가 유일한 안정 패턴
- 무출력 약 10분 뒤 완료된 실측이 있다. 무출력만으로 중단, 프로세스 생존만으로 정상이라 판정하지 않는다.
- outer timeout과
ServerAliveInterval을 적용하고 종료 뒤test -s로 산출물을 확인한다.
상세: references/patterns.md 패턴 5
Harness 셀프테스트 요약
--output-format json의 init 이벤트로 harness 구성요소를 자동 검증한다.
| 테스트 | 목적 | 비용 |
|--------|------|------|
| T1 | init 인벤토리 (skills/tools/MCP/plugins 수) | ~$0.07 |
| T2a | 스킬 등록 spot check | ~$0 (T1 재사용) |
| T2b | 스킬 발동 회귀 (positive/negative 대조) | 호출 2회 (haiku) |
| T3 | hooks 파일 존재/실행 가능 여부 | $0 |
| T4 | MCP 서버 init 등록 확인 | ~$0 (T1 재사용) |
| T5 | 권한 모델 (차단/허용) | ~$0.14 |
| T6 | SSH 크로스머신 실행 | ~$0.07 |
| T7 | 세션 체이닝 (--resume) | ~$0.14 |
| T8 | 동시 실행 안정성 | ~$0.14 |
상세 코드 및 판정 로직: references/harness-testing.md 비용 수치는 재검증 미수행 (v2.1.202 기준 서술 유지).
하지 말아야 할 패턴
| 금지 패턴 | 발생 에러 | 올바른 대안 |
|-----------|----------|------------|
| --allowed-tools "Bash" "prompt" | 프롬프트가 도구 이름으로 파싱 | stdin pipe 사용 |
| --dangerously-skip-permissions + --allowed-tools | allowlist 구조적 무효 | 제한 필요: allowed-tools + stdin / 제한 불필요: skip 단독 |
| --max-turns 1 + 도구 실행 기대 | exit 1 + subtype=error_max_turns + is_error:true (2.1.233 실측 — 메시지는 stderr가 아니라 stdout/result.errors[]) | --max-turns 2 이상 |
| exit 또는 subtype=success 하나로 성공 판정 | 무산출물·auth 실패 오판 | 성공 계약 네 조건 확인 |
| JSON parser 앞 2>&1 | stderr 혼입으로 파싱 실패 | stdout/stderr/산출물 분리 |
| 판정 pipeline 끝의 head/tail/; echo $? | 원 exit 은폐 | pipefail과 즉시 exit 보존 |
| SSH에서 c -p alias | command not found | claude -p full path |
| 3중 중첩 quote (SSH) | unmatched quote | stdin pipe 패턴 |
| --verbose/--debug로 디버그 | stderr 출력 없음 | --debug-file 사용 |
| 플러그인 캐시 디렉토리 수동 수정 | 인식 안 됨 (설치 시점 인덱싱) | SKILL.md stdin 주입 (패턴 9) |
| child가 같은 collector를 다시 생성 | 무한 자기증식 | 오케스트레이션은 부모 1계층에서만 수행 |
참조
- 숨겨진 동작: references/gotchas.md
- 사용 패턴: references/patterns.md
- 셀프테스트 T1~T8: references/harness-testing.md
- 플래그 호환성 매트릭스: references/flag-matrix.md
문서와 CLI 동작이 다를 때는 CLAUDE.md의 "스킬 문서 불일치 시 행동 원칙"을 따른다. help는 공개 surface의 SSOT다. help에 없는 hidden flag의 제거 여부는 실행 smoke로만 판정한다.