내 환경 × Herdr — 도입 이득과 권장 세팅
전제 환경: wezterm 단독(tmux 미사용) · OpenCode + Claude Code 병렬 사용 · diff 확인용 pane과 nvim pane 상시 운용 · git worktree 2~3개로 동시 작업
함께 볼 문서: Herdr 개요 (일반 레퍼런스)
1. 왜 도입하나 — 이득 정리
1-1. 지속성이 순수 신규 이득
tmux를 안 쓰고 계셨으므로 wezterm 창을 닫으면 그 안의 프로세스가 같이 죽습니다. Herdr를 도입하면 이게 사라집니다.
- 창을 닫아도, SSH가 끊겨도, 노트북을 덮어도 pane과 에이전트가 살아있음
herdr재실행으로 그대로 복귀- 워크트리 여러 개에 에이전트를 걸어놓고 자리를 뜨는 패턴에서 특히 큼
⚠️ 주의: wezterm 재시작 후 복원된 것처럼 보인 건 "복원"이 아니라 재부착입니다. 서버가 애초에 안 죽었던 것. 진짜 복원 경로(스냅샷/네이티브 세션)는
herdr server stop이후에만 발동합니다.
1-2. 워크트리가 1급 시민
herdr worktree 커맨드 그룹이 브랜치를 개별 workspace에 매핑합니다.
지금은 워크트리 2~3개를 wezterm 탭 이름이나 기억으로 관리하고 계실 텐데, 거기엔 상태 개념이 없습니다. Herdr는 workspace 단위로 에이전트 상태를 롤업하므로:
사이드바
● feature-a ← blocked (승인 대기 중)
○ feature-b ← working
◐ hotfix-c ← done (아직 안 봄)
한 컬럼만 보면 어느 브랜치가 나를 기다리는지 알 수 있습니다. 탭 순회가 사라집니다.
1-3. 미확인 완료 추적
done은 "끝났는데 아직 내가 안 본 것"입니다. 탭을 포커스해야 "봤음" 처리됩니다.
에이전트 2개 × 워크트리 3개면 사실상 6개 이상을 상태 없이 순회하고 계신 겁니다. "저거 결과 확인했던가?"를 머리에서 사이드바로 넘기는 게 실질 이득입니다.
1-4. OpenCode / Claude Code 둘 다 공식 통합 존재
이게 운이 좋은 부분입니다. 둘 다 훅/플러그인 기반의 권위 있는 상태 보고를 받을 수 있어서, 화면 스크래핑 추측이 아닙니다. unknown 오탐이 크게 줄어듭니다.
구조적 배경: OpenCode는 session.idle, permission.asked, permission.replied 같은 세션 레벨 이벤트를 노출해서 오케스트레이션에 더 친화적입니다. Claude Code도 훅 시스템은 강력하지만 성격이 달라서 통합이 메꿔야 할 간극이 더 큽니다. → 감독당하는 쪽(워커)을 OpenCode로 두면 상태 신호가 더 정확할 가능성이 높습니다.
1-5. nvim / diff pane은 그대로
각 pane이 portable-pty 기반 진짜 PTY입니다. 웹뷰나 이스케이프 시퀀스가 빠진 유사 터미널이 아니므로 nvim, lazygit, delta 전부 wezterm에서와 동일하게 동작합니다.
1-6. 나중을 위한 옵션: 오케스트레이션
CLI/소켓 API로 에이전트가 다른 에이전트를 부릴 수 있습니다. 헤드리스 모드 대비:
헤드리스 (claude -p, SDK) | Herdr pane | |
|---|---|---|
| 진행 상황 | 블랙박스 | 실시간 관측 |
| 권한 요청 | 사전 허용 or 실패 | blocked로 잡히고 직접 승인 |
| 작업 후 | 프로세스 종료 | 살아있어 이어서 대화 가능 |
| 재시작 | 소실 | 네이티브 세션 복원 대상 |
| 과금 | SDK 별도 풀 | 1st-party CLI 그대로 |
2. 도입하지 않을 이유 (솔직하게)
- tmux와 병행 불가. Herdr pane 안에서 tmux를 열면 에이전트 상태 감지가 죽습니다. 대체재입니다 (지금 tmux를 안 쓰시니 이 비용은 없음)
- 긴 응답 회수는 여전히 취약. alternate screen 한계는
tmux capture-pane과 동일한 성질 - 0.x 버전대. 감지 매니페스트가 핫리로드되긴 하지만 UI 변경에 따른 오탐 가능성 존재
- 수동 조작 비중이 크면 자동화 이득은 나중 얘기. 다만 위 1-1~1-5는 자동화 없이도 즉시 발생
3. 초기 세팅
Step 1 — 설치
curl -fsSL https://herdr.dev/install.sh | sh
# 또는 brew install herdr
herdr --version
Step 2 — 통합 (가장 중요)
herdr integration install claude
herdr integration install opencode # OpenCode를 최소 1회 실행한 뒤에
herdr integration status # 버전 확인 — 네이티브 세션 복원 조건
통합이 두 가지를 동시에 해결합니다: 상태 감지 정확도 + 네이티브 세션 복원 자격.
Step 3 — 설정
# ~/.config/herdr/config.toml
[ui.toast]
delivery = "system" # 데스크톱 알림. 알림 플러그인을 쓰면 "terminal"로 변경
[session]
# resume_agents_on_restore = true # 기본값. 프로젝트를 자주 옮기면 워크스페이스가
# 과하게 쌓일 수 있으니 그때 false 고려
herdr --default-config > /tmp/herdr-default.toml # 전체 옵션 확인용
herdr server reload-config # 재시작 없이 적용
화면 히스토리는 켜지 마세요. pane 출력이 디스크에 남고 시크릿/토큰이 포함될 수 있습니다. 네이티브 세션 복원이 있으니 대부분 불필요합니다.
Step 4 — 알림
권장 조합:
# (a) 자리를 떠도 폰으로 — 크로스 플랫폼
herdr plugin install cobanov/herdr-ntfysh
cp .env.example "$(herdr plugin config-dir cobanov.herdr-ntfysh)/.env"
# HERDR_NTFY_SERVER, HERDR_NTFY_TOPIC 설정
herdr plugin action invoke cobanov.herdr-ntfysh.test
# (b) macOS라면 — 클릭 시 해당 pane으로 점프
herdr plugin install yankewei/herdr-focus-notify
# HERDR_FOCUS_NOTIFY_ACTIVATE_APP=wezterm
⚠️ 플러그인 사용 시 [ui.toast] delivery = "terminal"로 내장 토스트를 끄세요. 아니면 중복 알림.
Step 5 — 검증 (여기까지 하면 도입 완료)
# 1) 워크트리 하나에서 OpenCode + Claude Code를 각각 pane에 띄우기
# 2) 사이드바에 두 상태가 뜨는지 확인
herdr agent list
# 3) 상태가 이상하면 이유 확인
herdr agent explain <target> --json
진짜 복원 테스트 (선택, 격리 세션 권장):
herdr session attach test # 별도 세션에서 실험
# ... 에이전트 띄우고 대화 몇 번
herdr server stop <세션 지정> # 정확한 플래그는 herdr server stop --help 확인
herdr session attach test # 대화 맥락을 들고 살아나면 통합 성공
⚠️ 기본 세션에서
herdr server stop을 실행하면 모든 pane 프로세스가 죽습니다. 실험은 반드시 명명 세션에서.
4. 권장 토폴로지
워크트리 = workspace
session: default
├── workspace: feature-a (워크트리 A)
├── workspace: feature-b (워크트리 B)
└── workspace: main (메인 체크아웃)
workspace를 프로젝트/작업 단위로 하나씩 두는 게 사이드바 상태를 읽기 좋게 유지하는 원칙입니다.
workspace 안의 탭 분리
workspace: feature-a
├── tab: main ← 오케스트레이터 에이전트 1개 + diff pane
├── tab: workers ← 서브에이전트 전용
└── tab: edit ← nvim
agent start는 이미 존재하는 사용 가능한 셸 pane을 요구합니다. 사용 가능하다는 건 대화형 프롬프트 상태이고 셸 자체가 포그라운드이며 명령·에디터·에이전트가 돌고 있지 않은 상태입니다. → nvim 탭과 워커 탭을 분리해야 하는 실질적 이유입니다.
5. 오케스트레이션 셋업 (2단계 이후)
즉시 필요하지 않다면 §3까지만 하고 며칠 써보신 뒤 진행하세요.
스킬 설치
npx skills add herdrdev/herdr --skill herdr -g
스킬 시스템이 없으면 원본을 글로벌 커스텀 인스트럭션에 붙여넣기:
https://raw.githubusercontent.com/herdrdev/herdr/master/skills/herdr/SKILL.md
⚠️ 프롬프트에 "herdr"를 명시해야 발동합니다. 스킬 설명이 "사용자가 Herdr를 명시적으로 언급했을 때만" 쓰도록 제한하고 있습니다.
herdr로 오른쪽에 pane 열고 codex 띄워서 현재 diff 리뷰시켜줘
커스텀 하우스 룰
원본 스킬 위에 프로젝트 규칙을 얹는 방식을 권합니다.
# Herdr orchestration — house rules
## 역할 분리 (재귀 방지)
HERDR_ROLE=worker 이면 herdr 제어 명령을 일절 사용하지 않는다.
pane/tab/workspace를 만들지 않고, 다른 에이전트를 시작하지 않는다.
작업 결과만 보고한다.
## 토폴로지
- 오케스트레이터는 main 탭에만 존재. 워커를 main 탭에 띄우지 않는다.
- 워커는 label="workers" 탭에만 생성. 없으면 만든다.
- 탭/pane ID는 항상 list로 조회한다. 하드코딩 금지.
- 워커 pane은 최대 3개. 그 이상은 좁아서 못 쓴다.
## 결과 교환 (컨텍스트 절약 + alternate screen 회피)
워커 프롬프트 말미에 항상 추가:
"전체 결과를 $HANDOFF_DIR/<name>.md 에 쓰고, 응답은 파일 경로 한 줄만."
오케스트레이터는 파일을 읽는다. agent read는 진단 용도로만.
## 권한
자동 승인은 아래를 모두 만족할 때만:
- 읽기 전용 (ls, cat, git diff, git log, rg)
- 워크트리 경로 밖을 건드리지 않음
그 외 전부 사용자 호출:
herdr notification show "승인 필요: <name>" \
--body "$(herdr agent read <name> --source detection --lines 5)" \
--sound request
git push / rm / 파일 삭제 / 네트워크 쓰기는 예외 없이 사용자.
## 금지
- 자기가 만들지 않은 pane/tab/workspace 닫기
- herdr server stop
- 메인 Herdr 프로세스 kill
파일 핸드오프에 대한 메모: 공식 스킬은 파일 출력을 alternate-screen 폴백으로만 쓰라고 합니다. 그건 1:1 대화를 전제한 조언이고, 오케스트레이터 패턴에서는 처음부터 파일로 받는 게 맞습니다. 컨텍스트 소모와 alternate screen 문제가 동시에 해결됩니다.
교차 호출
Herdr에게 CC와 OpenCode는 그냥 다른 --kind 값이라 양방향이 완전히 대칭입니다.
herdr agent start impl --kind opencode --pane "$p1" # CC가 OpenCode를
herdr agent start reviewer --kind claude --pane "$p2" # OpenCode가 CC를
실용적 가치: 같은 모델이 자기 코드를 리뷰하면 같은 맹점을 공유합니다. 크로스 모델 리뷰가 이 구성의 가장 큰 실익입니다.
표준 시퀀스
test "${HERDR_ENV:-}" = 1
split=$(herdr pane split --current --direction right --cwd "$PWD" --no-focus)
p=$(printf '%s\n' "$split" | jq -r '.result.pane.pane_id')
herdr agent start reviewer --kind claude --pane "$p"
herdr agent prompt reviewer "$TASK" --wait --timeout 300000
# blocked로 멈췄으면 판단 전에 반드시 확인
herdr agent get reviewer
herdr agent read reviewer --source detection
6. 함정 체크리스트
| # | 함정 | 대응 |
|---|---|---|
| 1 | 재귀 폭발 — -g 설치 시 워커도 스킬을 가짐 | HERDR_ROLE=worker 규칙을 하우스 룰에 명시 |
| 2 | 오케스트레이터 컨텍스트 고갈 | 파일 핸드오프를 기본 프로토콜로 |
| 3 | alternate screen — --lines 늘려도 안 나옴 | 파일 핸드오프로 우회 (근본 해결) |
| 4 | unknown을 성공으로 처리 | 완료의 증거가 아님. 명시적으로 분기 처리 |
| 5 | 턴 미추적 — 바쁜 에이전트에 프롬프트+--wait | 프롬프트 전 agent get으로 idle 확인 |
| 6 | 에이전트 이름 소실 — 죽으면 별칭도 사라짐 | 재기동 시 이름 재등록 |
| 7 | pane 점유 상태 — nvim 있는 pane에 agent start 불가 | 탭 분리 |
| 8 | herdr server stop 오발사 | 실험은 명명 세션에서만 |
| 9 | 중복 알림 | 플러그인 사용 시 내장 토스트 끄기 |
| 10 | 권한 자동 승인 폭주 | blocked는 "무엇을" 승인하는지 알려주지 않음. 화이트리스트 필수 |
7. 단계별 도입 순서
Phase 1 — 기본 (즉시, 30분)
- 설치
herdr integration install claude / opencode- 워크트리 하나를 workspace로 전환해서 며칠 사용
- 판단: 사이드바만으로 회수되는가?
Phase 2 — 운용 (Phase 1이 만족스러우면) 5. 워크트리 전부를 workspace로 6. 알림 플러그인 (ntfy 또는 focus-notify) 7. 탭 구조 정리 (main / workers / edit)
Phase 3 — 오케스트레이션 (필요를 느끼면) 8. 스킬 설치, 원본 그대로 1:1 위임부터 9. 파일 핸드오프 추가 10. 하우스 룰 (역할 분리 + 토폴로지)
Phase 4 — 권한 자동화 (마지막, 신중하게)
11. 층 1부터: 워커 기동 시 네이티브 권한 옵션으로 애초에 안 묻게
12. 그래도 남는 것만 화이트리스트
13. 나머지는 notification show로 사람 호출
Phase 3까지만 해도 실용적으로 충분합니다. Phase 4는 잘못 만들면 조용히 위험해지는 유일한 구간이니 서두르지 마세요.
8. 자주 쓸 명령
# 상태 확인
herdr agent list
herdr agent explain <target> --json
herdr integration status
herdr status
# 레이아웃
herdr workspace list
herdr tab list --workspace "$HERDR_WORKSPACE_ID"
herdr pane list --workspace "$HERDR_WORKSPACE_ID"
herdr pane current --current
herdr pane layout --pane "$HERDR_PANE_ID"
# 설정
herdr --default-config
herdr server reload-config
# 커맨드 그룹 도움말 (서브커맨드 없이 실행)
herdr agent / pane / workspace / tab / worktree / notification / plugin / session
# 알림
herdr notification show "제목" --body "내용" --sound request
키바인딩: prefix+?로 라이브 전체 목록. 기본 프리픽스는 ctrl+b.