# ๐Ÿ“‘ Herdr Runtime Contract and Backend Capability Matrix - **Document Version**: Rev.3 (Post Cross-Review Corrections) - **Issue**: [Gitea Issue #5](https://git.godopu.com/tmpl/multi-agent-mux/issues/5) - **Target Herdr Version**: `herdr 0.8.2` - **Scope**: Native Herdr API Contract, External Collector Specification, and Backend Matrix --- ## 1. Herdr 0.8.2 ๋„ค์ดํ‹ฐ๋ธŒ API ๊ณ„์•ฝ (Native API Contract) ### 1-1. ํ•ต์‹ฌ CLI ๋ช…๋ น์–ด ๋ฐ ๋ฐ˜ํ™˜ ํŽ˜์ด๋กœ๋“œ `herdr`๋Š” AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ ์ „์šฉ ํ„ฐ๋ฏธ๋„ ๋ฉ€ํ‹ฐํ”Œ๋ ‰์„œ๋กœ์„œ, ์†Œ์ผ“ API๋ฅผ ํ†ตํ•ด ํ„ฐ๋ฏธ๋„ ์Šคํฌ๋ฆฐ ๊ฐ์‹œ ์ƒํƒœ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค: 1. **`herdr agent list`**: ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ๋ชจ๋“  ์—์ด์ „ํŠธ ๋ชฉ๋ก ๋ฐ ์ƒํƒœ ๋ฐ˜ํ™˜ (JSON stdout, exit 0). 2. **`herdr agent get `**: ํŠน์ • ์—์ด์ „ํŠธ์˜ ๋‹จ์ผ ์‹œ์  ์Šค๋ƒ…์ƒท ๋ฐ˜ํ™˜ (`agent_status`, `interactive_ready`, `pane_id`, `revision`, `state_change_seq` ๋“ฑ). 3. **`herdr agent wait [OPTIONS]`**: ์—์ด์ „ํŠธ๊ฐ€ ์ง€์ •๋œ ์ƒํƒœ์— ๋„๋‹ฌํ•  ๋•Œ๊นŒ์ง€ ๋ธ”๋กœํ‚น ๋Œ€๊ธฐ. 4. **`herdr agent explain [OPTIONS] [target]`**: ๋‚ด๋ถ€ ์ •๊ทœ์‹ ๋งค์นญ ๊ทœ์น™(`matched_rule`, `evaluated_rules`) ํ‰๊ฐ€ ์„ธ๋ถ€์ •๋ณด ๋ฐ˜ํ™˜. ### 1-2. ๋„ค์ดํ‹ฐ๋ธŒ ์ƒํƒœ ์ง‘ํ•ฉ (`agent_status`) - **์ง€์› Enum**: `idle`, `working`, `blocked`, `done`, `unknown` (์ด 5์ข…). - **`interactive_ready` (boolean)**: - ํ„ฐ๋ฏธ๋„์ด ํ‚ค ์ž…๋ ฅ์„ ์ˆ˜์‹ ํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ. - **์‹ค์ธก ๋ถˆ๋ณ€์‹**: ์—์ด์ „ํŠธ๊ฐ€ ์ฝ”๋”ฉ ์ž‘์—… ์ค‘(`agent_status: "working"`)์ผ ๋•Œ๋„ `interactive_ready: true`์ž„์ด ์ž…์ฆ๋จ. ๋”ฐ๋ผ์„œ `interactive_ready` ๋‹จ๋…์œผ๋กœ๋Š” ์ž‘์—… ์™„๋ฃŒ์˜ ์ถฉ๋ถ„์กฐ๊ฑด์ด ๋  ์ˆ˜ ์—†์œผ๋ฉฐ, ์˜ค์ง `agent_status in {"idle", "done"}` ์ƒํƒœ์™€ ๊ฒฐํ•ฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ### 1-3. `herdr agent wait` ํ˜ธ์ถœ ๊ทœ๊ฒฉ ๋ฐ ์ฑ„๋„ ๋ถ„๋ฆฌ ์‹ค์ธก ์‹ค์ œ `herdr 0.8.2` ์‹คํ–‰(`wait-contract.json` ๋ฐ `evidence/timeout_stderr.json`)์„ ํ†ตํ•ด ๊ฒ€์ฆ๋œ ์ž…์ถœ๋ ฅ ์ฑ„๋„ ๋ฐ ์ข…๋ฃŒ ์ฝ”๋“œ ๊ณ„์•ฝ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค: | ํ˜ธ์ถœ ์กฐ๊ฑด | ๋ช…๋ น ์˜ˆ์‹œ | ์ข…๋ฃŒ ์ฝ”๋“œ | ์ถœ๋ ฅ ์ฑ„๋„ | ๋ฐ˜ํ™˜ JSON ํŽ˜์ด๋กœ๋“œ ๊ตฌ์กฐ | |---|---|---|---|---| | **์ƒํƒœ ๋„๋‹ฌ (์„ฑ๊ณต)** | `herdr agent wait creator-agy-01 --until working --timeout 1000` | `exit 0` | `stdout` | `{"id":"cli:agent:wait","result":{"agent":{...},"type":"agent_info"}}` | | **ํƒ€์ž„์•„์›ƒ (Timeout)** | `herdr agent wait creator-agy-01 --until done --timeout 50` | `exit 1` | **`stderr`** | `{"error":{"code":"timeout","message":"timed out waiting for agent status"},"id":"cli:agent:wait"}` | | **๋Œ€์ƒ ๋ถ€์žฌ (Unknown)** | `herdr agent wait non-existent --until idle --timeout 50` | `exit 1` | **`stderr`** | `{"error":{"code":"agent_not_found","message":"agent target non-existent not found"},"id":"cli:agent:wait"}` | | **๊ธฐ๋ณธ ๋Œ€๊ธฐ ์˜ต์…˜ ์ƒ๋žต** | `herdr agent wait ` | N/A | N/A | `--until` ์ƒ๋žต ์‹œ ๊ธฐ๋ณธ ๋งค์นญ ๋Œ€์ƒ์€ `idle, done, blocked`์ž„. `--timeout` ์ƒ๋žต ์‹œ ๋ฌด๊ธฐํ•œ ๋Œ€๊ธฐํ•จ | > ๐Ÿšจ **Critical Empirical Finding (์ˆ˜์ • ๋ฐ˜์˜)**: > `herdr agent wait`์—์„œ ์„ฑ๊ณต(์ƒํƒœ ์ผ์น˜) ์‹œ์—๋Š” ์ •์ƒ JSON์ด `stdout`์œผ๋กœ ์ถœ๋ ฅ๋˜์ง€๋งŒ, **ํƒ€์ž„์•„์›ƒ(`timeout`) ๋ฐ ๋Œ€์ƒ ๋ถ€์žฌ(`agent_not_found`) ๋“ฑ ๋ชจ๋“  ์—๋Ÿฌ ์‘๋‹ต์€ `stderr`๋กœ ์—๋Ÿฌ JSON์ด ์ถœ๋ ฅ๋˜๋ฉฐ ์ข…๋ฃŒ ์ฝ”๋“œ๋Š” `exit 1`**์ž…๋‹ˆ๋‹ค (`stdout`์€ ๋น„์–ด์žˆ์Œ). ๋”ฐ๋ผ์„œ Watcher ์—”์ง„์€ `exit 1` ์‹œ ๋ฐ˜๋“œ์‹œ `stderr` ์ŠคํŠธ๋ฆผ์—์„œ JSON ์—๋Ÿฌ ํŽ˜์ด๋กœ๋“œ๋ฅผ ํŒŒ์‹ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. --- ## 2. ์™ธ๋ถ€ ์‹œํ€€์Šค ์ˆ˜์ง‘๊ธฐ ๊ณ„์•ฝ (External Sequence Collector) ### 2-1. ๋‹จ์ผ `wait` ํ˜ธ์ถœ์˜ ๋ณธ์งˆ์  ํ•œ๊ณ„ - `herdr agent wait`๋Š” ํƒ€๊ฒŸ์ด ํŠน์ • ์ƒํƒœ์— ๋„๋‹ฌํ•œ ์‹œ์ ์— **๋‹จ 1๊ฐœ์˜ ์ตœ์ข… ์Šค๋ƒ…์ƒท JSON**๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋™๊ธฐ์  ์žฅ๋ฒฝ(Barrier)์ž…๋‹ˆ๋‹ค. - ํ˜ธ์ถœ ๋„์ค‘ ๊ฑฐ์ณ๊ฐ„ ์ค‘๊ฐ„ ์ „์ด ๊ณผ์ •(Transition Stream)์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. - ๋”ฐ๋ผ์„œ `working โž” idle`๊ณผ ๊ฐ™์€ ์ƒํƒœ ์ „์ด๋ฅผ ์ž…์ฆํ•˜๋ ค๋ฉด, ์™ธ๋ถ€ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ/์ˆ˜์ง‘๊ธฐ๊ฐ€ ์‚ฌ์ „ ์Šค๋ƒ…์ƒท(`before`)๊ณผ ์‚ฌํ›„ ์Šค๋ƒ…์ƒท(`after`)์„ ๋…๋ฆฝ์ ์œผ๋กœ ํš๋“ํ•˜์—ฌ ํƒ€์ž„์Šคํƒฌํ”„์™€ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ### 2-2. ์ˆ˜์ง‘๊ธฐ(Collector) ๊ถŒ์žฅ ๊ทœ๊ฒฉ - **ํด๋ง ์ฃผ๊ธฐ**: 1~2์ดˆ ์ˆ˜์ค€์˜ ์œ ๊ณ„(Bounded) ํด๋ง (`agent get`). ๊ณ ์ •๋ฐ€ 10ms ์Šคํ•€ ํด๋ง์€ ๋ถˆํ•„์š”ํ•˜๋ฉฐ CPU ๋‚ญ๋น„๋ฅผ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค. - **Envelope ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ**: ๋‹จ์กฐ ์‹œ๊ณ„ ์˜คํ”„์…‹(`monotonic_start`, `monotonic_end`), `collector_clock_id`, `capture_id`, `source_command`๋ฅผ ํ•„์ˆ˜๋กœ ๋ณด์กดํ•˜์—ฌ ์‹œ์  ๊ฐ„ ์™œ๊ณก์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. --- ## 3. ์ด๋ฒคํŠธ, ํŒŒ์ผ์‹œ์Šคํ…œ ๋ฐ ๋””์ŠคํŒจ์น˜ ์—ฐ๊ณ„ ๊ฒฝ๊ณ„ Herdr ๋„ค์ดํ‹ฐ๋ธŒ ํŽ˜์ด๋กœ๋“œ์™€ Multi-Agent-Mux ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์‚ฌ์ด์—๋Š” ์—„๊ฒฉํ•œ ์ฑ…์ž„ ๊ฒฉ๋ฆฌ๊ฐ€ ์œ ์ง€๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค: ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Herdr Native API Boundary โ”‚ โ”‚ โ€ข agent_status (idle/working/blocked/done/unknown) โ”‚ โ”‚ โ€ข interactive_ready (true/false) โ”‚ โ”‚ โ€ข pane_id, state_change_seq, terminal_title โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ ๊ด€์ธก ์ฆ๊ฑฐ ์ œ๊ณต (์ฑ„๋„ 2) โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Multi-Agent-Mux Watcher Boundary โ”‚ โ”‚ โ€ข 4-Fold Attribution: โ”‚ โ”‚ (job_id, attempt_id, session_uuid, โ”‚ โ”‚ pane_process_generation) โ”‚ โ”‚ โ€ข File Evidence (report mtime debounce >=15s, hash) โ”‚ โ”‚ โ€ข Backplane Events (seq, HMAC signature, started/progress)โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` - **๋ถˆ๋ณ€์‹**: Herdr ์›๋ณธ ์‘๋‹ต ํŽ˜์ด๋กœ๋“œ์—๋Š” `job_id`, `attempt_id`, `report phase`, `expected_decision` ๋“ฑ์˜ MAM ๋‚ด๋ถ€ ํ•„๋“œ๋ฅผ ์ ˆ๋Œ€ ์ฃผ์ž…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. --- ## 4. 6๊ฐœ ๋ฐฑ์—”๋“œ ๊ธฐ๋Šฅ ๋ฐ ์‹ค์ธก ์ฆ๊ฑฐ ํ–‰๋ ฌ (Capability Matrix) ๋ณธ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ง€์›ํ•˜๋Š” 6๊ฐœ ์—์ด์ „ํŠธ ๋ฐฑ์—”๋“œ(`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`)์˜ ํ˜„ ํ™˜๊ฒฝ ์‹ค์ธก ์ƒํƒœ ๋ฐ Gap ํ˜„ํ™ฉ์ž…๋‹ˆ๋‹ค (๋ชจ๋“  ์Šฌ๋กฏ์€ `tests/fixtures/issue_5/herdr/manifest.json`๊ณผ 100% ์ผ์น˜): | ๋ฐฑ์—”๋“œ | ์„ค์น˜ ๋ฐ”์ด๋„ˆ๋ฆฌ ๊ฒฝ๋กœ | ํ™œ์„ฑ ์„ธ์…˜๋ช… | ์‹ค์ธก ์บก์ฒ˜ ์Šฌ๋กฏ | ๋ฏธ๊ด€์ธก ์Šฌ๋กฏ (Gaps) ๋ฐ ์‚ฌ์œ  | Provenance | |---|---|---|---|---|---| | **`claude`** | `~/.local/bin/claude` | `planner-reviewer-claude-01` | `idle` (`claude/idle.json`) | `working`, `blocked`, `done`, `unknown` (์บก์ฒ˜ ์‹œ์ ์— idle ์ƒํƒœ์˜€์Œ) | `observed` | | **`agy`** | `~/.local/bin/agy` | `creator-agy-01` | `working` (`agy/working.json`), `wait_timeout` (`agy/wait_timeout.json`) | `idle`, `blocked`, `done`, `unknown` (์ž‘์—… ์ˆ˜ํ–‰ ์ค‘์ด๋ฉฐ ๊ถŒํ•œ ๊ฑด๋„ˆ๋›ฐ๊ธฐ ์ ์šฉ) | `observed` | | **`grok`** | `~/.grok/bin/grok` | `reviewer-creator-grok-01` | `idle` (`grok/idle.json`) | `working`, `blocked`, `done`, `unknown` (๋ฆฌ๋ทฐ ๋Œ€๊ธฐ ์ค‘ ์œ ํœด ์ƒํƒœ ์บก์ฒ˜) | `observed` | | **`codex`** | `~/.local/bin/codex` | `planner-reviewer-codex-01` | `done` (`codex/done.json`) | `idle`, `working`, `blocked`, `unknown` (์ด์ „ ํ”Œ๋ž˜๋„ˆ ์ž‘์—… ์™„๋ฃŒ ์งํ›„ ์บก์ฒ˜) | `observed` | | **`hermes`** | `~/.local/bin/hermes` | N/A (๋ฏธ๊ฐ€๋™) | ์—†์Œ | `idle`, `working`, `blocked`, `done`, `unknown` (Herdr ์„œ๋ฒ„์— ํ™œ์„ฑ ์„ธ์…˜ ๋ถ€์žฌ) | `unobserved` | | **`opencode`**| `~/.opencode/bin/opencode` | N/A (๋ฏธ๊ฐ€๋™) | ์—†์Œ | `idle`, `working`, `blocked`, `done`, `unknown` (Herdr ์„œ๋ฒ„์— ํ™œ์„ฑ ์„ธ์…˜ ๋ถ€์žฌ) | `unobserved` | > ๐Ÿ“Œ **์ •์งํ•œ ์ฆ๊ฑฐ ๋ณด๊ณ  ์›์น™ (D3, D6)**: > 1. ์˜ค์ง ์‹ค์ œ๋กœ ์‹คํ–‰ํ•˜์—ฌ ์บก์ฒ˜ํ•œ ์Šฌ๋กฏ๋งŒ `observed`๋กœ ์ธ์ •ํ•˜๋ฉฐ, ๋ชจ์˜ ์‹คํ–‰์ด๋‚˜ ๊ฐ€์ƒ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ๋„ค์ดํ‹ฐ๋ธŒ ์บก์ฒ˜๋กœ ๋‘”๊ฐ‘์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. > 2. `hermes`์™€ `opencode`์˜ ๋ฏธ๊ฐ€๋™ ์Šฌ๋กฏ ๋ฐ ๊ธฐ์กด 4๊ฐœ ๋ฐฑ์—”๋“œ์˜ ๋ฏธ๊ด€์ธก ์ƒํƒœ๋Š” ๋ชจ๋‘ ์ •์งํ•˜๊ฒŒ `unobserved gap`์œผ๋กœ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. > 3. Grok ์„ธ์…˜ ๋“ฑ์€ ์บก์ฒ˜ ์‹œ์ ์— `idle`์ด์—ˆ์œผ๋‚˜ ๋ฆฌ๋ทฐ ์‹คํ–‰ ์‹œ `working`์œผ๋กœ ์ „์ด๋˜๋ฏ€๋กœ, ์ •์  ์บก์ฒ˜๊ฐ€ ์—์ด์ „ํŠธ์˜ ์˜๊ตฌ ๋ถˆ๋ณ€ ๋Šฅ๋ ฅ์„ ๋œปํ•˜์ง€ ์•Š์Œ์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. --- ## 5. ๋ณตํ•ฉ ์‹œ๋‚˜๋ฆฌ์˜ค ๊ธฐ๋Œ€ ์ •์ฑ… (Composite Expected Policy) Watcher๊ฐ€ ๋‹ค์ค‘ ์ฑ„๋„ ์ฆ๊ฑฐ๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ๋‚ด๋ฆฌ๋Š” ์ตœ์ข… ์™„๋ฃŒ ํŒ์ • ์ •์ฑ…: 1. **`initial_idle`**: ๋””์ŠคํŒจ์น˜ ๊ธฐ๋ก์€ ์žˆ์œผ๋‚˜ ํ•ด๋‹น ์‹œ๋„์˜ ์‹คํ–‰ ์•ต์ปค๊ฐ€ ์—†์œผ๋ฉด โž” **`hold`** (์™„๋ฃŒ ๊ฑฐ๋ถ€). 2. **`tool_running`**: Herdr๋Š” `working`์ด๋‚˜ ํ•˜๋„ค์Šค์—์„œ ๋„๊ตฌ ์‹คํ–‰ ์ค‘์ด๋ฉด โž” **`hold`** (๋Œ€๊ธฐ). 3. **`report_pause_15s`**: ํŒŒ์ผ์ด 15์ดˆ๊ฐ„ ๋ฉˆ์ถ”์—ˆ์œผ๋‚˜ ํ™•์ • ๋งค๋‹ˆํŽ˜์ŠคํŠธ๊ฐ€ ์—†์œผ๋ฉด โž” **`hold`** (๋Œ€๊ธฐ). 4. **`finalized_candidate`**: 4์ค‘ ๊ท€์† ์ผ์น˜ + Fresh `idle/done` + ์›์ž์  ๋งค๋‹ˆํŽ˜์ŠคํŠธ/ํ•ด์‹œ ์ผ์น˜ โž” **`candidate_approved`** (CAS ์ปค๋ฐ‹ ํ—ˆ์šฉ). 5. **`blocked_permission`**: Herdr๊ฐ€ `blocked`์ด๋ฉด โž” **`hold_blocked`** (์™„๋ฃŒ ๊ธˆ์ง€). 6. **`transport_disconnected`**: ์†Œ์ผ“ ํ†ต์‹  ์‹คํŒจ ์‹œ โž” **`hold_reconnect`** (์Šค๋ƒ…์ƒท ์žฌ๋™๊ธฐํ™”). 7. **`restarted_generation`**: PID/์„ธ์…˜ ์‹๋ณ„์ž๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ณผ๊ฑฐ ์‹œ๋„์˜ ์‹ ํ˜ธ โž” **`reject_stale`** (์ „์ด ๊ฑฐ๋ถ€).