Away Run (무인 실행)
운영자가 자리를 비운 동안, 대기열(queue)이 처리됩니다. 각 항목은 새로운 무인(headless) 프로세스에서 실행되므로, 사용량 제한이나 충돌이 발생해도 전체 실행이 중단되지 않고 해당 항목 하나만 손실됩니다. 상태는 실행 폴더(run folder)의 디스크에 저장되며, 프로세스 종료가 /clear를 대체합니다. claude -p 용 플래그 사실(Flag facts)은 headless-claude 스킬에 있습니다.
저장소 구성 및 프로필. <repo>/.claude/project-workflow.json은 선택 사항입니다. 이 스킬은 projects_dir (기본값 my-projects), profile (기본값 <projects_dir>/WORKFLOW.md), backlog_file (기본값 <projects_dir>/backlog.md) 및 bootstrap (argv 목록 또는 null) 키를 읽습니다. 프로필이 존재하는 경우 해당 파일의 § Away run 섹션을 읽습니다: 테스트 명령, 발견(discovery) 소스, 자동 허용 클래스. 이 스킬과 프로필이 다른 경우 프로필이 우선합니다.
단계 — 해당 단계 진입 시 하나의 파일 로드
| 단계 | 담당자 | 읽을 파일 |
|---|---|---|
| arm | 운영자 | 아래 § Arm, 이후 대기열 구축을 위한 discover.md |
| iteration | away-orchestrator, 프로세스당 하나 | iteration.md |
| status, disarm | 운영자 | 아래 § Status, § Disarm |
project-workflow와 away-run은 호출이 아닌 파일(백로그 파일, <projects_dir>/proposals/open/)을 공유합니다. 단, project 행은 Skill 도구를 통해 무인 모드에서 /project-workflow를 호출합니다.
프로젝트 웨이브는 여러 개의 project 행과 하나의 wave.md § Session shape 단계 그룹(1; 2-3; 4-7)으로 구성됩니다. 각 행은 ## Resume 이름이 지정하는 단계부터 해당 그룹의 끝까지 작업하고, chore(<NNNN>): checkpoint wave N at step <n> 형식으로 커밋하며, 경계에 도달하지 않은 경우 다음 단계를 위한 후속 행을 추가합니다. 행은 하나의 단계라도 완료한 경우에만 attempts 0으로 후속 행을 하나 추가합니다. 단계를 하나도 완료하지 못한 행은 claimed 상태로 유지되며 자체 attempts 카운터로 재시도합니다. 이는 종료가 보장됩니다: 각 후속 행은 웨이브의 7개 단계 중 적어도 하나를 따르며, attempts 상한은 완료되지 않는 단계를 종료시키기 때문입니다. 체크포인트와 ## Resume이 유일한 핸드오프(hand-off)입니다(iteration.md § 3).
레이아웃
<repo>-worktrees/away-<date>/ worktree, branch away/<date> off main
<run folder>/ tracked on away/<date>; arm.ps1 -RunFolder,
queue.md decisions.md log.md default <projects_dir>/away/<date>/
morning-report.md written by the close-out iteration
<repo>-worktrees/away-<date>-run/ scratch, untracked: away.env, watchdog.sh,
entry-prompt.md, watchdog.log, iter-NNN.*, locks
scheduled task away-<repo>-<date> every 15 min until the hard stop
대기열 행(Queue rows)
templates/queue.md에 스키마가 있습니다. 열(Columns): id | item | agent | status | claimed_by | lease_until | attempts | evidence. agent는 mechanical-worker, stream-worker, researcher, project 또는 discover 중 하나입니다. 모든 대기열 편집은 잠금(lock)을 획득해야 합니다: mkdir <scratch>/queue.lock (원자적; 실패 시 10초마다 2분간 재시도; 마지막 수정 후 10분이 지난 잠금 폴더는 owner 파일 유무와 관계없이 스테일(stale)로 간주하여 제거), 편집, rm -rf 잠금. 2분 재시도에 실패했을 때의 처리는 iteration.md § 2 및 § 4에 있습니다. 클레임(claim)은 claimed_by를 해당 iteration의 클레임 태그(iter-NNN, entry-prompt가 제공하는 그대로)로 설정하고 lease_until을 설정합니다. 임대(lease)가 만료되면 데드 iteration을 의미하며 해당 행은 attempts를 1 증가시키고 다시 클레임 가능해집니다.
Arm (운영자 참석)
- 대기열.
discover.md를 사용하여 구축합니다: 티어-1 행만 포함하며, 각각 명명된 검사(named check)가 있어야 합니다. 티어-2 작업은 제안(proposal)이 됩니다. 행이 도달할 수 있는 모든 결정(decision)에 대한 기본값(default)을 지정합니다. 열린 결정(open decision)과 기본값이 없는 행은 대기열에 포함되지 않습니다. - 자세(Posture). 명확히 말합니다: 실행은
--permission-mode bypassPermissions를 사용하므로 모든 도구 호출이 프롬프트 없이 실행됩니다. 전역 거부 규칙은 여전히 적용됩니다. "게이트 없음(No gates)" (열린 질문이 명명된 기본값이 되고, 실패는 건너뛰고 재시도)은 실행별로 옵트인(opt-in)이며, 대기열 헤더에gates: none으로 설정합니다. 이전 실행에서 추론하지 않습니다. - Arm. 먼저 건식 실행(dry run)한 다음, PowerShell에서 실제 실행합니다:
powershell -NoProfile -File <skill>/arm.ps1 -Repo <path> -StopAt "<YYYY-MM-DD HH:MM>" -Queue <queue.md> -WhatIf. 이 스크립트는main에서away/<date>브랜치로 워크트리를 만들고,templates/에서 실행 폴더를 초기화하여 대기열과 함께 커밋하고, 구성의bootstrapargv ({worktree}는 워크트리 경로로 대체, cwd는 메인 체크아웃; 키가 없거나 null이면 건너뜀)를 실행하고 완료를 기다린 후,watchdog.sh와entry-prompt.md를 스크래치(scratch) 영역에 복사하고,away.env를 작성하며, 작업을 등록합니다(Register-ScheduledTask,schtasks /Create사용 금지: PowerShell 5.1은/TR인용(quoting)을 망가뜨림). 부트스트랩의 0이 아닌 종료 코드는 작업이 생성되기 전에 거부됩니다. 이 경우 워크트리와 브랜치는 검사를 위해 남아 있습니다. 작업에는 보안 주체(principal)가 없으므로 운영자가 로그온한 상태에서만 실행되며, 콘솔 창을 닫으면 종료됩니다: 화면을 잠그고 로그오프하지 마십시오. - 확인.
Get-ScheduledTask -TaskName 'away-*'로 작업을 확인합니다. 첫 번째 실행은watchdog up을watchdog.log에 기록합니다. - 이후 대기열 편집. arm.ps1은 대기열을 한 번 커밋합니다. 준비(arming) 후에 이루어진 대기열 편집은 직접
away/<date>브랜치에 커밋하십시오 (작업이 실행된 후 대기열 잠금 하에): iteration은 자신이 만들지 않은 커밋되지 않은 작업을 다른 사람의 작업으로 간주하고 스테이징하지 않습니다.
감시 프로세스(watchdog)의 역할 (watchdog.sh)
- 표준 입력(stdin)으로 프롬프트를 받아
claude -p --agent away-orchestrator --max-turns N을 실행합니다. 모델과 노력(effort)은 에이전트 frontmatter에서 가져옵니다.--effort없음, TTL 플래그 없음,--disable-slash-commands없음 (Skill을 비활성화함). is_error/api_error_status와queue.md변경 여부로 iteration을 판단하며,num_turns는 사용하지 않습니다. 대기열 변경 없이 3회 연속 iteration이 발생하면 종료합니다.- 사용량 제한: 메시지에 명시된 재설정 시간까지 대기합니다. "Opus 한도에 도달했습니다" 메시지가 뜨면
mechanical-worker행에 대해서만--model sonnet으로 Sonnet 모델을 계속 사용합니다. 클레임 가능한mechanical-worker행이 없으면 재설정 시간까지 대기합니다. - 예산 초과(
subtypeerror_max_budget_usd,kindbudget): 대기하지 않습니다. 상한은 프로세스별로 적용되기 때문입니다. 해당 행의 클레임을 유지하므로, 다음 iteration은 다음 행을 처리하고, 이 행은 임대가 만료되면 반환됩니다. 초과 횟수는 오류와 마찬가지로FAIL_MAX에 포함됩니다. - 할당량 예비(Quota reserve): 최근 5시간 동안의 예상 지출액이
WINDOW_CAP_USD에 도달하면, 할당량이 해제될 때까지 대기합니다. 마지막RESERVE_MIN분은 마무리(close-out)를 위해 예약됩니다. - 대기열이 비어 있음: 한 번의 마무리 iteration이 아침 보고서를 작성한 후 종료됩니다. 다른 모든 종료는 감시 프로세스가 작성한 스텁 보고서(stub report)를 남깁니다. 모든 종료 시
STOP파일을 작성하므로 이후 작업 실행은 아무것도 하지 않습니다.STOP을 삭제하면 재개됩니다. - 각 항목 iteration 후, 해당 iteration의 클레임 태그 아래에 있는 임대를 만료시켜, 제한이나 오류로 중단된 행이 마무리될 때까지 방치되지 않고 재시도되도록 합니다. 이 작업은 아무것도 클레임하지 않는 마무리 iteration 이후와 위의 예산 초과 이후에는 건너<0xEB><0x99><0x84>니다.
- 각 iteration 시작 시
claude: <path>를 기록합니다: 실행할 바이너리 경로입니다. main브랜치, 메인 체크아웃, 또는away/*가 아닌 브랜치에서 실행을 거부합니다.- 건식 실행(dry run):
CLAUDE=<stub script> AWAY_NO_SLEEP=1 bash watchdog.sh <away.env>를away/*브랜치의 스크래치 워크트리에서 실행합니다. 대기(sleep)는 기록되지만 실제로 수행되지는 않습니다. 환경에CLAUDE또는PY가 설정되어 있으면away.env에 지정된 것보다 우선하므로, arm이 작성한away.env가 있어도 스텁이 실행됩니다. 로그의claude: <stub>줄로 확인합니다.
상태 확인(Status)
<scratch>/watchdog.log를 확인합니다. queue.md를 읽습니다. "다른 감시 프로세스가 살아있다"는 것을 신뢰하기 전에 claude.exe 프로세스(tasklist)와 최근의 iteration N starting 로그 줄을 확인하십시오: 고아 잠금(orphaned lock)은 모든 작업 실행을 조용히 차단합니다. Git Bash에는 pgrep이 없습니다.
해제(Disarm)
powershell -NoProfile -File <skill>/disarm.ps1 -Repo <path> -Date <date>: STOP 파일을 쓰고, 작업을 등록 해제(unregister)한 후 Get-ScheduledTask -TaskName 'away-*'가 아무것도 반환하지 않는지 확인합니다. 등록된 작업이 남아 있으면 15분마다 bash를 계속 생성합니다. 워크트리와 브랜치는 검토를 위해 남아 있습니다: 아침 보고서를 읽은 후, 저장소의 일반적인 방법으로 away/<date> 브랜치를 병합하거나 삭제합니다.
이렇게 구축한 이유
- 복원력은 CLI 외부에 있습니다.
CronCreate durable:true는 세션 전용으로 돌아왔습니다(2026-09-19)./loop는 동일한 세션에 재진입합니다. Bash 도구 호출의nohup … &는 해당 셸의 자식 프로세스입니다. Git Bash에는setsid가 없습니다. - 사용량 제한은 증가하는 백오프(backoff)가 아니라 메시지에 명시된 재설정 시간까지 대기하며, 낮은
num_turns로 iteration이 실패한 것으로 판단하지 않습니다. 백오프는 재설정 시간을 초과할 수 있고, iteration은 한 번의 보고된 턴(turn)으로 행을 종료할 수 있기 때문입니다.