---
title: "클로드코드 자동화 : 외부 스케줄러 + 헤드리스 모드"
description: "정의 한 줄을 외부 스케줄러가 주기적으로 호출하는 구조다. 운영체제 cron, Node의 node-schedule, GitHub Actions cron, Kubernetes CronJob 어디든 붙는다. 빌트인 루틴과 달리 인프라를 직접 들고 있어야…"
date: 2026-05-03
updated: 2026-05-03T13:15:01.466Z
tags: [클로드, 클로드코드, claude, claude code, 스케줄러, scheduler]
canonical: https://blog.wooncloud.com/posts/5
---

## 정의

`claude -p "프롬프트"` 한 줄을 외부 스케줄러가 주기적으로 호출하는 구조다. 운영체제 cron, Node의 node-schedule, GitHub Actions cron, Kubernetes CronJob 어디든 붙는다. 빌트인 루틴과 달리 인프라를 직접 들고 있어야 한다.

## 헤드리스 모드란

`-p` (또는 `--print`) 플래그로 Claude Code를 비대화형으로 실행하는 모드다. 터미널 세션 없이 프롬프트를 받아 한 번 실행하고 종료한다. stdin 입력, stdout 출력, JSON 포맷 지원이라 유닉스 파이프와 그대로 합쳐진다.

```bash
claude -p "어제 커밋 요약해줘"
cat error.log | claude -p "이 에러의 근본 원인을 짧게 설명"
claude -p "@src/auth.ts를 async/await로 리팩터" --output-format json
```

`--allowedTools`로 도구를 화이트리스트하고, `--max-turns`로 루프 길이를 제한하고, `--dangerously-skip-permissions`로 권한 프롬프트를 끈다.

## 왜 직접 짜나

빌트인(/loop, 루틴)이 있는데도 이 방식을 고르는 이유는 세 가지다.

**사내망 접근.** 회사 DB, 사내 API, VPN 안쪽 리소스를 건드려야 하면 클라우드 루틴은 못 쓴다. 사내 서버에서 cron이 도는 게 답이다.

**데이터 통제.** 코드와 로그를 외부 인프라에 올리지 않고 끝내고 싶을 때.

**기존 인프라 재사용.** 이미 Jenkins, Airflow, GitHub Actions, 사내 스케줄러가 있으면 거기 한 줄 추가하는 게 새 시스템 도입보다 싸다.

## 가장 단순한 형태: cron

```bash
# crontab -e
0 9 * * * /usr/local/bin/claude -p "어제 PR들 리뷰 요약" >> /var/log/claude-daily.log 2>&1
```

세 줄이면 끝난다. 다만 cron은 환경변수를 안 읽어오니 `ANTHROPIC_API_KEY`와 PATH를 crontab 안에 직접 박아야 한다. 이게 첫 시도에서 가장 자주 깨지는 지점이다.

## 한 단계 위: Node 스케줄러

node-schedule, BullMQ, Agenda를 쓰면 큐, 재시도, 동시성 제어, 분산 락이 따라온다. cron 한 줄로는 못 푸는 운영 요건이 생기면 여기로 올라간다.

```js
import schedule from 'node-schedule';
import { execSync } from 'child_process';

schedule.scheduleJob('0 */1 * * *', () => {
  const out = execSync('claude -p "신규 이슈 트리아지" --output-format json');
  // 결과를 DB에 적재, Slack에 전송, 다음 잡으로 체이닝
});
```

ClaudeOps가 정확히 이 패턴이다. 스케줄러가 깨워서, 에이전트가 REST API로 할 일을 받아오고, 끝나면 자동 커밋한다.

## 출력 처리: JSON 포맷

`--output-format json`을 쓰면 결과·세션 ID·토큰 사용량·소요시간이 구조화된 객체로 나온다. 그대로 jq로 자르거나 다음 단계로 넘기면 된다.

```bash
claude -p "버그 찾아줘" --output-format json | jq '.result'
```

`stream-json`은 토큰을 스트리밍으로 받아 실시간 로깅·관측에 쓴다.

## 운영 시 유의점

**비용 통제가 1순위다.** 새벽 3시에 40개 PR을 도느라 토큰 폭주해도 사람이 못 본다. `--max-turns`로 캡, 워크플로별 토큰 한도, 주간 누적 알람 — 이 셋은 운영 시작 전에 깔아야 한다.

**프롬프트 인젝션을 가정하라.** PR 본문, 이슈 코멘트, 사용자 입력이 프롬프트에 들어가면 그건 untrusted다. 권한 도구를 좁히고, 위험한 명령은 사람 승인 게이트를 둔다.

**컨텍스트는 매번 fresh다.** 헤드리스는 세션 상태가 없다. 필요한 정보는 프롬프트나 파일로 매번 넣어야 한다. 운구름님이 ClaudeOps에서 progress 파일·git history로 인수인계하는 구조가 이걸 푸는 정석이다.

**`--dangerously-skip-permissions`는 격리 환경에서만.** 검증 끝난 프롬프트, 컨테이너나 CI 러너 안에서, 도구 화이트리스트와 함께 쓴다.

## /loop·루틴과의 차이

같은 "스케줄 자동화"여도 책임 경계가 다르다.

| | /loop·루틴 | 외부 스케줄러 + 헤드리스 |
|---|---|---|
| 실행 인프라 | Anthropic | 직접 |
| 사내망 접근 | 제한 | 자유 |
| 데이터 위치 | Anthropic 클라우드 | 자기 서버 |
| 운영 책임 | Anthropic | 본인 |
| 비용 모델 | 구독 한도 차감 | API 토큰 + 인프라비 |
| 셋업 시간 | 분 단위 | 시간~일 단위 |
