# ๐Ÿ“œ Multi-Agent Mux ๋ฒ„์ „ ์ด๋ ฅ (`VERSIONS.md`) ์ด ๋ฌธ์„œ๋Š” `multi-agent-mux` ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ฒ„์ „๋ณ„ ์ฃผ์š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€, ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„ , ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ํ’ˆ์งˆ ๊ฒ€์ฆ ์ด๋ ฅ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. --- ## ๐Ÿ“Œ ํ˜„์žฌ ๋ฒ„์ „ ๊ฐœ์š” (Current Release) - **ํ”„๋ ˆ์ž„์›Œํฌ ๋ฒ„์ „**: `v4.4.2` - **์ตœ์‹  ๋ฆด๋ฆฌ์Šค ์ผ์‹œ**: 2026-09-12 (KST) - **๊ธฐ์ค€ ๋ธŒ๋žœ์น˜**: `main` - **ํ•ต์‹ฌ ์•„ํ‚คํ…์ฒ˜**: - **Terminal ์ƒํƒœ ๋‹จ๋ฐฉํ–ฅ ๋ถˆ๋ณ€์„ฑ (`engine.py`, Issue #6 Phase 1)**: `completed`, `error`, `cancelled` ํ„ฐ๋ฏธ๋„ ์ƒํƒœ ์ง„์ž… ํ›„ ํ›„์† ์ด๋ฒคํŠธ๋‚˜ ์—…๋ฐ์ดํŠธ์— ์˜ํ•œ ๋ฎ์–ด์“ฐ๊ธฐ๋ฅผ ์—„๊ฒฉํžˆ ์ฐจ๋‹จ(Terminal Immutability). `registry.py close` ์„œ๋ธŒ์ปค๋งจ๋“œ ๋ฐ fail-closed ์กฐ๊ธฐ ์ข…๋ฃŒ ๋„์ž…. - **Herdr ํ„ด ์™„๋ฃŒ ํ•ธ๋“œ์…ฐ์ดํฌ (`lib.sh: wait_for_agent_idle`, Issue #6 Phase 2)**: ์œ„์ž„ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `codex` ๋“ฑ)์˜ ํ”„๋กฌํ”„ํŠธ ์ „์†ก ํ›„ Herdr ๋ทฐํฌํŠธ ๋ฐ ํ”„๋กœ์„ธ์Šค ์ƒํƒœ๋ฅผ ๊ด€์ธกํ•˜์—ฌ ๋น„๋™๊ธฐ ํ„ด ์ข…๋ฃŒ๋ฅผ ๊ฒฐ์ •๋ก ์ ์œผ๋กœ ๋Œ€๊ธฐํ•˜๋Š” ํ•ธ๋“œ์…ฐ์ดํฌ ํ”„๋กœํ† ์ฝœ ํ™•๋ฆฝ. - **Loop ๋ชจ๋“œ `attempt_id` ์ถ”์  ๋ฐ ์•ˆ์ „ ์ „์ด (Issue #6 Phase 3)**: ์›Œ์ปค/๋ฆฌ๋ทฐ์–ด ์ „ํ™˜ ์‹œ ๋™์ผ ํšŒ์ฐจ ๋‚ด ์žฌ์ „์ด ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๋Š” `attempt_id` ๊ทœ์•ฝ ์ ์šฉ ๋ฐ 4๋‹จ๊ณ„ fail-closed `finalize_unfinished` ๋ณด์žฅ. - **๊ฒฐ์ •๋ก ์  ์ข…๋ฃŒ ์ฝ”๋“œ ๊ณ„์•ฝ (Issue #6 Phase 4 & R1)**: `0` (Success), `1` (Failure / Inject error), `2` (Subscriber timeout; ๋‹จ, ์—์ด์ „ํŠธ๊ฐ€ Herdr์—์„œ working ์ค‘์ด๋ฉด ๋ฒฝ์‹œ๊ณ„ --timeout๊นŒ์ง€ ๋””์Šคํฌ ์žฌ๊ด€์ธก ํ›„ fail-close), `3` (Broker unavailable), `5` (Precondition failed / session_busy) ํ‘œ์ค€ํ™”. (send_keys_safe ํ—ฌํผ์˜ ๋ฐฐ๋‹ฌ ์‹คํŒจ/busy ํƒ€์ž„์•„์›ƒ rc=4๋Š” ๋ž˜ํผ ์ฐจ์›์—์„œ rc=1 ์‹คํŒจ๋กœ ์ˆ˜์šฉ). - **4-Way ๋ฒ„์ „ ๋ฝ์Šคํ…**: `lib.sh`(`MAM_VERSION`) โ†” `lib_py/loop/eager.py`(`FRAMEWORK_VERSION`) โ†” `VERSIONS.md` โ†” 8๊ฐœ `SKILL.md`. --- ## ๐Ÿงญ ์Šคํ‚ฌ ํŒจํ‚ค์ง€ ๋ฒ„์ „ ๋งคํŠธ๋ฆญ์Šค (Skills Version Matrix) ๋ชจ๋“  8๊ฐœ ์Šคํ‚ฌ์€ YAML frontmatter ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(`author`, `version`, `platforms`, `environments`) ํ‘œ์ค€ํ™”๋ฅผ ํ†ตํ•ด `v4.4.2`๋กœ ๋™๊ธฐํ™”๋˜์–ด ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. | ์Šคํ‚ฌ๋ช… | ๋ฒ„์ „ | ์—ญํ•  ๋ฐ ์ฃผ์š” ์ฑ…์ž„ | ์ƒํƒœ | | :--- | :---: | :--- | :---: | | **`multi-agent-mux-create`** | `4.4.2` | ์—์ด์ „ํŠธ ์„ธ์…˜ ์‹ ๊ทœ ์ƒ์„ฑ ๋ฐ Herdr ์ปจํ…Œ์ด๋„ˆ ๊ฒฉ๋ฆฌ ์Šคํฐ | โœ… ๋ฐฐํฌ | | **`multi-agent-mux-stop`** | `4.4.2` | ๋Œ€ํ™” UUID ์›์ž์  ์บก์ฒ˜ ๋ฐ ์„ธ์…˜ ์•ˆ์ „ ์ข…๋ฃŒ (Graceful Stop) | โœ… ๋ฐฐํฌ | | **`multi-agent-mux-resume`** | `4.4.2` | ์˜จ๋””์Šคํฌ ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ Tier-1 ์ดˆ๊ณ ์† ์„ธ์…˜ ๋ณต์› | โœ… ๋ฐฐํฌ | | **`multi-agent-mux-status`** | `4.4.2` | ์‹ค์‹œ๊ฐ„ Herdr ์„ธ์…˜ ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋“œ๋ฆฌํ”„ํŠธ ์Šค๋ƒ…์ƒท ์กฐํšŒ | โœ… ๋ฐฐํฌ | | **`multi-agent-mux-monitor`** | `4.4.2` | YAML โ†” ๋Ÿฐํƒ€์ž„ ์ƒํƒœ ๊ฐ„ ์ž์œจ ์กฐ์ •์ž (Reconciler Loop) | โœ… ๋ฐฐํฌ | | **`multi-agent-mux-delegate-job`** | `4.4.2` | MQTT ์ด๋ฒคํŠธ ์ฑ„๋„ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ๋‹จ์œ„ ์ž‘์—… ์œ„์ž„ | โœ… ๋ฐฐํฌ | | **`multi-agent-mux-loop`** | `4.4.2` | Planner-Creator-Reviewer 3์ž ์ž์œจ ๊ณ„ํšยท์‹คํ–‰ยทํ”ผ์–ด๋ฆฌ๋ทฐ ๋ฃจํ”„ | โœ… ๋ฐฐํฌ | | **`multi-agent-mux-orc-onboard`** | `4.4.2` | ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ UUID ๊ฒฉ๋ฆฌ ๋“ฑ๋ก ๋ฐ ์„œ๋ธŒ ์„ธ์…˜ ์˜ค์—ผ ๋ฐฉ์ง€ | โœ… ๋ฐฐํฌ | --- ## ๐Ÿ“‹ ๋ฒ„์ „๋ณ„ ์ƒ์„ธ ๋ณ€๊ฒฝ ๋‚ด์—ญ (Changelog) ### ๐Ÿš€ `v4.4.2` โ€” Issue #9 herdr ์„œ๋ฒ„ ํ™˜๊ฒฝ ๊ฒฉ๋ฆฌ ๋ฐ Issue #14 ํ”„๋กฌํ”„ํŠธ ์ „๋‹ฌ ํ™•์ธ ๋ณด๊ฐ• (2026-09-12) > **ํŒจ์น˜ ๋งˆ์ผ์Šคํ†ค (PATCH Release)**: ์—์ด์ „ํŠธ ๋Ÿฐํƒ€์ž„(์˜ˆ: Claude Code ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ) ์•ˆ์—์„œ herdr ์„œ๋ฒ„๊ฐ€ ์ฒ˜์Œ ๊ธฐ๋™๋  ๋•Œ ์„ธ์…˜ ์‹๋ณ„ ๋งˆ์ปค๊ฐ€ ์„œ๋ฒ„์™€ ์ดํ›„ ๋ชจ๋“  ์—์ด์ „ํŠธ pane ์— ์ƒ์†๋˜๋˜ ๋ฌธ์ œ(Issue #9)์™€, `working` ์„ ๋ณด๊ณ ํ•˜์ง€ ์•Š๋Š” ์—์ด์ „ํŠธ(herdr 0.9.0 ์˜ codex)์—๊ฒŒ ์ •์ƒ ์ „๋‹ฌ๋œ ํ”„๋กฌํ”„ํŠธ๋ฅผ `send_keys_safe` ๊ฐ€ ์‹คํŒจ๋กœ ์˜คํŒํ•ด ์žก์„ `agent_blocked` ๋กœ ๋‹ซ๊ณ  ์—์ด์ „ํŠธ์˜ `started`/`completed` ๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋˜ ๋ฌธ์ œ(Issue #14)๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค. ์‹ ๊ทœ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” ๋ชจ๋‘ ๊ธฐ๋ณธ๊ฐ’์ด ์žˆ๋Š” ์ถ”๊ฐ€ ์„ค์ •์ด๋ฉฐ ๊ณต๊ฐœ ๊ณ„์•ฝยท์ข…๋ฃŒ ์ฝ”๋“œ ๋ณ€๊ฒฝ์€ ์—†๋‹ค. #### ๐ŸŒŸ ์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ 1. **herdr ์„œ๋ฒ„ ๊ธฐ๋™ env ๋งˆ์ปค denylist (Issue #9, `lib.sh` ์‰ผ)**: ์‰ผ์ด `herdr --session server` ๋ฅผ ๋ถ€ํŠธ์ŠคํŠธ๋žฉํ•  ๋•Œ ์„ธ์…˜ ์‹๋ณ„ ๋งˆ์ปค๋งŒ ์ œ๊ฑฐํ•œ ํ™˜๊ฒฝ์„ ๋„˜๊ธด๋‹ค โ€” `CLAUDECODE`, `CLAUDE_CODE_CHILD_SESSION`, `CLAUDE_CODE_SESSION_ID`, `CLAUDE_CODE_SESSION_ATTENDED`, `CLAUDE_CODE_ENTRYPOINT`, `CLAUDE_PID`, `CLAUDE_CODE_MESSAGING_TOKEN`, `CLAUDE_CODE_MESSAGING_SOCKET`, `CLAUDE_CODE_BRIDGE_SESSION_ID`, `ANTIGRAVITY_CONVERSATION_ID`, `HERMES_SESSION_ID`, `GROK_SESSION_ID`, `OPENCODE_SESSION_ID`. `CLAUDE_PROJECT_DIR`ยท`CLAUDE_CONFIG_DIR` ๋“ฑ ์‚ฌ์šฉ์ž ์„ค์ •์€ ๊ทธ๋Œ€๋กœ ์ƒ์†๋œ๋‹ค. ์ƒ์†๋œ `CLAUDE_CODE_CHILD_SESSION` ๋•Œ๋ฌธ์— ์„œ๋ธŒ์—์ด์ „ํŠธ claude ์˜ transcript ์ €์žฅ์ด ๊บผ์ ธ resume ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋˜ ์ฆ์ƒ์„ ํ•ด์†Œ. 2. **์กฐํšŒ ๊ฒฝ๋กœ ์ž๋™ ๊ธฐ๋™ ๊ธˆ์ง€ `MAM_NO_AUTOSTART=1` (Issue #9)**: ์ด ๊ฐ’์ด ์„ค์ •๋˜๋ฉด ์‰ผ์€ ์„œ๋ฒ„๋ฅผ ๋„์šฐ์ง€ ์•Š๊ณ  ํ˜ธ์ถœ๋งŒ ์ „๋‹ฌํ•œ๋‹ค. `status.sh`ยท`reconcile.sh` ๊ฐ€ ์ด๋ฅผ export ํ•˜๋ฏ€๋กœ read-only `multi-agent-mux-status` ์กฐํšŒ๊ฐ€ ๋” ์ด์ƒ ์„œ๋ฒ„ ๋ฐ๋ชฌ์„ ๊ธฐ๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค. 3. **์‰ผ `ls` ์˜ "no server running" ๋ฒˆ์—ญ (Issue #9)**: ์„œ๋ฒ„๊ฐ€ ๋‚ด๋ ค๊ฐ€ ์žˆ์œผ๋ฉด ์‰ผ์˜ `ls` ๊ฐ€ `no server running (herdr session )` ์œผ๋กœ ๋ณด๊ณ ํ•˜๊ณ , `reconcile.sh` ๋Š” ์ด๋ฅผ ๋นˆ ์„œ๋ฒ„๋กœ ํŒ์ •ํ•ด `herdr_confirmed` ๋ฅผ ์œ ์ง€ํ•œ๋‹ค(ํŒŒ์‹ฑ ์‹คํŒจ๋กœ ๋ชจ๋“  ์„œ๋ฒ„์˜ drift ๊ฐ์ง€๊ฐ€ ๋ฉˆ์ถ”๋Š” ํšŒ๊ท€ ๋ฐฉ์ง€). ๋ฒˆ์—ญ์€ `agent list` ๊ฐ€ **์‹คํŒจ**ํ•˜๊ณ  ๊ทธ ์˜ค๋ฅ˜ ๋ด‰ํˆฌ(stderrยทstdout ์–ด๋А ์ชฝ์ด๋“ )์˜ `error.code` ๊ฐ€ ์ •ํ™•ํžˆ `server_not_running` ์ผ ๋•Œ๋งŒ ์ ์šฉํ•œ๋‹ค. ์„ฑ๊ณตํ•œ ๋ชฉ๋ก์— ๊ฐ™์€ ๋ฌธ์ž์—ด์ด ๋“ค์–ด ์žˆ์œผ๋ฉด(์˜ˆ: ์—์ด์ „ํŠธ ์ด๋ฆ„ `server_not_running-codex`) ๋ฒˆ์—ญํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์‚ด์•„ ์žˆ๋Š” ์„œ๋ฒ„๊ฐ€ ๋นˆ ์„œ๋ฒ„๋กœ ์˜คํŒ๋˜์–ด drift A ๋กœ ์ „ ์„ธ์…˜์ด ์ข…๋ฃŒ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ ๋ฐ–์˜ ์‹คํŒจ๋Š” ์ถœ๋ ฅ์ด ๋ชฉ๋ก ํŒŒ์„œ์— ๋‹ฟ๊ธฐ ์ „์— ๋น„-0 ์œผ๋กœ ๋๋‚˜(`โ€ฆ state unknown`, reconcile ์˜ ๋นˆ ์„œ๋ฒ„ ๋ฌธ๊ตฌ์™€ ๊ฒน์น˜์ง€ ์•Š์Œ) unknown(`herdr_confirmed=False`)์œผ๋กœ ๋‚จ๋Š”๋‹ค โ€” stdout ์œผ๋กœ ์˜จ ์˜ค๋ฅ˜ ๋ฌธ์„œ๋„ ๋” ์ด์ƒ ๋นˆ ๋ชฉ๋ก์œผ๋กœ ์ฝํžˆ์ง€ ์•Š๋Š”๋‹ค. 4. **accepted ์ œ์ถœ์˜ ์ „๋‹ฌ ํ™•์ธ `SKS_DELIVERY_GRACE_S` (Issue #14, `send_keys_safe`)**: `agent prompt --wait` ๊ฒฐ๊ณผ๊ฐ€ `timeout`/`agent_prompt_stalled` ์ด๋ฉด herdr ๊ฐ€ ์ž…๋ ฅ์„ ์ด๋ฏธ ์ˆ˜๋ฝํ•œ ๊ฒƒ์œผ๋กœ ๋ณด๊ณ , `SKS_DELIVERY_GRACE_S`(๊ธฐ๋ณธ 15์ดˆ) ๋™์•ˆ `agent_status` working, ์ œ์ถœ ์ „ ํ™”๋ฉด์— ์—†๋˜ busy ํ† ํฐ(`esc to interrupt`), ์ œ์ถœ ์ „ ์Šค๋ƒ…์ƒท ๋Œ€๋น„ pane ๋ณ€ํ™” ์ค‘ ํ•˜๋‚˜๋ฅผ ์ „๋‹ฌ ํ™•์ธ ์‹ ํ˜ธ๋กœ ์ธ์ •ํ•œ๋‹ค. ์‹ ํ˜ธ๊ฐ€ ์—†์œผ๋ฉด ์ข…์ „๋Œ€๋กœ rc 4 ๋กœ fail-closed ํ•˜๊ณ , ๊ทธ ๋ฐ–์˜ ์˜ค๋ฅ˜(`transport_error` ๋“ฑ)๋Š” accepted ๋กœ ์ทจ๊ธ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‹จ์ผ ์ฃผ์ž… ๊ณ„์•ฝ(์žฌ์ „์†ก ์—†์Œ)์€ ์œ ์ง€๋œ๋‹ค. 5. **๋ž˜ํผ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ack ์œ ์˜ˆ `MAM_INJECT_ACK_GRACE_S` (Issue #14, `multi-agent-mux-delegate-job`)**: `send_keys_safe` ๊ฐ€ ์ „๋‹ฌ์„ ํ™•์ธํ•˜์ง€ ๋ชปํ•ด๋„ ์žก์„ `agent_blocked` ๋กœ ๋‹ซ๊ธฐ ์ „์— `MAM_INJECT_ACK_GRACE_S`(๊ธฐ๋ณธ 10์ดˆ) ๋™์•ˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๊ด€์ธกํ•˜๊ณ , `pending` ์ด ์•„๋‹Œ ์ƒํƒœ(์—์ด์ „ํŠธ์˜ `started` ๋“ฑ)๊ฐ€ ๋ณด์ด๋ฉด ์ „๋‹ฌ๋œ ๊ฒƒ์œผ๋กœ ๋ณด๊ณ  ์ง„ํ–‰ํ•œ๋‹ค(`_inject_acknowledged`). 6. **R1 ์œ ์˜ˆ์˜ pane busy ํ† ํฐยท๋””์Šคํฌ heartbeat ์ธ์ • (Issue #14, `_agent_still_working`, `_recent_disk_heartbeat`)**: ๊ตฌ๋…์ž idle ํƒ€์ž„์•„์›ƒ ํ›„ R1 ์œ ์˜ˆ๊ฐ€ herdr `working` ์™ธ์— pane ์ตœ๊ทผ 8์ค„์˜ `esc to interrupt` ํ† ํฐ, ๊ทธ๋ฆฌ๊ณ  ์žก `events.log` ์˜ ์ตœ๊ทผ ์ด๋ฒคํŠธ(`publish_event` ๊ฐ€ ์™€์ด์–ด ๋ฐœํ–‰ ์‹œ๋„ **๋’ค**์— ์„ฑ๊ณต ์—ฌ๋ถ€์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋กœ์ปฌ์— ๊ธฐ๋กํ•˜๋Š” `progress` heartbeat โ€” ๋ธŒ๋กœ์ปค ์žฅ์•  ์‹œ์—๋Š” ๋ฐœํ–‰ ์žฌ์‹œ๋„ ์‹œ๊ฐ„๋งŒํผ ๋Šฆ๊ฒŒ ๊ธฐ๋ก๋œ๋‹ค)๋„ ์ž‘์—… ์ค‘ ๊ทผ๊ฑฐ๋กœ ๋ฐ›์•„๋“ค์ธ๋‹ค. ์œ ์˜ˆ์— ๋“ค์–ด๊ฐ€๋ฉด `IDLE_TIMEOUT` ์ฐฝ ํ•˜๋‚˜๊ฐ€ ์—ด๋ฆฌ๊ณ , ๊ทผ๊ฑฐ๊ฐ€ ๊ด€์ธก๋  ๋•Œ๋งˆ๋‹ค ๊ทธ ์‹œ์ ๋ถ€ํ„ฐ ์ฐฝ์ด ๋‹ค์‹œ ์—ด๋ฆฐ๋‹ค. ๋”ฐ๋ผ์„œ **์•„๋ฌด ๊ทผ๊ฑฐ๋„ ์—†๋Š” ๋ฌด์‘๋‹ต ์—์ด์ „ํŠธ๋Š” ๋งˆ์ง€๋ง‰ ์™€์ด์–ด ์ด๋ฒคํŠธ ํ›„ ์•ฝ 2ร—`IDLE_TIMEOUT` ์— ๋‹ซํžˆ๊ณ **(๋””์Šคํฌ heartbeat ๋ฅผ ์ธ์ •ํ•˜๊ธฐ ์ „์—๋Š” `IDLE_TIMEOUT`; Issue #6 ์ˆ˜์šฉ ๊ธฐ์ค€ "โ‰ค `IDLE_TIMEOUT`+5s ๋‚ด `error`"๋Š” "โ‰ค 2ร—`IDLE_TIMEOUT` + ์—ฌ์œ "๋กœ ๋ฐ”๋€๋‹ค), **heartbeat ๊ฐ„๊ฒฉ์€ ์•ฝ 2ร—`IDLE_TIMEOUT` ๊นŒ์ง€ ํ—ˆ์šฉ๋œ๋‹ค**(heartbeat ํ•˜๋‚˜๊ฐ€ `IDLE_TIMEOUT` ๋งŒํผ ์˜ค๋ž˜๋  ๋•Œ๊นŒ์ง€ ๊ทผ๊ฑฐ๋กœ ์ธ์ •๋˜๋ฏ€๋กœ). ๊ทผ๊ฑฐ๋Š” idle ์ฐฝ๋งŒ ๋Š˜๋ฆด ๋ฟ ๋ฒฝ์‹œ๊ณ„๋Š” ๋Š˜๋ฆฌ์ง€ ์•Š๋Š”๋‹ค: ๋ฃจํ”„๋Š” ๋งค ๋ฐ˜๋ณต ์‹œ๊ณ„๋กœ ๋‹ค์‹œ ์ฝ์€ `START_TIME + TIMEOUT` ์—์„œ ๋๋‚˜๊ณ , herdr ๊ด€์ธก ํ˜ธ์ถœ๋„ ๊ทธ ์‹œ๊ฐ์— ๋Š๋Š”๋‹ค(`_within_deadline`). `broker_unavailable` ๋””์Šคํฌ ์žฌ๊ด€์ธก ๋ฃจํ”„๋„ ๊ฐ™์€ ์‹œ๊ณ„ ๊ธฐ์ค€์ด๋‹ค. ์ด๋กœ์จ idle ํƒ€์ž„์•„์›ƒ๋ณด๋‹ค ๊ธด codex ๋ฆฌ๋ทฐ, heartbeat ๊ฐ„๊ฒฉ์ด ํ•œ ๋ฒˆ idle ์ฐฝ์„ ๋„˜๊ธด ๋ฆฌ๋ทฐ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์…ธ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ๋Œ๋ ค herdr ์— idle ๋กœ ๋ณด์ด๋Š” creator ๊ฐ€ ํ„ด ๋„์ค‘ `deadline_timeout` ์œผ๋กœ ๋‹ซํžˆ๊ณ  ์ดํ›„ `completed` ๊ฐ€ ๊ฑฐ๋ถ€๋˜๋˜ ๋ฌธ์ œ๋ฅผ ๋ง‰๋Š”๋‹ค. #### โœ… ํ’ˆ์งˆ ๊ฒ€์ฆ - **T1-7 ํŠธ๋ฆฌ๊ฑฐ ๋ณ€๊ฒฝ** (`tests/test_issue6_fail_closed.py`): ์ฃผ์ž… ์‹คํŒจ ์œ ๋ฐœ๊ฐ’์„ `prompt_wait_result=timeout` โ†’ `transport_error` ๋กœ ๋ณ€๊ฒฝ(Issue #14 ์ดํ›„ `timeout` ์€ accepted ์ œ์ถœ์ด๋ฏ€๋กœ ๋” ์ด์ƒ ํ™•์ • ์‹คํŒจ๊ฐ€ ์•„๋‹˜)ํ•˜๊ณ  `MAM_INJECT_ACK_GRACE_S=1` ๋กœ ๋Œ€๊ธฐ๋ฅผ ๋‹จ์ถ•. - **์‹ ๊ทœ ํ…Œ์ŠคํŠธ 19๊ฐœ**: `tests/test_issue9_server_env.py` 9๊ฐœ(๋งˆ์ปค ์ œ๊ฑฐ, `MAM_NO_AUTOSTART` ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ์ƒ๋žตยทํ˜ธ์ถœ ์ „๋‹ฌ, status ์กฐํšŒ ๋ฌด๊ธฐ๋™, ์ •์  opt-out, `ls` ๋ฒˆ์—ญ(์ตœ์†Œยทherdr 0.9 ์‹ค์ œ ์˜ค๋ฅ˜ ๋ด‰ํˆฌยทstdout ๋ด‰ํˆฌ), ์„ฑ๊ณต ๋ชฉ๋ก ์† `server_not_running` ๋ฌธ์ž์—ด ๋น„์˜คํŒ, ๊ทธ ๋ฐ–์˜ ์‹คํŒจ unknown ์œ ์ง€(stderrยทstdout), reconcile drift A ๋น„๋ฐœ์ƒ, ๋‹ค๋ฅธ ์‹คํŒจ ์‹œ reconcile `herdr_confirmed=False`), `tests/test_issue14_delivery_ack.py` 10๊ฐœ(busy ํ† ํฐยทpane ๋ณ€ํ™” ํ™•์ธ, ๋ฌด์‹ ํ˜ธ fail-closed, ์„ ํ–‰ busy ํ† ํฐ ๋ฐฐ์ œ, `transport_error` ๋น„์ˆ˜์šฉ, mock herdr timeout ํ™•์ธ, ๋ž˜ํผ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ack, idle ํƒ€์ž„์•„์›ƒ pane busy ์œ ์˜ˆ, idle ํƒ€์ž„์•„์›ƒ ๋””์Šคํฌ heartbeat ์œ ์˜ˆ, heartbeat ๊ฐ€ ์ด์–ด์ ธ๋„ ๋ฒฝ์‹œ๊ณ„ `TIMEOUT` ์•ˆ์—์„œ ์ข…๋ฃŒ). - **ํ…Œ์ŠคํŠธ ๊ธฐ๋Œ€๊ฐ’ ์ •์ •**: `tests/test_a4_adapter_contract.py` ๊ฐ€ `4d444ce` ์˜ agy `exit_key=/exit` ๋ณ€๊ฒฝ์„ ๋ฐ˜์˜ํ•˜๋„๋ก ์ˆ˜์ •(๊ทธ๋™์•ˆ ์ „์ฒด ์Šค์œ„ํŠธ์—์„œ 1๊ฑด ์‹คํŒจํ•˜๋˜ ๋ฌธ์ œ ํ•ด์†Œ). - **์‹ค์ธก (์ปค๋ฐ‹ `497633f` ๊ธฐ๋ก)**: ์ƒˆ๋กœ ๋ถ€ํŠธ์ŠคํŠธ๋žฉํ•œ ์„œ๋ฒ„์— ๋งˆ์ปค๊ฐ€ ์—†๊ณ  claude pane ์˜ transcript ์ €์žฅ์ด ๋ณต๊ตฌ๋จ, codex ์žก `d04ebcb5` ์˜ `started`/`completed` ๊ฐ€ `agent_blocked` ์—†์ด ์ˆ˜๋ฝ๋จ. ### ๐Ÿš€ `v4.4.1` โ€” Issue #6 ๋น„๋™๊ธฐ ์žก ์œ„์ž„ ์•ˆ์ •ํ™” ๋ฐ Fail-Closed / Turn Handshake ์™„๊ฒฐ (2026-09-08) > **ํŒจ์น˜ ๋งˆ์ผ์Šคํ†ค (PATCH Release)**: Issue #6 ๋น„๋™๊ธฐ ์žก ์œ„์ž„ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ๋ฐœ์ƒํ•˜๋˜ ํ„ฐ๋ฏธ๋„ ์ƒํƒœ ๋ฎ์–ด์“ฐ๊ธฐ ๋ ˆ์ด์Šค, Herdr ํ”„๋กฌํ”„ํŠธ ์™„๋ฃŒ ๊ด€์ธก ๋ถ€์žฌ, Subscriber ํƒ€์ž„์•„์›ƒ ์‹œ pending ๋ฐฉ์น˜ ๋ฒ„๊ทธ๋ฅผ ๊ทผ๋ณธ ํ•ด๊ฒฐ. ๊ฒฐ์ •๋ก ์  ์ข…๋ฃŒ ์ฝ”๋“œ ๊ณ„์•ฝ(0, 1, 2, 3, 5) ๋ฐ 4๋‹จ๊ณ„ fail-closed finalizer๋ฅผ ์™„๋น„ํ–ˆ๋‹ค. #### ๐ŸŒŸ ์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ 1. **Terminal ์ƒํƒœ ๋‹จ๋ฐฉํ–ฅ ๋ถˆ๋ณ€์„ฑ**: ํ„ฐ๋ฏธ๋„ ์ƒํƒœ(`completed`, `error`, `cancelled`)์— ๋„๋‹ฌํ•œ ์žก์— ๋Œ€ํ•ด ์ดํ›„ ๋„์ฐฉํ•˜๋Š” ์ด๋ฒคํŠธ์˜ ์ž„์˜ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์›์ฒœ ์ฐจ๋‹จ. `registry.py close` ์„œ๋ธŒ์ปค๋งจ๋“œ๋กœ ๋น„์ •์ƒ ์ค‘๋‹จ ์‹œ ๋‹จ๋ฐฉํ–ฅ ์ข…๋ฃŒ ์ฒ˜๋ฆฌ ๋ณด์žฅ. 2. **Herdr ํ„ด ์™„๋ฃŒ ํ•ธ๋“œ์…ฐ์ดํฌ (`lib.sh: wait_for_agent_idle`, `watcher.py`)**: `wait_for_agent_idle`์„ ํ†ตํ•ด ์—์ด์ „ํŠธ ํ”„๋กฌํ”„ํŠธ ์ „์†ก ์ „ํ›„ ์œ ํœด ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ํ„ด์ด ์™„์ „ํžˆ ์™„๋ฃŒ๋˜์–ด ์ž…๋ ฅ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋ณต๊ท€ํ•  ๋•Œ๊นŒ์ง€ ์‹ ๋ขฐ์„ฑ ์žˆ๊ฒŒ ์ถ”์ . 3. **Loop ๋ชจ๋“œ `attempt_id` ์ „์ด ๊ฒฉ๋ฆฌ**: ๋™์ผ iteration ๋‚ด์—์„œ ์›Œ์ปคโ†’๋ฆฌ๋ทฐ์–ด ์ „ํ™˜ ์‹œ `attempt_id`๋ฅผ ๊ฐฑ์‹ ํ•˜์—ฌ CAS ์žฌ์ „์ด ์ถฉ๋Œ(rc=4)์„ ๊ตฌ์กฐ์ ์œผ๋กœ ๋ฐฉ์ง€. 4. **Subscriber ๋น„์ •์ƒ ์ข…๋ฃŒ ์‹œ Fail-Closed ๋ฐ R1 Working ํšŒ๋ณต๋ ฅ ๋ณด์žฅ**: ๊ตฌ๋…๊ธฐ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํƒ€์ž„์•„์›ƒ๋˜๋”๋ผ๋„ ์—์ด์ „ํŠธ๊ฐ€ Herdr์—์„œ ์—ฌ์ „ํžˆ ์ž‘์—… ์ค‘(`working`)์ด๋ฉด ๋ฒฝ์‹œ๊ณ„ `--timeout`๊นŒ์ง€ ์œ ์˜ˆํ•˜๋ฉฐ ๋””์Šคํฌ ์™„๋ฃŒ ์ƒํƒœ๋ฅผ ์žฌ๊ด€์ธก(R1)ํ•˜๊ณ , ๋ฏธ์ข…๋ฃŒ ์žก์„ ์•ˆ์ „ํ•˜๊ฒŒ `error`๋กœ ์™„๊ฒฐ. 5. **๊ฒฐ์ •๋ก ์  ์ข…๋ฃŒ ์ฝ”๋“œ ๊ณ„์•ฝ**: `multi-agent-mux-delegate-job` ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ์ •๊ทœํ™”(`0`=์„ฑ๊ณต, `1`=์‹คํŒจ/์ฃผ์ž… ์˜ค๋ฅ˜, `2`=๊ตฌ๋…๊ธฐ ํƒ€์ž„์•„์›ƒ, `3`=๋ธŒ๋กœ์ปค ์žฅ์• , `5`=์„ธ์…˜ ์„ ๊ฒฐ ์กฐ๊ฑด ๋ฏธ์ถฉ์กฑ/session_busy). ### ๐Ÿš€ `v4.4.0` โ€” Issue #5 Python ์ฝ”์–ด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์™„๊ฒฐ ๋ฐ `main` ๋ณ‘ํ•ฉ (2026-09-07) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (MINOR Release)**: Issue #5 Phase 1~4 ์ „ ๋‹จ๊ณ„ ์™„๋ฃŒ ๋ฐ `refactor` โ†’ `main` ๋ณ‘ํ•ฉ. ์œ„์ž„ยท๋ฃจํ”„ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜์˜ ๊ตฌํ˜„ ์–ธ์–ด๋ฅผ Bash์—์„œ Python์œผ๋กœ ์˜ฎ๊ธฐ๊ณ , CAS ๋‹จ์ผ ์ƒํƒœ ์ „์ดยท์„€๋„์šฐ ์™€์ฒ˜ยท์ž๋™ ์™„๋ฃŒ ๊ฒŒ์ดํŠธยทEager Import ๋ถˆ๋ณ€ ๋Ÿฐํƒ€์ž„์„ ๋„์ž…ํ–ˆ๋‹ค. **๊ณต๊ฐœ ๊ณ„์•ฝ(์Šคํฌ๋ฆฝํŠธ ๊ฒฝ๋กœ, CLI ์ธ์žยท์ข…๋ฃŒ ์ฝ”๋“œ, ์ด๋ฒคํŠธ ์™€์ด์–ด ์Šคํ‚ค๋งˆ `schema_version=1`, YAML ๋ ˆ์ด์•„์›ƒ)์€ ํ•œ ๊ฑด๋„ ์ œ๊ฑฐยท๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ**, ๋ชจ๋“  ๊ธฐ๋ณธ ๋™์ž‘ ๋ณ€๊ฒฝ์€ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ•œ ๊ฐœ๋กœ ์ฆ‰์‹œ ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ๋‹ค. #### โš–๏ธ SemVer ํŒ์ • ๊ทผ๊ฑฐ (MINOR โ€” `v4.4.0`, MAJOR `v5.0.0` ๋ฏธ์ฑ„ํƒ) SemVer 2.0.0 ยง8์€ MAJOR๋ฅผ **ํ•˜์œ„ ํ˜ธํ™˜์„ ๊นจ๋Š” ๊ณต๊ฐœ API ๋ณ€๊ฒฝ**์— ํ•œ์ •ํ•œ๋‹ค. ๋ณธ ๋ฆด๋ฆฌ์Šค๋Š” ๊ทœ๋ชจ๋Š” ํฌ์ง€๋งŒ ๊ทธ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜์ง€ ์•Š๋Š”๋‹ค. | ํŒ์ • ์ถ• | ๊ด€์ธก ์‚ฌ์‹ค | ๊ทผ๊ฑฐ | | :--- | :--- | :---: | | ๊ณต๊ฐœ ๊ณ„์•ฝ ์ œ๊ฑฐ/์ด๋™ | Issue #5 ์ „ ๊ตฌ๊ฐ„์—์„œ **์‚ญ์ œยทrename ํŒŒ์ผ 0๊ฑด** | `git diff --name-status fc0bd96..HEAD` | | ์™€์ด์–ด ์Šคํ‚ค๋งˆ | `SCHEMA_VERSION = 1` ๋ถˆ๋ณ€ | `mqtt_common.py:135` | | ์Šคํฌ๋ฆฝํŠธ ๋ฆฌํ„ฐ๋Ÿด ๊ฒฝ๋กœ | `scripts/*.py` 4์ข… ์ „๋ถ€ ์กด์† (ํ˜ธํ™˜ shim) | Phase 1 D2 | | CLI ์ธ์žยท์ข…๋ฃŒ ์ฝ”๋“œ | `run_loop.sh`ยท`publish_event`ยท`job_subscriber` ๊ณ„์•ฝ ํšŒ๊ท€ ํ†ต๊ณผ | G-1~G-9 | | ๊ธฐ๋ณธ ๋™์ž‘ ๋ณ€๊ฒฝ์˜ ๊ฐ€์—ญ์„ฑ | `MAM_DELEGATION_PY=0` / `MAM_ENGINE_CAS=0` / `MAM_LOOP_PY=0` / `MAM_LOOP_FREEZE=1` ๋กœ ์ด์ „ ๋™์ž‘ ์™„์ „ ๋ณต์› (๋ ˆ๊ฑฐ์‹œ ๋ณธ์ฒด ์กด์น˜, 968์ค„ ์…ธ ๋ฃจํ”„ ํฌํ•จ) | `test_issue5_phase3_loop.py`, `test_issue5_phase4_runtime.py` | | ์ตœ๊ณ ์œ„ํ—˜ ์‹ ๊ทœ ๊ธฐ๋Šฅ | ์ž๋™ ์™„๋ฃŒ๋Š” **๊ธฐ๋ณธ ๋น„ํ™œ์„ฑ** ์˜ตํŠธ์ธ | `MAM_AUTO_COMPLETE` ๊ธฐ๋ณธ๊ฐ’ `0` | > **์šด์˜์ž ์กฐ์น˜ ํ•„์š” ์‚ฌํ•ญ ์—†์Œ**: ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ ˆ์ฐจ, ์„ค์ • ๋ณ€ํ™˜, ์žฌ๋ฐฐํฌ๊ฐ€ ์š”๊ตฌ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ด๊ฒƒ์ด MAJOR๋ฅผ ์ฑ„ํƒํ•˜์ง€ ์•Š์€ ๊ฒฐ์ •์  ์ด์œ ๋‹ค. ๋‹ค๋งŒ `MAM_VERSION` ๋ถˆ์ผ์น˜๋Š” ์ƒˆ๋กœ fail-closed ๊ฑฐ๋ถ€๋˜๋ฏ€๋กœ, **ํ”„๋ ˆ์ž„์›Œํฌ ํŠธ๋ฆฌ๋Š” ๋ถ€๋ถ„ ๊ฐฑ์‹ ํ•˜์ง€ ๋ง๊ณ  ํ†ต์งธ๋กœ ๋ฐฐํฌํ•ด์•ผ ํ•œ๋‹ค**(ยง ์•„๋ž˜ ์ฃผ์˜). #### ๐ŸŒŸ ์‹ ๊ทœ ๊ธฐ๋Šฅ ๋ฐ ์•„ํ‚คํ…์ฒ˜ ํ™•์žฅ * **Phase 1 โ€” `lib_py.delegation` ํŒจํ‚ค์ง€ ์ถ”์ถœ**: `v4.3.0`์—์„œ ์„ ํ–‰ ์™„๋ฃŒ(ํ•˜๋‹จ ํ•ญ๋ชฉ ์ฐธ์กฐ). * **Phase 2a โ€” CAS ๋‹จ์ผ ์ƒํƒœ ์ „์ด ์—”์ง„ ๋ฐ ์„€๋„์šฐ ์™€์ฒ˜**: ์žก ๋ ˆ์ฝ”๋“œ ์ „์ด๋ฅผ `claim`/`redispatch` ์‹œ์ ์— ๋ฐœ๊ธ‰๋˜๋Š” ๋ถˆํˆฌ๋ช… `dispatch_token`์„ ์„ ๊ฒฐ ์กฐ๊ฑด์œผ๋กœ ํ•˜๋Š” compare-and-set์œผ๋กœ ๊ฒฐ์†. ๊ด€์ธก ์ฆ๊ฑฐ ์ˆ˜์ง‘(`attribution.py`)ยทํŒ์ • ์ •์ฑ…(`policy.py`)ยท์ฆ๊ฑฐ ์ €์žฅ์†Œ(`store.py`)๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ , `shadow.py`๊ฐ€ ์‹ค์ œ ์ „์ด ์—†์ด "Would-Complete" ํŒ์ •๋งŒ ๊ธฐ๋กํ•œ๋‹ค. * **Phase 2b โ€” ์ž๋™ ์™„๋ฃŒ ๊ฒŒ์ดํŠธ (`autocomplete.py`)**: ์„€๋„์šฐ ์ฆ๊ฑฐ๊ฐ€ ์ถฉ๋ถ„ํ•  ๋•Œ์—๋งŒ ์žก์„ ์ž๋™ ์ข…๊ฒฐํ•˜๋Š” ํ‰๊ฐ€๊ธฐ. `MAM_AUTO_COMPLETE`(๊ธฐ๋ณธ `0`), `MAM_AUTO_COMPLETE_BACKENDS`๋กœ ๋ฐฑ์—”๋“œ ๋‹จ์œ„ ์˜ตํŠธ์ธ. CAS๊ฐ€ ๋กค๋ฐฑ๋œ ์ƒํƒœ(`MAM_ENGINE_CAS=0`)์—์„œ๋Š” ์Šค์Šค๋กœ ๋น„ํ™œ์„ฑํ™”ํ•œ๋‹ค. * **Phase 2b โ€” ๋‚ด๊ตฌ์„ฑ ์žˆ๋Š” ๋ณด๋ฅ˜ ์•Œ๋ฆผ (`notifier.py`)**: ์•Œ๋ฆผ ์˜๋„๋ฅผ ์žก ๋ ˆ์ฝ”๋“œ์— ์ €์žฅํ•˜๊ณ  CAS ๋ฝ ๋ฐ”๊นฅ์—์„œ ๋ฐœํ–‰ํ•œ ๋’ค `notification_settled` ๋ถ€๊ธฐ ์š”์ฒญ์œผ๋กœ ์กฐ๊ฑด๋ถ€ ์ •์‚ฐ. ์žฌ์‹œ๋„๋Š” ์ƒˆ ์™€์ด์–ด ์‹œํ€€์Šค๋ฅผ ๋ฐ›์œผ๋ฏ€๋กœ ๋‹จ์กฐ ์‹œํ€€์Šค ๊ฐ€๋“œ๋กœ๋Š” ์ค‘๋ณต์„ ์‹๋ณ„ํ•  ์ˆ˜ ์—†๊ณ , ์•ˆ์ •์ ์ธ `(seq, event, timestamp)` ์˜๋„ ์‹ ์›์œผ๋กœ ์ค‘๋ณต์„ ํŒ๋ณ„ํ•œ๋‹ค. * **Phase 3 โ€” `run_loop.sh` ์–‡์€ ๋ž˜ํผ ์ „ํ™˜ ๋ฐ `lib_py.loop` ์Šน๊ฒฉ**: 936์ค„ Bash ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜์„ ๋‹จ์ผ ์ œ์–ด ๊ตฌ์กฐ์˜ Python ๋ชจ๋“ˆ๋กœ ์ด์‹. `run_loop.sh`๋Š” CLI ๊ณ„์•ฝ๊ณผ ๊ธฐ์กด ์ •์  ๊ฒ€์‚ฌ ์•ต์ปค๋ฅผ ๋ณด์กดํ•˜๋Š” ๋ž˜ํผ๊ฐ€ ๋˜์—ˆ๊ณ , `MAM_LOOP_PY=0`์œผ๋กœ ๋ ˆ๊ฑฐ์‹œ ์…ธ ๋ฃจํ”„๋ฅผ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. * **Phase 3 โ€” Strict ํŒ์ • ํŒŒ์„œ (`parser.py`)**: ๋งˆํฌ๋‹ค์šด ์ฝ”๋“œ ํŽœ์Šค(` ``` `, `~~~`) ๋‚ด๋ถ€๋ฅผ ์ œ๊ฑฐํ•œ ๋’ค **๋งˆ์ง€๋ง‰ ๋น„๊ณต๋ฐฑ ๋ผ์ธ**๋งŒ์„ ํŒ์ •์œผ๋กœ ์ธ์ •ํ•œ๋‹ค. ๋ฆฌํฌํŠธ ๋ณธ๋ฌธ์˜ ์˜ˆ์‹œ ์ฝ”๋“œ์— ์ ํžŒ `[VERDICT: PASS]`๊ฐ€ ์‹ค์ œ ํŒ์ •์œผ๋กœ ์˜ค์ธ๋˜๋˜ ๊ฒฐํ•จ(`baseline.md` Gap)์„ ํ•ด์†Œํ–ˆ๋‹ค. ํŒ์ • ๋ถ€์žฌยท`PASS`/`NOT PASS` ๋ชจํ˜ธ ์ถฉ๋Œยท๋ฏธ์ง€ ํƒœ๊ทธ๋Š” ๋ชจ๋‘ fail-closed `NOT PASS`. * **Phase 3 โ€” ์›์ž์  ์ฒดํฌํฌ์ธํŠธ ๋ฐ ์šฐ์•„ํ•œ ์ •์ง€ (`checkpoint.py`)**: `.mam/loop-checkpoint.json`์— ํšŒ์ฐจยทํ™œ์„ฑ ์žกยท๊ณ„ํšยท๋ฆฌ๋ทฐ ์ƒํƒœยท๊ธฐ์ค€ ์ปค๋ฐ‹์„ ์ž„์‹œ ํŒŒ์ผ + `replace` ์›์ž ์ปค๋ฐ‹์œผ๋กœ ๊ธฐ๋ก. SIGINT/SIGTERM ์ˆ˜์‹  ์‹œ ์„œ๋ธŒํ”„๋กœ์„ธ์Šค๋ฅผ ์ •๋ฆฌํ•˜๊ณ  ์ฒดํฌํฌ์ธํŠธ๋ฅผ ๋‚จ๊ธด ๋’ค ๊ฐ€๋“œ๋ฅผ ํ•ด์ œํ•˜๊ณ  ์ข…๋ฃŒ(130/143). * **Phase 4 โ€” Eager Import ๋ถˆ๋ณ€ ๋Ÿฐํƒ€์ž„ (`eager.py`)**: ๊ธฐ๋™ ์ตœ์šฐ์„  ๋‹จ๊ณ„์—์„œ ํ‘œ์ค€ยทํ”„๋ ˆ์ž„์›Œํฌ ์ฝ”์–ด ๋ชจ๋“ˆ ์ „๋Ÿ‰์„ `sys.modules`์— ์ƒ์ฃผ์‹œ์ผœ, ๋ฃจํ”„ ์‹คํ–‰ ์ค‘ ๋””์Šคํฌ์˜ `.py`๊ฐ€ ํŽธ์ง‘๋˜์–ด๋„ ๋Ÿฐํƒ€์ž„์ด ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. `PYTHONDONTWRITEBYTECODE=1`๋กœ `.pyc` ํŒŒํŽธ์— ์˜ํ•œ ์ž‘์—… ํŠธ๋ฆฌ ์˜ค์—ผ์„ ์ฐจ๋‹จํ•œ๋‹ค. * **Phase 4 โ€” B-13 Freeze ์Šค๋ƒ…์ƒท ์ œ๊ฑฐ**: Bash๊ฐ€ ์‹คํ–‰ ์ค‘ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋””์Šคํฌ์—์„œ ์žฌ๋…ํ•ดํ•˜๋ฉฐ ๋ฐœ์ƒํ•˜๋˜ ํฌ๋ž˜์‹œ(B-13)์˜ ์›์ธ์ด Python ์ƒ์ฃผ ํ”„๋กœ์„ธ์Šค ์ „ํ™˜์œผ๋กœ ๊ทผ๋ณธ ํ•ด์†Œ๋˜์—ˆ์œผ๋ฏ€๋กœ, ์ž„์‹œ ๋น„๊ณ„์˜€๋˜ `/tmp/mam-loop-freeze.XXXXXX` ํŠธ๋ฆฌ ๋ณต์‚ฌ๋ฅผ ๊ธฐ๋ณธ ๊ฒฝ๋กœ์—์„œ ์ฒ ๊ฑฐํ–ˆ๋‹ค. ํ„ด๋‹น ์ˆ˜๋ฐฑ ๊ฐœ ํŒŒ์ผ ๋ณต์‚ฌ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค. #### ๐Ÿ”’ ๋กค๋ฐฑ ๋ฐ ์•ˆ์ „์žฅ์น˜ * **๋‹จ์ผ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋กค๋ฐฑ 4์ข…**: `MAM_DELEGATION_PY=0`(์œ„์ž„ ์…ธ ํ—ฌํผ ๋ ˆ๊ฑฐ์‹œ ๋ณธ์ฒด), `MAM_ENGINE_CAS=0`(๋ฌด์กฐ๊ฑด ๋ณ‘ํ•ฉ ๋ณต์›), `MAM_LOOP_PY=0`(๋ ˆ๊ฑฐ์‹œ ์…ธ ๋ฃจํ”„), `MAM_LOOP_FREEZE=1`(Freeze ์Šค๋ƒ…์ƒท ์žฌํ™œ์„ฑํ™”). ์žฌ๋ฐฐํฌยทrevert ๋ถˆํ•„์š”. * **โš ๏ธ ๋ถ€๋ถ„ ๋ฐฐํฌ ๊ธˆ์ง€ (์‹ ๊ทœ fail-closed ๊ฒŒ์ดํŠธ)**: `lib.sh`์˜ `MAM_VERSION`๊ณผ `lib_py/loop/eager.py`์˜ `FRAMEWORK_VERSION`์ด ๋‹ค๋ฅด๋ฉด `verify_framework_version()`์ด `RuntimeError`๋กœ ๋ฃจํ”„ ๊ธฐ๋™์„ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ๋‘ ํŒŒ์ผ ์ค‘ ํ•˜๋‚˜๋งŒ ๊ฐฑ์‹ ๋œ ํ˜ผ์žฌ ํŠธ๋ฆฌ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ํ•ญ์ƒ ํŠธ๋ฆฌ ๋‹จ์œ„๋กœ ๋ฐฐํฌํ•œ๋‹ค. * **4-Way ๋ฝ์Šคํ… ์ž๋™ ๊ฒ€์ฆ**: `test_version_consistency.py`๊ฐ€ `lib.sh` โ†” `eager.py` โ†” `VERSIONS.md`(ํ˜„์žฌ ๋ฒ„์ „ + ๋งคํŠธ๋ฆญ์Šค 8ํ–‰) โ†” 8๊ฐœ `SKILL.md` frontmatter์˜ ์™„์ „ ์ผ์น˜๋ฅผ ๊ฐ•์ œํ•œ๋‹ค. `eager.py` ์ปค๋ฒ„๋ฆฌ์ง€๋Š” ๋ณธ ๋ฆด๋ฆฌ์Šค์—์„œ ์‹ ๊ทœ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. #### โœ… ํ’ˆ์งˆ ๊ฒ€์ฆ * ์ „์ฒด ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ **750๊ฐœ ํ†ต๊ณผ, 0 ์‹คํŒจ, 0 skip** (Issue #5 ์ฐฉ์ˆ˜ ์‹œ์  510๊ฐœ ๋Œ€๋น„ +240). * Issue #5 ์ „์šฉ ํšŒ๊ท€: `test_issue5_phase{0,1,2a,2b,3,4}_*.py`. * **ํ…Œ์ŠคํŠธ ๊ฒฉ๋ฆฌ ๊ฒฐํ•จ 1๊ฑด ์ˆ˜์ • (`tests/conftest.py`)**: `lib.sh`๊ฐ€ exportํ•œ `MAM_VERSION`์ด pytest๋ฅผ ๊ธฐ๋™ํ•œ ์…ธ์—์„œ ์ƒ์†๋˜์–ด, ๋ฃจํ”„ ํ…Œ์ŠคํŠธ๊ฐ€ *๊ฒ€์‚ฌ ๋Œ€์ƒ ํŠธ๋ฆฌ*๊ฐ€ ์•„๋‹ˆ๋ผ *๋Ÿฌ๋„ˆ๋ฅผ ๋„์šด ์…ธ์ด ์–ธ์ œ `lib.sh`๋ฅผ sourceํ–ˆ๋Š”์ง€*์— ๋”ฐ๋ผ ํ†ต๊ณผยท์‹คํŒจํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€๋Š” ์ƒ์†๊ฐ’๊ณผ ์ƒ์ˆ˜๊ฐ€ ์šฐ์—ฐํžˆ ๊ฐ™์•„ ์ž ๋ณตํ•ด ์žˆ์—ˆ๊ณ , ๋ณธ ๋ฆด๋ฆฌ์Šค์˜ ๋ฒ„์ „ ์ƒ์Šน์ด ์ด๋ฅผ ๋“œ๋Ÿฌ๋ƒˆ๋‹ค(4๊ฑด ์‹คํŒจ). ์„ธ์…˜ ์Šค์ฝ”ํ”„ fixture๊ฐ€ ์ƒ์†๋œ ๊ฐ’์„ ์ œ๊ฑฐํ•˜์—ฌ ์Šค์œ„ํŠธ๊ฐ€ ํŠธ๋ฆฌ๋ฅผ ์ธก์ •ํ•˜๋„๋ก ๋ฐ”๋กœ์žก์•˜๋‹ค. - ํ”„๋กœ๋•์…˜ ๊ฒฝ๋กœ๋Š” ์˜ํ–ฅ ์—†์Œ: `run_loop.sh:17`์ด ์‹คํ–‰ ์ตœ์ดˆ์— `lib.sh`๋ฅผ sourceํ•˜๊ณ  `lib.sh:32-33`์ด `MAM_VERSION`์„ ๋ฌด์กฐ๊ฑด ์žฌexportํ•˜๋ฏ€๋กœ, ๋‚ก์€ ์ƒ์†๊ฐ’์€ ํŒŒ์ด์ฌ ๊ธฐ๋™ ์ „์— ํ•ญ์ƒ ๋ฎ์–ด์จ์ง„๋‹ค(`MAM_VERSION=4.3.0 bash -c 'source lib.sh; echo $MAM_VERSION'` โ†’ `4.4.0`). ### ๐Ÿš€ `v4.3.0` โ€” `lib_py.delegation` ํŒจํ‚ค์ง€ ์ถ”์ถœ ๋ฐ ์žฅ์ˆ˜ MQTT ์—ฐ๊ฒฐ ํ”„๋กœํ† ํƒ€์ž… (2026-09-06) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (MINOR Release)**: Issue #5 Phase 1. `lib.sh`์˜ ์œ„์ž„ ํ—ฌํผ 3์ข…๊ณผ `multi-agent-mux-delegate-job/scripts/*.py` 4์ข…์„ `lib_py/delegation/` ํŒŒ์ด์ฌ ํŒจํ‚ค์ง€๋กœ ์ถ”์ถœ. ์Šคํฌ๋ฆฝํŠธ ๊ฒฝ๋กœ๋Š” ์™€์ด์–ด ๊ณ„์•ฝ์ด๋ฏ€๋กœ ํ˜ธํ™˜ shim์œผ๋กœ ๋ณด์กดํ•˜๋ฉฐ, ํ”„๋กœ๋•์…˜ ๋™์ž‘ยท์ด๋ฒคํŠธ ์Šคํ‚ค๋งˆยท์ž๋™์™„๋ฃŒ ์ •์ฑ…์€ ํ•œ ์ค„๋„ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. #### ๐ŸŒŸ ์‹ ๊ทœ ๊ธฐ๋Šฅ ๋ฐ ์•„ํ‚คํ…์ฒ˜ ํ™•์žฅ * **ํŒจํ‚ค์ง€ ๋ฐ”์ธ๋”ฉ shim (D2)**: `scripts/{mqtt_common,registry,publish_event,job_subscriber}.py`๋Š” `lib_py.delegation` **ํŒจํ‚ค์ง€**๋ฅผ ์ž๊ธฐ ์˜† ํŠธ๋ฆฌ์— ํ”„๋กœ์„ธ์Šค๋‹น 1ํšŒ ๋ฐ”์ธ๋”ฉํ•˜๊ณ  `sys.path`๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. `import mqtt_common`์€ `lib_py.delegation.mqtt_common`๊ณผ ๋™์ผํ•œ ๋ชจ๋“ˆ ๊ฐ์ฒด๊ฐ€ ๋œ๋‹ค. - `sys.path.insert(0, ...)` ๋ฐฉ์‹์€ pytest์—์„œ ์ตœ์ดˆ๋กœ ์ž„ํฌํŠธ๋œ ์ƒŒ๋“œ๋ฐ•์Šค ์‚ฌ๋ณธ์ด `lib_py.agents`/`layout`/`state`๊นŒ์ง€ ์„ธ์…˜ ์ „์ฒด์— ๊ฑธ์ณ ๊ฐ€๋กœ์ฑ„๋ฏ€๋กœ ์ฑ„ํƒํ•˜์ง€ ์•Š์•˜๋‹ค. - ๋ชจ๋“ˆ ๋‹จ์œ„ ํŒŒ์ผ ์ ์žฌ ๋ฐฉ์‹์€ ํ˜•์ œ๋ฅผ ์ž„ํฌํŠธํ•˜๋Š” ๋ชจ๋“ˆ์ด ๋‹ค๋ฅธ ํŠธ๋ฆฌ์˜ ์˜์กด์„ฑ์„ ๋Œ์–ด์™€ freeze(B-13) ๋ณดํ˜ธ๋ฅผ ๋ถ€๋ถ„ ์ƒ์‹คํ•˜๋ฏ€๋กœ ์ฑ„ํƒํ•˜์ง€ ์•Š์•˜๋‹ค. * **`DelegationService` / `cli.py` / `daemon.py`**: ์…ธ ํ—ฌํผ 3์ข…์˜ ๋ณธ์ฒด๋ฅผ `python -m lib_py.delegation.cli`๋กœ ๊ต์ฒด. `start_watchdog`์€ `ensure_subscriber_daemon`์˜ ๋ณ„์นญ์œผ๋กœ ์œ ์ง€. * **`PersistentPublisher` ํ”„๋กœํ† ํƒ€์ž… (`publisher.py`) ๋ฐ ๋ฒค์น˜๋งˆํฌ ํ•˜๋‹ˆ์Šค (`bench.py`)**: ์žฅ์ˆ˜ ์—ฐ๊ฒฐ์€ Phase 2a ์—”์ง„์šฉ์ด๋ฉฐ ํ”„๋กœ๋•์…˜ ๊ฒฝ๋กœ(CLIยท์…ธ)๋Š” ๊ณ„์† 1ํšŒ์„ฑ ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•œ๋‹ค. * **`ensure_env_loaded()` (D6)**: `.mam.env` ๋กœ๋”ฉ์„ ์ž„ํฌํŠธ ์‹œ์ ์—์„œ ํ”„๋กœ์„ธ์Šค ์ง„์ž…์ ์œผ๋กœ ์ด๋™. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž„ํฌํŠธ๊ฐ€ `os.environ`์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค. #### ๐Ÿ”’ ๋กค๋ฐฑ ๋ฐ ์•ˆ์ „์žฅ์น˜ * **`MAM_DELEGATION_PY=0`**: ์…ธ ํ—ฌํผ๊ฐ€ ๋ณด์กด๋œ ๋ ˆ๊ฑฐ์‹œ ์ธ๋ผ์ธ ๋ณธ์ฒด(`_*_legacy`)๋กœ ์ฆ‰์‹œ ๋ถ„๊ธฐ. ์žฌ๋ฐฐํฌยทrevert ๋ถˆํ•„์š”. ๋ ˆ๊ฑฐ์‹œ ๋ณธ์ฒด ์ œ๊ฑฐ๋Š” Phase 4. * **ํŠน์„ฑํ™” ํ…Œ์ŠคํŠธ ์„ ํ–‰ (P1-00)**: ์ด์ „๊นŒ์ง€ ์œ„์ž„ ์…ธ ํ—ฌํผ 3์ข…์„ ์ง์ ‘ ๊ฒ€์ฆํ•˜๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ 0๊ฑด์ด์—ˆ์œผ๋ฏ€๋กœ, ์ด๋™ **์ „์—** ๊ณจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ถ”๊ฐ€ํ•˜๊ณ  ๋‘ ๊ฒฝ๋กœ(`MAM_DELEGATION_PY` 0/1) ๋ชจ๋‘์—์„œ ํ†ต๊ณผ์‹œ์ผฐ๋‹ค. ### ๐Ÿš€ `v4.2.0` โ€” OpenAI Codex First-Class Agent Backend Integration (2026-09-05) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (MINOR Release)**: OpenAI Codex CLI(`codex`)๋ฅผ 6๋ฒˆ์งธ ์ •์‹ 1๊ธ‰ ์—์ด์ „ํŠธ ๋ฐฑ์—”๋“œ๋กœ ํ†ตํ•ฉ. 46๊ฐœ ์ „์ฒด ์•„ํ‚คํ…์ฒ˜ ๊ฒฐํ•ฉ ์ง€์ (Shell ๋ผ์ดํ”„์‚ฌ์ดํด, Python ์–ด๋Œ‘ํ„ฐ, ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ, ์ƒํƒœ ๋จธ์‹ , ๋™๊ธฐํ™” ๋ฃจํ”„, ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ, ๋ฌธ์„œ) ์ „๋ฉด ์—ฐ๋™ ์™„๋ฃŒ. #### ๐ŸŒŸ ์‹ ๊ทœ ๊ธฐ๋Šฅ ๋ฐ ์•„ํ‚คํ…์ฒ˜ ํ™•์žฅ (New Features & Architecture) * **A-1: Codex Agent Adapter (`CodexAgentAdapter`) ์‹ ๊ทœ ๊ตฌํ˜„ (`codex.py`, `registry.py`)**: - `BaseAgentAdapter` ์™„์ „ ๊ตฌํ˜„: `name='codex'`, `own_key='codex_session_id_own'`, `ready_tokens='Codex|Ask Codex to do anything'`, `exit_key='Ctrl+C'`, `delegate_agent_key='codex-cli'`. - Class A ์—์ด์ „ํŠธ ๋ผ์ดํ”„์‚ฌ์ดํด ์ฑ„ํƒ: ์„ธ์…˜ ์ƒ์„ฑ ์‹œ UUID๋ฅผ ์‚ฌ์ „ ํ• ๋‹นํ•˜์ง€ ์•Š๊ณ  ๋Ÿฐํƒ€์ž„์— ๋™์ ์œผ๋กœ ๋ฐœ๊ฒฌ. - Rev.2 ๋™์  SQLite DB ํƒ์ƒ‰: ๊ณ ์ • ๋ฒ„์ „ ํŒŒ์ผ ๋Œ€์‹  `state_*.sqlite` ํŒจํ„ด์„ ์ตœ์‹  mtime ์ˆœ์œผ๋กœ ํƒ์ƒ‰ํ•˜์—ฌ `threads` ํ…Œ์ด๋ธ”์—์„œ `(rollout_path, cwd)`๋ฅผ O(1)๋กœ ์ƒ‰์ธ. - Fallback ํƒ์ƒ‰: SQLite ๋ฏธ์กด์žฌ ์‹œ `~/.codex/sessions/*/*/*/rollout-*-.jsonl` date-nested ๊ฒฝ๋กœ ๋ฐ ์žฌ๊ท€ ํŒจํ„ด ์ง€์›. - Safe Purge: `codex delete --force` CLI ํ˜ธ์ถœ ๋ฐ ์˜จ๋””์Šคํฌ jsonl/DB ๋ ˆ์ฝ”๋“œ ํด๋ฐฑ ์‚ญ์ œ. * **A-2: Shell ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฐ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 46๊ฐœ ์ง€์  ์™„์ „ ์—ฐ๋™**: - `lib.sh`: `resolve_agent_type_from_registry`, `_sanitize_herdr_agent_name`, `send_keys_safe`์— codex ๋“ฑ๋ก. - `create_session.sh`: `--agent codex` ํ—ˆ์šฉ, `~/.codex/auth.json` / `OPENAI_API_KEY` ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ๊ฒ€์ฆ, `--dangerously-bypass-approvals-and-sandbox` ํ”Œ๋ž˜๊ทธ ์Šคํฐ, `codex_session_id_own: null` ์ดˆ๊ธฐํ™”. - `resume_session.sh`: `codex` ๋ณต์› ์ง€์›, 0-turn ์„ธ์…˜์— ๋Œ€ํ•œ `FRESH_SPAWN=1` Class A ์•ˆ์ „ ํด๋ฐฑ. - `update_yaml_resumed.sh`: `codex` ์„ธ์…˜ ๋ณต์› ์‹œ YAML ํ•„๋“œ ์›์ž์  ๊ฐฑ์‹ . - `stop_session.sh`: `codex` ์ง€์›, ์ข…๋ฃŒ ์‹œ ์ตœ์ข… session id ์บก์ฒ˜ ๋ฐ ์ €์žฅ. - `orc_onboard.sh`: flag-tolerant regex ๊ธฐ๋ฐ˜์œผ๋กœ `codex resume [options] ` ๋ช…๋ นํ–‰์—์„œ UUID ์ •ํ™• ์ถ”์ถœ. - `reconcile.sh`: drift C (codex) ์ „์šฉ ๊ฐ์ง€ ๋ธ”๋ก ์ถ”๊ฐ€ (state DB ์šฐ์„  + glob ํด๋ฐฑ), discovery sweep ์—ฐ๋™. - `status.sh`: text/JSON ํฌ๋งทํ„ฐ ์–‘์ธก์— codex ์˜จ๋””์Šคํฌ ๋ณต์› ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ ๋กœ์ง ์—ฐ๋™. * **A-3: ๋ฌธ์„œ ๋ฐ ํ‘œ์ค€ ํ—Œ์žฅ ๋™๊ธฐํ™”**: - `README.md`, `README.ko.md`, `BOOTSTRAP.md`, `BOOTSTRAP.ko.md`, `deploy/INSTALL.md`, `.agents/MULTI_AGENT_RULES.md`, `.mam.env.example`, `docs/NEW_AGENT_INTEGRATION_GUIDE.md` ์ „๋ฉด ์—…๋ฐ์ดํŠธ. --- ### ๐Ÿ› ๏ธ `v4.1.3` โ€” Herdr Daemon Isolation & Class A 0-Turn Resume Reliability Fixes (2026-08-31) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (PATCH Release)**: Issue #3 ๊ฒฐํ•จ ํ•ด์†Œ โ€” Herdr ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฐ๋ชฌ์˜ `start_new_session=True` ๊ธฐ๋ฐ˜ ํ”„๋กœ์„ธ์Šค ๊ทธ๋ฃน(setsid) ์™„์ „ ๊ฒฉ๋ฆฌ, Class A(`agy`, `hermes`, `opencode`) ์—์ด์ „ํŠธ 0-turn ์ค‘์ง€ ์„ธ์…˜์˜ `FRESH_SPAWN` fallback ๋ฐ discovery epoch ์›์ž์  ์žฌ์„ค์ •, Class B(`claude`, `grok`) ๊ณ„์•ฝ ๋ถˆ๋ณ€ ๋ณด์กด, 455๊ฐœ ์ „์ฒด ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ 100% PASS ๋‹ฌ์„ฑ. #### ๐Ÿฉน ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ์•ˆ์ •์„ฑ ๊ฐœ์„  (Bug Fixes & Resilience) * **C-1: Herdr ๋ฐ๋ชฌ ํ”„๋กœ์„ธ์Šค ๊ทธ๋ฃน(PGID/SID) ์™„์ „ ๋ถ„๋ฆฌ (`lib.sh`)**: - `.mam/shim/herdr` ํ…œํ”Œ๋ฆฟ์˜ `nohup ... & disown` ์Šคํฐ ๋ฐฉ์‹์„ ํŒŒ์ด์ฌ `subprocess.Popen(..., start_new_session=True)` ๊ธฐ๋ฐ˜ ์ „์šฉ ์Šคํฌ๋„ˆ๋กœ ๋Œ€์ฒดํ•˜์—ฌ ์ž์‹ ํ”„๋กœ์„ธ์Šค์—์„œ `os.setsid()` ํ˜ธ์ถœ ๋ณด์žฅ. - ๋ถ€๋ชจ ์…ธ์ด๋‚˜ ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ์˜ ์‹œ๊ทธ๋„ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ(`SIGTERM`/`SIGINT`)๋กœ ์ธํ•ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ Herdr ๋ฐ๋ชฌ์ด ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ์ข…๋ฃŒ๋˜๋Š” ๊ฒฐํ•จ์„ ์›์ฒœ ์ฐจ๋‹จ (`test_h26`). * **C-2: Class A ์—์ด์ „ํŠธ 0-turn resume ์ž์œจ Fallback ๋ฐ Discovery Watermark ๊ฐฑ์‹  (`resume_session.sh`, `update_yaml_resumed.sh`)**: - ๋Œ€ํ™” ํ„ด์ด ๋ฐœ์ƒํ•˜๊ธฐ ์ „์— ์ค‘์ง€๋œ Class A(`agy`, `hermes`, `opencode`) ์„ธ์…˜ resume ์‹œ, UUID ๋ฏธ์กด์žฌ๋กœ ์ธํ•œ ๋น„์ •์ƒ hard-fail(RC=1) ๋Œ€์‹  `FRESH_SPAWN=1`๋กœ ์ž๋™ ์ „ํ™˜ํ•˜์—ฌ `spawn-spec` ๊ธฐ๋ฐ˜์˜ ์ •์ƒ ์žฌ์Šคํฐ ์ˆ˜ํ–‰ (`test_t14`). - fresh-spawn resume ์‹œ `update_yaml_resumed.sh`์—์„œ `herdr_session_epoch`๋ฅผ resume ์‹œ์ ์˜ ํƒ€์ž„์Šคํƒฌํ”„๋กœ ์ฆ‰์‹œ ๊ฐฑ์‹ ํ•˜๊ณ  `session_id_source: pending-discovery`๋กœ ์žฌ์„ค์ •ํ•˜์—ฌ, ์„ธ์…˜ ์ƒ์„ฑ๊ณผ ๋ณต์› ์‚ฌ์ด์— ์ƒ์„ฑ๋œ ๋ฌด๊ด€ํ•œ ์ด์ „ ๋Œ€ํ™” ํŒŒ์ผ์ด `reconcile.sh`์˜ discovery sweep์— ์˜ํ•ด ์˜ค์ธ ์บก์ฒ˜๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ (`test_t16`). - Class B(`claude`, `grok`) ์—์ด์ „ํŠธ์˜ `verify_session.py:99-101` assigned escape hatch ๋ฐ `test_t8` ๊ณ„์•ฝ์€ ์ˆ˜์ • ์—†์ด ์™„๋ฒฝํžˆ ๋ณด์กด (`test_t15`). --- ### ๐Ÿ› ๏ธ `v4.1.2` โ€” Pane Resolution & Reuse Reliability Fixes (2026-08-30) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (PATCH Release)**: `bug-report/mam_upstream_bug_fix_report.md`์— ๋ณด๊ณ ๋œ 4๊ฑด์„ ์‹ค ์ฝ”๋“œ ๋Œ€๋น„ ๋…๋ฆฝ ๊ฒ€์ฆ โ€” 2๊ฑด์€ ์‹ค์žฌํ•˜๋Š” ๊ฒฐํ•จ์œผ๋กœ ํ™•์ธ๋˜์–ด ์ˆ˜์ •(SemVer 2.0.0 ยง6 PATCH), 1๊ฑด(`ready_tokens`)์€ v4.1.1์—์„œ ์ด๋ฏธ ํ•ด๊ฒฐ๋จ์„ ํ™•์ธ, 1๊ฑด(`resume_spec` `materialized` ๊ฒŒ์ดํŠธ)์€ 5๊ฐœ ์–ด๋Œ‘ํ„ฐ ๊ณตํ†ต์˜ ์˜๋„๋œ ์•ˆ์ „์žฅ์น˜๋กœ ํŒ๋‹จ๋˜์–ด ์ œ์•ˆ๋œ ์ˆ˜์ •์„ ์ฑ„ํƒํ•˜์ง€ ์•Š์Œ(๊ทผ๊ฑฐ๋Š” ์•„๋ž˜ ์ฐธ์กฐ). #### ๐Ÿฉน ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ์•ˆ์ •์„ฑ ๊ฐœ์„  (Bug Fixes & Resilience) * **C-1: `_resolve_herdr_pane_id` Generic `agent_kind` ์˜ค์ธ ๋งค์นญ ๋ฐฉ์ง€ (`lib.sh`)**: - ์„ธ์…˜๋ช… ๋งค์นญ ์‹คํŒจ ์‹œ ์ˆ˜ํ–‰๋˜๋˜ `agent_kind` ๊ด‘์—ญ ํด๋ฐฑ์„ ํ˜ธ์ถœ ๋Œ€์ƒ ์ž์ฒด๊ฐ€ kind ๋ฆฌํ„ฐ๋Ÿด(์˜ˆ: `"agy"`)์ธ ๊ฒฝ์šฐ๋กœ๋งŒ ํ•œ์ •ํ•˜๊ณ , ์ƒ์œ„ ๋ฃจํ”„์˜ exact match ๋Œ€์ƒ์—์„œ `'agent'`๋ฅผ ์ œ์™ธํ•˜์—ฌ ๋™์ข… ํŽ˜์ธ ๋‹ค์ˆ˜ ์กด์žฌ ์‹œ R-1 fail-closed ๊ณ„์•ฝ์ด ์˜จ์ „ํžˆ ์ ์šฉ๋˜๋„๋ก ๋ณด์žฅ. ์ด์ „์—๋Š” ๋Œ€์ƒ ์„ธ์…˜์˜ yaml ํ•ญ๋ชฉ์—์„œ ์กฐํšŒํ•œ kind๋กœ "๋™์ข… ํŽ˜์ธ ์•„๋ฌด๊ฑฐ๋‚˜" ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰ํ•ด, ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ๋ฌด๊ด€ํ•œ ๋™์ข… ์—์ด์ „ํŠธ(์˜ˆ: ๋ณ„๋„ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ `agy` ์„ธ์…˜)๊ฐ€ ๋‹จ 1๊ฐœ๋ผ๋„ ์‚ด์•„์žˆ์œผ๋ฉด ๊ทธ ํŽ˜์ธ์„ ๋Œ€์ƒ์œผ๋กœ ์˜ค์ธ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฐํ•จ์ด ์žˆ์—ˆ์Œ. * **C-2: `new-session` ์œ ํœด ํŽ˜์ธ(Idle Pane) ์šฐ์„  ์žฌ์‚ฌ์šฉ ๋ฐ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ฃผ์ž… ๋ณด์ „ (`lib.sh`)**: - ๊ธฐ์กด ์›Œํฌ์ŠคํŽ˜์ด์Šค๊ฐ€ ๊ฐ์ง€๋˜๋ฉด ๊ณง๋ฐ”๋กœ `pane split`์„ ํ˜ธ์ถœํ•˜๋˜ ๊ธฐ์กด ๋™์ž‘์„ ๋ณ€๊ฒฝ, ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ์—์ด์ „ํŠธ ๋ฏธํ• ๋‹น(์œ ํœด) ํŽ˜์ธ์ด ์กด์žฌํ•˜๋ฉด ์ด๋ฅผ `target_pane`์œผ๋กœ ์ฆ‰์‹œ ์žฌ์‚ฌ์šฉํ•˜๊ณ  split์„ ์ƒ๋žต. ์žฌ์‚ฌ์šฉ ์‹œ ํ˜ธ์ถœ์ž๊ฐ€ ์ „๋‹ฌํ•œ `$env_flags` ๋ฐ `HERDR_WORKSPACE_ID`๊ฐ€ ์œ ์‹ค๋˜์ง€ ์•Š๋„๋ก `env` ์ ‘๋‘์–ด๋กœ `$final_cmd`์— ์ฃผ์ž…ํ•˜์—ฌ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ „๋‹ฌ ์ผ๊ด€์„ฑ ๋ณด์žฅ. ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ์‹œ ์‹ ๊ทœ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ƒ์„ฑ ์ •์ฑ…(W2b)์€ ์œ ํœด ํŽ˜์ธ์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋งŒ ๊ทธ๋Œ€๋กœ ์ ์šฉ๋จ. * **๊ฒ€ํ†  ํ›„ ๋ฏธ์ฑ„ํƒ โ€” `opencode.py::resume_spec` `materialized` ๊ฒŒ์ดํŠธ**: - ๋ณด๊ณ ์„œ๋Š” `if materialized and session_uuid:` ์กฐ๊ฑด ์ œ๊ฑฐ๋ฅผ ์ œ์•ˆํ–ˆ์œผ๋‚˜, ์ด๋Š” `claude`/`grok`/`agy`/`hermes`/`opencode` 5๊ฐœ ์–ด๋Œ‘ํ„ฐ ์ „์›์— ๋™์ผํ•˜๊ฒŒ ์กด์žฌํ•˜๋Š” ์˜๋„๋œ ๊ณ„์•ฝ์ด๋ฉฐ, `materialized`๋Š” `verify_artifact()`(opencode์˜ ๊ฒฝ์šฐ ์‹ค์ œ SQLite ์„ธ์…˜ DB ์กฐํšŒ)๋กœ ์‚ฐ์ถœ๋จ โ€” ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์„ธ์…˜ ID๋กœ `--session`์„ ๋„˜๊ฒจ CLI๊ฐ€ ์‹คํŒจ/ํ–‰(hang)ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ ์œ„ํ•œ ์•ˆ์ „์žฅ์น˜. ์ œ์•ˆ๋Œ€๋กœ ์ˆ˜์ • ์‹œ 5-์–ด๋Œ‘ํ„ฐ ์ผ๊ด€์„ฑ์ด ๊นจ์ง€๊ณ  ์•ˆ์ „์žฅ์น˜๊ฐ€ ๋ฌด๋ ฅํ™”๋˜๋ฏ€๋กœ ์ฑ„ํƒํ•˜์ง€ ์•Š์Œ. `resume_session.sh`๋Š” `WORKSPACE`๋ฅผ ํ•„์ˆ˜ ์ธ์ž๋กœ ๊ฒ€์ฆํ•˜๋ฏ€๋กœ `ctx`๊ฐ€ ๋น„์–ด `materialized`๊ฐ€ ๊ฑฐ์ง“์ด ๋˜๋Š” ๊ฒฝ๋กœ๋„ ํ™•์ธ๋˜์ง€ ์•Š์Œ. * **์žฌํ™•์ธ(์กฐ์น˜ ๋ถˆํ•„์š”) โ€” `opencode.py::ready_tokens`**: - ๋ณด๊ณ ์„œ๊ฐ€ ์ง€์ ํ•œ ASCII ๋ฐฐ๋„ˆ ๋ฏธ์ธ์‹ ๋ฌธ์ œ๋Š” v4.1.1(B-1, job `c38ddfcf`)์—์„œ ์ด๋ฏธ ํ•ด๊ฒฐ๋˜์–ด ํ˜„์žฌ `ready_tokens`๊ฐ€ ๋ณด๊ณ ์„œ์˜ "์ˆ˜์ • ํ›„" ๊ฐ’๊ณผ ์™„์ „ํžˆ ์ผ์น˜ํ•จ์„ ํ™•์ธ. ๋ณด๊ณ ์„œ ์ž‘์„ฑ ์‹œ์ ์ด v4.1.1 ์ด์ „ ์ฒดํฌ์•„์›ƒ์ด์—ˆ๋˜ ๊ฒƒ์œผ๋กœ ์ถ”์ •. --- ### ๐Ÿ› ๏ธ `v4.1.1` โ€” Agent Creation & Runtime Reliability Fixes (2026-08-30) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (PATCH Release)**: ์—์ด์ „ํŠธ ์ƒ์„ฑ ๋ฐ ๋Ÿฐํƒ€์ž„ ์‹ ๋ขฐ์„ฑ ํ–ฅ์ƒ์„ ์œ„ํ•œ 4๋Œ€ ๋ณดํŽธ ๋ฒ„๊ทธ ์ˆ˜์ •(SemVer 2.0.0 ยง6 PATCH), Herdr ๊ฒฉ๋ฆฌ ํ™˜๊ฒฝ `PYTHONPATH` ์ž๋™ ์ฃผ์ž…, OpenCode TUI ๋ ˆ๋”” ํ† ํฐ ๋ณด๊ฐ•, ์„ธ์…˜ ํŽ˜์ธ ์‹๋ณ„์ž Fast-Path ๋ฐ ์‹œ์ž‘ ํƒ€์ž„์•„์›ƒ ๋ณต์›๋ ฅ ๊ฐ•ํ™”. #### ๐Ÿฉน ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ์•ˆ์ •์„ฑ ๊ฐœ์„  (Bug Fixes & Resilience) * **B-1: OpenCode TUI ์ค€๋น„ ๊ฐ์ง€ ํ† ํฐ ๋ณด๊ฐ• (`lib_py/agents/adapters/opencode.py`)**: - `ready_tokens`๋ฅผ `'OpenCode|Chat|Ask anything|tab agents|ctrl\+p|Build auto|commands'`๋กœ ํ™•์žฅํ•˜์—ฌ ASCII ๋ฐฐ๋„ˆ ๋ฐ `Build auto` ์ดˆ๊ธฐ ํ™”๋ฉด์—์„œ 30์ดˆ ๋Œ€๊ธฐ ์—†์ด ์ฆ‰๊ฐ ์ค€๋น„ ์™„๋ฃŒ ํŒ์ •. * **B-2: Herdr Shim ํ…œํ”Œ๋ฆฟ ๋‚ด ๋…๋ฆฝ `PYTHONPATH` ์ฃผ์ž… (`lib.sh`)**: - `.mam/shim/herdr` ์Šคํฌ๋ฆฝํŠธ ์ƒ๋‹จ์—์„œ ์ž์‹ ์˜ ๊ฒฝ๋กœ๋ฅผ ๊ธฐ์ค€์œผ๋กœ `_SKILL_DIR`์„ ์‚ฐ์ถœํ•˜๊ณ  `PYTHONPATH`์— ์ฃผ์ž…ํ•˜์—ฌ ๋ถ€๋ชจ ์…ธ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋ฏธ์ƒ์† ์„œ๋ธŒ์…ธ์—์„œ๋„ `lib_py` ๋ชจ๋“ˆ ์ •์ƒ ๋กœ๋“œ ๋ณด์žฅ. * **B-3: `herdr agent start` ํƒ€์ž„์•„์›ƒ ๋ณต์›๋ ฅ ๋ฐ send-text ํด๋ฐฑ (`lib.sh`)**: - ์‹œ์ž‘ ํƒ€์ž„์•„์›ƒ ๋ฐœ์ƒ ์‹œ ๋ฌด์กฐ๊ฑด ์‹คํŒจ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ , ์‹ค์ œ ์—์ด์ „ํŠธ ํ”„๋กœ์„ธ์Šค ์ƒ์กด์„ ํ™•์ธํ•˜๊ฑฐ๋‚˜ `pane send-text` + Enter ํด๋ฐฑ์œผ๋กœ ๋ช…๋ น์„ ์ง์ ‘ ์žฌ์ฃผ์ž…ํ•˜์—ฌ ์„ธ์…˜ ์ดˆ๊ธฐํ™” ์„ฑ๊ณต๋ฅ  ์ œ๊ณ . * **B-4: `_resolve_herdr_pane_id` ํŽ˜์ธ ID Fast-Path ๋ฐ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ ˆ์ด๋ธ” ๋งค์นญ (`lib.sh`)**: - ์ด๋ฏธ ํ•ด์„๋œ ํŽ˜์ธ ID(`wN:pM`) ์ž…๋ ฅ ์‹œ ์ฆ‰๊ฐ ๋ฐ˜ํ™˜ํ•˜๋Š” Fast-Path ์ถ”๊ฐ€. - `herdr workspace list`๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ ˆ์ด๋ธ”(์˜ˆ: `mam-agents`)์„ ์‹ค์ œ `workspace_id`๋กœ ์ž๋™ ๋ณ€ํ™˜ ๋งค์นญ. --- ### ๐Ÿš€ `v4.1.0` โ€” OpenCode AI Agent Integration (2026-08-29) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (MINOR Release)**: OpenCode AI ์—์ด์ „ํŠธ(`anomalyco/opencode`) ๋ฐฑ์—”๋“œ ์™„์ „ ํ†ตํ•ฉ(SemVer 2.0.0 ยง7 MINOR), 5๋Œ€ ํ•ต์‹ฌ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `grok`, `opencode`) ํ‘œ์ค€ํ™”, 29๊ฐœ CLI ์Šคํฌ๋ฆฝํŠธ/์Šคํ‚ฌ ์—ฐ๋™ ๋ฐ 447๊ฐœ ์ „์ฒด ํ…Œ์ŠคํŠธ 100% PASS ๋‹ฌ์„ฑ. #### โœจ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ (New Features & Enhancements) * **F-1: OpenCode ์—์ด์ „ํŠธ ์–ด๋Œ‘ํ„ฐ(`OpenCodeAgentAdapter`) ๊ตฌํ˜„**: - `lib_py/agents/adapters/opencode.py` ์‹ ๊ทœ ๊ตฌํ˜„ ๋ฐ `lib_py/agents/registry.py` ๋“ฑ๋ก. - SQLite ์Šคํ† ๋ฆฌ์ง€(`opencode.db`) ๋‚ด `directory` ๋ฐ `time_created`(๋ฐ€๋ฆฌ์ดˆ) ์‹ค ์Šคํ‚ค๋งˆ ๊ธฐ๋ฐ˜์˜ ๋ฐฉ์–ด์  ์„ธ์…˜ ๊ฒ€์ฆ(`verify_artifact`) ๋ฐ ๋ฉ€ํ‹ฐ ํ›„๋ณด์ž ๋ฐœ๊ฒฌ(`discover`) ์ง€์›. - `_resolve_db()`๋ฅผ ํ†ตํ•œ `opencode db path` CLI ๋™์  ํ•ด์„ ๋ฐ ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ(`HOME`/`XDG_DATA_HOME`) ๊ฒฉ๋ฆฌ ์ง€์›. * **F-2: CLI ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฐ ์Šคํฌ๋ฆฝํŠธ ์ „๋ฉด ์—ฐ๋™ (29๊ฐœ ํ„ฐ์น˜ํฌ์ธํŠธ)**: - `create_session.sh`, `resume_session.sh`, `stop_session.sh`, `status.sh`, `reconcile.sh`, `run_loop.sh`, `orc_onboard.sh` ๋‚ด `--agent opencode` ์™„์ „ ์ง€์›. - ์„ธ์…˜ ์ƒ์„ฑ ๋ฐ ์žฌ๊ฐœ ์‹œ `OPENCODE_PERMISSION='{"*":"allow"}'` ์ž๋™ ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐ ์‚ฌ์šฉ์ž ์‚ฌ์ „ ์„ค์ • ๋ณด์กด(Empty-Guard). - ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์กฐ์ •์ž(`reconcile.sh`) drift-C ๋ธ”๋ก์—์„œ ์–ด๋Œ‘ํ„ฐ ๊ณต์œ  ํ—ฌํผ๋ฅผ ํ†ตํ•œ ์„ธ์…˜ ID ์‚ฌํ›„ ์ž์œจ ๊ฐ์ง€ ๋ฐ YAML ๋“ฑ๋ก. * **F-3: ํฌ๊ด„์  ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ ํ™•์žฅ**: - `tests/test_a4_adapter_contract.py`: ์–ด๋Œ‘ํ„ฐ ๊ณ„์•ฝ, ์‹ค ์Šคํ‚ค๋งˆ ๋ฐ€๋ฆฌ์ดˆ ๋น„๊ต, CLI DB ๊ฒฝ๋กœ ๋™์  ํ•ด์„ ๊ฒ€์ฆ. - `tests/test_tier1_unit.py`, `tests/test_tier2_component.py`, `tests/test_c1_tui_readiness.py`: TUI ๋ฐ ๋ผ์ดํ”„์‚ฌ์ดํด ํ†ตํ•ฉ ๊ฒ€์ฆ (์ด 447๊ฐœ ํ…Œ์ŠคํŠธ 100% ํ†ต๊ณผ). --- ### ๐Ÿš€ `v4.0.0` โ€” Complete Cline Agent Deprecation & Hermes Modernization (2026-08-28) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค (MAJOR Release)**: `cline` ์—์ด์ „ํŠธ ๋ฐฑ์—”๋“œ์˜ ์™„์ „ํ•œ ์ œ๊ฑฐ ๋ฐ ํ์ง€(Breaking Change per SemVer 2.0.0 ยง8), Hermes ์—์ด์ „ํŠธ ํ’€ ๋ชจ๋”๋‹ˆ์ œ์ด์…˜ ๋ฐ Ollama ๋กœ์ปฌ ์—ฐ๋™ ์ •์‹ ์ง€์›, 4๋Œ€ ํ•ต์‹ฌ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `grok`) ํ‘œ์ค€ํ™” ๋ฐ 439๊ฐœ ์ „์ฒด ํ…Œ์ŠคํŠธ 100% PASS ๋‹ฌ์„ฑ. #### โš ๏ธ ๋™์ž‘ ๋ณ€๊ฒฝ ๋ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์•ˆ๋‚ด (Breaking Changes) * **B-1: `--agent cline` ์ง€์› ์™„์ „ ์ œ๊ฑฐ ๋ฐ ํŒŒ์„œ ๊ฑฐ๋ถ€**: - `adapters/cline.py` ์‚ญ์ œ ๋ฐ `registry.py` ๋“ฑ๋ก ํ•ด์ œ์— ๋”ฐ๋ผ ๋ชจ๋“  ์Šคํ‚ฌ ์—”ํŠธ๋ฆฌํฌ์ธํŠธ(`create_session.sh`, `resume_session.sh`, `stop_session.sh`, `reconcile.sh`, `orc_onboard.sh`, `multi-agent-mux-delegate-job` ๋“ฑ)์—์„œ `--agent cline` ์ž…๋ ฅ ์‹œ `exit 2`๋กœ ์ฆ‰์‹œ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค. - ์ง€์›๋˜๋Š” ์—์ด์ „ํŠธ ํŒจ๋ฐ€๋ฆฌ๋Š” `claude`, `agy`, `hermes`, `grok` 4์ข…์œผ๋กœ ์—„๊ฒฉํžˆ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. * **B-2: ์˜ํ–ฅ๋„ ํ™•์ธ (Detection)**: - ์ €์žฅ๋œ ์Šคํฌ๋ฆฝํŠธ๋‚˜ ์ปค์Šคํ…€ ์„ธ์…˜์—์„œ Cline ๊ด€๋ จ ์„ค์ •์ด ๋‚จ์•„์žˆ๋Š”์ง€ ํ™•์ธ: ```bash grep -rn "agent: cline\|cline_conversation_id_own\|--agent cline" .mam/ *.sh 2>/dev/null ``` * **B-3: ์—…๊ทธ๋ ˆ์ด๋“œ ์ „ ์„ธ์…˜ ์ •๋ฆฌ (Pre-upgrade Cleanup โ€” ๊ถŒ์žฅ)**: - v3.1.0 ์ƒํƒœ์—์„œ `deploy/update.sh` ์‹คํ–‰ ์ „, ๊ธฐ์กด์˜ ํ™œ์„ฑ/๋ณด๊ด€ ์ค‘์ธ Cline ์„ธ์…˜์„ ์›์ž์ ์œผ๋กœ ์ •๋ฆฌ: ```bash multi-agent-mux-stop --session --agent cline --purge-conversation --yes ``` * **B-4: ์—…๊ทธ๋ ˆ์ด๋“œ ํ›„ ๊ณ ์•„ ์„ธ์…˜ ๋ ˆ์ฝ”๋“œ ์ •๋ฆฌ (Post-upgrade YAML Pruning)**: - `deploy/update.sh`๋Š” `.mam/agent-sessions.yaml`์„ ๋ฎ์–ด์“ฐ์ง€ ์•Š๊ณ  ๋ณด์กดํ•˜๋ฏ€๋กœ, ์‚ฌ์ „์— ์ •๋ฆฌ๋˜์ง€ ์•Š์€ v3.x `cline` ์„ธ์…˜ ํ–‰์€ ์•„๋ž˜ ์›์ž์  ๊ฐฑ์‹  ๋ช…๋ น์„ ํ†ตํ•ด ์•ˆ์ „ํ•˜๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ```bash source .agents/skills/lib.sh atomic_dump_yaml .mam/agent-sessions.yaml <<'MUT' d['herdr_sessions'] = [ s for s in d.get('herdr_sessions', []) if s.get('agent') != 'cline' and not str(s.get('name', '')).endswith('-cline') ] MUT ``` * **B-5: Hermes ์—์ด์ „ํŠธ ๋ชจ๋”๋‹ˆ์ œ์ด์…˜**: - ํ—ค๋“œ๋ฆฌ์Šค ํ”Œ๋ž˜๊ทธ(`--yolo --accept-hooks`), TUI ์ž…๋ ฅ ์˜์—ญ ๊ตฌ๋ถ„์ž(`โ”€{10,}` ๋ฐ `โฏ`), ์ค€๋น„ ํ† ํฐ ๊ฐ•ํ™”, `reconcile.sh` ํƒ€์ž„์Šคํƒฌํ”„ ๊ธฐ๋ฐ˜ ๋‹ค์ค‘ ํ›„๋ณด์ž ๋™๋“ฑ์„ฑ(`discover()`) ์ง€์›์ด ์ •์‹ ํ†ตํ•ฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. --- ### ๐Ÿš€ `v3.1.0` โ€” 2-Tier TUI Readiness Model, Adapter Modal Contract & Fail-Closed Pane Resolution (2026-08-28) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ๋‹ค์ด์–ผ๋กœ๊ทธ ๊ธฐ์•„(starvation) ๊ตฌ์กฐ์  ํ•ด์†Œ๋ฅผ ์œ„ํ•œ 2๊ณ„์ธต TUI ์ค€๋น„ ํŒ์ • ๋ชจ๋ธ(`S โˆจ (W โˆง C)`), ๋ชจ๋‹ฌ/ํžŒํŠธ 2๊ณ„์ธต ํ† ํฐ ๋ถ„๋ฆฌ, ์–ด๋Œ‘ํ„ฐ๋ณ„ `modal_tokens` ๊ณ„์•ฝ(`T-2d`) ์ •๋ฆฝ, ๋™์ข… ํŽ˜์ธ ๋‹ค์ค‘ ๋งค์น˜ fail-closed ๋ฐฉ์–ด, ์ค€๋น„ ์‹คํŒจ ์„ธ์…˜ ์ง„๋‹จ ๋ณด์กด(`create_session.sh`), `lib.sh` ๋Ÿฐํƒ€์ž„ ๋ฒ„์ „ ์ƒ์ˆ˜(`MAM_VERSION="3.1.0"`) ์‹ ์„ค ๋ฐ 436๊ฐœ ์ „์ฒด ํ…Œ์ŠคํŠธ 100% PASS ๋‹ฌ์„ฑ. #### โš ๏ธ ๋™์ž‘ ๋ณ€๊ฒฝ ๋ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์•ˆ๋‚ด * **B-1: TUI ๋ฏธ์ค€๋น„ ์„ธ์…˜ ๋ณด์กด (`create_session.sh`)**: - TUI ์ค€๋น„ ๊ฐ์ง€ ํƒ€์ž„์•„์›ƒ ๋ฐœ์ƒ ์‹œ, PID๊ฐ€ ์ƒ์กดํ•ด ์žˆ๋‹ค๋ฉด ์„ธ์…˜์„ ๊ฐ•์ œ ์ข…๋ฃŒ(`kill-session`)ํ•˜์ง€ ์•Š๊ณ  `status: running`, `last_visible_status: tui-ready-timeout`์œผ๋กœ ๋“ฑ๋กํ•œ ๋’ค `exit 0`(์„ฑ๊ณต)์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. - ๊ตฌ `v3.0.1`์˜ ๋ฌด์กฐ๊ฑด ๋กค๋ฐฑ ๋ฐ ์ข…๋ฃŒ ๋™์ž‘์„ ์›ํ•  ๊ฒฝ์šฐ `MAM_KILL_ON_READY_TIMEOUT=1`์„ ์„ค์ •ํ•˜์‹ญ์‹œ์˜ค. * **B-2: ํ”„๋กœ์„ธ์Šค ์‚ฌ๋ง ์‹œ ์ข…๋ฃŒ ์ฝ”๋“œ ๋ณ€๊ฒฝ**: - `create_session.sh` ์‹คํ–‰ ์ค‘ PID๊ฐ€ ์‚ฌ๋งํ•œ ๊ฒฝ์šฐ ๋ช…์‹œ์  ๊ตฌ๋ถ„ ์ฝ”๋“œ `42`(`MAM_EXIT_READY_TIMEOUT`)๋กœ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค. * **B-3: ๋™์ข… ํŽ˜์ธ ๋‹ค์ค‘ ๋งค์น˜ ์‹œ Fail-Closed ๊ฑฐ๋ถ€ (`_resolve_herdr_pane_id`)**: - ๋™์ผํ•œ ์—์ด์ „ํŠธ ์ข…๋ฅ˜์˜ ํŽ˜์ธ์ด ์—ฌ๋Ÿฌ ๊ฐœ ๋ฐœ๊ฒฌ๋˜๊ณ  ์ •ํ™•ํ•œ ์„ธ์…˜๋ช… ์ผ์น˜๊ฐ€ ์‹คํŒจํ•  ๊ฒฝ์šฐ, ์ž„์˜์˜ ์ฒซ ๋ฒˆ์งธ ํŽ˜์ธ์„ ์„ ํƒํ•˜์ง€ ์•Š๊ณ  ์ฆ‰์‹œ `exit 1`๋กœ ์‹คํŒจํ•˜์—ฌ ๊ต์ฐจ ์„ธ์…˜ ์˜ค์—ผ์„ ์›์ฒœ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. * **B-4 & B-5: ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ „ํŒŒ (`WORKSPACE_ROOT`, `MAM_VERSION`)**: - `WORKSPACE_ROOT` ๋ฐ `MAM_VERSION`์ด ์ž์‹ ํ”„๋กœ์„ธ์Šค๋กœ ์ž๋™ `export`๋ฉ๋‹ˆ๋‹ค. `MAM_VERSION`์€ ๋Ÿฐํƒ€์ž„ ์œ„์กฐ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์˜ค๋ฒ„๋ผ์ด๋“œ๊ฐ€ ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. #### ๐Ÿ”ง ๊ธฐ์กด ์›Œํฌ์ŠคํŽ˜์ด์Šค ์‚ฌ์šฉ์ž ์•ˆ๋‚ด ๊ธฐ์กด ๋ฐฐํฌ๋œ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์‚ฌ์šฉ์ž๋Š” `.mam.env`์— ์•„๋ž˜ 3์ข…์˜ ์‹ ๊ทœ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋™์ž‘์„ ํŠœ๋‹ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: | ๋ณ€์ˆ˜๋ช… | ๊ธฐ๋ณธ๊ฐ’ | ์„ค๋ช… | | :--- | :---: | :--- | | `MAM_KILL_ON_READY_TIMEOUT` | `0` | `1`๋กœ ์„ค์ • ์‹œ TUI ์ค€๋น„ ํƒ€์ž„์•„์›ƒ ๋ฐœ์ƒ ์‹œ ์„ธ์…˜์„ ๋ณด์กดํ•˜์ง€ ์•Š๊ณ  ๊ฐ•์ œ ์ข…๋ฃŒ(v3.0.1 ๋™์ž‘) | | `MAM_DIALOG_TAIL_LINES` | `8` | ๋ธ”๋กœํ‚น ๋ชจ๋‹ฌ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๊ฒ€์‚ฌํ•  ํŽ˜์ธ ํ•˜๋‹จ ๋น„๊ณต๋ฐฑ ๋ผ์ธ ์ˆ˜ | | `MAM_READY_EMPTY_GIVEUP` | `5` | `wait_for_tui_ready`๊ฐ€ ํŽ˜์ธ์„ ๊ด€์ธก ๋ถˆ๊ฐ€(Headless)๋กœ ํŒ์ •ํ•˜๊ธฐ๊นŒ์ง€์˜ ์—ฐ์† ๋นˆ ์บก์ฒ˜ ํšŸ์ˆ˜ | #### 1. 2๊ณ„์ธต TUI ์ค€๋น„ ํŒ์ • ๋ชจ๋ธ (`S โˆจ (W โˆง C)`) * **๋‹จ๋… ์ถฉ๋ถ„ ๊ฐ•ํ•œ ์‹ ํ˜ธ (`S`)**: `strong_ready_tokens` ๋˜๋Š” 8์ž ์ด์ƒ์˜ ์œ ์˜๋ฏธํ•œ `input_placeholder`(`Ask anything...`) ์ผ์น˜ ์‹œ ์ค€๋น„ ์™„๋ฃŒ ์„ ์–ธ. * **๋ณด๊ฐ• ๊ฒฐํ•ฉ ์•ฝํ•œ ์‹ ํ˜ธ (`W โˆง C`)**: `weak_ready_tokens`(`history`, `Chat` ๋“ฑ)๋Š” `input_prompt`(`โฏ`, `>`) ๋˜๋Š” `input_rule_pattern`(`โ”€{10,}`)๊ณผ ๋™์‹œ ์ผ์น˜ํ•  ๋•Œ๋งŒ ์ค€๋น„ ์™„๋ฃŒ๋กœ ํŒ์ •ํ•˜์—ฌ ์˜คํƒ ์ฐจ๋‹จ. * **ํ•˜๊ฐ• ํ˜ธํ™˜์„ฑ (Fallback)**: `input_*` ์†์„ฑ์ด ๋ฏธ์ •์˜๋œ ์—์ด์ „ํŠธ(Hermes ๋“ฑ)๋Š” ๊ฐ•ํ•œ ํ† ํฐ ๋‹จ๋… ๊ฒ€์‚ฌ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ํ•˜๊ฐ•. #### 2. ๋ชจ๋‹ฌ/ํžŒํŠธ ํ† ํฐ ๋ถ„๋ฆฌ ๋ฐ ์–ด๋Œ‘ํ„ฐ `modal_tokens` ๊ณ„์•ฝ (`T-2a` / `T-2d`) * **ํ† ํฐ ์ง‘ํ•ฉ ๋ถ„๋ฆฌ**: `_MAM_MODAL_TOKENS`(๊ณ ์‹ ๋ขฐ ๋ธ”๋กœํ‚น ๋ชจ๋‹ฌ)์™€ `_MAM_HINT_TOKENS`(์ž์—ฐ์–ด TUI ์•ˆ๋‚ด ํŒ)๋ฅผ ๋ถ„๋ฆฌ. `_pane_dialog_open`์ด ํžŒํŠธ ํ…์ŠคํŠธ๋กœ ์ธํ•ด ์˜๊ตฌ ์ฐจ๋‹จ(Starvation)๋˜๋Š” ๊ฒฐํ•จ ํ•ด์†Œ. `_MAM_DIALOG_TOKENS`๋Š” ํ•˜์œ„ํ˜ธํ™˜์šฉ ํ•ฉ์ง‘ํ•ฉ์œผ๋กœ ์กด์น˜. * **`BaseAgentAdapter.modal_tokens`**: ์—์ด์ „ํŠธ๋ณ„ ํŠนํ™” ๋ชจ๋‹ฌ(Claude์˜ `Try the new fullscreen renderer?`, Cline์˜ `Select API Provider` ๋“ฑ)์„ ํŒฉํŠธ ๋ธŒ๋ฆฌ์ง€(`MAM_MODAL_TOKENS`)๋กœ ํ†ตํ•ฉ. #### 3. Fail-Closed ํŽ˜์ธ ํ•ด์„ ๋ฐ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์Šค์ฝ”ํ”„ ๊ฐ•ํ™” (`R-1` / `R-2`) * `_resolve_herdr_pane_id`์—์„œ ๋‹ค์ค‘ ๋งค์น˜ ์‹œ `sys.exit(1)` ์ฒ˜๋ฆฌ ๋ฐ `export WORKSPACE_ROOT` ๋ณด๊ฐ•์œผ๋กœ ๊ฒฉ๋ฆฌ ์•ˆ์ •์„ฑ ํ™•๋ณด. #### 4. ์ค€๋น„ ์‹คํŒจ ์„ธ์…˜ ์ง„๋‹จ ๋ณด์กด ๋ฐ `MAM_VERSION` ์Šคํƒฌํ”„ * `create_session.sh` ์‹คํŒจ/ํƒ€์ž„์•„์›ƒ ์‹œ `.mam/diagnostics/-.txt`๋กœ ํŽ˜์ธ ๋คํ”„ ๋ฐ `MAM Version` ์Šคํƒฌํ”„ ์ž๋™ ๊ธฐ๋ก. #### 5. ๋Ÿฐํƒ€์ž„ ๋ฒ„์ „ ์ƒ์ˆ˜ `MAM_VERSION` ์‹ ์„ค ๋ฐ 3์ž ๋ฝ์Šคํ… ๊ฒ€์ฆ * `lib.sh` ๋‚ด `MAM_VERSION="3.1.0"` ์„ ์–ธ ๋ฐ `test_version_consistency.py`๋ฅผ ํ†ตํ•œ `lib.sh` โ†” `VERSIONS.md` โ†” 8๊ฐœ `SKILL.md` 3์ž ์ผ์น˜ ์ž๋™ ๊ฒ€์ฆ. #### 6. ์‹ ๊ทœ ํ™˜๊ฒฝ๋ณ€์ˆ˜ 3์ข… ๋ฌธ์„œํ™” * `.mam.env.example`์— `MAM_KILL_ON_READY_TIMEOUT`, `MAM_DIALOG_TAIL_LINES`, `MAM_READY_EMPTY_GIVEUP` 3์ข… ๋“ฑ๋ก. #### 7. ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ ํ™•์žฅ: 412 โ†’ 436 (+24, 100% PASS) * `test_c1_tui_readiness.py` (21 tests), `test_adapter_modal_tokens_contract`, `test_version_consistency.py` ์‹ ์„ค ๋“ฑ ์ด 436๊ฐœ ํ…Œ์ŠคํŠธ ๋ฌด๊ฒฐ์  ํ†ต๊ณผ. #### 8. ๊ต์ฐจ ํ”ผ์–ด ๋ฆฌ๋ทฐ ์ด๋ ฅ * F-1~F-8 ๋ฐ R-1, R-2 ์ด 10๊ฑด์˜ ํ”ผ์–ด ๋ฆฌ๋ทฐ ์ด์Šˆ ๋„์ถœ ๋ฐ ํ•ด์†Œ: - F-1 (`Yes, try it` ํŒ ์˜คํƒ ์ œ๊ฑฐ), F-2 (์—…์…€ ๋ชจ๋‹ฌ ์„ ํ–‰ ๊ฒ€์‚ฌ), F-3 (๋ณ€์ˆ˜ ์Šค์ฝ”ํ”„ ๊ฒฉ๋ฆฌ), F-4 (๋ฆฌ๋ทฐ์–ด ์‹ค์ธก ๊ฒ€์ฆ ํ›„ ์ž์ง„ ์ฒ ํšŒ), F-5/F-6/F-7 (์–ด๋Œ‘ํ„ฐ ํŒฉํŠธ ์—ฐ๋™ ๋ฐ ์„ธ์…˜ ํŒจํ„ด ๋ณด๊ฐ•), F-8 (๋น„-ํด๋กœ๋“œ ์–ด๋Œ‘ํ„ฐ modal_tokens ๊ณ„์•ฝ ์ •๋ฆฝ), R-1 (Fail-closed ํŽ˜์ธ ๋ฆฌ์กธ๋ฒ„), R-2 (`WORKSPACE_ROOT` export ์ „ํŒŒ). - ๊ณ„ํš ๋‹จ๊ณ„ ์ฑŒ๋ฆฐ์ง€(`b9c29c3b`)๋ฅผ ํ†ตํ•œ C-1 (`MAM_VERSION` 3์ž ๋ฝ์Šคํ…) ๋ฐ C-2 (๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์•ˆ๋‚ด) ์ˆ˜์šฉ. ### ๐Ÿš€ `v3.0.1` โ€” Herdr Shim Routing Contract Refactor, Multi-Workspace Isolation & 412-Test Milestone (2026-08-27) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: Herdr ์‹ฌ ๋ผ์šฐํŒ… 5๋Œ€ ๊ฒฐํ•จ(ISSUE-1~5) ๋ฐ F-1~F-4 ๋ณด์™„ ์™„๊ฒฐ, `HERDR_WORKSPACE_ID` ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์Šค์ฝ”ํ•‘ ๋ฐ ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๊ฒฉ๋ฆฌ ์˜์†ํ™” ์—”์ง„ ํƒ‘์žฌ, `pane send-text` ๊ธฐ๋ฐ˜ ๋‹จ์ผ ์•ˆ์ „ ์‚ฝ์ž… ๊ณ„์•ฝ ์ •๋ฆฝ, ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ๋งค์นญ(`in tn`) ์™„์ „ ์ œ๊ฑฐ, 412๊ฐœ ์ „์ฒด ํ…Œ์ŠคํŠธ 100% PASS ๋‹ฌ์„ฑ. #### 1. Herdr ์‹ฌ ๋ผ์šฐํŒ… ๋ฐ ๋‹ค์ค‘ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๊ฒฉ๋ฆฌ ๊ฐ•ํ™” (`.agents/skills/lib.sh`) * **`HERDR_WORKSPACE_ID` ๋ช…์‹œ์  ์Šค์ฝ”ํ”„ & ์˜์†ํ™” (`ISSUE-3`, `F-2b`)**: - `_herdr_ws_id_file()`, `_herdr_persist_ws_id()`, `_herdr_ws_scope()` ํ—ฌํผ ๋„์ž…. - `new-session` ์‹œ ์ƒ์„ฑ๋œ ์›Œํฌ์ŠคํŽ˜์ด์Šค ID๋ฅผ `$WORKSPACE_ROOT/.mam/herdr_workspace_id`์— ์˜์†ํ™”. - `_herdr_agent_get_scoped`๋Š” ํ˜ธ์ถœ์ž์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜(`HERDR_WORKSPACE_ID`)๋งŒ์„ ์šฐ์„  ํ‰๊ฐ€ํ•˜์—ฌ ๋‹จ์ถ• ๊ฒฝ๋กœ์—์„œ์˜ ๊ต์ฐจ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ผ์šฐํŒ… ์˜ค์—ผ ์ฐจ๋‹จ. * **์—„๊ฒฉ ์ผ์น˜(Exact-Match) ๋‹จ์ผ ํŽ˜์ธ ๋ฆฌ์กธ๋ฒ„ ์ •๋ฆฝ (`ISSUE-2`, `ISSUE-5`, `F-3`)**: - ๊ธฐ์กด์˜ ์—์ด์ „ํŠธ CLI ๋ช…์นญ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ๋งค์นญ(`in tn`, `agent in tn`) ์™„์ „ ์ œ๊ฑฐ. - ๋‹จ์ผ ์ค‘์•™ ํ—ฌํผ `_resolve_herdr_pane_id`๋กœ `has-session`, `kill-session`, `capture-pane`, `send-keys`, `paste-buffer`์˜ ํŽ˜์ธ ํ•ด์„ ํ†ตํ•ฉ. - ์˜์ˆซ์ž ์›Œํฌ์ŠคํŽ˜์ด์Šค ์‹๋ณ„์ž ํŒจํ„ด(`^w[A-Za-z0-9]+:p[A-Za-z0-9]+$`) ์ง€์› (`H-20`). #### 2. ์›์ž์  ํ…์ŠคํŠธ ์‚ฝ์ž… ๋ฐ ์•ˆ์ „ ์ „์†ก ๊ณ„์•ฝ ๊ต์ • (`ISSUE-1`, `F-4`) * **`paste-buffer`์˜ `pane send-text` ์ „์šฉํ™”**: - Herdr CLI์— ๋ฏธ์กด์žฌํ•˜๋˜ `agent send` ์ œ๊ฑฐ ๋ฐ `pane send-text`๋กœ ๊ต์ฒด. - ์‚ฝ์ž…๊ณผ ์ œ์ถœ(Enter) ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์˜๋„์น˜ ์•Š์€ ์ž๋™ ์ œ์ถœ ๋ฐ ์ด์ค‘ ์ œ์ถœ(Double Submit) ๋ฐฉ์ง€. - ํŽ˜์ธ ๋ฏธํ•ด์„ ๋˜๋Š” ์‚ฝ์ž… ์‹คํŒจ ์‹œ `send_keys_safe`๋กœ ์—๋Ÿฌ ์ฝ”๋“œ(`rc 3`) ๋ช…์‹œ์  ์ „ํŒŒ. * **`capture-pane` ํด๋ฐฑ ์ฒด์ธ ๋ณต์› (`F-4`)**: - `pane read` ์‹คํŒจ ์‹œ `agent read`๋กœ์˜ ํด๋ฐฑ ์ฒด์ธ์„ ์•ˆ์ •์ ์œผ๋กœ ๋ณต์›ํ•˜์—ฌ TUI ์บก์ฒ˜ ์‹ ๋ขฐ์„ฑ ๋ณด์žฅ. #### 3. TUI ์ค€๋น„ ์ƒํƒœ ๊ฐ์ง€ ๋ฐ ๋‹ค์ด์–ผ๋กœ๊ทธ ํ† ํฐ ์ •๋ฐ€ํ™” (`N-1`, `F-1`) * **`_MAM_DIALOG_TOKENS` ์ผ๋ฐ˜ ํŒ ํ† ํฐ ๋ถ„๋ฆฌ**: - ์ผ๋ฐ˜ ๋Œ€ํ™”ํ˜•/TUI ํŒ์— ๋“ฑ์žฅํ•˜๋Š” `Yes, try it`์„ ๋ธ”๋กœํ‚น ๋‹ค์ด์–ผ๋กœ๊ทธ ํ† ํฐ ๋ชฉ๋ก์—์„œ ์ œ์™ธํ•˜์—ฌ ์„ธ์…˜ ์‹œ์ž‘ ์‹œ์˜ ์˜คํƒ ๋ฐฉ์ง€. - ํ’€์Šคํฌ๋ฆฐ ์—…์…€ ๋ชจ๋‹ฌ์— ๋Œ€ํ•ด์„œ๋Š” ์ „์šฉ Escape ๊ฑฐ์ ˆ ๋ธŒ๋žœ์น˜๋กœ ๊ฒฉ๋ฆฌ ์ฒ˜๋ฆฌ. #### 4. ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ ๋ฐ Mock Herdr ๊ณ„์•ฝ ์ •๊ธฐ ๋™๊ธฐํ™” (`tests/`) * **Mock Herdr (`tests/conftest.py`)**: ์‹ค์ œ Herdr 0.8.2 CLI ๊ณ„์•ฝ๊ณผ ์™„๋ฒฝ ๋™๊ธฐํ™” (`pane send-text`, `pane read`, `pane rename` ๋ฐ˜์˜, ๋ฏธ์ง€์› `agent send` ์‹คํŒจ ์ฒ˜๋ฆฌ). * **์‹ ๊ทœ ๊ณ„์•ฝ & ํšŒ๊ท€ ํ…Œ์ŠคํŠธ 19๊ฑด ์ถ”๊ฐ€**: - `test_herdr_shim_contract.py`: H-15 ~ H-23 (๋‹จ์ผ ๋ฆฌ์กธ๋ฒ„ ๋ถˆ๋ณ€์‹, ์›Œํฌ์ŠคํŽ˜์ด์Šค ๊ฒฉ๋ฆฌ, ๋‹จ์ถ•๊ฒฝ๋กœ ์Šค์ฝ”ํ•‘). - `test_b19_headless_reconcile_fixes.py`: D-4 ~ D-7 (set -e ์•ˆ์ „์„ฑ, send_keys_safe ์‹คํŒจ ์ „ํŒŒ, ๋‹ค์ด์–ผ๋กœ๊ทธ ํ† ํฐ ์ œ์™ธ ํšŒ๊ท€ ๋ฐฉ์ง€). * **์ „์ฒด ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ**: 412 passed in 681.20s (100% PASS). --- ### ๐Ÿš€ `v3.0.0` โ€” 5th Agent (Grok) Ecosystem Expansion, Mux Loop CLI Redesign & Deterministic 2xK Layout Engine 2.0 (2026-08-26) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: 5๋ฒˆ์งธ ๊ณต์‹ ์—์ด์ „ํŠธ `grok`(Grok Build) ์ „๋ฉด ํ†ตํ•ฉ, `/multi-agent-mux-loop`์˜ `--target-agent` ํ์ง€ ๋ฐ `--creator`/`--planner` ์—ญํ•  ๋ถ„๋ฆฌ(Breaking Change), 2ร—2 ๋Œ€์นญ ๊ทธ๋ฆฌ๋“œ๋ฅผ ๋ณด์žฅํ•˜๋Š” ๊ฒฐ์ •๋ก ์  ๋ ˆ์ด์•„์›ƒ ์—”์ง„ 2.0 ํƒ‘์žฌ, 393๊ฐœ ์ „์ฒด ํ…Œ์ŠคํŠธ 100% PASS ๋‹ฌ์„ฑ. #### โš ๏ธ Breaking Changes & Migration Guide * **`multi-agent-mux-loop` CLI ํ”Œ๋ž˜๊ทธ ๊ฐœํŽธ**: - ๊ธฐ์กด์˜ ๋‹จ์ผ ๋Œ€์ƒ ์ง€์ • ํ”Œ๋ž˜๊ทธ `--target-agent `๊ฐ€ **๊ณต์‹ ์ œ๊ฑฐ(Drop)** ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - ๊ธฐ์กด ๋ช…๋ น์€ ์ด์ œ `ERROR: --target-agent was removed. Use --creator instead.`์™€ ํ•จ๊ป˜ ์ข…๋ฃŒ(`exit 1`)๋ฉ๋‹ˆ๋‹ค. - **๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•**: - ๊ธฐ์กด: `bash run_loop.sh --target-agent --task "..."` - ๋ณ€๊ฒฝ: `bash run_loop.sh --creator --task "..."` - ํ”Œ๋ž˜๋„ˆ ์ง€์ • ์‹œ: `bash run_loop.sh --plan --planner --creator --task "..."` #### 1. 5๋ฒˆ์งธ ๊ณต์‹ AI ์—์ด์ „ํŠธ Grok Build (`grok`) ์ „๋ฉด ํ†ตํ•ฉ * **์–ด๋Œ‘ํ„ฐ ๋ฐ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ด€๋ฆฌ (`lib_py/agents/`, `lib.sh`)**: - `GrokAgentAdapter` ๊ตฌํ˜„ ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๊ณต์‹ ๋“ฑ๋ก (`claude, agy, hermes, cline, grok`). - `create_session.sh`, `resume_session.sh`, `stop_session.sh`, `resolve_session_id.sh`์˜ ์—์ด์ „ํŠธ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋ฐ ๋””์ŠคํŒจ์น˜ ์ง€์› ์™„๋น„. - ์˜จ๋””์Šคํฌ ์„ธ์…˜ UUID ํ•ด์„ ๋ฐ TUI ๋ Œ๋”๋ง ์ค€๋น„ ๊ฐ์ง€ ํ† ํฐ ๋ฐ˜์˜. #### 2. ๊ฒฐ์ •๋ก ์  2ร—K ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ ์—”์ง„ 2.0 (`lib_py/layout.py`, `lib.sh`) * **$N=1\to 2$ `right` ๋ถ„ํ•  ์šฐ์„  ์ •์ฑ… (R-1 ๊ฒฐํ•จ ํ•ด์†Œ)**: - 1๊ฐœ ํŽ˜์ธ์—์„œ 2๋ฒˆ์งธ ์—์ด์ „ํŠธ ์ถ”๊ฐ€ ์‹œ `down` ๋Œ€์‹  `right`๋กœ ๋ถ„ํ• (`single_pane_split_right`)ํ•˜์—ฌ ์ขŒ/์šฐ 2๊ฐœ์˜ ์ „๊ณ (Full-height) ์—ด ํ™•๋ณด. - ์ดํ›„ $N=3$(์ขŒ์ธก down), $N=4$(์šฐ์ธก down)๋กœ ์ด์–ด์ ธ ์™„๋ฒฝํ•œ 2ร—2 ๊ท ๋“ฑ ๋Œ€์นญ ๊ฒฉ์ž ๊ธฐํ•˜ํ•™(`widths=[138,139], heights=[39]`) ์™„์„ฑ. * **GUI โ†” ํ—ค๋“œ๋ฆฌ์Šค ๋‹จ์ผ ๊ฒฐ์ •ํ‘œ ํ†ตํ•ฉ (`_decide_from_cols`)**: - ๊ธฐ์กด์˜ ๋ถˆ์™„์ „ํ•œ `n % 2` ํ™€์ง ํŒจ๋ฆฌํ‹ฐ ๋กœ์ง์„ ํ๊ธฐํ•˜๊ณ , ์—ด ์ ์œ  ์ƒํƒœ(`cols=(a, b)`) ๊ธฐ๋ฐ˜์˜ ํ†ตํ•ฉ 3๋‹จ๊ณ„ ๊ฒฐ์ • ๋งคํŠธ๋ฆญ์Šค๋กœ ์ผ์›ํ™”. * **์•ˆ์ „ ๊ฐ€๋“œ ๋ฐ 4์ค‘ ์šฉ๋Ÿ‰ ๋ฐฐ์„ **: - `_full_height_pane` ๊ฐ€๋“œ๋กœ ๋ฐ˜์ชฝ ์—ด ๋ถ„ํ•  ์›์ฒœ ์ฐจ๋‹จ. - `layout.py` ๊ธฐ๋ณธ๊ฐ’(`default=2`), `lib.sh:435` CLI ์ธ์ž(`--max-cols`, `--max-rows`), `.mam.env.example` ๋™๊ธฐํ™” ์™„๋ฃŒ. #### 3. ์‚ฌ์ „ ๊ฒ€์ฆ ๋ฐ ์ธํ”„๋ผ ๋™๊ธฐํ™” * `create_session.sh`์˜ `--workspace` ํ•„์ˆ˜ ์ธ์ž ์‚ฌ์ „ ๊ฒ€์ฆ(preflight) ๊ฐ•ํ™”. * ์‚ฌ์„ค NATS ๋ธŒ๋กœ์ปค(`nats-docker`) 2.14-alpine ์ตœ์‹  ํƒœ๊ทธ ๋™๊ธฐํ™”. --- ### ๐Ÿš€ `v2.2.1` โ€” Single-Workspace 2xK Multi-Pane Tiling Optimization & Premature Overflow Fix (2026-08-24) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: `MAM_MIN_PANE_COLS` ๊ธฐ๋ณธ๊ฐ’ 60โ†’40 ์™„ํ™”, ํ‘œ์ค€ 80~100์ปฌ๋Ÿผ ํ„ฐ๋ฏธ๋„ ๋ทฐํฌํŠธ์—์„œ ์กฐ๊ธฐ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์˜ค๋ฒ„ํ”Œ๋กœ(๊ฐ€์ƒ ๋ฐ์Šคํฌํ†ฑ ๋ถ„๋ฆฌ) ๋ฐฉ์ง€ ๋ฐ ๋‹จ์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค 2x2 ํ†ตํ•ฉ ํƒ€์ผ๋ง ์™„์„ฑ, ์‹ ๊ทœ 80/79 ๊ฒฝ๊ณ„ ๋ฐ 90/100 col ํƒ€์ผ๋ง ํ…Œ์ŠคํŠธ 6์ข… ์ถ”๊ฐ€, ๋‹ค์ค‘ ์—์ด์ „ํŠธ ํ”ผ์–ด ๋ฆฌ๋ทฐ 100% PASS ๋‹ฌ์„ฑ. #### 1. 2xK ๋ ˆ์ด์•„์›ƒ ์—”์ง„ ์ตœ์†Œ ํญ ์™„ํ™” (`lib_py/layout.py`, `lib.sh`) - `compute_2xk_layout` ๊ธฐ๋ณธ `min_cols` ๋ฐ CLI `--min-cols`, `lib.sh:432`์˜ `${MAM_MIN_PANE_COLS:-40}`, `.mam.env.example` ๋ฌธ์„œ๋ฅผ `40`์œผ๋กœ 4์ค‘ ์ผ์น˜ํ™”. - 90~100์ปฌ๋Ÿผ ๋„ˆ๋น„ ํ„ฐ๋ฏธ๋„์—์„œ 3๋ฒˆ์งธ, 4๋ฒˆ์งธ ์—์ด์ „ํŠธ ์ƒ์„ฑ ์‹œ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊ฐ€์ƒ ๋ฐ์Šคํฌํ†ฑ(Workspace)์ด ๋ถ„๋ฆฌ๋˜๋˜ ํ˜„์ƒ ์™„์ „ ํ•ด์†Œ. #### 2. ๊ฒฝ๊ณ„๊ฐ’ ๋ฐ ํƒ€์ผ๋ง ์ž๋™ํ™” ํ…Œ์ŠคํŠธ ํ™•์ถฉ (`tests/test_layout.py`, `tests/test_tier1_unit.py`) - `80` ์ปฌ๋Ÿผ(๋ถ„ํ•  ์„ฑ๊ณต) vs `79` ์ปฌ๋Ÿผ(์˜ค๋ฒ„ํ”Œ๋กœ) ํ•˜ํ•œ ๊ฒฝ๊ณ„๊ฐ’ ๊ฒ€์ฆ. - `90` ๋ฐ `100` ์ปฌ๋Ÿผ ๋‹จ์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค 1โ†’2โ†’3โ†’4 ๋‹จ๊ณ„ 2x2 ํƒ€์ผ๋ง ๋ฐ 5๋ฒˆ์งธ ์—์ด์ „ํŠธ ์˜ค๋ฒ„ํ”Œ๋กœ ์ „ ๊ณผ์ • ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ฒ€์ฆ. --- ### ๐Ÿš€ `v2.2.0` โ€” Herdr Workspace Label Standardization, Runtime Sync & Legacy Fallback Decoupling (2026-08-24) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: `--herdr-workspace` ์˜ต์…˜ ์ „ ์Šคํ‚ฌ ๋„์ž… ๋ฐ YAML ๋…๋ฆฝ ์ง๋ ฌํ™”, Herdr ๋Ÿฐํƒ€์ž„ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ ˆ์ด๋ธ” ์‹ค์‹œ๊ฐ„ ๋™๊ธฐํ™”, ๋ ˆ๊ฑฐ์‹œ ์†Œ์ผ“ ํด๋ฐฑ ์ฒด์ธ ๋ถ„๋ฆฌ(Breaking Change ๋ฐฉ์–ด), ์ตœ์‹  Claude Code TUI ๊ฐ์ง€ ํ† ํฐ ๋ฐ˜์˜, 27๊ฐœ ์‹ ๊ทœ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€ ๋ฐ ๋งŒ์žฅ์ผ์น˜ PASS ๋‹ฌ์„ฑ. #### 1. `--herdr-workspace` ์˜ต์…˜ ๋„์ž… ๋ฐ Herdr ๋Ÿฐํƒ€์ž„ ๋ ˆ์ด๋ธ” ๋™๊ธฐํ™” - **CLI ์˜ต์…˜ ๋ฐ YAML ์ง๋ ฌํ™” ํ‘œ์ค€ํ™”**: - `create_session.sh`, `resume_session.sh`, `update_yaml_resumed.sh`, `stop_session.sh`์— `--herdr-workspace ` ํŒŒ์„œ ๋ฐ ํ™˜๊ฒฝ๋ณ€์ˆ˜(`HERDR_WORKSPACE`) ์ง€์› ์ถ”๊ฐ€. - `agent-sessions.yaml`์— `herdr_session`(์†Œ์ผ“๋ช…)๊ณผ `herdr_workspace`(์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ผ๋ฒจ)๋ฅผ ๊ฐ๊ฐ ๋…๋ฆฝ ํ•„๋“œ๋กœ ์˜๊ตฌ ์ง๋ ฌํ™”. - **Herdr ๋Ÿฐํƒ€์ž„ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ ˆ์ด๋ธ” ์‹ค์‹œ๊ฐ„ ์—ฐ๋™ (`lib.sh`, `resume_session.sh`)**: - `herdr workspace create` ํ˜ธ์ถœ ์‹œ `--label "$MAM_WS_LABEL"` ์ „๋‹ฌ ๋ฐ ๊ธฐ์กด ์›Œํฌ์ŠคํŽ˜์ด์Šค ์‚ฌ์šฉ ์‹œ `herdr workspace rename` ์ž๋™ ํ˜ธ์ถœ. - `resume_session.sh` ์‹คํ–‰ ์‹œ ์ €์žฅ๋œ `herdr_workspace`๋ฅผ ์ฝ์–ด Herdr ๋Ÿฐํƒ€์ž„ ๋ ˆ์ด๋ธ” ๋ณต์› ๋ณด์žฅ. #### 2. ๋ ˆ๊ฑฐ์‹œ ์†Œ์ผ“ ํด๋ฐฑ ์ฒด์ธ ๋ถ„๋ฆฌ ๋ฐ Breaking Change ์›์ฒœ ์ฐจ๋‹จ - **์†Œ์ผ“ vs ์›Œํฌ์ŠคํŽ˜์ด์Šค ํ•จ์ˆ˜ ์™„์ „ ๋ถ„๋ฆฌ (`lib.sh`)**: - `resolve_herdr_session()`: ๋ฐ๋ชฌ/์†Œ์ผ“ ์„ธ์…˜๋ช…๋งŒ ๋ฐ˜ํ™˜ (row `herdr_session` -> row `herdr_server` -> env -> slug). - `resolve_herdr_workspace()`: ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ผ๋ฒจ๋งŒ ๋ฐ˜ํ™˜ (row `herdr_workspace` -> `pane.cwd` slug -> caller `ws` arg). - ๊ธฐ์กด ์ฝ”๋“œ๋ฒ ์ด์Šค 6๊ฐœ ์ง€์ (`lib.sh:1027`, `reconcile.sh:135, 399, 495`, `status.sh:145, 270`)์—์„œ ์†Œ์ผ“ ๊ฒ€์ƒ‰ ์‹œ `herdr_workspace`๋ฅผ ์˜ค์ธ ์ฐธ์กฐํ•˜๋˜ ๊ตฌ๋ฌธ์„ ์™„์ „ํžˆ ์ œ๊ฑฐ. - **์™ธ๋ถ€ ์„ธ์…˜ ์ž…์–‘(Drift-B) ๋ณด๊ฐ• (`reconcile.sh`)**: - ์™ธ๋ถ€ ์„ธ์…˜ ์ž…์–‘ ์‹œ `herdr_workspace`์™€ `herdr_server`๋ฅผ ์ž๋™ ์ฑ„๋ฒˆ ๋ฐ ์ง๋ ฌํ™”. #### 3. ์ตœ์‹  ์—์ด์ „ํŠธ TUI ์ค€๋น„ ๊ฐ์ง€ ๋ณด๊ฐ• (`claude.py`, `lib.sh`) - ์ตœ์‹  Claude Code(`v2.1.241`)์˜ ์‹œ์ž‘ ๋ฐฐ๋„ˆ(`Claude Code`, `Opus 5 with high effort` ๋“ฑ)๋ฅผ `ready_tokens`์— ์ถ”๊ฐ€ํ•˜์—ฌ ์„ธ์…˜ ์ƒ์„ฑ ํƒ€์ž„์•„์›ƒ ๋ฐฉ์ง€. --- ### ๐Ÿš€ `v2.1.0` โ€” 2xK Grid Layout Engine, Explicit Agent Standardization & Herdr Session Hardening (2026-08-24) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: 2xK ์šฐ์ธก ์„ฑ์žฅ ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ ์—”์ง„(`lib_py.layout`) ๊ตฌ์ถ•(B-20), ์ „ ์Šคํฌ๋ฆฝํŠธ `--agent` / `--herdr-session` ํ‘œ์ค€ํ™” ๋ฐ ์ „ํŒŒ ๊ฐ€๋“œ, ์ „์ฒด 346๊ฐœ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ 100% PASS ๋‹ฌ์„ฑ. #### 1. 2xK ์šฐ์ธก ์„ฑ์žฅ ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ ์—”์ง„ ๊ตฌ์ถ• (B-20 / I-2, I-3, C-1, J-1) - **์ˆœ์ˆ˜ ํŒŒ์ด์ฌ ๋ ˆ์ด์•„์›ƒ ์—”์ง„ ์‹ ์„ค (`lib_py/layout.py`)**: - `tput` ๊ธฐ๋ฐ˜ ํ„ฐ๋ฏธ๋„ ํฌ๊ธฐ ๋™์  ๊ฐ์ง€ ๋ฐ 2xK(2ํ–‰ ๊ณ ์ •, ์šฐ์ธก ์—ด ์ถ”๊ฐ€) ๊ทธ๋ฆฌ๋“œ ๊ธฐํ•˜ํ•™ ๊ณ„์‚ฐ ์—”์ง„ ๊ตฌํ˜„. - ํŒจ๋„ ๋ฒˆํ˜ธ ์ˆœ์„œ(0:์ขŒ์ƒ, 1:์ขŒํ•˜, 2:์ค‘์ƒ, 3:์ค‘ํ•˜...)์— ๋”ฐ๋ฅธ ์šฐ์ธก ํ™•์žฅ ํƒ€์ผ๋ง ๋ถ„ํ•  ๋ช…๋ น(`split-pane -h/-v`, `select-pane`) ๊ณ„์‚ฐ. - ํ—ค๋“œ๋ฆฌ์Šค/CI ์ตœ์†Œ ์ฐจ์›(์ตœ์†Œ ๋„ˆ๋น„ 60, ์ตœ์†Œ ๋†’์ด 20) ๊ฐ€๋“œ ๋ฐ `default=60` falsy-zero trap ํ•ด๊ฒฐ (`_env_int`). - **33๊ฐœ ์‹ ๊ทœ ๋ ˆ์ด์•„์›ƒ ๋‹จ์œ„/ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ๊ตฌ์ถ• (`tests/test_layout.py`)**: - 1~8๊ฐœ ํŒจ๋„ ์ˆ˜์‹ ๊ฒ€์ฆ, ๋น„์ •์ƒ ์ธ์ž/ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋ฐฉ์–ด, ๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€ ๊ฐ€๋“œ ๊ฒ€์ฆ. #### 2. ์—์ด์ „ํŠธ ์ธ์ž ํ‘œ์ค€ํ™” ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ž๋™ ์ถ”๋ก  - `stop_session.sh`, `create_session.sh`, `resume_session.sh`, `update_yaml_resumed.sh`, `resolve_session_id.sh` ์ „๋ฐ˜์— ๊ฑธ์ณ `--agent ` ๋ช…์‹œ์  ํ‘œ์ค€ํ™”. - ๋ฏธ์ง€์ • ์‹œ YAML ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ(`agent-sessions.yaml`) ๊ธฐ๋ฐ˜ ์—์ด์ „ํŠธ ํƒ€์ž… ์ž๋™ ์ถ”๋ก (`resolve_agent_type_from_registry`) ์—ฐ๋™. #### 3. `--herdr-session` ๊ฒฉ๋ฆฌ ์„ธ์…˜ ์˜ต์…˜ ํ‘œ์ค€ํ™” ๋ฐ ์ „ํŒŒ ๊ฐ€๋“œ - `create_session.sh`, `resume_session.sh`, `stop_session.sh`, `update_yaml_resumed.sh` ์ „๋ฐ˜์— `--herdr-session ` ํ‘œ์ค€ ์˜ต์…˜ํ™” (๋ ˆ๊ฑฐ์‹œ `--herdr-server` ์™„์ „ ํ˜ธํ™˜). - `create_session.sh`์—์„œ ๋ช…์‹œ์  ์„ธ์…˜๋ช…์ด ์›Œํฌ์ŠคํŽ˜์ด์Šค ์Šฌ๋Ÿฌ๊ทธ์— ์˜ํ•ด ๋ฎ์–ด์”Œ์›Œ์ง€์ง€ ์•Š๋„๋ก ๊ฐ€๋“œ ๋ณด๊ฐ•. - `resume_session.sh`์˜ post-spawn ์žฌ๊ฐœ ์‹œ ์‹ ๊ทœ Herdr ์„ธ์…˜๋ช…์ด YAML ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์ •ํ™•ํžˆ ์ „ํŒŒ๋˜๋„๋ก ๊ฐฑ์‹  ๋กœ์ง ๋ฐ ์‹ ๊ทœ Tier 2 ํ…Œ์ŠคํŠธ 5๊ฑด ์ถ”๊ฐ€. #### 4. ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ ํ™•์žฅ ๋ฐ ํ”ผ์–ด ๋ฆฌ๋ทฐ ์ „์› ๋งŒ์žฅ์ผ์น˜ PASS - ์ „์ฒด ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ ์ˆ˜ **276๊ฑด โ†’ 346๊ฑด (100% PASS)** ํ™•์žฅ. - Multi-Agent Loop๋ฅผ ํ†ตํ•œ Reviewer(`claude`, `cline`) ์ „์› `[VERDICT: PASS]` ๊ฒ€์ฆ ์™„๋ฃŒ. --- ### ๐Ÿš€ `v2.0.0` โ€” Unified Agent Adapter Architecture & Herdr Standardization (2026-08-17) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ์—์ด์ „ํŠธ ์ง€์‹ ๊ณ„์ธต ๋‹จ์ผ ์†Œ์Šคํ™”(A-4), ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์™„์ „ ํ๊ธฐ(Option B), ์…ธ ๋ธŒ๋ฆฌ์ง€ ํ•˜๋“œ๋‹ ๋ฐ ์Šคํ‚ฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ทœ๊ฒฉํ™” ์™„๋ฃŒ. #### 1. ์—์ด์ „ํŠธ ์ง€์‹ ๊ณ„์ธต ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (A-4 Phase 2 / P3-1) - **`BaseAgentAdapter` ์ถ”์ƒ ํด๋ž˜์Šค ๋ฐ 4๋Œ€ ์–ด๋Œ‘ํ„ฐ ๊ตฌ์ถ•**: - [`.agents/skills/lib_py/agents/base.py`](.agents/skills/lib_py/agents/base.py): `DiscoveryContext` ๋ฐ ์ถ”์ƒ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜ (`ready_tokens`, `exit_key`, `delegate_agent_key`, `identity_cache_fields`, `artifact_path`, `verify_artifact`, `purge_artifacts`, `spawn_spec`, `resume_spec`, `auth_ok`, `discover`). - [`.agents/skills/lib_py/agents/adapters/`](.agents/skills/lib_py/agents/adapters/): `ClaudeAgentAdapter`, `AgyAgentAdapter`, `HermesAgentAdapter`, `ClineAgentAdapter` 4๊ฐœ ๊ตฌ์ฒด ํด๋ž˜์Šค ๊ตฌํ˜„. - **`facts` ๋ธŒ๋ฆฌ์ง€ ์…ธ ์ธํ„ฐํŽ˜์ด์Šค ํ•˜๋“œ๋‹**: - `lib_py.agents` CLI ๋ชจ๋“ˆ์„ ํ†ตํ•ด 8๊ฐœ `MAM_*` ๋ณ€์ˆ˜๋ฅผ `shlex.quote` ์•ˆ์ „ ์ธ์šฉ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฐฉ์ถœ. - `wait_for_tui_ready` ๋นˆ ํ† ํฐ ์‹œ ์ „๋Ÿ‰ ๋งค์นญ ์˜คํƒ ๋ฐฉ์ง€ ๋ฐ ๋ฏธ์ง€ ์—์ด์ „ํŠธ fail-closed ๊ฐ€๋“œ ๋‚ด์žฅ. - **์…ธ ์Šคํฌ๋ฆฝํŠธ ์ „๋ฐ˜ ์–ด๋Œ‘ํ„ฐ ์ด๊ด€**: - `create_session.sh`, `resume_session.sh`, `stop_session.sh`, `reconcile.sh`์— ์‚ฐ์žฌ๋˜์–ด ์žˆ๋˜ 40์—ฌ ๊ฐœ ํ•˜๋“œ์ฝ”๋”ฉ ๋ถ„๊ธฐ๋ฅผ ์–ด๋Œ‘ํ„ฐ ํ˜ธ์ถœ๋กœ ์ผ์›ํ™”. #### 2. ๋ ˆ๊ฑฐ์‹œ `isolation.root` ๋ฐ C-3b ์†Œ๋น„์ž ์™„์ „ ํ๊ธฐ (Option B) - Universal Global Config ์ „ํ™˜ ์ดํ›„ ๋‚จ์•„์žˆ๋˜ 4๊ฐœ ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์†Œ๋น„์ž ์ฝ”๋“œ(`lib.sh::mam_session_iso_root`, `workspace_uuid.py::iso_root_of`, `verify_session.py`, `stop_session.sh`) ๋ฐ `atomic_yaml.py`์˜ ๋ ˆ๊ฑฐ์‹œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ ˆ 100% ์‚ญ์ œ. - ์ €์žฅ์†Œ ๋‚ด ๊ฒฉ๋ฆฌ ์ž”์žฌ ์ฐธ์กฐ 0๊ฑด ๋‹ฌ์„ฑ. #### 3. ์…ธ ๋ธŒ๋ฆฌ์ง€ ๋ณด์•ˆ ๋ฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ฐ•ํ™” (R1, R2, N1 ๊ต์ •) - **R1 (์œ„์ž„ ์—์ด์ „ํŠธ ํ‚ค ํด๋ฐฑ ๋ณด๊ฐ•)**: ๋ธŒ๋ฆฌ์ง€ ๋ฏธ์ž‘๋™ ์‹œ `delegate_agent`๊ฐ€ `antigravity-cli`๋กœ ์ผ๊ด„ ํ‡ดํ™”ํ•˜์ง€ ์•Š๊ณ  `claude-code`, `hermes-agent`, `cline-agent`๋กœ ๋ช…์‹œ์  `case` ํด๋ฐฑํ•˜๋„๋ก ๊ฐœ์„ . - **R2 (`argv` ์„œ๋ธŒ์ปค๋งจ๋“œ ์ „ํ™˜)**: `python -c` ์…ธ ๋ณ€์ˆ˜ ๋ฌธ์ž์—ด ๋ณด๊ฐ„์„ `spawn-spec`, `resume-spec`, `exit-key` ์„œ๋ธŒ์ปค๋งจ๋“œ๋กœ ์ „๋ฉด ์ „ํ™˜ํ•˜์—ฌ ๊ณต๋ฐฑ/์ž‘์€๋”ฐ์˜ดํ‘œ ๊ฒฝ๋กœ ์—๋Ÿฌ ๋ฐ ์ฝ”๋“œ ์ฃผ์ž… ์œ„ํ˜‘ ์›์ฒœ ์ฐจ๋‹จ. - **N1 (ํด๋ฆฐ ํ™˜๊ฒฝ ๊ฒฉ๋ฆฌ ๊ฐ€๋“œ)**: `test_a4_adapter_contract.py` ๋‚ด CLI ํ…Œ์ŠคํŠธ๊ฐ€ ์•ฐ๋น„์–ธํŠธ `PYTHONPATH` ์—†์ด๋„ ๋…๋ฆฝ ํ†ต๊ณผํ•˜๋„๋ก ํ™˜๊ฒฝ ๊ฒฉ๋ฆฌ ๋ณด๊ฐ•. #### 4. ์Šคํ‚ฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ทœ๊ฒฉํ™” ๋ฐ ํ”ผ์–ด ๋ฆฌ๋ทฐ 100% PASS - 8๊ฐœ `SKILL.md` frontmatter `version: 2.0.0` ํ†ต์ผ ๋ฐ ๋ฐฐํฌ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ. - Reviewer `cline` (Job `e7b9812b`) ๋ฐ Planner/Senior Reviewer `claude` (Job `31730364`) ์ „์› `[VERDICT: PASS]` ํš๋“. #### 5. ๋ ˆ๊ฑฐ์‹œ ์ฃผ์„ ๋ฐ ์‚ฌ์šฉ๋ฒ• ์ •ํ•ฉ์„ฑ ์ตœ์‹ ํ™” (C-6) - `stop_session.sh` ์ƒ๋‹จ ์ฃผ์„ ๋ฐ `usage()` ๋‚ด ํ๊ธฐ๋œ ํ”Œ๋ž˜๊ทธ(`--mode soft|hard`, `--capture-id`, `--graceful`) ์•ˆ๋‚ด ๋ฌธ๊ตฌ๋ฅผ ์™„์ „ ์ œ๊ฑฐํ•˜๊ณ  ํ˜„ํ–‰ 4๋Œ€ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `cline`) ๋ฐ ํ”Œ๋ž˜๊ทธ ์ฒด๊ณ„๋กœ ๋™๊ธฐํ™”. - ํšŒ๊ท€ ๋ฐฉ์ง€ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ(`test_comp_stop_usage_matches_parser`) ์‹ ์„ค. - ํšŒ๊ท€ ๋ฐ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ: **263/263 PASS (100%)** ๋‹ฌ์„ฑ. #### 6. macOS NFS ๊ฐ์ง€ `df -P` ํด๋ฐฑ ๊ฒ€์ฆ ๋ฐ ์ข…๊ฒฐ (B-5) - `_check_is_nfs`(`lib.sh`)์˜ macOS/BSD ํ™˜๊ฒฝ ๋‚ด GNU ์ „์šฉ `df --output` ๊ตฌ๋ฌธ ์˜ค๋ฅ˜ ์‹œ POSIX `df -P` ํด๋ฐฑ ๋™์ž‘์„ ์‹ค์ธก ๋ฐ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ(`test_stop_check_is_nfs_local`)๋กœ ๊ฒ€์ฆ ์™„๋ฃŒํ•˜์—ฌ B-5 ์ด์Šˆ๋ฅผ ์ •์‹ ์ข…๊ฒฐ. #### 7. `agent_identities` tier-3 ์‹ ์› ์บ์‹œ ์™„์ „ ์ œ๊ฑฐ ๋ฐ UUID ํ•ด๊ฒฐ ๊ฒฝ๋กœ PyYAML ํƒˆ์˜์กด (B-10 / Option A) - ์“ฐ๊ธฐ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์•„ ๊ตฌ์กฐ์ ์œผ๋กœ ํžˆํŠธ ๋ถˆ๊ฐ€์˜€๋˜ tier-3 ํด๋ฐฑ๊ณผ ๋ถ€์† ์†Œ๋น„์ž(`workspace_uuid.py`, `reconcile.sh` drift D, `stop_session.sh` ์บ์‹œ ์†Œ๊ฑฐ)๋ฅผ ์ „๋ฉด ์‚ญ์ œ. - UUID ํ•ด๊ฒฐ ๊ฒฝ๋กœ๋ฅผ **tier-1(per-row own id) โ†’ tier-2(์–ด๋Œ‘ํ„ฐ `discover()`)** 2๋‹จ๊ณ„๋กœ ๋‹จ์ˆœํ™”. - `verify_session.py::mam_orchestrator_uuids` ์˜ ์ฆ‰์‹œ `yaml` import ๋ฅผ YAML ํด๋ฐฑ ๋ถ„๊ธฐ๋กœ ์ด๋™, UUID ํ•ด๊ฒฐ ๊ฒฝ๋กœ๊ฐ€ PyYAML ์—†์ด ์™„์ฃผํ•จ์„ ์‹คํ–‰ ๊ฐ€๋“œ๋กœ ๊ณ ์ •(`atomic_yaml.py` ์˜ ์‹œ์Šคํ…œ PyYAML ์š”๊ตฌ๋Š” ์„ค๊ณ„์ƒ ์œ ์ง€). - ํšŒ๊ท€ ๊ฐ€๋“œ 3์ข… ์‹ ์„ค โ€” ์ฝ๊ธฐ ๊ฒฝ๋กœ ๋ถ€ํ™œ ์ฐจ๋‹จ, `import yaml` AST ๊ฒ€์‚ฌ(์ง€์—ฐ import ํฌํ•จ), ์‹คํ–‰ ๊ฒฝ๋กœ ๊ฒ€์ฆ. - ํšŒ๊ท€ ๋ฐ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ: **266/266 PASS (100%)** ๋‹ฌ์„ฑ. #### 8. ์…€ํ”„ ํ˜ธ์ŠคํŒ… ๋ฃจํ”„ ๋Ÿฐํƒ€์ž„ ํ”„๋ฆฌ์ฆˆ ์Šค๋ƒ…์ƒท (B-13 / Stage 2) - ๋ฃจํ”„ ๊ธฐ๋™ ์‹œ `.agents/skills/` ๋ฅผ `$TMPDIR` ์— 1ํšŒ ๋™๊ฒฐํ•˜๊ณ  ์Šค๋ƒ…์ƒท์—์„œ ์žฌ์‹คํ–‰ํ•˜์—ฌ, ํ„ด ๋„์ค‘ ํ”„๋ ˆ์ž„์›Œํฌ ์Šคํ‚ฌ ํŽธ์ง‘์ด ์ง„ํ–‰ ์ค‘์ธ ๋ฃจํ”„๋ฅผ ๊นจ๋œจ๋ฆฌ์ง€ ๋ชปํ•˜๋„๋ก ์ฐจ๋‹จ. - ์ฝ”๋“œ ๋ฃจํŠธ(์Šค๋ƒ…์ƒท)์™€ ์ƒํƒœ ๋ฃจํŠธ(`MAM_REAL_ROOT`)๋ฅผ ๋ถ„๋ฆฌํ•ด ๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท๋ฃจํ”„ ๋ฝยทdiff ์ˆ˜์ง‘์€ ์‹ค์ œ ์ €์žฅ์†Œ๋ฅผ ๊ณ„์† ์‚ฌ์šฉ. - ์žฌ์‹คํ–‰ ์‹œ ์›๋ณธ argv ๋ฅผ ๋ฐฐ์—ด๋กœ ๋ณด์กดํ•ด ์ธ์ž ์œ ์‹ค์„ ๋ฐฉ์ง€(ํŒŒ์„œ๊ฐ€ `$@` ๋ฅผ ์†Œ๋น„ํ•˜๋ฏ€๋กœ ํ•„์ˆ˜). - ์Šค๋ƒ…์ƒท ์ƒ์„ฑ ์‹คํŒจ ์‹œ `log_*` ์ •์˜ ์ด์ „ ๊ตฌ๊ฐ„์ž„์„ ๊ณ ๋ คํ•ด `echo` ๋กœ ๊ฒฝ๊ณ ํ•˜๊ณ  ๋ฏธ๋™๊ฒฐ ์ง„ํ–‰. - `MAM_LOOP_NO_FREEZE=1` ๋กœ ๋น„ํ™œ์„ฑํ™” ๊ฐ€๋Šฅ. ์Šค๋ƒ…์ƒท ์ƒ์„ฑ ์‹คํŒจ๋Š” ๊ฒฝ๊ณ  ํ›„ ๊ธฐ์กด ๋™์ž‘์œผ๋กœ ํด๋ฐฑ. - ํšŒ๊ท€ ๊ฐ€๋“œ 5์ข… ์‹ ์„ค โ€” argv ๋ณด์กด, ํŒŒ์† ๋ž˜ํผ ๋ฉด์—ญ, ์Šคํ‚ฌ ํŠธ๋ฆฌ ๋ฌด์˜ค์—ผ(B-6 ๊ฒฝ๊ณ„), ๋ฝ ํ•ด์ œ ๋ฐ ์Šค๋ƒ…์ƒท ์ •๋ฆฌ(B-12 ๊ฒฝ๊ณ„), ๋น„ํ™œ์„ฑํ™” ์Šค์œ„์น˜. - ํšŒ๊ท€ ๋ฐ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ: **271/271 PASS (100%)** ๋‹ฌ์„ฑ. #### 9. ๊ฐ์‚ฌ ๋กœ๊ทธ ๋ฃจํŠธ ์ง€์—ฐ ํ‰๊ฐ€ (B-9 / P4-1) - `mqtt_common.LOGS_DIR` ์˜ import ์‹œ์  cwd ๊ณ ์ •์„ ์ œ๊ฑฐํ•˜๊ณ  ํ˜ธ์ถœ ์‹œ์ ์— ํ•ด์„ํ•˜๋Š” `get_logs_dir()` ๋ฅผ ๋„์ž…. `chdir` ์ดํ›„์—๋„ ๊ฐ์‚ฌ ๋กœ๊ทธ๊ฐ€ ํ˜„์žฌ ์›Œํฌ์ŠคํŽ˜์ด์Šค์— ์ •ํ™•ํžˆ ๊ธฐ๋ก๋จ. - PEP 562 ๋ชจ๋“ˆ `__getattr__` ๋กœ `LOGS_DIR` ์†์„ฑ ์ ‘๊ทผ ํ•˜์œ„ ํ˜ธํ™˜ ์œ ์ง€(๋™์  ํ‰๊ฐ€). - PEP 562 `__dir__` ๋ณ‘ํ–‰ ์ •์˜๋กœ `dir()`ยทํƒญ ์™„์„ฑ ๊ฐ€์‹œ์„ฑ ์œ ์ง€. - `DELEGATE_JOB_LOGS_DIR` ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์‹คํ–‰ ์ค‘ ๋ณ€๊ฒฝ๊นŒ์ง€ ๋ฐ˜์˜. - ํšŒ๊ท€ ๊ฐ€๋“œ 5์ข… ์‹ ์„ค โ€” cwd ์ถ”์ข…, ์‹ค์ œ ํŒŒ์ผ ์ƒ์„ฑ, ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋™์  ๋ฐ˜์˜, ์ „์—ญ ์žฌ๋„์ž… ์ฐจ๋‹จ, dir() ํƒ์ƒ‰์„ฑ. - ํšŒ๊ท€ ๋ฐ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ: **276/276 PASS (100%)** ๋‹ฌ์„ฑ. --- ### ๐Ÿ› ๏ธ `v1.4.0` โ€” Stability, Cleanup & Safe Job Delegation (2026-08-16) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ๊ฒฉ๋ฆฌ ์ž”์žฌ ์ •๋ฆฌ, ์„œ๋ธŒ์…ธ ๋ฃจํ”„ ๋ฝ ์กฐ๊ธฐ ํ•ด์ œ ๋ฒ„๊ทธ ํ”ฝ์Šค, ์‹ ๊ทœ ํŒŒ์ผ ์บก์ฒ˜ ๋ฐ ๊ฒฝ๋Ÿ‰ํ™”. - **P2-2 (C-3a / C-4 ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์Šคํ… ๋ฐ ๋ฏธ์‚ฌ์šฉ ์‹ฌ๋ณผ ์ œ๊ฑฐ)**: - `lib.sh` ๋‚ด ๋นˆ ์Šคํ… 4์ข…(`provision_isolation`, `isolation_lever`, `isolation_env_prefix`, `isolation_cmd_args`) ๋ฐ `_REAL_HERDR_PATH` ์™„์ „ ์‚ญ์ œ. - `registry.py::TERMINAL_STATUSES` ๋ฐ `create_session.sh::ISOLATE` ์ œ๊ฑฐ. - **P2-1 (B-6 / B-12 `delegate_job_safe` ์•ˆ์ •ํ™”)**: - `.agents/skills/...` ๋‚ด ๋ถˆํ•„์š”ํ•œ `.tmp` ๋ณต์‚ฌ๋ณธ ์ƒ์„ฑ ์ œ๊ฑฐ ๋ฐ ์ธํ”Œ๋ ˆ์ด์Šค ์ง์ ‘ ์‹คํ–‰(`bash "$orig_script"`) ์ „ํ™˜. - ์„œ๋ธŒ์…ธ ๋‚ด `trap`์œผ๋กœ ์ธํ•œ ๋ฃจํ”„ ๋ฝ ๋งˆ์ปค(`.mam/loop-guard-active`) ์กฐ๊ธฐ ์‚ญ์ œ ๊ฒฐํ•จ(D1) ์›์ฒœ ์ฐจ๋‹จ. - **P0-2 (O-2 ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ๋ฐฉ์ง€ ์›์ž์  ๋ฝ)**: - `loop_lock.sh` ์‹ ์„ค: `set -C` ๊ธฐ๋ฐ˜ ์›์ž์  ๋ฝ ํš๋“ ๋ฐ PID + lstart ์†Œ์œ ๊ถŒ ๊ฒ€์ฆ์œผ๋กœ ๋™์‹œ ์‹คํ–‰ ๋ฐฉ์ง€. - **P0-1 (B-7 ์™ธ๊ณฝ diff ์ˆ˜์ง‘ ๋ฐ ๋ฏธ์ถ”์  ํŒŒ์ผ ์บก์ฒ˜)**: - `diff_collect.sh` ๋„์ž…: CWD ๋…๋ฆฝ `$REPO_ROOT` ๊ธฐ์ค€ diff ์ˆ˜์ง‘ ๋ฐ `git ls-files -o` ๋ฏธ์ถ”์  ํŒŒ์ผ ๋ณ‘ํ•ฉ. - **B-4 (์‹œํ”„ํŠธ `ls` ๋™์  ํฌ์‹œ์Šค ํƒ€์ž„์Šคํƒฌํ”„ ๋ณต์›)**: - `lib.sh` 554ํ–‰์˜ `created=999999` ํ•˜๋“œ์ฝ”๋”ฉ์„ ์‹ค์‹œ๊ฐ„ ํƒ€์ž„์Šคํƒฌํ”„(`int(time.time())`)๋กœ ๋ณต์›. - **ํ…Œ์ŠคํŠธ ์ŠˆํŠธ ๊ฒฝ๋Ÿ‰ํ™”**: - ๋…ธํ›„ํ™”๋œ ์ค‘๋ณต ๋ ˆ๊ฑฐ์‹œ ํ…Œ์ŠคํŠธ 7๊ฐœ ํŒŒ์ผ(1,559์ค„) ์‚ญ์ œ (`cf51b2c`). --- ### ๐Ÿ›ก๏ธ `v1.3.0` โ€” Orchestrator Onboarding & Scoped Guarding (2026-08-15) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์‹ ์› ๊ฒฉ๋ฆฌ ๋ฐ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ํ˜‘์—… ๊ฐ€๋“œ๋ ˆ์ผ ํ™•๋ฆฝ. - **`multi-agent-mux-orc-onboard` ์Šคํ‚ฌ ์‹ ์„ค**: - ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ(`agy`)์˜ ๋Œ€ํ™” UUID๋ฅผ `.mam/agent-sessions.yaml` ๋‚ด `orchestrator_uuids` ๋ฆฌ์ŠคํŠธ๋กœ ๋“ฑ๋ก. - `find_workspace_uuid` ๋ฐ `verify_session_uuid`์—์„œ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ UUID๋ฅผ ์Šคํ‚ตํ•˜์—ฌ ์„œ๋ธŒ์—์ด์ „ํŠธ ์„ธ์…˜ ์˜ค์—ผ ๋ฐฉ์ง€. - **O-3 (์กฐ๊ฑด๋ถ€ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์œ„์ž„ ๊ฐ€๋“œ โ€” Scoped Guard)**: - ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ๊ฐ€ `/multi-agent-mux-loop` ํ™œ์„ฑํ™” ์ƒํƒœ์—์„œ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์Šคํฌ๋ฆฝํŠธ๋กœ ์œ„์ž„ํ•˜๋„๋ก ํ†ต์ œ. - `AGENTS.md` ยง5 ๋ฐ `MULTI_AGENT_RULES.md` ๋‚ด ๊ฐ€๋“œ๋ ˆ์ผ ๋ช…์‹œ. - **๋ฐฐํฌ ๋ฐ ํŒจํ‚ค์ง• ํŒŒ์ดํ”„๋ผ์ธ ํ˜„๋Œ€ํ™”**: - `deploy/lib_ownership.sh` ์‹ ์„ค ๋ฐ `hooks.json` 3-way ๋ณ‘ํ•ฉ(`MERGE_REGISTRY`) ์ง€์›. - Gitea CI/CD ํŒŒ์ดํ”„๋ผ์ธ (`deploy/gitea-ci.yml`) ์—ฐ๋™. --- ### ๐Ÿ”Œ `v1.2.0` โ€” Universal Herdr Server Isolation & Cline Integration (2026-08-14) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: Herdr ๋‹จ์ผ ์„œ๋ฒ„ ๊ฒฉ๋ฆฌ ๋ฐ ๋‹ค์ค‘ AI ์—์ด์ „ํŠธ ํ™•์žฅ. - **Universal Herdr Session Isolation**: - `HERDR_SESSION_NAME` ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒฉ๋ฆฌ ์„œ๋ฒ„๋ฅผ ํ†ต์ผํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค ์ถฉ๋Œ ๋ฐฉ์ง€. - **Cline ์—์ด์ „ํŠธ ํ†ตํ•ฉ**: - `cline` CLI ๊ธฐ๋ฐ˜ ๋Œ€ํ™” ์„ธ์…˜ ์ƒ์„ฑ, ์ •์ง€, ๋ณต์› ๋ฐ TUI ๋ ˆ๋”” ํ† ํฐ ํ•ธ๋“ค๋ง ์ง€์›. - **SQLite WAL ํŠธ๋žœ์žญ์…˜ ๋™์‹œ์„ฑ**: - ์„ธ์…˜ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋™์‹œ ์“ฐ๊ธฐ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋ฝ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด SQLite WAL ๋ชจ๋“œ ์ „๋ฉด ์ ์šฉ. --- ### ๐Ÿงฑ `v1.0.0` ~ `v1.1.0` โ€” Initial Multi-Agent Mux Framework (2026-08-10 ~ 2026-08-13) > **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ํ„ฐ๋ฏธ๋„ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๊ธฐ์ดˆ ์„ค๊ณ„ ๋ฐ ๋น„๋™๊ธฐ ๋ฃจํ”„ ์™„์„ฑ. - **ํ•ต์‹ฌ ์ˆ˜๋ช…์ฃผ๊ธฐ ์Šคํ‚ฌ๊ตฐ ๊ตฌ์ถ•**: `create`, `stop`, `resume`, `status`, `monitor` ์Šคํ‚ฌ ๊ธฐ๋ณธ ๊ตฌํ˜„. - **MQTT ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์žก ์œ„์ž„**: `multi-agent-mux-delegate-job`์„ ํ†ตํ•œ ์—์ด์ „ํŠธ ๊ฐ„ ์ด๋ฒคํŠธ ํ†ต์‹  ๋ฐ ๊ฒฐ๊ณผ ๊ตฌ๋…. - **์ž์œจ ํ˜‘์—… ๋ฃจํ”„**: `multi-agent-mux-loop` ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ†ตํ•œ Planner-Creator-Reviewer ์—ญํ•  ๋ถ„๋‹ด ์ฒด๊ณ„ ์ •๋ฆฝ. --- ## ๐Ÿงช ํ’ˆ์งˆ ๋ณด์ฆ ๋ฐ ๊ฒ€์ฆ ๊ธฐ์ค€ (Verification Standards) ๋ชจ๋“  ๋ฆด๋ฆฌ์Šค๋Š” ๋‹ค์Œ 4๋‹จ๊ณ„ ์—„๊ฒฉํ•œ ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•ด์•ผ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค: 1. **์ •์  ๋ฌธ๋ฒ• ๊ฒ€์‚ฌ**: `bash -n` (๋ชจ๋“  ์…ธ ์Šคํฌ๋ฆฝํŠธ) ๋ฐ AST ๋ฏธ์‚ฌ์šฉ ์ฝ”๋“œ ๋ถ„์„. 2. **๋‹จ์œ„ ๋ฐ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ (Tier 1~2)**: ์ธํ”Œ๋ ˆ์ด์Šค ๋ฐ ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ ๊ฒ€์ฆ. 3. **ํ†ตํ•ฉ ๋ฐ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ (Tier 3~4 / Contract)**: clean environment (`env -u PYTHONPATH`) ํ•˜์—์„œ์˜ ์–ด๋Œ‘ํ„ฐ ๊ณ„์•ฝ ๋ฐ CLI ๋ธŒ๋ฆฌ์ง€ ๊ฒ€์ฆ. 4. **๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ๊ต์ฐจ ํ”ผ์–ด ๋ฆฌ๋ทฐ**: Planner(`claude`) ๋ฐ Reviewer(`cline`) ๊ฐ„ ๊ต์ฐจ ๊ฒ€์ฆ ๋ฐ `[VERDICT: PASS]` 100% ํ•ฉ์˜.