# π Multi-Agent Mux λ²μ μ
λ°μ΄νΈ νμμ± λ° μ μ λ²μ κ²ν λ³΄κ³ μ
- **λ¬Έμ ID**: `version-update-assessment-issue-3`
- **κ΄λ ¨ μμ
ID (Job ID)**: `6c24ddd0`
- **μμ± μμ΄μ νΈ**: `creator-agy-01` (`agy`)
- **κ²ν λμ μ»€λ° λ²μ**: `0644e77..HEAD` (`c49ee3b`, `7e15081`, `94f2e21`)
- **μμ 리뷰μ΄**: `planner-reviewer-claude-01` (`claude`), `reviewer-creator-grok-01` (`grok`), `reviewer-opencode-01` (`opencode`)
- **μμ± μΌμ**: 2026-08-31 (KST)
---
## 1. κ°μ λ° κ²ν λ°°κ²½ (Executive Summary)
λ³Έ λ³΄κ³ μλ Issue #3('[Bug] herdr λ°λͺ¬ νλ‘μΈμ€ λΆλ¦¬(setsid) λλ½μΌλ‘ μΈν μΈμ
리μ
λ° UUID λ―Έν λΉ μΈμ
resume λ°λλ½ λ¬Έμ ') ν΄κ²°μ μν΄ μνλ μ½λ λ³κ²½ μ¬ν(`c49ee3b`, `7e15081`)μ λν΄, **SemVer 2.0.0(μ μμ λ²μ 2.0.0)** λͺ
μΈ λ° λ³Έ νλ‘μ νΈμ λ¦΄λ¦¬μ€ κ΄λ¦¬ μμΉμ μ
κ°νμ¬ **λ²μ μ
λ°μ΄νΈμ νμμ± μ¬λΆ**, **μ μ λͺ©ν λ²μ λ²νΈ**, κ·Έλ¦¬κ³ **3-Way Version Lockstep μ μ© ν°μΉν¬μΈνΈ**λ₯Ό μ’
ν© κ²ν ν κ²°κ³Όλ₯Ό μ μν©λλ€.
### π ν΅μ¬ κ²°λ‘ μμ½
1. **λ²μ μ
λ°μ΄νΈ νμμ±**: **νμ (REQUIRED)**
- νλ μμν¬ λ°νμ μ§μ€ 곡κΈμμΈ `.agents/skills/lib.sh` λ° λ³΅μ μ€ν¬μ ν΅μ¬ λΌμ΄νμ¬μ΄ν΄ μ€ν¬λ¦½νΈ(`.agents/skills/multi-agent-mux-resume/scripts/`)μ μ€μ λ°νμ λ²κ·Έ μμ μ΄ λ°μλμμΌλ©°, μ κ· νκ· ν
μ€νΈ(`test_h26`, `test_t14`, `test_t15`, `test_t16`)κ° μΆκ°λμμΌλ―λ‘ λ¦΄λ¦¬μ€ ν¨ν€μ§ λ° λ²μ μΆμ μ΄ λ°λμ μνλμ΄μΌ ν©λλ€.
2. **μ μ λͺ©ν λ²μ λ²νΈ**: **`v4.1.3` (PATCH Release)**
- κ³΅κ° APIμ νΈνλμ§ μλ λ³κ²½(Breaking Changes) μμ $\rightarrow$ MAJOR(`v5.0.0`) λ°°μ
- μλ‘μ΄ κΈ°λ₯ μλΈμμ€ν
μ΄λ μ κ· μμ΄μ νΈ μ΄λν° μΆκ° μμ $\rightarrow$ MINOR(`v4.2.0`) λ°°μ
- κΈ°μ‘΄ κ²°ν¨μ λν 100% νμ νΈν λ΄λΆ λ²κ·Έ μμ $\rightarrow$ **SemVer 2.0.0 Β§6μ μκ±°νμ¬ PATCH(`v4.1.3`)κ° μ μΌνκ² νλΉν¨**
3. **νμ¬ μν μ μ§ μμΉ**:
- λ³Έ λ¨κ³μμλ μꡬμ¬νμ λ°λΌ μ€μ μ½λ/μ€ν¬/λ²μ νμΌμ μμ νμ§ μκ³ , λ¦¬λ·°μ΄ λ§μ₯μΌμΉ ν©μ μλ ΄ ν νμ λ¦΄λ¦¬μ€ ν¨ν€μ§ μμ
μμ 3μ λκΈ°ν(3-Way Lockstep)λ₯Ό μμμ μΌλ‘ μΌκ΄ μνν κ²μ μ μν©λλ€.
---
## 2. λ³κ²½ λ΄μ λΆμ (Detailed Code Diff Analysis)
`v4.1.2` λ¦΄λ¦¬μ€ μ»€λ°(`0644e77`) μ΄ν νλ μμν¬μ λ°μλ ν΅μ¬ λ³κ²½ μ¬νμ λ€μκ³Ό κ°μ΅λλ€:
### 1) Item 1: Herdr λ°λͺ¬ νλ‘μΈμ€ κ·Έλ£Ή μμ λΆλ¦¬ (`c49ee3b`)
- **μμ νμΌ**: [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh#L207-L224)
- **λ³κ²½ λ΄μ©**: `.mam/shim/herdr` ν
νλ¦Ώ λ΄μ λΆμμ ν `nohup "$REAL_HERDR" ... server >/dev/null 2>&1 & disown` ꡬ문μ νμ΄μ¬ `subprocess.Popen(sys.argv[1:], start_new_session=True)` κΈ°λ°μ μ€ν¬λλ‘ μ λ©΄ κ΅μ²΄.
- **μν₯λ λΆμ**:
- `start_new_session=True`λ μμ νλ‘μΈμ€μμ `os.setsid()`λ₯Ό νΈμΆνμ¬ μμ ν μλ‘μ΄ νλ‘μΈμ€ κ·Έλ£Ή(PGID) λ° μΈμ
ID(SID)λ₯Ό λΆμ¬ν©λλ€.
- λΆλͺ¨ μ
Έμ΄λ ν
μ€νΈ νλ€μ€ λ¬λμ μκ·Έλ λΈλ‘λμΊμ€νΈ(`SIGINT`/`SIGTERM`)κ° λ°±κ·ΈλΌμ΄λ Herdr λ°λͺ¬μΌλ‘ μ νλμ§ μλλ‘ μλ²½ν 격리ν©λλ€.
- μΈλΆ μΈν°νμ΄μ€λ CLI μΈμμ λ³κ²½ μμ΄ λ΄λΆ λ°λͺ¬ ꡬλ μ λ’°μ±λ§μ κ°μ ν **μ νμ μΈ νμ νΈν λ΄λΆ λ²κ·Έ μμ **μ
λλ€.
### 2) Item 2: Class A μμ΄μ νΈ 0-turn resume fallback λ° Discovery Epoch κ°±μ (`7e15081`)
- **μμ νμΌ**:
- [`.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh#L50-L136)
- [`.agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh#L165-L178)
- **λ³κ²½ λ΄μ©**:
- `resume_session.sh`: `resolve_session_id.sh` κ²°κ³Ό UUIDκ° λΉμ΄μλ κ²½μ°, Class A μμ΄μ νΈ(`agy`, `hermes`, `opencode`)λ `create_session.sh --role` νΈμΆ μ€ν¨ λμ `FRESH_SPAWN=1`λ‘ μ ννμ¬ `spawn-spec` λͺ
λ Ήμ΄λ‘ μμ¨ fallback μ€ν°.
- `update_yaml_resumed.sh`: `--uuid` κ²μ¦ κ°λλ₯Ό μννκ³ , `if not uuid:` 쑰건 νμμ `herdr_session_epoch = epoch`, `herdr_session_created_at = now`, `session_id_source = 'pending-discovery'`, `session_id_verified = False`λ₯Ό μμμ μΌλ‘ μ¬μ€μ .
- **Class B λΆλ³μ± 보쑴**: `claude`, `grok`μ κΈ°μ‘΄ `verify_session.py:99-101` escape hatch λ° `test_t8` κ³μ½μ κ·Έλλ‘ μ μ§νλ©°, λ―Έμλ³ μΈμ
μ λν RC=1 hard-exit λμμ λ°μ΄νΈ λ¨μλ‘ λ³΄μ‘΄.
- **μν₯λ λΆμ**:
- 0-turn μ€μ§λ Class A μΈμ
볡μ μ λ°μνλ λ°λλ½/κ°μ μ’
λ£ κ²°ν¨μ ν΄μνκ³ , `reconcile.sh`μ stale transcript μ€μΈ λ§€μΉμ λ°©μ§.
- κΈ°μ‘΄ μ μ resume λμμ΄λ Class B μμ΄μ νΈμ κ³μ½μ μ ν μΉ¨ν΄νμ§ μλ **μμ ν νμ νΈν λ²κ·Έ μμ **μ
λλ€.
---
## 3. SemVer 2.0.0 κΈ°λ° μ μ λ²μ κ²ν (SemVer 2.0.0 Evaluation)
μ μμ λ²μ 2.0.0 (Semantic Versioning 2.0.0) λͺ
μΈμ λ°λ₯Έ κ° λ²μ κ³μ΄μ μ ν©μ± κ²ν κ²°κ³Όλ λ€μκ³Ό κ°μ΅λλ€:
| λ²μ λΆλ₯ | SemVer 2.0.0 κ·μΉ | λ³Έ λ³κ²½ μ¬ν ν΄λΉ μ¬λΆ | μ±ν μ¬λΆ | μμΈ λ
Όκ±° |
| :--- | :--- | :---: | :---: | :--- |
| **MAJOR (`v5.0.0`)** | **Β§8**: κ³΅κ° APIμ κΈ°μ‘΄κ³Ό νΈνλμ§ μλ λ³κ²½(Breaking Changes)μ΄ λμ
λ λ μ¦κ° | β ν΄λΉ μμ | **κΈ°κ°** | - κΈ°μ‘΄ CLI νλκ·Έ, YAML μ€ν€λ§, μ΄λν° μΈν°νμ΄μ€ μΌμ²΄ 보쑴
- Class B(`claude`, `grok`)μ κΈ°μ‘΄ λμ λ° κ²μ¦ κ³μ½ 100% λΆλ³
- μ¬μ©μ μν¬νλ‘μ°μ νκ΄΄μ λ³κ²½ μμ |
| **MINOR (`v4.2.0`)** | **Β§7**: κ³΅κ° APIμ νμ νΈνμ±μ μ μ§νλ μ κ· κΈ°λ₯μ΄ μΆκ°λκ±°λ λκ·λͺ¨ μλΈμμ€ν
μ΄ μ μ€λ λ μ¦κ° | β ν΄λΉ μμ | **κΈ°κ°** | - μ κ· μμ΄μ νΈ μ΄λν° μΆκ° μμ (v4.1.0 OpenCode μΆκ°μ ꡬλ³)
- μ κ· CLI λͺ
λ Ήμ΄λ μ€ν¬ μ μ€ μμ
- κΈ°μ‘΄ resume μ€ν¬λ¦½νΈμ λΉμ μ μ’
λ£ λ²κ·Έλ₯Ό μ μ λμνλλ‘ λ΄λΆ λΆκΈ° μ²λ¦¬ν κ²μ |
| **PATCH (`v4.1.3`)** | **Β§6**: νμ νΈνμ±μ μ μ§νλ λ²κ·Έ μμ (Bug Fixes)λ§ ν¬ν¨λ λ μ¦κ° | β
**μμ μΌμΉ** | **μ ν© (μ ν)** | - Issue #3μ 2λ κ²°ν¨(λ°λͺ¬ μκ·Έλ μ ν μ¬λ§, 0-turn resume λ°λλ½)μ λν μμ κ²°ν¨ μμ
- κΈ°μ‘΄ κ³΅κ° μΈν°νμ΄μ€ μλ²½ νΈν
- 455κ° μ 체 ν
μ€νΈ μ€μνΈ 100% 무결μ ν΅κ³Ό |
λ°λΌμ μ μμ λ²μ κ·μΉ λ° μ
κ³ νμ€μ λ°λ₯Έ κ°μ₯ μ ννκ³ νλΉν λͺ©ν λ²μ μ **`v4.1.3` (PATCH)** μ
λλ€.
---
## 4. 3-Way Version Lockstep λκΈ°ν ν°μΉν¬μΈνΈ λͺ
μΈ
λ³Έ νλ‘μ νΈλ λ²μ μΌκ΄μ± μ μ§λ₯Ό μν΄ `test_version_consistency.py`λ₯Ό ν΅ν΄ **3μ λ½μ€ν
(3-Way Version Lockstep)**μ κ°μ ν©λλ€. νμ λ¦΄λ¦¬μ€ ν¨ν€μ§ μμ
μ μλ μ§μ λ€μ΄ μμμ μΌλ‘ κ°±μ λμ΄μΌ ν©λλ€:
### 1) λ°νμ μ§μ€ 곡κΈμ (Single Source of Truth)
- [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh#L16)
```bash
MAM_VERSION="4.1.3"
```
### 2) λ²μ μ΄λ ₯ λ° λ§€νΈλ¦μ€ (`VERSIONS.md`)
- [`VERSIONS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/VERSIONS.md)
- Line 9: `- **νλ μμν¬ λ²μ **: `v4.1.3``
- Line 10: `- **μ΅μ λ¦΄λ¦¬μ€ μΌμ**: 2026-08-31 (KST)`
- Line 15: `lib.sh λ΄ MAM_VERSION="4.1.3" λ°νμ μ§μ€ 곡κΈμ μ μ...`
- Line 21: `... νμ€νλ₯Ό ν΅ν΄ v4.1.3μΌλ‘ λκΈ°νλμ΄ λ°°ν¬λ©λλ€.`
- Line 23~33: 8κ° μ€ν¬ λ²μ λ§€νΈλ¦μ€ ν μ 체 `4.1.2` $\rightarrow$ `4.1.3` κ°±μ
- Line 38 μλ¨: μ κ· `v4.1.3` λ¦΄λ¦¬μ€ μ²΄μΈμ§λ‘κ·Έ μΉμ
μ½μ
### 3) 8κ° μ€ν¬ λ©νλ°μ΄ν° (`SKILL.md` frontmatter)
- `.agents/skills/multi-agent-mux-create/SKILL.md`: `version: 4.1.3`
- `.agents/skills/multi-agent-mux-stop/SKILL.md`: `version: 4.1.3`
- `.agents/skills/multi-agent-mux-resume/SKILL.md`: `version: 4.1.3`
- `.agents/skills/multi-agent-mux-status/SKILL.md`: `version: 4.1.3`
- `.agents/skills/multi-agent-mux-monitor/SKILL.md`: `version: 4.1.3`
- `.agents/skills/multi-agent-mux-delegate-job/SKILL.md`: `version: 4.1.3`
- `.agents/skills/multi-agent-mux-loop/SKILL.md`: `version: 4.1.3`
- `.agents/skills/multi-agent-mux-orc-onboard/SKILL.md`: `version: 4.1.3`
### 4) μλν κ²μ¦ κ³μ½
- [`tests/test_version_consistency.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_version_consistency.py):
- `test_three_way_version_lockstep()`: `lib.sh(MAM_VERSION)` == `VERSIONS.md(Current + Matrix 8 items)` == `8x SKILL.md frontmatters` 100% μΌμΉ κ²μ¦
- `test_mam_version_is_not_env_overridable()`: νκ²½λ³μ μμ‘° μ°¨λ¨ κ²μ¦
---
## 5. `VERSIONS.md` λ°μμ© `v4.1.3` 체μΈμ§λ‘κ·Έ μ΄μ
νμ λ¦΄λ¦¬μ€ μμ
μ `VERSIONS.md`μ μΆκ°λ νμ€ λ³κ²½ μ΄λ ₯ μ΄μμ
λλ€:
```markdown
### π οΈ `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`).
```
---
## 6. κ²°λ‘ λ° νΌμ΄ 리뷰 μμ² (Conclusion & Consensus Request)
1. **μ΅μ’
κ²°λ‘ **:
- Issue #3μ μμ μ¬νμ νλ μμν¬μ ν΅μ¬ μ€ν λΌμ΄νμ¬μ΄ν΄μ μ§μ μ μΈ μν₯μ λ―ΈμΉλ μ€μν μμ μ± κ°μ μ΄λ―λ‘ λ²μ μ
λ°μ΄νΈκ° νμμ μ
λλ€.
- λ³κ²½μ μ±κ²©μ 100% νμ νΈνμ±μ μ μ§νλ κ²°ν¨ μμ μ΄λ―λ‘, **`v4.1.3` (PATCH)** λ‘ νμ νλ κ²μ΄ SemVer 2.0.0 κ·μΉμ λΆν©ν©λλ€.
2. **λ¦¬λ·°μ΄ νΌμ΄ 리뷰 μμ²**:
- `planner-reviewer-claude-01`, `reviewer-creator-grok-01`, `reviewer-opencode-01` μΈ λ¦¬λ·°μ΄κ» λ³Έ κ²ν λ³΄κ³ μμ λ²μ νμ λ
Όλ¦¬(`v4.1.3` PATCH) λ° 3-Way Lockstep κ³νμ λν κ²ν μ ν©μλ₯Ό μμ²λ립λλ€.