# relay-baton v0.5.0 릴리즈 노트 날짜: 2026-05-28 > 배포 완료. 이 노트는 v0.5에 들어간 내용을 설명한다. 아래 설계 섹션은 작업 spec을 > 겸했고 구현과 일치한다. ## 요약 v0.5는 두 개의 독립적인 headline 기능과 v0.4 이월 항목을 갖는다. **1. Plan-execute mode** — fallback mode 옆에 두 번째 workflow shape. 한 agent (planner, 기본 Claude)가 구조화된 `plan.md`를 작성하고, 다른 agent (executor, 기본 Codex)가 그걸 보고 구현. quality gate 적용. **2. Context compression mode** — `state.md` / `commands.log`를 세션 *중간*에 proactive하게 압축해서 한 agent가 fallback 없이 더 오래 갈 수 있게 함. deterministic만 (LLM 호출 없음). 명시적 `relay-baton compress-context` 명령 + `run` 안의 auto-watcher. 이 문서는 두 가지를 차례로 다룬다. ### 배포된 내용 - `relay-baton plan ""` + `relay-baton execute` (+ `--then-execute` chaining). - `.ai-session/plan.md` + `PlanQualityGate`; `PromptBuilder.planner` / `.executor`. - `SessionMeta.workflowMode` + `planning` / `plan_ready` / `executing` / `compressing` status. - `relay-baton compress-context` (`--dry-run` / `--threshold` / `--force`) + `run` 내 auto-pass. - `ContextCompressor` + inline gate (반드시 줄어듦, state parse 유지, 마지막 fallback hit 생존, 실패 시 rollback); `LogCompactor.compressLog`. - `planExecute` / `contextCompression` config 블록 (기본값 포함). - 릴리즈 시점 테스트: **124 tests** (core 111, cli 13), CI green. 원래 계획에서 v0.6으로 미룸: 신규 mode용 TUI 패널, project-level fallback override (테스트/관측성 척추 작업 우선). ### Plan-execute mode v0.5는 **두 번째 workflow mode**를 도입한다. v0.4까지 relay-baton은 워크플로우가 하나뿐이었다 — **fallback mode**: primary agent가 quota / context 한도까지 가다가 막히면 secondary agent가 compact handoff에서 이어받음. 오케스트레이션이 *reactive(반응형)*. v0.5는 **plan-execute mode**를 추가한다 — *proactive(주도형)* 순서. 한 agent(보통 Claude Code = planner)가 구조화된 plan 문서를 작성하고, 다른 agent(보통 Codex = executor)가 그걸 보고 구현한다. 두 역할이 명시적이고, plan은 1급 artifact이고, execute 단계 내부에서는 기존 fallback 기계가 그대로 동작한다. 실제 사용에서 반복해서 나온 질문에 대한 답: *"Codex는 spec이 명확하면 코드 잘 짜고, Claude는 repo 읽어서 뭘 해야할지 결정하는 거 잘하는데 — fallback 안 기다리고 그냥 Claude가 plan 짜고 Codex가 실행하게 할 순 없나?"* 가능. 그게 이 mode다. 범위는 의도적으로 좁힘: - 신규 명령어: `relay-baton plan`, `relay-baton execute`. - 신규 artifact: `.ai-session/plan.md` + PlanQualityGate. - `SessionMeta.workflowMode: "fallback" | "plan-execute"` 추가. - token diet 통합: plan도 동일한 profile budget 적용. - 하위 호환: 기존 `run` / `handoff` 동작 안 바뀜. v0.4의 "다음 개선 추천"에서 이월: - OpenCode / Gemini / Aider adapter scaffold (실제 사용자가 나타나는 첫 번째만). - macOS / Windows CI matrix. - Project-level fallback pattern override. 명시적 out-of-scope (이유와 함께): - TUI fuzzy switcher / command palette — plan-execute가 TUI dashboard에 들어가고 나서 입력 surface 한 번에 설계. - Per-model tokenizer / semantic plan diff / autopilot — `CLAUDE.md` MVP 정책 위반. - planner-executor multi-turn loop + auto review — v0.6 후보 (아래 "v0.5 이후" 참조). ## 설계 — plan-execute mode ### 왜 "mode"이고, "run의 또 다른 flag"가 아닌가 받았던 질문: *"이거 그냥 `run`에 flag 하나 추가하면 되는 거 아니냐?"* 솔직한 답은 No. flow shape이 다름: | | Fallback mode (현재) | Plan-execute mode (v0.5) | |---|---|---| | Trigger | Reactive — primary agent 실패 | Proactive — 사용자가 명시적으로 호출 | | Artifact | `handoff.md` ("이렇게 이어서") | `plan.md` ("이거 만들어") | | Sequence | 한 agent → 실패 시 다른 agent | planner → executor, 항상 | | Status 전이 | `running → fallback_detected → running_fallback → completed` | `initialized → planning → plan_ready → executing → completed` | | Quality gate | HandoffQualityGate | PlanQualityGate (신규) + execute 단계에는 기존 gate | `run --plan`으로 합치면 의도가 다른 두 흐름이 섞임. 차라리 별도 command pair로 mode를 surface — `handoff`가 별도 command인 것과 같은 패턴. ### Commands ```bash # 1) Planner phase. Claude가 repo 읽고 .ai-session/plan.md 작성. relay-baton plan "" [--with claude] [--diet balanced] [--no-run] # 2) Executor phase. Codex가 (또는 다른 agent) plan.md 기반으로 구현. relay-baton execute [--with codex] [--from .ai-session/plan.md] [--diet balanced] # 3) 합친 형태. planner를 충분히 믿을 때. relay-baton plan "" --then-execute [--planner claude] [--executor codex] ``` 기본값: `plan`은 `--with claude`, `execute`는 `--with codex`. 둘 다 override 가능. `plan --no-run`은 파일만 쓰고 executor 안 띄움 — commit 전에 사람이 plan 검토할 때 유용. ### `.ai-session/plan.md` 필수 섹션 (`PlanQualityGate`가 강제): ``` # relay-baton plan ## Goal … ## Scope (in) … ## Out of scope … ## Approach … ## Steps 1. … 2. … ## Risks … ## Verification executor가 끝났는지 어떻게 알 수 있는가 ## Next step executor가 시작할 단 하나의 bullet ``` 이 섹션들을 강제하는 이유: 각각이 executor가 안 물어봐도 되는 질문을 미리 답해줌. plan은 채팅 transcript가 아니라 **계약**이어야 함. ### Plan용 token diet - `plan.md`도 `handoff.md`와 같은 profile 시스템 적용. - 신규 profile field: `maxPlanChars` (default는 `maxHandoffChars` 미러). - planner는 plan에 큰 diff / log를 절대 inline하지 말라고 prompt에서 강제 — handoff와 동일한 규칙. - `PlanQualityGate`는 `AGENTS.md`, `CLAUDE.md`, 큰 diff 블록 inline을 거부 — `TokenDietQualityGate`와 같은 형태. ### Status 전이 + 관측성 `SessionMeta` (additive): ```ts interface SessionMeta { // 기존 필드들... workflowMode?: "fallback" | "plan-execute"; planAuthor?: AgentId | null; executor?: AgentId | null; planFinalizedAt?: string; executeStartedAt?: string; // v0.4 필드 (startedAt / endedAt / durationMs / handoffCount) 그대로 } ``` Status 값에 두 개 추가: - `planning` — planner 실행 중, plan.md 미완료. - `plan_ready` — plan.md 존재, executor 미시작. - `executing` — executor 실행 중. 기존 `fallback_detected` / `running_fallback` / `completed` / `failed`는 의미 그대로 유지. `execute` 단계에서 다른 agent로 fallback도 가능 — 즉, plan-execute mode와 fallback mode는 *합성 가능*하지 배타적이지 않음. ### Quality gates 신규: `PlanQualityGate` (HandoffQualityGate 미러) - plan.md 존재 + 비어있지 않음. - 필수 섹션: Goal, Scope (in), Out of scope, Approach, Steps, Risks, Verification, Next step. - Steps 리스트 비어있지 않음. - Next step 비어있지 않음. - `plan.md` ≤ 활성 profile의 `maxPlanChars`. - 큰 `commands.log` / `AGENTS.md` / `CLAUDE.md` inline 금지. `execute` 실행 차단도 HandoffQualityGate가 fallback 차단하는 것과 같은 방식. `--force`로 override 가능. ### Prompt 구성 - **Planner prompt** (`PromptBuilder.planner(task)`): - `AGENTS.md` / `CLAUDE.md` / `task.md` / `repo-map.md` 먼저 읽기 (참조로, inline 안 함), - **코드는 작성하지 말고 plan 문서만** 작성하도록 명시, - 구조화된 출력 강제 — 섹션 누락 시 실패, - 불확실한 건 Risks에 명시하라고 권장 — Steps에서 추측하지 말 것. - **Executor prompt** (`PromptBuilder.executor()`): - `plan.md` 먼저 읽기, - 단계별로 진행, 각 단계 후 `.ai-session/state.md` 갱신, - 현실이 plan과 다르면 **조용히 즉흥 처리하지 말고 STOP + `errors.md`에 기록** 권장. ### Agent 역할 매트릭스 역할은 hardcoded가 아니라 설정 가능: | Planner | Executor | 용도 | |---|---|---| | Claude Code | Codex CLI | **기본** — Claude가 repo 잘 읽고, Codex가 spec대로 실행 | | Codex CLI | Claude Code | Codex가 이미 context 많을 때 (긴 Codex 세션 중간) | | Claude Code | Claude Code | "two-pass" — token 예산 이유로 planning과 execution의 context를 분리 | | Codex CLI | Codex CLI | 같은 패턴, Codex 쪽 | `relay-baton.config.json`에 optional `planExecute` 블록: ```json { "planExecute": { "defaultPlanner": "claude", "defaultExecutor": "codex", "maxPlanChars": 30000 } } ``` ## Context compression mode plan-execute mode와 나란히 v0.5의 **두 번째 headline 기능**. 둘은 서로 독립적. ### 문제 오늘의 token diet는 **결정적 pre-compaction**이다: handoff 시점에 diff / log / state를 character budget으로 자르고 새 문서를 쓴다. agent 사이 *경계*에는 잘 작동하지만 agent run의 *내부*에는 아무 도움이 안 된다: - agent의 자체 context window가 턴마다 차오른다. - `state.md`, `commands.log`, 누적 tool-call 히스토리가 긴 run 동안 무한히 자란다. - `context length exceeded`를 fallback으로 감지할 즈음에는 agent가 이미 자기 자신의 사고를 다시 읽느라 토큰을 수천 개 낭비한 뒤다. 해법은 **mid-session 압축**이다 — 연속성을 깨지 않고 주기적/주도적으로 진행 중 context를 더 작은 형태로 요약. Claude Code 자체의 `/compact` 류 명령에서 영감을 받았지만, 어떤 agent가 active이든 동일하게 동작하도록 relay-baton의 자체 artifact에 적용. ### v0.5에 추가될 것 **신규 명령** ```bash relay-baton compress-context [--profile caveman] [--threshold 0.8] [--dry-run] ``` - 현재 `.ai-session/`의 "무게" 검사 — `state.md`, `commands.log`, `decisions.md`, `errors.md`의 총 char 수 vs 활성 profile budget. - 무게가 `--threshold` (기본 80%) 넘으면 `state.md`와 `commands.log`를 in-place 압축 형태로 재작성. - `--dry-run`은 쓰지 않고 무엇이 바뀔지 보고만. **Deterministic 전용.** 오늘의 MVP 규칙 그대로: relay-baton 안에서 LLM 호출 없음. 압축의 의미: - `state.md` → `StateCompactor`로 재출력 + 히스토리에서 반복된 `Done:` / `In Progress:` bullet dedup. - `commands.log` → 마지막 N줄 + fallback-pattern hit 주변 라인 + exit code 주변 라인 유지; 나머지는 `[N lines elided]` marker로 접음. 원본은 1회 rotation으로 `commands.log.full.`에 보관. - `decisions.md` / `errors.md` → 마지막 성공적 handoff보다 오래된 항목 drop (필요 시 git 히스토리에서 복구 가능). **`run`의 auto-trigger** `run`은 이미 agent stdout을 stream한다. N줄마다 진행 중 context (active `state.md` + `commands.log`의 char 수)를 추정하는 watcher를 추가. threshold 넘으면: - 한 줄 표시 `[relay-baton] context approaching limit; compressing…`. - `relay-baton compress-context`와 같은 로직 실행. - 다음 agent 턴은 더 작은 `state.md`와 더 빡빡한 `commands.log` tail을 보게 됨 — 이게 continuation prompt가 가리키는 데이터. 이는 기존 **reactive** fallback 기계에 대한 **proactive** counterpart. context 고갈에 대한 두 겹 방어: 1. mid-run 압축 (이 기능) — 한 agent가 얼마나 멀리 갈 수 있는지를 늘림. 2. 다른 agent로 fallback (기존) — 압축만으론 부족할 때. ### Status 전이 선택적 status 한 개 추가: `compressing` — `running`과 다음 사용자 표시 status 사이. 짧음 — 보통 sub-second. `relay-baton status`와 TUI dashboard에 노출돼서 사용자가 잠시 멈춤을 이해할 수 있게. ### 설정 ```json { "contextCompression": { "enabled": true, "auto": true, "threshold": 0.8, "rotateRawArtifacts": true } } ``` - `enabled: false`는 v0.4 동작 — handoff 시점의 순수 pre-compaction만. - `auto: false`는 `run`의 watcher를 끄지만 명시적 `compress-context` 명령은 그대로 사용 가능. ### Quality gate 신규: `ContextCompressionGate` — 압축 사이클 후 다음 검증: - `state.md`가 여전히 canonical section으로 parse됨. - `commands.log`에 최소한 마지막 fallback-pattern hit (있다면)은 남아 있음 — 감지 기능 무력화 방지. - Rotation된 raw 파일이 디스크에 비어있지 않게 존재. - 압축 후 크기가 실제로 압축 전보다 작음 (그렇지 않으면 사이클이 헛수고). gate 실패 시 rotation된 raw 파일에서 압축이 롤백. 압축이 세션을 **나쁘게 만들면 절대 안 됨**. ### Out of scope (여전히) - semantic / LLM 기반 summarization. 비용 + 결정성에 대한 강한 이야기가 생길 때까지 미룸. - cross-session 압축 (과거 세션 artifact를 history archive로). v0.6 후보. - per-model context limit 기반 adaptive threshold. v0.6 후보. ### plan-execute mode와의 합성 - `relay-baton execute` (v0.5 plan-execute mode) 중에는 동일한 auto-compression watcher가 executor agent에 적용됨. - plan 문서 자체는 execute 중 auto-compress **하지 않음** — plan은 계약이고, 다시 쓰는 건 골대를 바꾸는 짓. 압축은 진행 중 state / log만 건드림. ## 그 외 v0.5 항목 ### OpenCode / Gemini / Aider adapter scaffold 실제 사용 케이스 가진 외부 사용자가 나타날 때만 trigger. 그 전에는 premature surface area. 트리거되면 구체 deliverable: - `packages/core/src/agents/Adapter.ts` — 기존 `AgentAdapter` 인터페이스 구현. - `CodexAdapter.test.ts` 미러 테스트 1개. - `README.md` 요구사항 표에 해당 구독 / CLI 링크 추가. ### macOS / Windows CI matrix `.github/workflows/ci.yml`에 `matrix.os` 추가. 비용이 빠르게 증가할 가능성. v0.5 구현 시점에 수용 여부 결정. 수용 시: - `matrix: { os: [ubuntu-latest, macos-latest, windows-latest] }`. - 경로 구분자 / 줄바꿈 테스트 주시. Windows 전용 fix가 최소 한 개 나올 거라고 예상. ### Project-level fallback pattern override `BatonProject`에 optional `fallbackPatterns?: string[]` 추가. 해당 project로 scoped된 `run` / `handoff`에서 global pattern 위에 덮어쓰기. 어떤 repo의 CI가 다른 repo와 달리 일관되게 특정 문자열을 출력할 때 유용. ## 호환성 - `plan`, `execute`는 신규 subcommand. 이름 변경 없음. - `SessionMeta` 추가는 optional 필드. 기존 session 그대로 동작. - fallback mode (기존 동작)로 만든 session은 `planning` / `plan_ready`를 절대 거치지 않음. 신규 status 값은 `plan` / `execute`만 emit. - `relay-baton.config.json.planExecute`는 optional. 없으면 default. - breaking change 계획 없음. v0.4에서 버그가 발견되면 v0.4.x로 fix하고 v0.5 범위는 안 흔든다. ## 작업 순서 (추천) 각 단계가 독립적으로 shippable하게. **A 블록**은 plan-execute mode, **B 블록**은 context compression mode. 두 블록은 서로 독립이라 한쪽만 ship 해도 됨. A. Plan-execute mode 1. **`SessionMeta.workflowMode` + 새 status 값** (~30분) — types-only, foundation. 2. **`plan.md` schema + PlanQualityGate** (~1시간) — 순수 함수, 테스트 쉬움. 3. **`PromptBuilder.planner` / `PromptBuilder.executor`** (~30분) — string template, snapshot test. 4. **`relay-baton plan` 명령어** (~1시간) — 기존 AgentRunner 감싸고 plan.md 쓰기, PlanQualityGate 실행. 5. **`relay-baton execute` 명령어** (~1시간) — plan.md 읽고 executor 실행. execute 중 fallback이 일어나면 기존 HandoffQualityGate 재사용. 6. **`--then-execute` chaining** (~30분) — plan → execute 한 번에 orchestrate. B. Context compression mode 7. **`StateCompactor` dedup pass + `LogCompactor` rotation helper** (~45분) — 기존 모듈에 순수 함수 추가. 8. **`relay-baton compress-context` 명령 + ContextCompressionGate** (~1시간) — 명시적 호출 경로 먼저. 9. **`run` 내 auto-watcher** (~1시간) — threshold check, 짧은 `compressing` status, gate 실패 시 롤백. 10. **`contextCompression` config 블록** (~20분) — config 배선 + 기본값. C. 마무리 11. **TUI: plan-execute 상태 패널 + 압축 상태 표시** (~45분). 12. **README + i18n 업데이트** (~45분) — 두 신규 mode 모두; 영문 먼저, 9개 번역 따라가기. 13. **Optional**: 시간 남으면 project-level fallback pattern override. 14. version 0.5.0 bump, 이 노트 finalize, tag. 1–5번 + 7–9번이 v0.5 최소. 나머지는 release 막지 않는 추가 항목. ## v0.5 이후 (v0.6 초기 후보) - **planner-executor multi-turn loop** — executor가 "plan이 현실과 다르다"고 보고하면 planner가 재진입. token 예산 폭주 안 하게 신중한 설계 필요. - **Plan diff** — 재계획 시 새 문서 통째로 다시 쓰지 말고 이전 plan 대비 무엇이 바뀌었는지 보여주기. - **Plan execution receipt** — 단계 완료될 때마다 `plan.md`에 `[done]` / `[skipped]` 마킹. 검증 가능한 trail. - **Cross-session plan reuse** — 한 repo의 `plan.md`를 다른 repo의 새 session에 입력으로 — "같은 변경, 다른 repo" 워크플로우. 명시적으로 v0.5에 안 함. 범위 작게 유지하면서 장기 비전을 적어둘 뿐.