Harness Internals — Execution Modes

같은 엔진,
다른 실행 기계

auto-issue 헤드리스 워커와 대화형 Claude Code 세션은 동일한 user scope 기계 위에서 돈다. hook pipeline · spawn · teammate · subagent · skill 다섯 축을 user/project scope 레벨에서 실측 비교하면, 분기는 정확히 세 곳에서 난다.

전제 — 둘 다 같은 user scope 기계 위에서 돈다

~/.claude의 훅·규칙·스킬·플러그인은 프로세스 종류를 가리지 않는다. 대화형 세션도 헤드리스 워커도 같은 기반을 로드하며, 차이는 전부 그 위층 — project scope의 획득 경로 — 에서 시작된다.

54user scope hooks
16hook events
~125skills 목록 주입
3분기 지점
실행 기계 스택 — user scope는 공유, project scope에서 분기 대화형 세션 project scope = cwd의 .claude/ (있으면) 실측 hugh-soft: settings.json 없음 → hook 0개 auto-issue 워커 project scope = 워크트리 .claude/ (설치됨) 실측 워크트리: hooks + settings.json 풀셋 동일 로드 동일 로드 USER SCOPE — ~/.claude settings.json hooks 54개 · 16 events · CLAUDE.md + rules 주입 · skills ~125 · plugins/MCP 모든 Claude Code 프로세스에 동일 로드 — 여기에는 차이가 없다 실측 2026-07-31~08-01 · ~/.claude/settings.json · bs-hanyang 워크트리 group-310-311-312
동일한 user scope 기반 위에서 project scope 획득 경로만 갈린다 — 대화형은 cwd에 있으면 로드, 워커는 부트스트랩이 워크트리에 설치한다.
같은 훅, 다른 발화 프로파일

16개 이벤트는 양쪽 모두 존재한다. 다른 것은 발화 빈도실패 완화 장치의 위치다 — 대화형은 턴마다 주입이 반복되고, 워커는 단 한 번의 프롬프트에 모든 주입이 실린다.

이벤트 대화형 세션 auto-issue 워커
SessionStart ×4 세션 시작 시 1회 디스패치마다 1회 — 매번 fresh 컨텍스트
UserPromptSubmit ×9 매 사용자 턴 재발화 — pending 신호·memory 주입이 턴마다 반복 정확히 1회claude -p 단발 프롬프트에 전부 실림
Stop ×10 차단이 사용자에게 표면화 → 대화로 수습 런 내부 루프 → attempts cap → dispatcher 산출물 게이트가 최종 방어
Pre/PostCompact 장수 세션에서 실제 발화 스래싱 실측 사실상 미발화 — 초과 시 BIGCTX 모델 스왑 재기동 (완화가 프로세스 외부에)
PreToolUse ×13 exit-2 게이트 + 권한 프롬프트 이중 exit-2 게이트만 — --dangerously-skip-permissions로 프롬프트 계층 제거
Project Scope의 반전 — 실측

통념과 반대다. 지금 이 대화형 세션(hugh-soft)은 project hook 0개로 돌고, bs 워커의 워크트리에는 hooks·settings.json 풀셋이 실재한다. 본 repo에서 이 파일들은 git 미추적이라 워크트리로 전파될 수 없다 — settings.local.json의 존재가 증거다: 부트스트랩이 디스패치 시점에 설치한 것이다. 워커가 project scope 게이트를 더 완전하게 받는다.

in-process 상속 vs OS-process 격리

대화형의 spawn은 같은 하네스 프로세스 안에서 일어나 부모의 컨텍스트와 대형 주입을 물려받는다. 워커의 spawn은 별도 OS 프로세스라 아무것도 물려받지 않는다 — 대신 환경도, 제어 수단도 완전히 다르다.

SPAWN 계층 — 무엇을 물려받고, 무엇으로 제어되는가 대화형 세션 — IN-PROCESS Claude Code 세션 프로세스 사용자 launch shell env 상속 Agent tool spawn subagent · teammate 세션 컨텍스트·대형 주입 상속 SubagentStart/Stop hook 발화 실측 07-31: Prompt is too long 대형 주입 상속 → 스폰 실패 → autocompact 스래싱 → 수동 종료 제어: TaskStop 통지: mailbox idle_notification auto-issue 워커 — OS-PROCESS auto_issue_loop.sh 디스패처 launchd/cron 최소 env — PATH 핀 필요 nohup · tmux OS spawn claude -p 헤드리스 프로세스 워크트리 cwd · 전용 워커 모델 --dangerously-skip-permissions 컨텍스트 초과 → BIGCTX 모델 스왑 완화 장치가 프로세스 외부(루프)에 있다 압축 대신 재기동 제어: run-locks · 2h timeout kill · 워치독 재디스패치 쿨다운 30분 왼쪽: 자식이 부모의 컨텍스트를 물려받는다 · 오른쪽: 자식은 아무것도 물려받지 않는다
spawn 실패의 형태도 다르다 — 대화형은 상속된 컨텍스트가 한도를 넘겨 죽고, 워커는 시간·잠금·쿨다운으로 외부에서 관리된다.
통신 채널과 상태 신원

대화형의 팀메이트는 주소 지정 가능한 mailbox 실체고, 워커는 팀메이트가 아니다. 그리고 상태 신원(세션 ID·ledger·memory scope)의 격리 수준이 실제 사고 3건의 발생 여부를 정확히 갈랐다.

interactive — shared state

mailbox + 공유 디렉토리

"말은 통하지만, 상태가 섞인다"

  • SendMessage · idle_notification 수신 (실측: 리뷰어 통지 2회 배달)
  • work-recheck ledger를 동시 세션들과 같은 디렉토리에서 공유
  • 실측: 내 ledger에 타 프로젝트 경로 2,719건 혼입
  • memory-bank 주입 = 이 프로젝트의 축적 facts + global
worker — isolated state

board + lock + 코멘트

"말은 안 통하지만, 상태가 깨끗하다"

  • SendMessage 불가 — GitHub 코멘트·보드 상태·산출물 파일·lock이 전부
  • 보드 상태 변경은 dispatcher 단일 writer
  • 세션 ID·transcript·ledger를 워크트리 경로 기준으로 신규 발급
  • memory-bank 주입 = global facts만 (워크트리 slug 기준)
사고 ① 07-31

스폰 실패 · 스래싱

백그라운드 subagent가 세션의 대형 주입을 상속해 Prompt is too long으로 죽고, autocompact 스래싱으로 자원만 소모.

2회
실패 통지
0
워커 구조 발생
사고 ② 07-31

ledger 오염

공유 상태 디렉토리에 타 세션·타 프로젝트 경로가 혼입 — 세션 무관 파일 변경이 검증 상태를 오염.

2,719
혼입 경로
0
워커 구조 발생
사고 ③ 08-01

attestation 반복 무효화

6시간 주기 스케줄러가 공유 경로(.seen.json)를 갱신할 때마다 검증 서명이 stale — 작업 없이도 게이트 재차단.

3회
거짓 stale
0
워커 구조 발생
스킬은 같게 로드되고, 다르게 호출된다
load — 동일

로드 경로

"목록은 양쪽에 똑같이 주입된다"

  • user scope 스킬 ~125개 목록이 양쪽 SessionStart에 동일 주입
  • project 스킬은 cwd의 .claude/skills 기준
  • 샘플 워크트리: skills/ 없음 → 워커는 user scope만 사용
  • 헬퍼에 ~/.claude 경로 오인 방지 가드 존재 (auto_issue.py:276)
invoke — 상이

호출 주체

"재량이냐, 계약이냐"

  • 대화형: 사용자 /명령 + 모델 자율 판단으로 호출
  • 워커: build_issue_prompt가 계약으로 호출을 지정
  • "/init-project → /team" 순서가 프롬프트에 명문화
  • 스킬이 재량이 아니라 파이프라인 단계로 소비됨
1
분기점 ① project scope 획득 경로
대화형 = cwd에 있으면 로드 · 워커 = 부트스트랩이 워크트리에 설치
2
분기점 ② spawn 계층
in-process 상속(컨텍스트·주입 물려받음) · OS-process 격리(lock·timeout으로 외부 제어)
3
분기점 ③ 상태 신원
공유 디렉토리(ledger·attestation 오염 가능) · 워크트리별 신규 발급(구조적 격리)
Verdict

user scope 기계는 완전히 동일하다. 갈리는 곳은 세 곳뿐이며, 이 세션이 이틀간 겪은 사고 3건(스폰 실패·ledger 오염·attestation 무효화)은 전부 대화형 쪽 구조의 약점이 발화한 것이다 — 워커 구조에서는 셋 다 설계상 발생하지 않는다. 반대로 대화 중에 과녁이 만들어지는 작업은 동결된 이슈로 표현할 수 없다. 스펙을 문장으로 적을 수 있으면 워커에게, 적을 수 없으면 대화형에.