From 20b1014717f2d8491a78a9722d11f49501a78153 Mon Sep 17 00:00:00 2001 From: Godopu Date: Tue, 13 Oct 2026 10:41:54 +0900 Subject: [PATCH 1/5] docs(readme): bring README.md up to date with v4.9.1 Rewritten against the current code: the per-workspace shim is .mam/shim/herdr routing with --session (not /tmp/multi-agent-herdr-shim with -L), registry writes run in the workspace .venv (no dual-interpreter split), and the missing pieces are added - the delegation contract (ack, heartbeat, budget, busy wait, remote transport, exit codes), the review loop (strict verdicts, review identity, sub-jobs, report promotion), create --onboard exits 44/45, the per-server pane claim, restore-off servers, worktree helpers and the test isolation rules. Layout and quick start follow the tree. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff --- README.md | 333 +++++++++++++++++++++++++++--------------------------- 1 file changed, 168 insertions(+), 165 deletions(-) diff --git a/README.md b/README.md index fa09584..be5a8cf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # herdr-agent-orchestration -An advanced, high-reliability **Multi-Agent Orchestration & Messaging Backplane** framework built on Herdr and MQTT. It is designed to coordinate, isolate, and audit long-running agent tasks (such as code generation, refactoring, and security reviews) across multiple LLM backend clients (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`). +A **Multi-Agent Orchestration & Messaging Backplane** built on [herdr](https://herdr.dev) and MQTT. It runs long-lived coding agents (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`) in isolated herdr panes, delegates work to them as tracked jobs, and drives planner / creator / reviewer loops until every reviewer passes the change. [![Version: v4.9.1](https://img.shields.io/badge/version-v4.9.1-blue.svg)](VERSIONS.md) @@ -8,230 +8,233 @@ An advanced, high-reliability **Multi-Agent Orchestration & Messaging Backplane* ## ๐Ÿš€ Overview -Modern agentic workflows often suffer from session timeout, lack of process isolation, terminal viewport truncation (scrollback limits), and complex concurrency issues. - -**herdr-agent-orchestration** addresses these problems by providing: -1. **Herdr-based Process Isolation:** Spawning LLM client sessions inside dedicated, isolated herdr environments to support persistent background runs. Background daemon servers detach into their own OS session/process group (`start_new_session=True`), ensuring they survive signal broadcasts to the parent shell. -2. **Asynchronous Event-Driven Architecture:** Leveraging an MQTT broker as a message backplane to coordinate state transitions (`started`, `progress`, `completed`, `error`) between collaborating agents. -3. **Multi-Agent Mux (MAM):** Combining local file-based locks (fcntl) and an ACID-compliant SQLite WAL database (`.mam/agent-sessions.db`) to manage concurrent job claims and track running agent sessions without drift. -4. **Automated Review & Quality Loop:** Implementing parallel reviewer loops where worker agents must receive a `PASS` rating from various specialized verification agents (e.g., Claude, Hermes, Grok, OpenCode, Codex) before merging code. +Long agent runs break in predictable ways: a session dies with its terminal, two jobs land in one pane, the orchestrator cannot tell a busy agent from a dead one, and a review approves code that changed after it was read. Multi-Agent Mux (MAM) addresses these with: +1. **Isolated, resumable agent sessions.** Each agent runs in its own herdr pane, usually on a herdr server dedicated to the workspace. Sessions are recorded in `.mam/agent-sessions.yaml` (backed by SQLite) with their conversation ids, so a stopped agent resumes the same conversation later. +2. **Jobs decided by events, not by the screen.** A delegated job is a registry record plus an MQTT event stream (`started`, `progress`, `completed`, `error`). The agent must acknowledge the prompt within a deadline and heartbeat while it works. A job is closed only by a protocol event or a timeout, never by reading the terminal. +3. **One job per session at a time.** Before injecting a prompt, the dispatcher waits by the registry for the session's earlier jobs (onboarding included) to end. Pane placement is serialised per herdr server, so concurrent `create` calls do not take the same pane. +4. **Reviewed loops with pinned evidence.** `multi-agent-mux-loop` sends a change to every registered reviewer and requires a unanimous `PASS`. With `--worktree`/`--base`, each review round is bound to a snapshot of the source. If the source changes during the round, its approvals are discarded and the round is reviewed again. --- ## ๐Ÿ“ฆ Installation & Setup -You can bootstrap the Multi-Agent Mux (MAM) framework in any workspace directory with a single command: +Bootstrap MAM in any workspace directory: ```bash curl -fsSL https://git.godopu.com/tmpl/multi-agent-mux/raw/branch/main/deploy/install.sh | bash ``` -Alternatively, if you have already cloned the repository locally, run the installer directly: +or, from a local clone: + ```bash bash deploy/install.sh ``` -The idempotent installer automatically validates system dependencies (herdr, python3, and PyYAML), creates the python virtual environment (`.venv`), installs dependencies, copies `.mam.env.example` as `.mam.env`, and initializes the `.agents/` scaffolding. +The installer is idempotent. It does the following: +- checks the dependencies (herdr, `python3` with PyYAML and sqlite3, rsync, uuidgen); +- copies `.agents/` and the templates; +- creates `.venv` and installs `paho-mqtt` and PyYAML into it; +- writes `.mam.env` from `.mam.env.example`; +- adds `.venv`, `.mam/` and `.mam.env` to `.gitignore`. + +Configure the broker in `.mam.env`. The default is the public `broker.hivemq.com`, which is fine for a trial but not for real work. See [MESSAGING.md](MESSAGING.md) for a private broker. `deploy/update.sh` and `deploy/remove.sh` update and uninstall. --- -## ๐Ÿ› ๏ธ Core Skills & Scaffolding +## ๐Ÿ› ๏ธ Core Skills -All orchestration functionalities are structured under the `.agents/skills/` directory: +Every skill lives under `.agents/skills/` with a `SKILL.md` that documents its options and exit codes. -* **`multi-agent-mux-create`**: Spawns isolated herdr sessions running specified agent CLI wrappers. It captures system processes, updates metadata registries, and enforces authentication checks. -* **`multi-agent-mux-stop`**: Gracefully terminates agent CLI sessions (using key macros like `/exit` or `Exit`) and handles disk purge operations (removing conversation JSON files and SQLite logs for deleted workspaces). -* **`multi-agent-mux-resume`**: Restores stopped sessions by resolving workspace UUIDs from disk or cache, and invokes the underlying agent using session-resume parameters (e.g., `claude -r `, `agy --conversation `, `hermes --resume `, `grok --resume `, `opencode --session `, or `codex resume `). -* **`multi-agent-mux-status`**: Queries the running states of all active sessions, detecting PID mismatches, command signatures, and drifts between actual herdr instances and the registry database. -* **`multi-agent-mux-monitor`**: A long-running reconcile worker that dynamically monitors herdr sessions and synchronizes states to `.mam/agent-sessions.yaml`. -* **`multi-agent-mux-delegate-job`**: The core asynchronous task distribution module (core implementation in `.agents/skills/lib_py/delegation/`; `scripts/*.py` serves as compatibility shims): - * `registry.py`: Atomically registers and claims jobs using file advisory locks (`fcntl`). - * `job_subscriber.py`: Connects to the MQTT backplane, captures live events, and appends them to audit trails. - * `publish_event.py`: Emits execution status transitions and error details from workspace scripts. - * `mqtt_common.py`: Manages connection policies, authentication, and HMAC signing. -* **`multi-agent-mux-loop`**: Autonomous planning-execution-review orchestration loop across Planner, Creator, and Reviewers until unanimous consensus (driven by Python loop runtime in `lib_py.loop`, eager-import immutable runtime, strict verdict parser). -* **`multi-agent-mux-orc-onboard`**: Helper to register and isolate orchestrator session UUIDs to prevent sub-agent discovery capture. +| Skill | What it does | +|---|---| +| **`multi-agent-mux-create`** | Starts an agent in a herdr pane and registers the session. `--onboard` waits until the onboarding job ends (exit 44 if it failed, 45 if it did not end in time; the session is kept). `scripts/worktree_prepare.sh` prepares an issue worktree for a creator. | +| **`multi-agent-mux-stop`** | Stops a session gracefully. The conversation id is saved on the row (`status: stopped`, `resumable: true`). `--purge-conversation --yes` deletes the conversation instead. `scripts/worktree_remove.sh` removes an issue worktree only after checking it is clean, including its submodules. | +| **`multi-agent-mux-resume`** | Brings a stopped session back with its saved conversation (`claude -r`, `agy --conversation`, `hermes --resume`, `grok --resume`, `opencode --session`, `codex resume`), in the directory it ran in. | +| **`multi-agent-mux-status`** | Read-only snapshot of every session: registry status, herdr liveness, pane command and cwd, resume id, drift. | +| **`multi-agent-mux-monitor`** | Long-running reconciler (`reconcile.sh --subscribe`). It reacts to job events, falls back to polling when the broker is down, and fixes registry drift. For example, it marks dead sessions `terminated` and registers live sessions the registry does not know. | +| **`multi-agent-mux-delegate-job`** | Delegates a job to a session (`herdr:`) or to a runner on another host (`remote:`) and waits for its result. See [Delegation contract](#-delegation-contract). | +| **`multi-agent-mux-loop`** | Plan, implement, review: an optional planner and a creator, then one or all reviewers until a unanimous `PASS` or `--max-loop`. It also supports `--review-only` for work finished outside the loop. Passing reports are promoted to `.agents/reports//`. | +| **`multi-agent-mux-orc-onboard`** | Registers the orchestrator's own session id, so session discovery never mistakes it for a sub-agent. | --- -## ๐Ÿ“ Big-Picture Architecture +## ๐Ÿ“ Architecture -The system coordinates LLM agents across multiple workspaces through two core layers: +MAM has two layers that share one registry: -1. **Layer A โ€” Herdr Orchestration (lib.sh + status/resume/stop/create)**: Runs the agents (one herdr session per agent-workspace combination) and maintains an authoritative registry in `.mam/agent-sessions.yaml` (+ `.mam/agent-sessions.db`). -2. **Layer B โ€” Async Job Delegation (delegate-job)**: Dispatches a task to an agent and observes progress and completion via an event channel. - -These two layers share one lock-guarded chokepoint for file I/O: `lib.sh::atomic_dump_yaml`. Every write is protected by an exclusive SQLite database transaction lock and schema validation. - -### Data Flow Overview +1. **Sessions (herdr)**: `lib.sh` and the create/stop/resume/status/monitor scripts run the agents and keep `.mam/agent-sessions.yaml` (+ `.mam/agent-sessions.db`) authoritative. +2. **Jobs (delegation)**: `lib_py/delegation/` registers a job in `.mam/jobs/.json`, injects the brief, and follows the job's events over MQTT. Every event is also appended to the job's audit log `.mam/delegate_job_logs//`. ```text - +-----------+ register_job +-------------------+ - | delegator | ---------------> | .mam/jobs/.json| <-- live record - +-----------+ +---------+---------+ - | - | atomic rename + fsync - v - +-----------------+ - | audit log | <-- append-only - | .mam/delegate_ | events.ndjson - | job_logs// | - +--------+--------+ - ^ - | (best-effort mirrors) - | - +-----------+ publish_event +-----+-----+ +---------+ - | agent | ---------------> | MQTT broker | <--- | monitor | - | (claude) | +-------------+ +----+----+ - +-----------+ | - ^ v - | subscriber atomic_dump_yaml - | (job_subscriber.py) (.mam/agent-sessions.yaml) - | ^ - +-------- delegator waits here ----------+ | - +---+---+ - | reconcil| - | e.sh | - +--------+ + +--------------+ register / pick +----------------------+ + | orchestrator | -----------------> | .mam/jobs/.json | live record + | (wrapper) | +----------+-----------+ + +------+-------+ | every transition + | inject brief v + v +----------------------+ + +--------------+ publish_event | .mam/delegate_job_ | append-only + | agent pane | --------+ | logs// | audit log + +--------------+ | +----------------------+ + v + +-------------+ events + retained state + | MQTT broker | -------------------------> job_subscriber (orchestrator) + +-------------+ -------------------------> monitor (reconcile.sh) + | + v + .mam/agent-sessions.yaml / .db ``` -### ๐Ÿ”’ Herdr Server Isolation +### ๐Ÿ”’ Herdr server isolation -To prevent workspace herdr processes from interfering with each other or with system herdr servers, the framework enforces isolated herdr environments: -* **Per-Workspace Shim:** `_init_herdr_isolation` and `_resolve_real_herdr_path` instantiate a per-workspace shim directory under `/tmp/multi-agent-herdr-shim//herdr` that intercepts herdr commands and wraps them in `herdr -L `. -* **PATH Rewriting:** The `PATH` environment variable is dynamically prepended with the shim path in all child processes. This ensures any `herdr` invocation within the agent's process tree is restricted to its isolated socket server. -* **Environment Restoration:** If `HERDR_SERVER_NAME` is set to `default`, the PATH override is removed, reverting to the default global herdr server. +- **Dedicated server per workspace (opt-in).** `create --herdr-session ` (or `HERDR_SESSION_NAME`) runs the agents on their own herdr server and socket, separate from your default herdr. The server name is recorded on the session row, and every later command routes to it. +- **The shim.** Sourcing `lib.sh` writes `/.mam/shim/herdr` and puts it first on `PATH`. The shim provides the tmux-style commands the scripts use (`new-session`, `has-session`, โ€ฆ) on top of herdr's agent API. It routes each call with `--session `, and it starts the server headless if the server is not running. +- **No surprise relaunches.** A server MAM starts uses your herdr config with `resume_agents_on_restore = false`. A herdr restart therefore does not relaunch saved agents without their permission flags. +- **One pane claim at a time.** Pane placement holds a per-server lock (`lib_py/pane_lock.py`, `flock` on macOS and Linux). Concurrent `create` calls in one folder each get their own pane. -### ๐Ÿ›ก๏ธ Concurrency Design & Write Serialization +### ๐Ÿ›ก๏ธ Registry writes and concurrency -The framework implements lock-guarded execution pathways to prevent race conditions during parallel agent operations: -* **SQLite Database Locks (`BEGIN IMMEDIATE`):** Every mutation of `agent-sessions.yaml` and the SQLite registry runs through `atomic_dump_yaml` inside `lib.sh`, which serializes writes via an exclusive `BEGIN IMMEDIATE` transaction lock on the SQLite database `.mam/agent-sessions.db`. -* **Dual-Interpreter Strategy:** To minimize dependency bloat and guarantee stability, the backplane splits execution environments: the virtual environment `.venv` handles MQTT communication and async jobs (requiring `paho-mqtt`), while the system `python3` executes `atomic_dump_yaml` (relying on system-wide `PyYAML`). -* **NFS and Network FS Safeguards:** Since file locking (`flock`) and SQLite WAL behave unreliably over network protocols (NFS, CIFS, SSHFS), `lib.sh` performs filesystem detection. If a network mount is identified, it outputs a safety warning and SQLite automatically switches its journaling mode from `WAL` to `DELETE`. +- **Serialised writes.** Every change to `agent-sessions.yaml` goes through `lib.sh::atomic_dump_yaml`. It runs under an exclusive SQLite transaction (`BEGIN IMMEDIATE`) on `.mam/agent-sessions.db` and is validated before the YAML is rewritten atomically. Job records use their own registry lock. +- **One interpreter.** The scripts run their Python in the workspace `.venv` (`AGENT_PYTHON_BIN`, else the active or nearest `.venv`). +- **Network filesystems.** If `.mam/` is on NFS/CIFS/SSHFS, `lib.sh` warns, and SQLite switches its journal from `WAL` to `DELETE`. +- **One loop per checkout.** A loop lock refuses a second `run_loop.sh` in the same control plane. --- -## ๐Ÿ“ Architecture & Coordination Loop +## ๐Ÿ“จ Delegation contract -The interaction between roles (Project Manager, Worker, and Reviewer) is structured as a strict iterative loop: +The full specification is in [MESSAGING.md ยง2.5](MESSAGING.md). + +- **Delivery**: after the prompt is handed over, the agent must publish `started` within **T** s (default 180). If it doesn't, the job fails closed (`agent_blocked`, exit 1), and the prompt is never injected twice. +- **Liveness**: `started --heartbeat N` starts an automatic heartbeat (default every 30 s). After **Kร—N** s of silence (default 120 s) the job counts as unresponsive. herdr status and pane text are logged for diagnosis only. +- **Budget**: each job has a wall-clock budget (`--timeout` / `MAM_JOB_TIMEOUT_S`, default 3600 s). A job that runs out is closed as `wall_clock_timeout`. +- **Busy sessions**: the wrapper waits up to `MAM_DISPATCH_WAIT_S` for the session's earlier open jobs to end. If they don't, it ends as `cancelled` (`session_busy`, exit 5), and the prompt is never delivered. +- **Remote agents**: `remote:` sends the brief as a signed, retained broker message to a `remote.py run` runner on another host. Use this only with a private broker. + +| Exit | Meaning | +|:---:|---| +| `0` | `completed` | +| `1` | failure, or no `started` within T | +| `2` | no event for Kร—N (`deadline_timeout`) or budget spent (`wall_clock_timeout`) | +| `3` | broker unavailable, and no terminal status on disk | +| `5` | session busy, or the record was taken over while waiting (never delivered) | + +--- + +## ๐Ÿ” Review loop ```mermaid sequenceDiagram autonumber - actor User as User - participant PM as Project Manager - participant W as Worker + actor User + participant L as run_loop.sh + participant P as Planner (optional) + participant C as Creator participant R as Reviewers - participant M as MQTT Backplane - User->>PM: Hand over requirements - Note over PM: Plan tasks & register jobs - PM->>M: Register Job & start Subscriber - PM->>W: Delegate task (Provide Job ID & Brief) - W->>M: Publish 'started' event - Note over W: Implement & verify code - W->>M: Publish 'completed' (or 'error') - PM->>R: Request parallel reviews (Provide Diff) - Note over R: Parallel analysis (Claude, Hermes, Grok, OpenCode, Codex) - alt Review Feedback (NOT PASS) - R->>PM: NOT PASS (Feedback with code blocks) - Note over PM: Apply fixes or re-delegate - PM->>W: Re-delegate with comments - else Verification PASS - R->>PM: PASS + User->>L: --task, --creator, --reviewer / --all-reviewer + opt --plan + L->>P: write the plan (Creator challenges it for --plan-talk turns) end - PM->>User: Commit changes & Report completion + L->>C: implement and commit (skipped with --review-only) + loop up to --max-loop + L->>R: review the snapshot diff (base..head) + alt every reviewer PASS and the source unchanged + R-->>L: [VERDICT: PASS] + else NOT PASS + R-->>L: [VERDICT: NOT PASS] + findings + L->>C: fix (or [REBUT:] up to --max-rebut) + end + end + L->>User: reports promoted to .agents/reports// ``` ---- - -## ๐Ÿ”’ Security & Replay Attack Defense - -To ensure communication integrity across public MQTT brokers, the backplane integrates an **HMAC-SHA256 signature protocol**: -* **PoC Mode (Unauthenticated):** Default mode where `auth_token` is `null`, skipping cryptographic validations for quick setups. -* **Production Mode (Authenticated):** A unique cryptographic token is issued per job. Event payloads must include an `hmac_sig` computed with the token. -* **Replay Attack Mitigation:** Each event carries a monotonically increasing integer sequence counter (`seq`). The subscriber (`job_subscriber.py`) drops any payload whose sequence number is not strictly greater than the highest sequence number it has already accepted for that job. Combined with the HMAC signature on the payload body, this rejects both re-injected and out-of-order packets without relying on clock synchronization. The wire-format timestamp field is advisory metadata only; the backplane does not enforce a clock-skew window. +- **Verdicts are strict**: the verdict token must stand alone on the last line of the report. A missing verdict counts as `NOT PASS`. +- **Review identity** (`--worktree` / `--base`): each round reviews a snapshot that includes uncommitted files. If the source changes during the round, its approvals are discarded. A promoted report gets a `report-.identity.json` sidecar that records the base, head, tree and reviewer. +- **Sub-jobs**: if the creator delegates part of its work (`--parent-job`), the loop waits for those jobs before the review and shows their status to the reviewers. --- -## ๐Ÿ“ Repository Layout +## ๐Ÿ” Security + +- **Signed events**: every job gets its own token (`auth_token`). Each event and each retained state message carries an HMAC-SHA256 signature made with it, and the subscriber drops anything that fails verification. The token itself never goes over the wire. +- **Replay and ordering**: each event carries an increasing `seq`. The subscriber accepts only sequence numbers higher than any it has seen and records gaps as `seq_gap`. Timestamps are informational only. +- **Credentials**: broker credentials live only in `.mam.env` (never in a job record). Remote dispatch is signed with `MAM_DISPATCH_SECRET`. + +--- + +## ๐Ÿงช Tests + +```bash +.venv/bin/python -m pytest -q -p no:cacheprovider tests +``` + +- The suite has about 1,900 tests, and a full run takes over an hour. +- It runs its own in-process MQTT broker, so it never needs `.mam.env`. Don't export `.mam.env` for tests. +- Tests run in sandboxes: + - they never write to the checkout's `.mam/`, your agent homes (`~/.claude/projects`, `~/.codex`, `~/.gemini`, โ€ฆ) or your herdr config; + - a test that does not use the mock herdr starts its own throwaway herdr server; + - session-level guards fail the run if a test leaves files behind in the real control plane or in an agent home. +- Some tests are platform-specific. A few need Python 3.11+ (`tomllib`), Linux (`/proc`) or the `nats-docker` submodule; elsewhere they are skipped. + +--- + +## ๐Ÿ“ Repository layout ```text . โ”œโ”€โ”€ .agents/ -โ”‚ โ”œโ”€โ”€ MULTI_AGENT_RULES.md # Agent roles, snapshottings, and execution charter -โ”‚ โ”œโ”€โ”€ MULTI_AGENT_RULES.ko.md # Agent roles, snapshottings, and execution charter (Korean) -โ”‚ โ””โ”€โ”€ skills/ # Core orchestration shell wrappers & libraries -โ”‚ โ”œโ”€โ”€ lib.sh # Shared orchestration library -โ”‚ โ”œโ”€โ”€ lib_py/ # Python core orchestration engine -โ”‚ โ”‚ โ”œโ”€โ”€ agents/ # Multi-agent CLI lifecycle adapters -โ”‚ โ”‚ โ”œโ”€โ”€ delegation/ # Asynchronous delegation & CAS state engine -โ”‚ โ”‚ โ””โ”€โ”€ loop/ # Autonomous planning-execution-review loop runtime -โ”‚ โ”œโ”€โ”€ multi-agent-mux-create/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-stop/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-resume/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-status/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-monitor/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-delegate-job/ -โ”‚ โ”‚ โ”œโ”€โ”€ requirements.txt # Python dependency declaration -โ”‚ โ”‚ โ””โ”€โ”€ scripts/ # Wire-compatibility shims (Python) -โ”‚ โ”œโ”€โ”€ multi-agent-mux-loop/ -โ”‚ โ””โ”€โ”€ multi-agent-mux-orc-onboard/ -โ”œโ”€โ”€ .mam/ # Multi-Agent Mux metadata (git-ignored) -โ”‚ โ”œโ”€โ”€ agent-sessions.db # SQLite WAL session database -โ”‚ โ”œโ”€โ”€ agent-sessions.yaml # Human-readable session registry -โ”‚ โ””โ”€โ”€ jobs/ # Asynchronous job metadata files -โ”œโ”€โ”€ deploy/ # Distribution and installation package -โ”‚ โ”œโ”€โ”€ INSTALL.md # User manual for installation and quick-start -โ”‚ โ”œโ”€โ”€ install_mam.sh # Local/Clone installer script -โ”‚ โ”œโ”€โ”€ generate-env.sh # Environment bootstrap helper -โ”‚ โ”œโ”€โ”€ install.sh # Remote/Network installer script -โ”‚ โ”œโ”€โ”€ update.sh # Updater script -โ”‚ โ””โ”€โ”€ remove.sh # Uninstaller script -โ”œโ”€โ”€ docs/ # Specifications, guides, and architectural contracts -โ”‚ โ”œโ”€โ”€ contracts/ # Issue/backplane contracts and migration roadmaps -โ”‚ โ”œโ”€โ”€ MAM_WEB_PTY_BRIDGE_PLAN.md # Web PTY terminal bridge design plan -โ”‚ โ”œโ”€โ”€ NEW_AGENT_INTEGRATION_GUIDE.md # Guide for integrating new AI coding agents -โ”‚ โ””โ”€โ”€ OPENCODE_OLLAMA_GUIDE.md # OpenCode interpreter + Ollama integration guide -โ”œโ”€โ”€ nats-docker/ # Private NATS broker deployment submodule -โ”œโ”€โ”€ tests/ # Comprehensive test suite (32 modules) -โ”œโ”€โ”€ AGENTS.md # Behavioral guidelines and orchestrator scope guards -โ”œโ”€โ”€ BOOTSTRAP.ko.md # Installation and verification guide (Korean) -โ”œโ”€โ”€ BOOTSTRAP.md # Detailed installation and verification guide -โ”œโ”€โ”€ IMPROVEMENTS.md # Backlog tracking issues and completed architectural tasks -โ”œโ”€โ”€ MESSAGING.md # MQTT wire protocol specification and internals -โ”œโ”€โ”€ README.ko.md # Project introduction and overview (Korean) -โ”œโ”€โ”€ README.md # Project introduction and overview (this file) -โ””โ”€โ”€ VERSIONS.md # Release notes and 4-way lockstep version ledger +โ”‚ โ”œโ”€โ”€ MULTI_AGENT_RULES.md / .ko.md # Roles, workflow and collaboration rules +โ”‚ โ”œโ”€โ”€ reports/ # Promoted review reports (+ identity sidecars) +โ”‚ โ””โ”€โ”€ skills/ +โ”‚ โ”œโ”€โ”€ lib.sh # Shared shell library (herdr shim, registry writes) +โ”‚ โ”œโ”€โ”€ lib_py/ # Python core +โ”‚ โ”‚ โ”œโ”€โ”€ agents/ # Per-agent CLI adapters (spawn/resume/discover) +โ”‚ โ”‚ โ”œโ”€โ”€ delegation/ # Job registry, wrapper, MQTT publish/subscribe, remote runner +โ”‚ โ”‚ โ”œโ”€โ”€ loop/ # Review-loop runtime +โ”‚ โ”‚ โ””โ”€โ”€ *.py # pane_lock, stall_watch, worktree, herdr_config, ... +โ”‚ โ””โ”€โ”€ multi-agent-mux-*/ # One directory per skill (SKILL.md + scripts/) +โ”œโ”€โ”€ .mam/ # Runtime state (git-ignored): sessions, jobs, audit logs, shim +โ”œโ”€โ”€ deploy/ # install.sh, install_mam.sh, update.sh, remove.sh, generate-env.sh +โ”œโ”€โ”€ docs/ # contracts/, design/, agent integration and bridge guides +โ”œโ”€โ”€ nats-docker/ # Private NATS broker deployment (submodule) +โ”œโ”€โ”€ tests/ # pytest suite +โ”œโ”€โ”€ AGENTS.md # Behavioural guidelines for agents +โ”œโ”€โ”€ BOOTSTRAP.md / BOOTSTRAP.ko.md # Step-by-step setup and verification +โ”œโ”€โ”€ IMPROVEMENTS.md # Backlog +โ”œโ”€โ”€ MESSAGING.md # MQTT wire protocol and delegation contract +โ”œโ”€โ”€ README.ko.md # Korean README +โ””โ”€โ”€ VERSIONS.md # Release notes (lockstep version ledger) ``` --- ## ๐Ÿšฆ Quick Start -For detailed setup instructions, please consult the **[BOOTSTRAP.md](./BOOTSTRAP.md)** file. Below is a quick summary: +See [BOOTSTRAP.md](BOOTSTRAP.md) for the full walkthrough. In short: -1. **Initialize Environment Config:** - ```bash - ./deploy/generate-env.sh - ``` -2. **Create Virtual Environment and Install Dependencies:** - ```bash - python3 -m venv .venv - source .venv/bin/activate - pip install -r .agents/skills/multi-agent-mux-delegate-job/requirements.txt - ``` -3. **Run Registry Diagnostics:** - ```bash - .venv/bin/python3 .agents/skills/multi-agent-mux-delegate-job/scripts/registry.py list - ``` +```bash +# 1. Install into the workspace, then set the broker in .mam.env +bash deploy/install.sh + +# 2. Start a creator and a reviewer on a dedicated herdr server +bash .agents/skills/multi-agent-mux-create/scripts/create_session.sh \ + --workspace "$PWD" --agent claude --role developer --herdr-session my-project --onboard +bash .agents/skills/multi-agent-mux-create/scripts/create_session.sh \ + --workspace "$PWD" --agent codex --role reviewer --herdr-session my-project --onboard + +# 3. Check the sessions +bash .agents/skills/multi-agent-mux-status/scripts/status.sh + +# 4. Run a task through the loop +bash .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh \ + --creator --all-reviewer --task "Fix the typo in docs/guide.md" +``` --- -## ๐Ÿ“ Guidelines for Collaborating Agents +## ๐Ÿ“ For agents joining the project -If you are an AI agent newly onboarded to this project: -1. Read **[MULTI_AGENT_RULES.md](.agents/MULTI_AGENT_RULES.md)** to align on development constraints and roles (PM, Worker, Reviewer). -2. Adhere to the **Pane Snapshotting Rules** in `MULTI_AGENT_RULES.md` (Section 4) to prevent scrollback data loss during long execution steps. -3. Never modify core logic without submitting a diff to the reviewer sessions for evaluation. \ No newline at end of file +1. Read [AGENTS.md](AGENTS.md) and [MULTI_AGENT_RULES.md](.agents/MULTI_AGENT_RULES.md) for roles and rules. +2. Follow the snapshotting rules in `MULTI_AGENT_RULES.md` ยง4, so long outputs are not lost to the pane's scrollback. +3. Publish your job's events as your brief instructs (`started --heartbeat`, then `completed` or `error`). Don't change core logic without a reviewed diff. From 423abc7844a85ca4307a4051191c337720d5c6a5 Mon Sep 17 00:00:00 2001 From: Godopu Date: Tue, 13 Oct 2026 11:14:31 +0900 Subject: [PATCH 2/5] docs(readme): review fixes (38a64423 / c5a8813c / 7d29a620) and README.ko.md in step - install.sh: what it actually checks; it writes a starter .mam.env with MQTT_BROKER=localhost (broker.hivemq.com is only the unset fallback); install_mam.sh is a separate installer. - Security: tokens exist only when given or when the broker has TLS or a username (PoC: no signature check); the remote dispatch carries the token. - Server isolation: create defaults to a workspace-named server; the shim bootstraps only a named server and never when MAM_NO_AUTOSTART=1 (status/monitor); restore-off is the normal path, with a warning fallback. - Loop: the selected reviewers must all pass; no reviewer option means a creator self-review. - Interpreter order with the PATH python3 fallback; exit 5 also covers target_not_found; two layers with their own registries; test isolation stated as sandboxes plus after-run guards; quick start uses named sessions. - README.ko.md now mirrors README.md. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff --- README.ko.md | 359 +++++++++++++++++++++++++++------------------------ README.md | 46 +++---- 2 files changed, 215 insertions(+), 190 deletions(-) diff --git a/README.ko.md b/README.ko.md index e7b2d56..b065174 100644 --- a/README.ko.md +++ b/README.ko.md @@ -1,6 +1,6 @@ # herdr-agent-orchestration (๋‹ค์ค‘ ์—์ด์ „ํŠธ Herdr ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฐ ๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ) -Herdr์™€ MQTT ๋ธŒ๋กœ์ปค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์ถ•๋œ ๊ณ ์‹ ๋ขฐ์„ฑ **๋‹ค์ค‘ ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฐ ๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ** ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. `claude`, `agy`, `hermes`, `grok`, `opencode`, `codex` ๋“ฑ ๋‹ค์ค‘ LLM ๋ฐฑ์—”๋“œ ์—์ด์ „ํŠธ ์ „๋ฐ˜์— ๊ฑธ์ณ ์žฅ์‹œ๊ฐ„ ์ˆ˜ํ–‰๋˜๋Š” ์ž‘์—…(์ฝ”๋“œ ์ƒ์„ฑ, ๋ฆฌํŒฉํ† ๋ง, ๋ณด์•ˆ ๊ฒ€ํ†  ๋“ฑ)์„ ์กฐ์ •, ๊ฒฉ๋ฆฌ ๋ฐ ๊ฐ์‚ฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. +[herdr](https://herdr.dev)์™€ MQTT ์œ„์— ๋งŒ๋“  **๋‹ค์ค‘ ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ยท๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ**์ž…๋‹ˆ๋‹ค. ์žฅ์‹œ๊ฐ„ ์‹คํ–‰๋˜๋Š” ์ฝ”๋”ฉ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`)๋ฅผ ๊ฒฉ๋ฆฌ๋œ herdr pane ์—์„œ ๋Œ๋ฆฌ๊ณ , ์ž‘์—…์„ ์ถ”์ ๋˜๋Š” ์žก์œผ๋กœ ์œ„์ž„ํ•˜๋ฉฐ, ๋ชจ๋“  ๋ฆฌ๋ทฐ์–ด๊ฐ€ ํ†ต๊ณผ์‹œํ‚ฌ ๋•Œ๊นŒ์ง€ planner / creator / reviewer ๋ฃจํ”„๋ฅผ ๋Œ๋ฆฝ๋‹ˆ๋‹ค. [![Version: v4.9.1](https://img.shields.io/badge/version-v4.9.1-blue.svg)](VERSIONS.md) @@ -8,212 +8,235 @@ Herdr์™€ MQTT ๋ธŒ๋กœ์ปค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์ถ•๋œ ๊ณ ์‹ ๋ขฐ์„ฑ **๋‹ค์ค‘ ์—์ด ## ๐Ÿš€ ๊ฐœ์š” -์ตœ๊ทผ์˜ ์—์ด์ „ํŠธ ์›Œํฌํ”Œ๋กœ์šฐ๋Š” ์„ธ์…˜ ํƒ€์ž„์•„์›ƒ, ํ”„๋กœ์„ธ์Šค ๊ฒฉ๋ฆฌ ๋ถ€์žฌ, ํ„ฐ๋ฏธ๋„ ๋ทฐํฌํŠธ ์ž˜๋ฆผ(์Šคํฌ๋กค๋ฐฑ ํ•œ๊ณ„๋กœ ์ธํ•œ ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ์œ ์‹ค), ๋ณต์žกํ•œ ๋™์‹œ์„ฑ ๊ฒฝ์Ÿ ๋“ฑ์˜ ๋ฌธ์ œ๋ฅผ ์ž์ฃผ ๊ฒช์Šต๋‹ˆ๋‹ค. +๊ธด ์—์ด์ „ํŠธ ์ž‘์—…์€ ์ •ํ•ด์ง„ ๋ฐฉ์‹์œผ๋กœ ๊นจ์ง‘๋‹ˆ๋‹ค. ํ„ฐ๋ฏธ๋„๊ณผ ํ•จ๊ป˜ ์„ธ์…˜์ด ์ฃฝ๊ณ , ํ•œ pane ์— ์žก ๋‘ ๊ฐœ๊ฐ€ ๋“ค์–ด๊ฐ€๊ณ , ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ๋Š” ๋ฐ”์œ ์—์ด์ „ํŠธ์™€ ์ฃฝ์€ ์—์ด์ „ํŠธ๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•˜๊ณ , ๋ฆฌ๋ทฐ๋Š” ์ฝ์€ ๋’ค์— ๋ฐ”๋€ ์ฝ”๋“œ๋ฅผ ์Šน์ธํ•ฉ๋‹ˆ๋‹ค. Multi-Agent Mux(MAM)๋Š” ์ด๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋ง‰์Šต๋‹ˆ๋‹ค. -**herdr-agent-orchestration**์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์†”๋ฃจ์…˜์„ ํ†ตํ•ด ์ด๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: -1. **Herdr ๊ธฐ๋ฐ˜ ํ”„๋กœ์„ธ์Šค ๊ฒฉ๋ฆฌ:** ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฒฉ๋ฆฌ๋œ herdr ํ™˜๊ฒฝ ๋‚ด๋ถ€์— ์—์ด์ „ํŠธ CLI ์„ธ์…˜์„ ๋„์›Œ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋Š๊น€ ์—†์ด ์žฅ์‹œ๊ฐ„ ์ž‘์—…์ด ์˜์†๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฐ๋ชฌ ์„œ๋ฒ„๋Š” ๋…๋ฆฝ๋œ OS ์„ธ์…˜/ํ”„๋กœ์„ธ์Šค ๊ทธ๋ฃน(`start_new_session=True`)์œผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ๋ถ€๋ชจ ์…ธ์˜ ์‹œ๊ทธ๋„ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜๊ฒŒ ๊ฒฉ๋ฆฌ๋ฉ๋‹ˆ๋‹ค. -2. **๋น„๋™๊ธฐ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜:** MQTT ๋ธŒ๋กœ์ปค๋ฅผ ๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ์œผ๋กœ ํ™œ์šฉํ•˜์—ฌ, ์—์ด์ „ํŠธ ๊ฐ„ ์ƒํƒœ ์ „์ด ๋‹จ๊ณ„(`started`, `progress`, `completed`, `error`)๋ฅผ ๊ธด๋ฐ€ํ•˜๊ฒŒ ์ œ์–ด ๋ฐ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. -3. **Multi-Agent Mux (MAM):** ํŒŒ์ผ ๊ธฐ๋ฐ˜์˜ ์–ด๋“œ๋ฐ”์ด์ €๋ฆฌ ๋ฝ(`fcntl`) ๋ฐ SQLite WAL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(`.mam/agent-sessions.db`)๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ, ๋™์‹œ์„ฑ ์ž‘์—… ์„ ์  ๊ฒฝ์Ÿ์„ ๋ฐฉ์ง€ํ•˜๊ณ  ์—์ด์ „ํŠธ ์„ธ์…˜์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ๋“œ๋ฆฌํ”„ํŠธ ์—†์ด ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. -4. **๋ฆฌ๋ทฐ์–ด ๊ธฐ๋ฐ˜ ๊ณ ์‹ ๋ขฐ ๊ฒ€์ฆ ๋ฃจํ”„:** Worker ์—์ด์ „ํŠธ๊ฐ€ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ƒ์ดํ•œ ๊ฐ•์ ์„ ์ง€๋‹Œ ์ „๋ฌธ ๊ฒ€์ฆ ์—์ด์ „ํŠธ(Claude, Hermes, Grok, OpenCode, Codex ๋“ฑ)๋“ค๋กœ๋ถ€ํ„ฐ ์ตœ์ข… `PASS` ํŒ์ •์„ ํš๋“ํ•œ ๋’ค ๋จธ์ง€ํ•˜๋„๋ก ๊ต์ฐจ ๊ฒ€์ฆ ๋ฃจํ”„๋ฅผ ์ž๋™ํ™”ํ•ฉ๋‹ˆ๋‹ค. +1. **๊ฒฉ๋ฆฌ๋˜๊ณ  ์žฌ๊ฐœ ๊ฐ€๋Šฅํ•œ ์—์ด์ „ํŠธ ์„ธ์…˜.** ์—์ด์ „ํŠธ๋งˆ๋‹ค ์ž๊ธฐ herdr pane ์—์„œ ๋Œ๊ณ , ๋ณดํ†ต ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ „์šฉ herdr ์„œ๋ฒ„๋ฅผ ์”๋‹ˆ๋‹ค. ์„ธ์…˜์€ ๋Œ€ํ™” ID ์™€ ํ•จ๊ป˜ `.mam/agent-sessions.yaml`(SQLite ๋ฐฑ์—…)์— ๊ธฐ๋ก๋˜๋ฏ€๋กœ, ๋ฉˆ์ถ˜ ์—์ด์ „ํŠธ๋ฅผ ๋‚˜์ค‘์— ๊ฐ™์€ ๋Œ€ํ™”๋กœ ์žฌ๊ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +2. **ํ™”๋ฉด์ด ์•„๋‹ˆ๋ผ ์ด๋ฒคํŠธ๋กœ ํŒ์ •ํ•˜๋Š” ์žก.** ์œ„์ž„ ์žก์€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋ ˆ์ฝ”๋“œ์™€ MQTT ์ด๋ฒคํŠธ ํ๋ฆ„(`started`, `progress`, `completed`, `error`)์ž…๋‹ˆ๋‹ค. ์—์ด์ „ํŠธ๋Š” ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ์•ˆ์— ํ”„๋กฌํ”„ํŠธ ์ˆ˜์‹ ์„ ์•Œ๋ฆฌ๊ณ , ์ผํ•˜๋Š” ๋™์•ˆ heartbeat ๋ฅผ ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์žก์„ ๋‹ซ๋Š” ๊ฒƒ์€ ํ”„๋กœํ† ์ฝœ ์ด๋ฒคํŠธ๋‚˜ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฟ์ด๋ฉฐ, ํ„ฐ๋ฏธ๋„์„ ์ฝ์–ด ํŒ์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +3. **์„ธ์…˜๋‹น ํ•œ ๋ฒˆ์— ์žก ํ•˜๋‚˜.** ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋„ฃ๊ธฐ ์ „์— ๋””์ŠคํŒจ์ฒ˜๊ฐ€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋กœ ๊ทธ ์„ธ์…˜์˜ ์•ž์„  ์žก(์˜จ๋ณด๋”ฉ ํฌํ•จ)์ด ๋๋‚˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. pane ๋ฐฐ์น˜๋Š” herdr ์„œ๋ฒ„๋งˆ๋‹ค ์ง๋ ฌํ™”๋˜์–ด, ๋™์‹œ์— ์‹คํ–‰ํ•œ `create` ๊ฐ€ ๊ฐ™์€ pane ์„ ์ฐจ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +4. **๊ทผ๊ฑฐ๋ฅผ ๊ณ ์ •ํ•œ ๋ฆฌ๋ทฐ ๋ฃจํ”„.** `multi-agent-mux-loop` ๋Š” ๋ณ€๊ฒฝ์„ ์„ ํƒํ•œ ๋ฆฌ๋ทฐ์–ด์—๊ฒŒ ๋ณด๋‚ด๊ณ , ๊ทธ ์ „์›์˜ `PASS` ๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ๋ทฐ์–ด๋Š” `--reviewer` ๋กœ ์ง€์ •ํ•˜๊ฑฐ๋‚˜ `--all-reviewer` ๋กœ ์‹คํ–‰ ์ค‘์ธ ๋ฆฌ๋ทฐ์–ด ์ „์›์„ ๊ณ ๋ฅด๋ฉฐ, ๋‘˜ ๋‹ค ์—†์œผ๋ฉด creator ๊ฐ€ ์Šค์Šค๋กœ ๋ฆฌ๋ทฐํ•ฉ๋‹ˆ๋‹ค. `--worktree`/`--base` ๋ฅผ ์“ฐ๋ฉด ๋ฆฌ๋ทฐ ๋ผ์šด๋“œ๋งˆ๋‹ค ์†Œ์Šค ์Šค๋ƒ…์ƒท์— ๋ฌถ์ด๋ฉฐ, ๋ผ์šด๋“œ ์ค‘ ์†Œ์Šค๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ทธ ์Šน์ธ์€ ๋ฒ„๋ฆฌ๊ณ  ๋‹ค์‹œ ๋ฆฌ๋ทฐํ•ฉ๋‹ˆ๋‹ค. --- -## ๐Ÿ› ๏ธ ํ•ต์‹ฌ ์Šคํ‚ฌ ๋ฐ ๊ตฌ์กฐ +## ๐Ÿ“ฆ ์„ค์น˜ ๋ฐ ์„ค์ • -๋ชจ๋“  ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์Šคํ‚ฌ๋“ค์€ `.agents/skills/` ๋””๋ ‰ํ„ฐ๋ฆฌ ํ•˜์œ„์— ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค: +์•„๋ฌด ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ MAM ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค: -* **`multi-agent-mux-create`**: ๊ฒฉ๋ฆฌ๋œ herdr ์„ธ์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ํŠน์ • ์—์ด์ „ํŠธ CLI๋ฅผ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๊ตฌ๋™ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค PID ์บก์ฒ˜, ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์—…๋ฐ์ดํŠธ ๋ฐ ์—์ด์ „ํŠธ ์ธ์ฆ ๊ฒ€์ฆ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. -* **`multi-agent-mux-stop`**: ์—์ด์ „ํŠธ CLI ์„ธ์…˜์„ ์ •์ƒ ์ข…๋ฃŒ ํ‚ค ์ž…๋ ฅ(`/exit` ๋˜๋Š” `Exit`)์„ ํ†ตํ•ด ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ซ๊ณ , ๊ฒฉ๋ฆฌ๋œ ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ ๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋กœ๊ทธ๋ฅผ ์‚ญ์ œ(purge)ํ•˜๋Š” ํด๋ฆฐ์—… ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. -* **`multi-agent-mux-resume`**: ๋””์Šคํฌ ๋˜๋Š” ์บ์‹œ์—์„œ ํŠน์ • ์›Œํฌ์ŠคํŽ˜์ด์Šค์˜ ์„ธ์…˜ UUID๋ฅผ ์กฐํšŒํ•˜์—ฌ ๊ธฐ์กด ๋Œ€ํ™” ์ƒํƒœ(`claude -r `, `agy --conversation `, `hermes --resume `, `grok --resume `, `opencode --session `, `codex resume `) ๊ทธ๋Œ€๋กœ ์„ธ์…˜์„ ๋ณต๊ตฌํ•˜๊ณ  ์žฌ๊ฐœํ•ฉ๋‹ˆ๋‹ค. -* **`multi-agent-mux-status`**: ํ™œ์„ฑํ™”๋œ ๋ชจ๋“  ์„ธ์…˜์˜ ์‹ค์‹œ๊ฐ„ ์ž‘๋™ ์ƒํƒœ๋ฅผ ์ฟผ๋ฆฌํ•˜์—ฌ PID ์ •ํ•ฉ์„ฑ, ์‹คํ–‰ ๋ช…๋ น ํฌ๋งท, herdr ์‹ค์ œ ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ๋™๊ธฐํ™” ๋“œ๋ฆฌํ”„ํŠธ๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค. -* **`multi-agent-mux-monitor`**: ๋ฐฑ๊ทธ๋ผ์šด๋“œ Reconcile ํ”„๋กœ์„ธ์Šค๋กœ ์‹คํ–‰๋˜์–ด, ์‹ค์‹œ๊ฐ„ herdr ์„ธ์…˜ ๋ณ€ํ™”๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ  `.mam/agent-sessions.yaml` ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŒŒ์ผ์— ์ƒํƒœ๋ฅผ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. -* **`multi-agent-mux-delegate-job`**: ํƒœ์Šคํฌ๋ฅผ ๋น„๋™๊ธฐ์‹ ๋…๋ฆฝ ์žก์œผ๋กœ ์œ„์ž„ ๋ฐ ๊ด€๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค (๋ณธ์ฒด ๊ตฌํ˜„์€ `.agents/skills/lib_py/delegation/`์— ์œ„์น˜ํ•˜๋ฉฐ, `scripts/*.py`๋Š” ํ•˜์œ„ ํ˜ธํ™˜ shim): - * `registry.py`: ํŒŒ์ผ ๋ฝ(`fcntl`)์„ ํ™œ์šฉํ•ด ๊ฒฝ์Ÿ ์กฐ๊ฑด ์—†์ด ์žก์„ ์›์ž์ ์œผ๋กœ ๋“ฑ๋ก ๋ฐ ์ ์œ (claim)ํ•ฉ๋‹ˆ๋‹ค. - * `job_subscriber.py`: MQTT ๋ฐฑํ”Œ๋ ˆ์ธ ์ฑ„๋„์„ ๊ตฌ๋…ํ•˜์—ฌ ์‹ค์‹œ๊ฐ„ ์ƒํƒœ ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ์ด๋ฅผ ๊ฐ์‚ฌ ๋กœ๊ทธ(audit trail)์— ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. - * `publish_event.py`: ์‹คํ–‰ ์ƒํƒœ ์ „ํ™˜ ๋ฐ ์„ธ๋ถ€ ์—๋Ÿฌ ๋‚ด์šฉ์„ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ฐฑํ”Œ๋ ˆ์ธ์œผ๋กœ ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค. - * `mqtt_common.py`: ๋ธŒ๋กœ์ปค ์ ‘์† ๊ทœ์น™, ํฌ๋ ˆ๋ด์…œ ์ธ์ฆ ๋ฐ HMAC ์„œ๋ช… ๊ธฐ๋Šฅ์„ ๊ณตํ†ต ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. -* **`multi-agent-mux-loop`**: Planner, Creator, Reviewer 3์ž ๊ฐ„์˜ ์ž์œจ์ ์ธ ๊ณ„ํš-์‹คํ–‰-๊ต์ฐจ๊ฒ€์ฆ ๋ฐ˜๋ณต ์ˆœํ™˜ ๋ฃจํ”„๋ฅผ ๊ตฌ๋™ํ•ฉ๋‹ˆ๋‹ค (Python ๋ฃจํ”„ ๋Ÿฐํƒ€์ž„ `lib_py.loop`, eager-import ๋ถˆ๋ณ€ ๋Ÿฐํƒ€์ž„, strict verdict parser ๊ธฐ๋ฐ˜). -* **`multi-agent-mux-orc-onboard`**: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ UUID๋ฅผ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๊ฒฉ๋ฆฌ ๋“ฑ๋กํ•˜์—ฌ ์„œ๋ธŒ ์—์ด์ „ํŠธ ์ž๋™ ํƒ์ƒ‰ ์˜ค์—ผ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. - ---- - -## ๐Ÿ“ ์ „์ฒด ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์„ฑ (Big-Picture Architecture) - -์ด ์‹œ์Šคํ…œ์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ๊ณ„์ธต(Layer)์„ ํ†ตํ•ด ๋‹ค์ค‘ ์›Œํฌ์ŠคํŽ˜์ด์Šค์—์„œ ์ž‘๋™ํ•˜๋Š” LLM ์—์ด์ „ํŠธ๋“ค์„ ์กฐ์œจํ•ฉ๋‹ˆ๋‹ค: - -1. **Layer A โ€” Herdr ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ (lib.sh + status/resume/stop/create)**: ์›Œํฌ์ŠคํŽ˜์ด์Šค๋ณ„ ์—์ด์ „ํŠธ ์„ธ์…˜์„ ๋…๋ฆฝ๋œ herdr ์ธ์Šคํ„ด์Šค๋กœ ๋ถ„๋ฆฌ ์‹คํ–‰ํ•˜๊ณ , `.mam/agent-sessions.yaml` ๋ฐ SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(`.mam/agent-sessions.db`)๋ฅผ ํ†ตํ•ด ์—์ด์ „ํŠธ ์„ธ์…˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์˜ ๋‹จ์ผ ์ฐธ์กฐ ์ง€์ (Single Source of Truth)์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. -2. **Layer B โ€” ๋น„๋™๊ธฐ ์žก ์œ„์ž„ (delegate-job)**: ์—์ด์ „ํŠธ์— ํŠน์ • ํƒœ์Šคํฌ๋ฅผ ์ „์†กํ•˜๊ณ  ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ ์ฑ„๋„(MQTT)์„ ํ†ตํ•ด ์ง„ํ–‰ ์ƒํ™ฉ๊ณผ ์™„๋ฃŒ ์—ฌ๋ถ€๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค. - -๋‘ ๋ ˆ์ด์–ด๋Š” ํŒŒ์ผ I/O ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ํ•˜๋‚˜์˜ ํ•ต์‹ฌ ๊ด€๋ฌธ์ธ `lib.sh::atomic_dump_yaml`์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  YAML/DB ์“ฐ๊ธฐ ์ž‘์—…์€ SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜ ๋ฝ๊ณผ ๋ฐ์ดํ„ฐ ์Šคํ‚ค๋งˆ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ๊ฑฐ์นฉ๋‹ˆ๋‹ค. - -### ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๊ฐœ์š” (Data Flow) - -```text - +-----------+ register_job +-------------------+ - | delegator | ---------------> | .mam/jobs/.json| <-- ์‹ค์‹œ๊ฐ„ ์žก ์ •๋ณด - +-----------+ +---------+---------+ - | - | atomic rename + fsync - v - +-----------------+ - | audit log | <-- ์ถ”๊ฐ€ ์ „์šฉ - | .mam/delegate_ | events.ndjson - | job_logs// | - +--------+--------+ - ^ - | (์ตœ์„  ๋…ธ๋ ฅ ๋ฏธ๋Ÿฌ๋ง) - | - +-----------+ publish_event +-----+-----+ +---------+ - | agent | ---------------> | MQTT broker | <--- | monitor | - | (claude) | +-------------+ +----+----+ - +-----------+ | - ^ v - | ๊ตฌ๋…์ž(subscriber) atomic_dump_yaml - | (job_subscriber.py) (.mam/agent-sessions.yaml) - | ^ - +-------- ์œ„์ž„ ๋Œ€๊ธฐ ์˜์—ญ -----------------+ | - +---+---+ - | reconcil| - | e.sh | - +--------+ +```bash +curl -fsSL https://git.godopu.com/tmpl/multi-agent-mux/raw/branch/main/deploy/install.sh | bash ``` -### ๐Ÿ”’ Herdr ์„œ๋ฒ„ ๊ฒฉ๋ฆฌ (Herdr Server Isolation) +๋กœ์ปฌ ํด๋ก ์—์„œ๋Š”: -์—์ด์ „ํŠธ ์„ธ์…˜ ๊ฐ„์˜ ์ถฉ๋Œ ๋ฐ ์‹œ์Šคํ…œ ์ „์—ญ herdr ํ”„๋กœ์„ธ์Šค์™€์˜ ํ˜ผ์„ ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ๋…๋ฆฝ๋œ ์„œ๋ฒ„ ์†Œ์ผ“ ํ™˜๊ฒฝ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค: -* **์›Œํฌ์ŠคํŽ˜์ด์Šค๋ณ„ ์‹ฌ(Shim):** `_init_herdr_isolation` ๋ฐ `_resolve_real_herdr_path` ํ•จ์ˆ˜๊ฐ€ `/tmp/multi-agent-herdr-shim//herdr` ๊ฒฝ๋กœ์— ๋…๋ฆฝ๋œ ์‹ฌ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ , ์ผ๋ฐ˜ herdr ๋ช…๋ น ์‹คํ–‰ ์‹œ ์ž๋™์œผ๋กœ `herdr -L ` ํ˜•ํƒœ์˜ ๋…๋ฆฝ ์†Œ์ผ“ ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. -* **PATH ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋ณ€์กฐ:** ์ž์‹ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ `PATH` ๋ณ€์ˆ˜ ๋งจ ์•ž์— ์‹ฌ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์—์ด์ „ํŠธ์˜ ๋‚ด๋ถ€ ์…ธ์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ๋ชจ๋“  `herdr` ๋ช…๋ น์–ด๋Š” ํ•ด๋‹น ๊ฒฉ๋ฆฌ ์„œ๋ฒ„ ์†Œ์ผ“์œผ๋กœ ๊ฐ•์ œ ์ œ์•ฝ๋ฉ๋‹ˆ๋‹ค. -* **ํ™˜๊ฒฝ ๋ณต๊ตฌ:** `HERDR_SERVER_NAME`์„ `default`๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒฝ์šฐ PATH ์˜ค๋ฒ„๋ผ์ด๋“œ๊ฐ€ ์ •๋ฆฌ๋˜๊ณ  ๊ธฐ๋ณธ ์ „์—ญ herdr ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. +```bash +bash deploy/install.sh +``` -### ๐Ÿ›ก๏ธ ๋™์‹œ์„ฑ ์„ค๊ณ„ ๋ฐ ์“ฐ๊ธฐ ์ง๋ ฌํ™” +`install.sh` ๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰ํ•ด๋„ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋Š” ์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. +- herdr ์™€ Python 3.9+ ๊ฐ€ ์„ค์น˜๋ผ ์žˆ๋Š”์ง€, ์‹œ์Šคํ…œ `python3` ์— PyYAML ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. +- `.agents/` ์™€ `.mam.env.example` ์„ ์›Œํฌ์ŠคํŽ˜์ด์Šค์— ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. +- `.venv` ๋ฅผ ๋งŒ๋“ค๊ณ  `paho-mqtt`ยทPyYAML ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. +- `MQTT_BROKER=localhost` ๋กœ ๋œ ์ดˆ๊ธฐ `.mam.env` ๋ฅผ ์”๋‹ˆ๋‹ค. ์ด๋ฏธ ์žˆ๋Š” `.mam.env` ๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ , ์˜ˆ์ „ `.env` ๋Š” `.mam.env` ๋กœ ์ด๋ฆ„์„ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. +- `.venv`, `.mam/`, `.mam.env` ๋ฅผ `.gitignore` ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. -์—ฌ๋Ÿฌ ์—์ด์ „ํŠธ๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋  ๋•Œ์˜ ๋ ˆ์ด์Šค ์ปจ๋””์…˜์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฝ ๊ธฐ๋ฐ˜์˜ ์‹คํ–‰ ํŒจํ„ด์„ ๊ณ ์ˆ˜ํ•ฉ๋‹ˆ๋‹ค: -* **SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฝ (`BEGIN IMMEDIATE`):** `agent-sessions.yaml` ๋˜๋Š” SQLite ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์“ฐ๊ธฐ ์—ฐ์‚ฐ์„ ์ง„ํ–‰ํ•  ๋•Œ, ๋ฐ˜๋“œ์‹œ `lib.sh` ๋‚ด๋ถ€์˜ `atomic_dump_yaml` ํ•จ์ˆ˜๋ฅผ ๊ฑฐ์ณ SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค `.mam/agent-sessions.db`์— `BEGIN IMMEDIATE` ํŠธ๋žœ์žญ์…˜ ๋ฝ์„ ํš๋“ํ•˜๋„๋ก ์ง๋ ฌํ™”ํ•ฉ๋‹ˆ๋‹ค. -* **์ด์ค‘ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ๋ถ„๋ฆฌ ๊ตฌ์กฐ:** ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐ„ ์˜์กด์„ฑ ์ถฉ๋Œ๊ณผ ์‹คํ–‰ ๋„๊ตฌ์˜ ์•ˆ์ •์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ™˜๊ฒฝ์„ ์ด์›ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. MQTT ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—… ํ†ต์‹ ์—๋Š” ๊ฐ€์ƒํ™˜๊ฒฝ `.venv` (paho-mqtt ํ•„์š”)์˜ Python์„ ์‚ฌ์šฉํ•˜๊ณ , YAML ์ง๋ ฌํ™” ์“ฐ๊ธฐ ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ๋‹ด๋‹นํ•˜๋Š” `atomic_dump_yaml`์€ ์‹œ์Šคํ…œ ์ „์—ญ `python3` (์‹œ์Šคํ…œ PyYAML ํ•„์š”)์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. -* **NFS ๋ฐ ๋„คํŠธ์›Œํฌ ํŒŒ์ผ์‹œ์Šคํ…œ ๋Œ€์‘:** ๋„คํŠธ์›Œํฌ ๋””๋ฐ”์ด์Šค(NFS, CIFS, SSHFS)์—์„œ๋Š” ํŒŒ์ผ ๋ฝ(`flock`) ๋ฐ SQLite WAL ๊ธฐ๋Šฅ์ด ์˜ค์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `lib.sh`๋Š” ์“ฐ๊ธฐ ๋Œ€์ƒ ํŒŒ์ผ์‹œ์Šคํ…œ ๊ฒฝ๋กœ์˜ ๋งˆ์šดํŠธ ํƒ€์ž…์„ ์ฒดํฌํ•˜์—ฌ, ๋„คํŠธ์›Œํฌ ํŒŒ์ผ์‹œ์Šคํ…œ ๊ฐ์ง€ ์‹œ ๊ฒฝ๊ณ  ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  SQLite์˜ ์ €๋„ ๋ชจ๋“œ๋ฅผ `WAL`์—์„œ `DELETE`๋กœ ์ž๋™ ์ „ํ™˜ํ•ด ๋™์‹œ์„ฑ ์•ˆ์ „์„ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค. +`.mam.env` ์˜ `MQTT_BROKER` ๋ฅผ ์ง์ ‘ ์šด์˜ํ•˜๋Š” ๋ธŒ๋กœ์ปค๋กœ ๋ฐ”๊พธ์‹ญ์‹œ์˜ค(์‚ฌ์„ค ๋ธŒ๋กœ์ปค๋Š” [MESSAGING.md](MESSAGING.md) ์ฐธ๊ณ ). `MQTT_BROKER` ๊ฐ€ ์•„์˜ˆ ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด ์ฝ”๋“œ๋Š” ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค `broker.hivemq.com` ์„ ์”๋‹ˆ๋‹ค. ์‹œํ—˜์šฉ์œผ๋กœ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ์‹ค์ œ ์ž‘์—…์šฉ์€ ์•„๋‹™๋‹ˆ๋‹ค. `deploy/generate-env.sh` ๋Š” `.mam.env.example` ๋กœ `.mam.env` ๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ์™€ ์ œ๊ฑฐ๋Š” `deploy/update.sh`, `deploy/remove.sh` ์ž…๋‹ˆ๋‹ค. `deploy/install_mam.sh` ๋Š” ๋กœ์ปฌ ํด๋ก ์—์„œ ๋‹ค๋ฅธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ๋ณต์‚ฌํ•ด ์„ค์น˜ํ•˜๋Š” ๋ณ„๋„ ์„ค์น˜๊ธฐ์ž…๋‹ˆ๋‹ค. --- -## ๐Ÿ“ ์•„ํ‚คํ…์ฒ˜ ๋ฐ ์กฐ์ • ๋ฃจํ”„ (Review Loop) +## ๐Ÿ› ๏ธ ํ•ต์‹ฌ ์Šคํ‚ฌ -Project Manager(PM), Worker, Reviewer ์—ญํ•  ๊ฐ„์˜ ํ˜‘์—… ๊ตฌ์กฐ๋Š” ์—„๊ฒฉํ•œ ๊ต์ฐจ ๊ฒ€์ฆ ๋ฃจํ”„๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค: +๋ชจ๋“  ์Šคํ‚ฌ์€ `.agents/skills/` ์•„๋ž˜์— ์žˆ๊ณ , ๊ฐ `SKILL.md` ๊ฐ€ ์˜ต์…˜๊ณผ ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. + +| ์Šคํ‚ฌ | ํ•˜๋Š” ์ผ | +|---|---| +| **`multi-agent-mux-create`** | ์—์ด์ „ํŠธ๋ฅผ herdr pane ์—์„œ ์‹œ์ž‘ํ•˜๊ณ  ์„ธ์…˜์„ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. `--onboard` ๋Š” ์˜จ๋ณด๋”ฉ ์žก์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค(์‹คํŒจํ•˜๋ฉด ์ข…๋ฃŒ ์ฝ”๋“œ 44, ์‹œ๊ฐ„ ์•ˆ์— ๋๋‚˜์ง€ ์•Š์œผ๋ฉด 45; ์„ธ์…˜์€ ๋‚จ๊น€). `scripts/worktree_prepare.sh` ๋Š” creator ์šฉ ์ด์Šˆ ์›ŒํฌํŠธ๋ฆฌ๋ฅผ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. | +| **`multi-agent-mux-stop`** | ์„ธ์…˜์„ ์ •์ƒ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค. ๋Œ€ํ™” ID ๋ฅผ ํ–‰์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค(`status: stopped`, `resumable: true`). `--purge-conversation --yes` ๋Š” ๋Œ€์‹  ๋Œ€ํ™”๋ฅผ ์ง€์›๋‹ˆ๋‹ค. `scripts/worktree_remove.sh` ๋Š” ์„œ๋ธŒ๋ชจ๋“ˆ๊นŒ์ง€ ๊นจ๋—ํ•œ์ง€ ํ™•์ธํ•œ ๋’ค์—๋งŒ ์ด์Šˆ ์›ŒํฌํŠธ๋ฆฌ๋ฅผ ์ง€์›๋‹ˆ๋‹ค. | +| **`multi-agent-mux-resume`** | ๋ฉˆ์ถ˜ ์„ธ์…˜์„ ์ €์žฅ๋œ ๋Œ€ํ™”๋กœ ๋˜์‚ด๋ฆฝ๋‹ˆ๋‹ค(`claude -r`, `agy --conversation`, `hermes --resume`, `grok --resume`, `opencode --session`, `codex resume`). ์„ธ์…˜์ด ์›๋ž˜ ๋Œ๋˜ ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ๋งŒ ์žฌ๊ฐœํ•ฉ๋‹ˆ๋‹ค. | +| **`multi-agent-mux-status`** | ๋ชจ๋“  ์„ธ์…˜์˜ ์ฝ๊ธฐ ์ „์šฉ ์Šค๋ƒ…์ƒท: ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ƒํƒœ, herdr ์ƒ์กด, pane ๋ช…๋ น๊ณผ cwd, ์žฌ๊ฐœ ID, ๋ถˆ์ผ์น˜(drift). | +| **`multi-agent-mux-monitor`** | ์žฅ๊ธฐ ์‹คํ–‰ ์กฐ์ •์ž(`reconcile.sh --subscribe`). ์žก ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•˜๊ณ , ๋ธŒ๋กœ์ปค๊ฐ€ ์ฃฝ์œผ๋ฉด ํด๋ง์œผ๋กœ ๋Œ์•„๊ฐ€๋ฉฐ, ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋ถˆ์ผ์น˜๋ฅผ ๊ณ ์นฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฃฝ์€ ์„ธ์…˜์„ `terminated` ๋กœ ํ‘œ์‹œํ•˜๊ณ , ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๊ฐ€ ๋ชจ๋ฅด๋Š” ์‚ด์•„ ์žˆ๋Š” ์„ธ์…˜์„ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. | +| **`multi-agent-mux-delegate-job`** | ์„ธ์…˜(`herdr:`)์ด๋‚˜ ๋‹ค๋ฅธ ํ˜ธ์ŠคํŠธ์˜ ๋Ÿฌ๋„ˆ(`remote:`)์— ์žก์„ ์œ„์ž„ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. [์œ„์ž„ ๊ณ„์•ฝ](#-์œ„์ž„-๊ณ„์•ฝ)์„ ๋ณด์‹ญ์‹œ์˜ค. | +| **`multi-agent-mux-loop`** | ๊ณ„ํšยท๊ตฌํ˜„ยท๋ฆฌ๋ทฐ: ์„ ํƒ์ ์ธ planner ์™€ creator, ๊ทธ๋‹ค์Œ ์„ ํƒํ•œ ๋ฆฌ๋ทฐ์–ด(`--reviewer A,B`, ๋˜๋Š” `--all-reviewer` ๋กœ creator ๋ฅผ ๋บ€ ์‹คํ–‰ ์ค‘์ธ ๋ฆฌ๋ทฐ์–ด ์ „์›)๊ฐ€ ๋ชจ๋‘ `PASS` ๋ฅผ ๋‚ผ ๋•Œ๊นŒ์ง€(๋˜๋Š” `--max-loop` ๊นŒ์ง€). ๋‘˜ ๋‹ค ์—†์œผ๋ฉด creator ๊ฐ€ ์Šค์Šค๋กœ ๋ฆฌ๋ทฐํ•ฉ๋‹ˆ๋‹ค. ๋ฃจํ”„ ๋ฐ–์—์„œ ๋๋‚œ ์ž‘์—…์€ `--review-only` ๋กœ ๋ฆฌ๋ทฐํ•ฉ๋‹ˆ๋‹ค. ํ†ต๊ณผํ•œ ๋ฆฌํฌํŠธ๋Š” `.agents/reports//` ์œผ๋กœ ์˜ฎ๊ฒจ ๋ณด๊ด€ํ•ฉ๋‹ˆ๋‹ค. | +| **`multi-agent-mux-orc-onboard`** | ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์ž์‹ ์˜ ์„ธ์…˜ ID ๋ฅผ ๋“ฑ๋กํ•ด, ์„ธ์…˜ ํƒ์ƒ‰์ด ๊ทธ๊ฒƒ์„ ํ•˜์œ„ ์—์ด์ „ํŠธ๋กœ ์ฐฉ๊ฐํ•˜์ง€ ์•Š๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. | + +--- + +## ๐Ÿ“ ์•„ํ‚คํ…์ฒ˜ + +MAM ์€ ๊ฐ์ž ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๊ฐ€์ง„ ๋‘ ๊ณ„์ธต์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. + +1. **์„ธ์…˜ (herdr)**: `lib.sh` ์™€ create/stop/resume/status/monitor ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์—์ด์ „ํŠธ๋ฅผ ๋Œ๋ฆฌ๊ณ , `.mam/agent-sessions.yaml`(+ `.mam/agent-sessions.db`)์„ ๊ธฐ์ค€ ๊ธฐ๋ก์œผ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. +2. **์žก (์œ„์ž„)**: `lib_py/delegation/` ์ด `.mam/jobs/.json` ์— ์žก์„ ๋“ฑ๋กํ•˜๊ณ , ๋ธŒ๋ฆฌํ”„๋ฅผ ์ฃผ์ž…ํ•˜๊ณ , MQTT ๋กœ ์žก์˜ ์ด๋ฒคํŠธ๋ฅผ ๋”ฐ๋ผ๊ฐ‘๋‹ˆ๋‹ค. ๋ชจ๋“  ์ด๋ฒคํŠธ๋Š” ์žก์˜ ๊ฐ์‚ฌ ๋กœ๊ทธ `.mam/delegate_job_logs//` ์—๋„ ๋ง๋ถ™์—ฌ์ง‘๋‹ˆ๋‹ค. + +```text + +--------------+ register / pick +----------------------+ + | orchestrator | -----------------> | .mam/jobs/.json | live record + | (wrapper) | +----------+-----------+ + +------+-------+ | every transition + | inject brief v + v +----------------------+ + +--------------+ publish_event | .mam/delegate_job_ | append-only + | agent pane | --------+ | logs// | audit log + +--------------+ | +----------------------+ + v + +-------------+ events + retained state + | MQTT broker | -------------------------> job_subscriber (orchestrator) + +-------------+ -------------------------> monitor (reconcile.sh) + | + v + .mam/agent-sessions.yaml / .db +``` + +### ๐Ÿ”’ Herdr ์„œ๋ฒ„ ๊ฒฉ๋ฆฌ + +- **์›Œํฌ์ŠคํŽ˜์ด์Šค ์ „์šฉ ์„œ๋ฒ„.** `create` ๋Š” ๊ธฐ๋ณธ์œผ๋กœ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ด๋ฆ„(slug)์„ ๋”ด herdr ์„œ๋ฒ„์—์„œ ์—์ด์ „ํŠธ๋ฅผ ๋Œ๋ฆฝ๋‹ˆ๋‹ค. ์ด ์„œ๋ฒ„๋Š” ๊ธฐ๋ณธ herdr ์™€ ๋ถ„๋ฆฌ๋œ ์ž๊ธฐ ์†Œ์ผ“์„ ์”๋‹ˆ๋‹ค. `--herdr-session ` ๋˜๋Š” `HERDR_SESSION_NAME` ์œผ๋กœ ๋‹ค๋ฅธ ์ด๋ฆ„์„ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ด๋ฆ„์€ ์„ธ์…˜ ํ–‰์— ๊ธฐ๋ก๋˜๊ณ , ์ดํ›„ ๋ชจ๋“  ๋ช…๋ น์ด ๊ทธ ์„œ๋ฒ„๋กœ ๊ฐ‘๋‹ˆ๋‹ค. +- **shim.** `lib.sh` ๋ฅผ source ํ•˜๋ฉด `/.mam/shim/herdr` ๋ฅผ ์“ฐ๊ณ  `PATH` ๋งจ ์•ž์— ๋‘ก๋‹ˆ๋‹ค. shim ์€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์“ฐ๋Š” tmux ์‹ ๋ช…๋ น(`new-session`, `has-session` โ€ฆ)์„ herdr ์˜ ์—์ด์ „ํŠธ API ์œ„์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„ ์žˆ๋Š” ์„œ๋ฒ„๋ฉด ํ˜ธ์ถœ๋งˆ๋‹ค `--session ` ๋ฅผ ๋ถ™์ด๊ณ , ๊ทธ ์„œ๋ฒ„๊ฐ€ ๋Œ๊ณ  ์žˆ์ง€ ์•Š์œผ๋ฉด ํ—ค๋“œ๋ฆฌ์Šค๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ `MAM_NO_AUTOSTART=1` ์ด๋ฉด ์‹œ์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. `status` ์™€ `monitor` ๊ฐ€ ์ด ๊ฐ’์„ ์„ค์ •ํ•˜๋ฏ€๋กœ, ์กฐํšŒ๋งŒ์œผ๋กœ ์„œ๋ฒ„๊ฐ€ ๋œจ๋Š” ์ผ์€ ์—†์Šต๋‹ˆ๋‹ค. `default` ์„œ๋ฒ„ ํ˜ธ์ถœ์€ ๋ฐ”๊พธ์ง€ ์•Š๊ณ  ์‚ฌ์šฉ์ž์˜ herdr ๋กœ ๊ทธ๋Œ€๋กœ ๊ฐ‘๋‹ˆ๋‹ค. +- **์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์žฌ์‹คํ–‰ ์—†์Œ.** MAM ์ด ์‹œ์ž‘ํ•œ ์„œ๋ฒ„๋Š” ๋ณดํ†ต ์‚ฌ์šฉ์ž์˜ herdr ์„ค์ •์— `resume_agents_on_restore = false` ๋ฅผ ๋”ํ•ด ์”๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ herdr ๊ฐ€ ์žฌ์‹œ์ž‘๋ผ๋„ ์ €์žฅ๋œ ์—์ด์ „ํŠธ๋ฅผ ๊ถŒํ•œ ํ”Œ๋ž˜๊ทธ ์—†์ด ๋‹ค์‹œ ๋„์šฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์„ค์ •์„ ๋งŒ๋“ค ์ˆ˜ ์—†์œผ๋ฉด ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์ด ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธฐ๊ณ , ์„œ๋ฒ„๋Š” restore ๊ฐ€ ์ผœ์ง„ ์ฑ„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. +- **pane ๋ฐฐ์น˜๋Š” ํ•œ ๋ฒˆ์— ํ•˜๋‚˜.** pane ๋ฐฐ์น˜๋Š” ์„œ๋ฒ„๋ณ„ ์ž ๊ธˆ(`lib_py/pane_lock.py`, macOSยทLinux ์—์„œ `flock`)์„ ์žก๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ•œ ํด๋”์—์„œ ๋™์‹œ์— ์‹คํ–‰ํ•œ `create` ๋„ ๊ฐ์ž ์ž๊ธฐ pane ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. + +### ๐Ÿ›ก๏ธ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์“ฐ๊ธฐ์™€ ๋™์‹œ์„ฑ + +- **์ง๋ ฌํ™”๋œ ์“ฐ๊ธฐ.** `agent-sessions.yaml` ์˜ ๋ชจ๋“  ๋ณ€๊ฒฝ์€ `lib.sh::atomic_dump_yaml` ์„ ๊ฑฐ์นฉ๋‹ˆ๋‹ค. `.mam/agent-sessions.db` ์˜ ๋ฐฐํƒ€์  SQLite ํŠธ๋žœ์žญ์…˜(`BEGIN IMMEDIATE`) ์•ˆ์—์„œ ์‹คํ–‰๋˜๊ณ , ๊ฒ€์ฆํ•œ ๋’ค์— YAML ์„ ์›์ž์ ์œผ๋กœ ๋‹ค์‹œ ์”๋‹ˆ๋‹ค. ์žก ๋ ˆ์ฝ”๋“œ๋Š” ๋ณ„๋„์˜ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ž ๊ธˆ์„ ์”๋‹ˆ๋‹ค. +- **Python ์ธํ„ฐํ”„๋ฆฌํ„ฐ.** ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์“ฐ๊ธฐ์™€ ์œ„์ž„ ํ—ฌํผ๋Š” ์ด ์ˆœ์„œ๋กœ Python ์„ ๊ณ ๋ฆ…๋‹ˆ๋‹ค: `AGENT_PYTHON_BIN`, ํ™œ์„ฑํ™”๋œ ๊ฐ€์ƒํ™˜๊ฒฝ, ์Šคํ‚ฌ ์œ„์ชฝ์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด `.venv`, ๋งˆ์ง€๋ง‰์œผ๋กœ `PATH` ์˜ `python3`. shim ๊ณผ `create` ์˜ ์ผ๋ถ€ ๊ฐ™์€ ์…ธ ๊ฒฝ๋กœ๋Š” `PATH` ์˜ `python3` ๋ฅผ ์ง์ ‘ ๋ถ€๋ฆ…๋‹ˆ๋‹ค. +- **๋„คํŠธ์›Œํฌ ํŒŒ์ผ์‹œ์Šคํ…œ.** `.mam/` ์ด NFS/CIFS/SSHFS ์— ์žˆ์œผ๋ฉด `lib.sh` ๊ฐ€ ๊ฒฝ๊ณ ํ•˜๊ณ , SQLite ์ €๋„ ๋ชจ๋“œ๋ฅผ `WAL` ์—์„œ `DELETE` ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. +- **์ฒดํฌ์•„์›ƒ๋‹น ๋ฃจํ”„ ํ•˜๋‚˜.** ๋ฃจํ”„ ์ž ๊ธˆ์ด ๊ฐ™์€ ์ œ์–ด ํ‰๋ฉด์—์„œ ๋‘ ๋ฒˆ์งธ `run_loop.sh` ๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. + +--- + +## ๐Ÿ“จ ์œ„์ž„ ๊ณ„์•ฝ + +์ „์ฒด ๋ช…์„ธ๋Š” [MESSAGING.md ยง2.5](MESSAGING.md)์— ์žˆ์Šต๋‹ˆ๋‹ค. + +- **์ „๋‹ฌ**: ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋„˜๊ธด ๋’ค **T** ์ดˆ(๊ธฐ๋ณธ 180) ์•ˆ์— ์—์ด์ „ํŠธ๊ฐ€ `started` ๋ฅผ ๋ฐœํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ์ง€ ์•Š์œผ๋ฉด ์žก์€ ์‹คํŒจ๋กœ ๋‹ซํžˆ๊ณ (`agent_blocked`, ์ข…๋ฃŒ ์ฝ”๋“œ 1), ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋‘ ๋ฒˆ ๋„ฃ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +- **์ƒ์กด**: `started --heartbeat N` ์ด ์ž๋™ heartbeat ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค(๊ธฐ๋ณธ 30 ์ดˆ๋งˆ๋‹ค). **Kร—N** ์ดˆ(๊ธฐ๋ณธ 120 ์ดˆ) ๋™์•ˆ ์•„๋ฌด ์ด๋ฒคํŠธ๊ฐ€ ์—†์œผ๋ฉด ๋ฌด์‘๋‹ต์œผ๋กœ ๋ด…๋‹ˆ๋‹ค. herdr ์ƒํƒœ์™€ pane ํ…์ŠคํŠธ๋Š” ์ง„๋‹จ์šฉ์œผ๋กœ๋งŒ ๋กœ๊ทธ์— ๋‚จ๊น๋‹ˆ๋‹ค. +- **์˜ˆ์‚ฐ**: ์žก๋งˆ๋‹ค ๋ฒฝ์‹œ๊ณ„ ์˜ˆ์‚ฐ์ด ์žˆ์Šต๋‹ˆ๋‹ค(`--timeout` / `MAM_JOB_TIMEOUT_S`, ๊ธฐ๋ณธ 3600 ์ดˆ). ์˜ˆ์‚ฐ์„ ๋‹ค ์“ด ์žก์€ `wall_clock_timeout` ์œผ๋กœ ๋‹ซํž™๋‹ˆ๋‹ค. +- **๋ฐ”์œ ์„ธ์…˜**: ๋ž˜ํผ๋Š” ๊ทธ ์„ธ์…˜์˜ ์•ž์„  ์—ด๋ฆฐ ์žก์ด ๋๋‚˜๊ธฐ๋ฅผ `MAM_DISPATCH_WAIT_S` ๋งŒํผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. ๋๋‚˜์ง€ ์•Š์œผ๋ฉด `cancelled`(`session_busy`, ์ข…๋ฃŒ ์ฝ”๋“œ 5)๋กœ ๋๋‚˜๊ณ , ํ”„๋กฌํ”„ํŠธ๋Š” ์ „๋‹ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +- **์›๊ฒฉ ์—์ด์ „ํŠธ**: `remote:` ์€ ๋ธŒ๋ฆฌํ”„๋ฅผ ์„œ๋ช…๋œ retained ๋ธŒ๋กœ์ปค ๋ฉ”์‹œ์ง€๋กœ ๋‹ค๋ฅธ ํ˜ธ์ŠคํŠธ์˜ `remote.py run` ๋Ÿฌ๋„ˆ์— ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์‚ฌ์„ค ๋ธŒ๋กœ์ปค์—์„œ๋งŒ ์“ฐ์‹ญ์‹œ์˜ค. + +| ์ข…๋ฃŒ ์ฝ”๋“œ | ์˜๋ฏธ | +|:---:|---| +| `0` | `completed` | +| `1` | ์‹คํŒจ, ๋˜๋Š” T ์•ˆ์— `started` ์—†์Œ | +| `2` | Kร—N ๋™์•ˆ ์ด๋ฒคํŠธ ์—†์Œ(`deadline_timeout`) ๋˜๋Š” ์˜ˆ์‚ฐ ์†Œ์ง„(`wall_clock_timeout`) | +| `3` | ๋ธŒ๋กœ์ปค๋ฅผ ์“ธ ์ˆ˜ ์—†๊ณ , ๋””์Šคํฌ์—๋„ ์ข…๊ฒฐ ์ƒํƒœ๊ฐ€ ์—†์Œ | +| `5` | ์ „๋‹ฌ ์•ˆ ๋จ(`cancelled`): ์„ธ์…˜์ด ๋ฐ”์จ, ๋Œ€์ƒ์„ ์ฐพ์ง€ ๋ชปํ•จ, ๋˜๋Š” ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ์ชฝ์ด ๊ฐ€์ ธ๊ฐ | + +--- + +## ๐Ÿ” ๋ฆฌ๋ทฐ ๋ฃจํ”„ ```mermaid sequenceDiagram autonumber - actor User as User - participant PM as Project Manager - participant W as Worker + actor User + participant L as run_loop.sh + participant P as Planner (optional) + participant C as Creator participant R as Reviewers - participant M as MQTT Backplane - User->>PM: ์š”๊ตฌ์‚ฌํ•ญ ์ „๋‹ฌ - Note over PM: ํƒœ์Šคํฌ ์ˆ˜๋ฆฝ ๋ฐ Job ๋“ฑ๋ก - PM->>M: Job ๋“ฑ๋ก ๋ฐ Subscriber ์‹œ์ž‘ - PM->>W: ์ž‘์—… ์œ„์ž„ (Job ID ๋ฐ ๊ฐ€์ด๋“œ ์ œ๊ณต) - W->>M: 'started' ์ด๋ฒคํŠธ ๋ฐœํ–‰ - Note over W: ์ฝ”๋“œ ๋ณ€๊ฒฝ ๋ฐ ์ž์ฒด ๊ฒ€์ฆ ์ˆ˜ํ–‰ - W->>M: 'completed' (๋˜๋Š” 'error') ๋ฐœํ–‰ - PM->>R: ๋ณ‘๋ ฌ ๋ฆฌ๋ทฐ ์š”์ฒญ (Diff ์ œ๊ณต) - Note over R: ์—์ด์ „ํŠธ ๊ต์ฐจ ๊ฒ€์ฆ (Claude, Hermes, Grok, OpenCode, Codex) - alt ๋ฆฌ๋ทฐ ํ”ผ๋“œ๋ฐฑ (NOT PASS) - R->>PM: NOT PASS (๋Œ€์•ˆ ์ฝ”๋“œ ๋ธ”๋ก๊ณผ ํ•จ๊ป˜ ํ”ผ๋“œ๋ฐฑ ์ „๋‹ฌ) - Note over PM: PM ์ง์ ‘ ์ˆ˜์ • ๋˜๋Š” ๋‹ค์‹œ ์œ„์ž„ ๊ฒฐ์ • - PM->>W: ๋ฆฌ๋ทฐ ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜ ์žฌ์š”์ฒญ - else ๊ฒ€์ฆ ํ†ต๊ณผ (PASS) - R->>PM: PASS + User->>L: --task, --creator, --reviewer / --all-reviewer + opt --plan + L->>P: write the plan (Creator challenges it for --plan-talk turns) end - PM->>User: ์ตœ์ข… ๋จธ์ง€ ์™„๋ฃŒ ๋ณด๊ณ  ๋ฐ ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ปค๋ฐ‹ + L->>C: implement and commit (skipped with --review-only) + loop up to --max-loop + L->>R: review the snapshot diff (base..head) + alt every reviewer PASS and the source unchanged + R-->>L: [VERDICT: PASS] + else NOT PASS + R-->>L: [VERDICT: NOT PASS] + findings + L->>C: fix (or [REBUT:] up to --max-rebut) + end + end + L->>User: reports promoted to .agents/reports// ``` ---- - -## ๐Ÿ”’ ๋ณด์•ˆ ํ”„๋กœํ† ์ฝœ ๋ฐ Replay ๊ณต๊ฒฉ ๋ฐฉ์–ด - -๊ณต์šฉ MQTT ๋ธŒ๋กœ์ปค ํ™˜๊ฒฝ์—์„œ๋„ ํ†ต์‹ ์˜ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด **HMAC-SHA256 ์•”ํ˜ธํ™” ์„œ๋ช…** ์ฒด๊ณ„๋ฅผ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค: -* **PoC ๋ชจ๋“œ (๋ฌด์ธ์ฆ):** ๊ธฐ๋ณธ ์„ค์ • ๋ชจ๋“œ๋กœ `auth_token`์ด `null`๋กœ ์„ธํŒ…๋˜์–ด ๊ฐ„๋‹จํ•œ ๋กœ์ปฌ ํ™˜๊ฒฝ ๊ฒ€์ฆ ์‹œ ์•”ํ˜ธํ™” ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ฒดํฌ๋ฅผ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค. -* **ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ (์ธ์ฆ ํ•„์ˆ˜):** ๊ฐ ์žก๋งˆ๋‹ค ๋ฌด์ž‘์œ„ ์•”ํ˜ธํ™” ํ† ํฐ์ด ๋ฐœ๊ธ‰๋˜๋ฉฐ, ๋ฐฑํ”Œ๋ ˆ์ธ์„ ์˜ค๊ฐ€๋Š” ๋ชจ๋“  ํŽ˜์ด๋กœ๋“œ์— ํ† ํฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ๋œ `hmac_sig` ์„œ๋ช…์„ ํƒ‘์žฌํ•ด์•ผ ์ˆ˜์‹ ์ธก์—์„œ ์ˆ˜์šฉํ•ฉ๋‹ˆ๋‹ค. -* **Replay ๊ณต๊ฒฉ ๋ฐฉ์–ด:** ๊ฐ ์ด๋ฒคํŠธ๋Š” ๋‹จ์กฐ ์ฆ๊ฐ€ํ•˜๋Š” ์ •์ˆ˜ํ˜• ์‹œํ€€์Šค ๋ฒˆํ˜ธ(`seq`)๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ๋…์ž(`job_subscriber.py`)๋Š” ํŠน์ • ์žก์— ๋Œ€ํ•ด ์ด๋ฏธ ์ˆ˜์šฉํ•œ ์ตœ๋Œ€ ์‹œํ€€์Šค ๋ฒˆํ˜ธ๋ณด๋‹ค ํฌ์ง€ ์•Š์€ ์‹œํ€€์Šค ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ฆ‰์‹œ ํ๊ธฐํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด๋กœ๋“œ ๋ฐ”๋””์— ๋Œ€ํ•œ HMAC ์„œ๋ช…๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ, ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ํด๋ก ๋™๊ธฐํ™”์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์žฌ์ „์†ก(re-injected) ๋ฐ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€ ํŒจํ‚ท์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€ ๋‚ด ํƒ€์ž„์Šคํƒฌํ”„ ํ•„๋“œ๋Š” ์ฐธ๊ณ ์šฉ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์ด๋ฉฐ, ๋ฐฑํ”Œ๋ ˆ์ธ์€ ์‹œ๊ฐ„ ์˜ค์ฐจ(clock-skew) ์œˆ๋„์šฐ๋ฅผ ๋ณ„๋„๋กœ ๊ฒ€์ฆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +- **์—„๊ฒฉํ•œ ํŒ์ •**: ํŒ์ • ํ† ํฐ์€ ๋ฆฌํฌํŠธ ๋งˆ์ง€๋ง‰ ์ค„์— ๋‹จ๋…์œผ๋กœ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŒ์ •์ด ์—†์œผ๋ฉด `NOT PASS` ๋กœ ๋ด…๋‹ˆ๋‹ค. +- **๋ฆฌ๋ทฐ identity** (`--worktree` / `--base`): ๋ผ์šด๋“œ๋งˆ๋‹ค ์ปค๋ฐ‹ํ•˜์ง€ ์•Š์€ ํŒŒ์ผ๊นŒ์ง€ ๋‹ด์€ ์Šค๋ƒ…์ƒท์„ ๋ฆฌ๋ทฐํ•ฉ๋‹ˆ๋‹ค. ๋ผ์šด๋“œ ์ค‘ ์†Œ์Šค๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ทธ ์Šน์ธ์€ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ๋ณด๊ด€๋˜๋Š” ๋ฆฌํฌํŠธ ์˜†์—๋Š” baseยทheadยทtreeยท๋ฆฌ๋ทฐ์–ด๋ฅผ ์ ์€ `report-.identity.json` ์ด ๋ถ™์Šต๋‹ˆ๋‹ค. +- **ํ•˜์œ„ ์žก**: creator ๊ฐ€ ์ž‘์—… ์ผ๋ถ€๋ฅผ ์œ„์ž„ํ•˜๋ฉด(`--parent-job`), ๋ฃจํ”„๋Š” ๋ฆฌ๋ทฐ ์ „์— ๊ทธ ์žก๋“ค์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์ƒํƒœ๋ฅผ ๋ฆฌ๋ทฐ์–ด์—๊ฒŒ ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค. --- -## ๐Ÿ“ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ตฌ์„ฑ +## ๐Ÿ” ๋ณด์•ˆ + +- **์„œ๋ช…๋œ ์ด๋ฒคํŠธ**: ํ† ํฐ์„ ์ง์ ‘ ๋„˜๊ธฐ๊ฑฐ๋‚˜ ๋ธŒ๋กœ์ปค๊ฐ€ TLS ๋˜๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ์“ฐ๋ฉด, ์žก์€ ๊ณ ์œ  ํ† ํฐ(`auth_token`)์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ๋•Œ ๋ชจ๋“  ์ด๋ฒคํŠธ์™€ retained ์ƒํƒœ ๋ฉ”์‹œ์ง€์— ๊ทธ ํ† ํฐ์œผ๋กœ ๋งŒ๋“  HMAC-SHA256 ์„œ๋ช…์ด ๋ถ™๊ณ , ๊ตฌ๋…์ž๋Š” ๊ฒ€์ฆ์— ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ์™€ ์ƒํƒœ ๋ฉ”์‹œ์ง€์—๋Š” ํ† ํฐ์ด ์•„๋‹ˆ๋ผ ์„œ๋ช…๋งŒ ์‹ค๋ฆฝ๋‹ˆ๋‹ค. TLS ๋„ ์‚ฌ์šฉ์ž ์ด๋ฆ„๋„ ์—†๋Š” ๋ธŒ๋กœ์ปค(PoC ๊ตฌ์„ฑ)์—์„œ๋Š” ์žก์— ํ† ํฐ์ด ์—†์–ด ์„œ๋ช…์„ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +- **์›๊ฒฉ ๋””์ŠคํŒจ์น˜์—๋Š” ํ† ํฐ์ด ์‹ค๋ฆฐ๋‹ค**: `remote:` ๋””์ŠคํŒจ์น˜ ๋ฉ”์‹œ์ง€์—๋Š” ์žก์˜ ํ† ํฐ์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค(`MAM_DISPATCH_SECRET` ์œผ๋กœ ์„œ๋ช…๋  ๋ฟ ์•”ํ˜ธํ™”๋˜์ง€๋Š” ์•Š์Œ). ์ ‘๊ทผ์ด ํ†ต์ œ๋œ ์‚ฌ์„ค ๋ธŒ๋กœ์ปค์—์„œ๋งŒ ์“ฐ์‹ญ์‹œ์˜ค. +- **์žฌ์ „์†ก๊ณผ ์ˆœ์„œ**: ์ด๋ฒคํŠธ๋งˆ๋‹ค ์ฆ๊ฐ€ํ•˜๋Š” `seq` ๊ฐ€ ๋ถ™์Šต๋‹ˆ๋‹ค. ๊ตฌ๋…์ž๋Š” ์ง€๊ธˆ๊นŒ์ง€ ๋ณธ ๊ฒƒ๋ณด๋‹ค ํฐ ๋ฒˆํ˜ธ๋งŒ ๋ฐ›๊ณ , ๋นˆ ๋ฒˆํ˜ธ๋Š” `seq_gap` ์œผ๋กœ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž„์Šคํƒฌํ”„๋Š” ์ฐธ๊ณ ์šฉ์ž…๋‹ˆ๋‹ค. +- **์ž๊ฒฉ ์ฆ๋ช…**: ๋ธŒ๋กœ์ปค ์ž๊ฒฉ ์ฆ๋ช…์€ `.mam.env` ์—๋งŒ ์žˆ๊ณ , ์žก ๋ ˆ์ฝ”๋“œ์—๋Š” ์—†์Šต๋‹ˆ๋‹ค. + +--- + +## ๐Ÿงช ํ…Œ์ŠคํŠธ + +```bash +.venv/bin/python -m pytest -q -p no:cacheprovider tests +``` + +- ํ…Œ์ŠคํŠธ๋Š” ์•ฝ 1,900 ๊ฐœ์ด๊ณ , ์ „์ฒด ์‹คํ–‰์— ํ•œ ์‹œ๊ฐ„ ๋„˜๊ฒŒ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. +- ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ์ž์ฒด MQTT ๋ธŒ๋กœ์ปค๋ฅผ ๋„์šฐ๋ฏ€๋กœ `.mam.env` ๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ `.mam.env` ๋ฅผ export ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. +- ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ HOMEยท๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท๊ฐ์‚ฌ ๋กœ๊ทธ ๋””๋ ‰ํ„ฐ๋ฆฌ์™€ mock herdr ๋ฅผ ์“ฐ๋Š” ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ๋•๋‹ˆ๋‹ค. + - ์‹ค์ œ herdr ๋ฅผ ๋‹ค๋ฃจ๋Š” ํ…Œ์ŠคํŠธ๋Š” ์ผํšŒ์šฉ herdr ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๋„์›๋‹ˆ๋‹ค. + - ์‹คํ–‰์ด ๋๋‚˜๋ฉด ์„ธ์…˜ ๋‹จ์œ„ ๊ฐ€๋“œ๊ฐ€ ์‹ค์ œ ์ œ์–ด ํ‰๋ฉด๊ณผ ์‚ฌ์šฉ์ž์˜ ์—์ด์ „ํŠธ ํ™ˆ(`~/.claude/projects`, `~/.codex`, `~/.gemini` โ€ฆ)์„ ํ™•์ธํ•˜๊ณ , ํ…Œ์ŠคํŠธ๊ฐ€ ๋‚จ๊ธด ํ•ญ๋ชฉ์ด ์žˆ์œผ๋ฉด ์‹คํ–‰์„ ์‹คํŒจ์‹œํ‚ต๋‹ˆ๋‹ค. +- ์ผ๋ถ€ ํ…Œ์ŠคํŠธ๋Š” ํ”Œ๋žซํผ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. Python 3.11+(`tomllib`), Linux(`/proc`), `nats-docker` ์„œ๋ธŒ๋ชจ๋“ˆ์ด ํ•„์š”ํ•œ ํ…Œ์ŠคํŠธ๋Š” ๊ทธ ๋ฐ–์˜ ํ™˜๊ฒฝ์—์„œ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค. + +--- + +## ๐Ÿ“ ์ €์žฅ์†Œ ๊ตฌ์กฐ ```text . โ”œโ”€โ”€ .agents/ -โ”‚ โ”œโ”€โ”€ MULTI_AGENT_RULES.md # ์—์ด์ „ํŠธ ์—ญํ•  ํ–‰๋™ ๊ฐ•๋ น ๋ฐ ๋ทฐํฌํŠธ ์Šค๋ƒ…์ƒท ๊ทœ์น™ -โ”‚ โ”œโ”€โ”€ MULTI_AGENT_RULES.ko.md # ์—์ด์ „ํŠธ ์—ญํ•  ํ–‰๋™ ๊ฐ•๋ น (ํ•œ๊ตญ์–ด ๋ฐฑ์—…) -โ”‚ โ””โ”€โ”€ skills/ # ์ฝ”์–ด ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์…ธ ์Šคํฌ๋ฆฝํŠธ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ -โ”‚ โ”œโ”€โ”€ lib.sh # ๊ณตํ†ต ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์…ธ ํ•จ์ˆ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ -โ”‚ โ”œโ”€โ”€ lib_py/ # ํŒŒ์ด์ฌ ์ฝ”์–ด ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์—”์ง„ -โ”‚ โ”‚ โ”œโ”€โ”€ agents/ # ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ CLI ์ˆ˜๋ช… ์ฃผ๊ธฐ ์–ด๋Œ‘ํ„ฐ -โ”‚ โ”‚ โ”œโ”€โ”€ delegation/ # ๋น„๋™๊ธฐ ์žก ์œ„์ž„ ๋ฐ CAS ์ƒํƒœ ์ „์ด ์—”์ง„ -โ”‚ โ”‚ โ””โ”€โ”€ loop/ # ์ž์œจ ๊ณ„ํš-์‹คํ–‰-๊ต์ฐจ๊ฒ€์ฆ ๋ฃจํ”„ ๋Ÿฐํƒ€์ž„ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-create/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-stop/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-resume/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-status/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-monitor/ -โ”‚ โ”œโ”€โ”€ multi-agent-mux-delegate-job/ -โ”‚ โ”‚ โ”œโ”€โ”€ requirements.txt # ํŒŒ์ด์ฌ ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ ์–ธ -โ”‚ โ”‚ โ””โ”€โ”€ scripts/ # ํ•˜์œ„ ํ˜ธํ™˜ shim ์Šคํฌ๋ฆฝํŠธ (Python) -โ”‚ โ”œโ”€โ”€ multi-agent-mux-loop/ -โ”‚ โ””โ”€โ”€ multi-agent-mux-orc-onboard/ -โ”œโ”€โ”€ .mam/ # Multi-Agent Mux ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ (git-ignored) -โ”‚ โ”œโ”€โ”€ agent-sessions.db # SQLite WAL ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค -โ”‚ โ”œโ”€โ”€ agent-sessions.yaml # ํ…์ŠคํŠธ ํ˜•์‹์˜ ์„ธ์…˜ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์Šค๋ƒ…์ƒท -โ”‚ โ””โ”€โ”€ jobs/ # ๋น„๋™๊ธฐ ์žก ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ JSON ํŒŒ์ผ๋“ค -โ”œโ”€โ”€ deploy/ # ๋ฐฐํฌ ๋ฐ ์„ค์น˜ ๋„๊ตฌ ํŒจํ‚ค์ง€ ํด๋” -โ”‚ โ”œโ”€โ”€ INSTALL.md # ์„ค์น˜ ๊ฐ€์ด๋“œ ๋ฐ ํ€ต์Šคํƒ€ํŠธ ๋งค๋‰ด์–ผ -โ”‚ โ”œโ”€โ”€ install_mam.sh # ๋กœ์ปฌ/ํด๋ก  ์ธ์Šคํ†จ๋Ÿฌ ์Šคํฌ๋ฆฝํŠธ -โ”‚ โ”œโ”€โ”€ generate-env.sh # ํ™˜๊ฒฝ ํŒŒ์ผ(.mam.env) ํ…œํ”Œ๋ฆฟ ๋ณต์‚ฌ ์Šคํฌ๋ฆฝํŠธ -โ”‚ โ”œโ”€โ”€ install.sh # ์›๊ฒฉ/๋„คํŠธ์›Œํฌ ์ธ์Šคํ†จ๋Ÿฌ ์Šคํฌ๋ฆฝํŠธ -โ”‚ โ”œโ”€โ”€ update.sh # ์—…๋ฐ์ดํŠธ ํ—ฌํผ ์Šคํฌ๋ฆฝํŠธ -โ”‚ โ””โ”€โ”€ remove.sh # ์‚ญ์ œ/์–ธ์ธ์Šคํ†จ ํ—ฌํผ ์Šคํฌ๋ฆฝํŠธ -โ”œโ”€โ”€ docs/ # ๊ธฐ์ˆ  ๊ทœ๊ฒฉ์„œ, ๊ฐ€์ด๋“œ ๋ฐ ์•„ํ‚คํ…์ฒ˜ ๊ณ„์•ฝ ๋ฌธ์„œ -โ”‚ โ”œโ”€โ”€ contracts/ # ์ด์Šˆ/๋ฐฑํ”Œ๋ ˆ์ธ ๊ณ„์•ฝ ๋ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋กœ๋“œ๋งต -โ”‚ โ”œโ”€โ”€ MAM_WEB_PTY_BRIDGE_PLAN.md # Web PTY ํ„ฐ๋ฏธ๋„ ๋ธŒ๋ฆฌ์ง€ ์„ค๊ณ„ ๊ณ„ํš์„œ -โ”‚ โ”œโ”€โ”€ NEW_AGENT_INTEGRATION_GUIDE.md # ์‹ ๊ทœ AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ ์—ฐ๋™ ๊ฐ€์ด๋“œ -โ”‚ โ””โ”€โ”€ OPENCODE_OLLAMA_GUIDE.md # OpenCode ์ธํ„ฐํ”„๋ฆฌํ„ฐ + Ollama ์—ฐ๋™ ๊ฐ€์ด๋“œ -โ”œโ”€โ”€ nats-docker/ # ์‚ฌ์„ค NATS ๋ธŒ๋กœ์ปค ๋ฐฐํฌ ์„œ๋ธŒ๋ชจ๋“ˆ -โ”œโ”€โ”€ tests/ # ์ข…ํ•ฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ (32๊ฐœ ๋ชจ๋“ˆ) -โ”œโ”€โ”€ AGENTS.md # ์—์ด์ „ํŠธ ํ–‰๋™ ์ง€์นจ ๋ฐ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์Šค์ฝ”ํ”„ ๊ฐ€๋“œ -โ”œโ”€โ”€ BOOTSTRAP.ko.md # ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ ์„ค์น˜ ๊ฐ€์ด๋“œ (ํ•œ๊ตญ์–ด ๋ฐฑ์—…) -โ”œโ”€โ”€ BOOTSTRAP.md # ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ ์„ค์น˜ ๋ฐ ๊ฒ€์ฆ ์ƒ์„ธ ๊ฐ€์ด๋“œ -โ”œโ”€โ”€ IMPROVEMENTS.md # ์ด์Šˆ ๋ฐฑ๋กœ๊ทธ ๋ฐ ์™„๋ฃŒ๋œ ์•„ํ‚คํ…์ฒ˜ ๊ณผ์ œ ์ถ”์  ์›์žฅ -โ”œโ”€โ”€ MESSAGING.md # MQTT ๋ฉ”์‹œ์ง• ํ”„๋กœํ† ์ฝœ ์™€์ด์–ด ๊ทœ๊ฒฉ์„œ -โ”œโ”€โ”€ README.ko.md # ํ”„๋กœ์ ํŠธ ๋Œ€ํ‘œ ์†Œ๊ฐœ ํŒŒ์ผ (ํ•œ๊ตญ์–ด) -โ”œโ”€โ”€ README.md # ํ”„๋กœ์ ํŠธ ๋Œ€ํ‘œ ์†Œ๊ฐœ ํŒŒ์ผ (์˜๋ฌธ ์›๋ณธ) -โ””โ”€โ”€ VERSIONS.md # ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ ๋ฐ 4-way ๋ฝ์Šคํ… ๋ฒ„์ „ ์›์žฅ +โ”‚ โ”œโ”€โ”€ MULTI_AGENT_RULES.md / .ko.md # ์—ญํ• , ์›Œํฌํ”Œ๋กœ์šฐ, ํ˜‘์—… ๊ทœ์น™ +โ”‚ โ”œโ”€โ”€ reports/ # ๋ณด๊ด€๋œ ๋ฆฌ๋ทฐ ๋ฆฌํฌํŠธ (+ identity ์‚ฌ์ด๋“œ์นด) +โ”‚ โ””โ”€โ”€ skills/ +โ”‚ โ”œโ”€โ”€ lib.sh # ๊ณต์šฉ ์…ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (herdr shim, ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์“ฐ๊ธฐ) +โ”‚ โ”œโ”€โ”€ lib_py/ # Python ์ฝ”์–ด +โ”‚ โ”‚ โ”œโ”€โ”€ agents/ # ์—์ด์ „ํŠธ๋ณ„ CLI ์–ด๋Œ‘ํ„ฐ (spawn/resume/discover) +โ”‚ โ”‚ โ”œโ”€โ”€ delegation/ # ์žก ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ, ๋ž˜ํผ, MQTT ๋ฐœํ–‰/๊ตฌ๋…, ์›๊ฒฉ ๋Ÿฌ๋„ˆ +โ”‚ โ”‚ โ”œโ”€โ”€ loop/ # ๋ฆฌ๋ทฐ ๋ฃจํ”„ ๋Ÿฐํƒ€์ž„ +โ”‚ โ”‚ โ””โ”€โ”€ *.py # pane_lock, stall_watch, worktree, herdr_config, ... +โ”‚ โ””โ”€โ”€ multi-agent-mux-*/ # ์Šคํ‚ฌ๋งˆ๋‹ค ๋””๋ ‰ํ„ฐ๋ฆฌ ํ•˜๋‚˜ (SKILL.md + scripts/) +โ”œโ”€โ”€ .mam/ # ๋Ÿฐํƒ€์ž„ ์ƒํƒœ (git ์ œ์™ธ): ์„ธ์…˜, ์žก, ๊ฐ์‚ฌ ๋กœ๊ทธ, shim +โ”œโ”€โ”€ deploy/ # install.sh, install_mam.sh, update.sh, remove.sh, generate-env.sh +โ”œโ”€โ”€ docs/ # contracts/, design/, ์—์ด์ „ํŠธ ํ†ตํ•ฉยท๋ธŒ๋ฆฌ์ง€ ๊ฐ€์ด๋“œ +โ”œโ”€โ”€ nats-docker/ # ์‚ฌ์„ค NATS ๋ธŒ๋กœ์ปค ๋ฐฐํฌ (์„œ๋ธŒ๋ชจ๋“ˆ) +โ”œโ”€โ”€ tests/ # pytest ์Šค์œ„ํŠธ +โ”œโ”€โ”€ AGENTS.md # ์—์ด์ „ํŠธ ํ–‰๋™ ์ง€์นจ +โ”œโ”€โ”€ BOOTSTRAP.md / BOOTSTRAP.ko.md # ๋‹จ๊ณ„๋ณ„ ์„ค์น˜ยท๊ฒ€์ฆ ๊ฐ€์ด๋“œ +โ”œโ”€โ”€ IMPROVEMENTS.md # ๋ฐฑ๋กœ๊ทธ +โ”œโ”€โ”€ MESSAGING.md # MQTT ์™€์ด์–ด ํ”„๋กœํ† ์ฝœ๊ณผ ์œ„์ž„ ๊ณ„์•ฝ +โ”œโ”€โ”€ README.md # ์˜๋ฌธ README +โ””โ”€โ”€ VERSIONS.md # ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ (๋ฝ์Šคํ… ๋ฒ„์ „ ์›์žฅ) ``` --- ## ๐Ÿšฆ ๋น ๋ฅธ ์‹œ์ž‘ -์ž์„ธํ•œ ๋นŒ๋“œ ์ ˆ์ฐจ๋Š” **[BOOTSTRAP.md](./BOOTSTRAP.md)** ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. ์•„๋ž˜๋Š” ๊ฐ„๋žตํ•œ ์š”์•ฝ์ž…๋‹ˆ๋‹ค: +์ „์ฒด ๊ณผ์ •์€ [BOOTSTRAP.ko.md](BOOTSTRAP.ko.md)๋ฅผ ๋ณด์‹ญ์‹œ์˜ค. ์š”์•ฝํ•˜๋ฉด: -1. **ํ™˜๊ฒฝ ์„ค์ • ํŒŒ์ผ(.mam.env) ์ƒ์„ฑ:** - ```bash - ./deploy/generate-env.sh - ``` -2. **๊ฐ€์ƒํ™˜๊ฒฝ ์ƒ์„ฑ ๋ฐ ์˜์กด์„ฑ ํŒจํ‚ค์ง€ ์„ค์น˜:** - ```bash - python3 -m venv .venv - source .venv/bin/activate - pip install -r .agents/skills/multi-agent-mux-delegate-job/requirements.txt - ``` -3. **๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋ฐ ํ™˜๊ฒฝ ์ž‘๋™ ์ž๊ฐ€ ๊ฒ€์ฆ:** - ```bash - .venv/bin/python3 .agents/skills/multi-agent-mux-delegate-job/scripts/registry.py list - ``` +```bash +# 1. ์›Œํฌ์ŠคํŽ˜์ด์Šค์— ์„ค์น˜ํ•œ ๋’ค .mam.env ์— ๋ธŒ๋กœ์ปค๋ฅผ ์„ค์ • +bash deploy/install.sh + +# 2. ์ „์šฉ herdr ์„œ๋ฒ„์—์„œ creator ์™€ reviewer ์‹œ์ž‘ +bash .agents/skills/multi-agent-mux-create/scripts/create_session.sh \ + --workspace "$PWD" --agent claude --role developer --session creator-claude-01 \ + --herdr-session my-project --onboard +bash .agents/skills/multi-agent-mux-create/scripts/create_session.sh \ + --workspace "$PWD" --agent codex --role reviewer --session reviewer-codex-01 \ + --herdr-session my-project --onboard + +# 3. ์„ธ์…˜ ํ™•์ธ +bash .agents/skills/multi-agent-mux-status/scripts/status.sh + +# 4. ๋ฃจํ”„๋กœ ์ž‘์—… ์‹คํ–‰ +bash .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh \ + --creator creator-claude-01 --all-reviewer --task "Fix the typo in docs/guide.md" +``` --- -## ๐Ÿ“ ํ˜‘์—… ์—์ด์ „ํŠธ ์ค€์ˆ˜ ์‚ฌํ•ญ +## ๐Ÿ“ ํ”„๋กœ์ ํŠธ์— ํ•ฉ๋ฅ˜ํ•˜๋Š” ์—์ด์ „ํŠธ์—๊ฒŒ -์ด ํ”„๋กœ์ ํŠธ์— ์ƒˆ๋กœ ํ•ฉ๋ฅ˜ํ•œ ์—์ด์ „ํŠธ๋Š” ๋‹ค์Œ ๊ทœ์น™์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค: -1. **[MULTI_AGENT_RULES.md](.agents/MULTI_AGENT_RULES.md)** ๋ฌธ์„œ๋ฅผ ์ •๋…ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ๋งค๋‹ˆ์ €(PM), ์ž‘์—…์ž(Worker), ๋ฆฌ๋ทฐ์–ด(Reviewer) ๊ฐ„์˜ ์—ญํ•  ๋ฐ ๊ฐœ๋ฐœ ์ œ์•ฝ์กฐ๊ฑด์„ ์ธ์ง€ํ•˜์‹ญ์‹œ์˜ค. -2. ์žฅ์‹œ๊ฐ„ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ํ„ฐ๋ฏธ๋„ ์Šคํฌ๋กค๋ฐฑ ๋กœ๊ทธ ์œ ์‹ค์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด `MULTI_AGENT_RULES.md` (์ œ4์žฅ)์— ๊ธฐ์žฌ๋œ **๋ทฐํฌํŠธ ์Šค๋ƒ…์ƒท ๊ทœ์น™(Pane Snapshotting Rules)**์„ ๋ฐ˜๋“œ์‹œ ์ ์šฉํ•˜์‹ญ์‹œ์˜ค. -3. ๋ฆฌ๋ทฐ์–ด ์„ธ์…˜์— diff ๊ฒ€์ฆ์„ ์š”์ฒญํ•˜๊ธฐ ์ „์—๋Š” ์–ด๋– ํ•œ ์ฝ”์–ด ํŒŒ์ผ์˜ ์ž„์˜ ์ˆ˜์ •๋„ ํ”„๋กœ๋•์…˜ ๋ธŒ๋žœ์น˜์— ์Šน์ธ ์—†์ด ๋จธ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. +1. ์—ญํ• ๊ณผ ๊ทœ์น™์€ [AGENTS.md](AGENTS.md)์™€ [MULTI_AGENT_RULES.ko.md](.agents/MULTI_AGENT_RULES.ko.md)๋ฅผ ์ฝ์œผ์‹ญ์‹œ์˜ค. +2. ๊ธด ์ถœ๋ ฅ์ด pane ์Šคํฌ๋กค๋ฐฑ ๋ฐ–์œผ๋กœ ์‚ฌ๋ผ์ง€์ง€ ์•Š๋„๋ก `MULTI_AGENT_RULES.ko.md` ยง4 ์˜ ์Šค๋ƒ…์ƒท ๊ทœ์น™์„ ๋”ฐ๋ฅด์‹ญ์‹œ์˜ค. +3. ๋ธŒ๋ฆฌํ”„๊ฐ€ ์ง€์‹œํ•˜๋Š” ๋Œ€๋กœ ์žก ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ•˜์‹ญ์‹œ์˜ค(`started --heartbeat`, ๊ทธ๋‹ค์Œ `completed` ๋˜๋Š” `error`). ๋ฆฌ๋ทฐ๋ฐ›์€ diff ์—†์ด ํ•ต์‹ฌ ๋กœ์ง์„ ๋ฐ”๊พธ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. diff --git a/README.md b/README.md index be5a8cf..256284b 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Long agent runs break in predictable ways: a session dies with its terminal, two 1. **Isolated, resumable agent sessions.** Each agent runs in its own herdr pane, usually on a herdr server dedicated to the workspace. Sessions are recorded in `.mam/agent-sessions.yaml` (backed by SQLite) with their conversation ids, so a stopped agent resumes the same conversation later. 2. **Jobs decided by events, not by the screen.** A delegated job is a registry record plus an MQTT event stream (`started`, `progress`, `completed`, `error`). The agent must acknowledge the prompt within a deadline and heartbeat while it works. A job is closed only by a protocol event or a timeout, never by reading the terminal. 3. **One job per session at a time.** Before injecting a prompt, the dispatcher waits by the registry for the session's earlier jobs (onboarding included) to end. Pane placement is serialised per herdr server, so concurrent `create` calls do not take the same pane. -4. **Reviewed loops with pinned evidence.** `multi-agent-mux-loop` sends a change to every registered reviewer and requires a unanimous `PASS`. With `--worktree`/`--base`, each review round is bound to a snapshot of the source. If the source changes during the round, its approvals are discarded and the round is reviewed again. +4. **Reviewed loops with pinned evidence.** `multi-agent-mux-loop` sends a change to the reviewers you select and requires every one of them to `PASS`. You can name reviewers with `--reviewer` or take every running reviewer with `--all-reviewer`; without either, the creator reviews its own work. With `--worktree`/`--base`, each review round is bound to a snapshot of the source. If the source changes during the round, its approvals are discarded and the round is reviewed again. --- @@ -31,14 +31,14 @@ or, from a local clone: bash deploy/install.sh ``` -The installer is idempotent. It does the following: -- checks the dependencies (herdr, `python3` with PyYAML and sqlite3, rsync, uuidgen); -- copies `.agents/` and the templates; +`install.sh` is idempotent. It does the following: +- checks that herdr and Python 3.9+ are installed, and that the system `python3` has PyYAML; +- copies `.agents/` and `.mam.env.example` into the workspace; - creates `.venv` and installs `paho-mqtt` and PyYAML into it; -- writes `.mam.env` from `.mam.env.example`; +- writes a starter `.mam.env` with `MQTT_BROKER=localhost`. An existing `.mam.env` is kept, and a legacy `.env` is renamed to `.mam.env`; - adds `.venv`, `.mam/` and `.mam.env` to `.gitignore`. -Configure the broker in `.mam.env`. The default is the public `broker.hivemq.com`, which is fine for a trial but not for real work. See [MESSAGING.md](MESSAGING.md) for a private broker. `deploy/update.sh` and `deploy/remove.sh` update and uninstall. +Point `MQTT_BROKER` in `.mam.env` at a broker you run (see [MESSAGING.md](MESSAGING.md) for a private broker). If `MQTT_BROKER` is not set at all, the code falls back to the public `broker.hivemq.com`. That is fine for a trial, but not for real work. `deploy/generate-env.sh` recreates `.mam.env` from `.mam.env.example`. `deploy/update.sh` and `deploy/remove.sh` update and uninstall. `deploy/install_mam.sh` is a separate installer that copies from a local clone into another directory. --- @@ -54,14 +54,14 @@ Every skill lives under `.agents/skills/` with a `SKILL.md` that documents its o | **`multi-agent-mux-status`** | Read-only snapshot of every session: registry status, herdr liveness, pane command and cwd, resume id, drift. | | **`multi-agent-mux-monitor`** | Long-running reconciler (`reconcile.sh --subscribe`). It reacts to job events, falls back to polling when the broker is down, and fixes registry drift. For example, it marks dead sessions `terminated` and registers live sessions the registry does not know. | | **`multi-agent-mux-delegate-job`** | Delegates a job to a session (`herdr:`) or to a runner on another host (`remote:`) and waits for its result. See [Delegation contract](#-delegation-contract). | -| **`multi-agent-mux-loop`** | Plan, implement, review: an optional planner and a creator, then one or all reviewers until a unanimous `PASS` or `--max-loop`. It also supports `--review-only` for work finished outside the loop. Passing reports are promoted to `.agents/reports//`. | +| **`multi-agent-mux-loop`** | Plan, implement, review: an optional planner and a creator, then the selected reviewers (`--reviewer A,B`, or `--all-reviewer` for every running reviewer except the creator) until all of them `PASS` or `--max-loop` is reached. With neither option the creator reviews its own work. `--review-only` reviews work finished outside the loop. Passing reports are promoted to `.agents/reports//`. | | **`multi-agent-mux-orc-onboard`** | Registers the orchestrator's own session id, so session discovery never mistakes it for a sub-agent. | --- ## ๐Ÿ“ Architecture -MAM has two layers that share one registry: +MAM has two layers, each with its own registry: 1. **Sessions (herdr)**: `lib.sh` and the create/stop/resume/status/monitor scripts run the agents and keep `.mam/agent-sessions.yaml` (+ `.mam/agent-sessions.db`) authoritative. 2. **Jobs (delegation)**: `lib_py/delegation/` registers a job in `.mam/jobs/.json`, injects the brief, and follows the job's events over MQTT. Every event is also appended to the job's audit log `.mam/delegate_job_logs//`. @@ -87,15 +87,15 @@ MAM has two layers that share one registry: ### ๐Ÿ”’ Herdr server isolation -- **Dedicated server per workspace (opt-in).** `create --herdr-session ` (or `HERDR_SESSION_NAME`) runs the agents on their own herdr server and socket, separate from your default herdr. The server name is recorded on the session row, and every later command routes to it. -- **The shim.** Sourcing `lib.sh` writes `/.mam/shim/herdr` and puts it first on `PATH`. The shim provides the tmux-style commands the scripts use (`new-session`, `has-session`, โ€ฆ) on top of herdr's agent API. It routes each call with `--session `, and it starts the server headless if the server is not running. -- **No surprise relaunches.** A server MAM starts uses your herdr config with `resume_agents_on_restore = false`. A herdr restart therefore does not relaunch saved agents without their permission flags. +- **A dedicated server per workspace.** By default `create` runs the agents on a herdr server named after the workspace (its slug), with its own socket, separate from your default herdr. `--herdr-session ` or `HERDR_SESSION_NAME` picks another name. The server name is recorded on the session row, and every later command routes to it. +- **The shim.** Sourcing `lib.sh` writes `/.mam/shim/herdr` and puts it first on `PATH`. The shim provides the tmux-style commands the scripts use (`new-session`, `has-session`, โ€ฆ) on top of herdr's agent API. For a named server it adds `--session ` to each call, and it starts that server headless if it is not running. It does not start one when `MAM_NO_AUTOSTART=1`, which `status` and `monitor` set, so looking never starts a server. Calls for the `default` server go to your ambient herdr unchanged. +- **No surprise relaunches.** A server MAM starts normally uses your herdr config plus `resume_agents_on_restore = false`. A herdr restart therefore does not relaunch saved agents without their permission flags. If that config cannot be built, the bootstrap prints a warning and the server starts with restore on. - **One pane claim at a time.** Pane placement holds a per-server lock (`lib_py/pane_lock.py`, `flock` on macOS and Linux). Concurrent `create` calls in one folder each get their own pane. ### ๐Ÿ›ก๏ธ Registry writes and concurrency - **Serialised writes.** Every change to `agent-sessions.yaml` goes through `lib.sh::atomic_dump_yaml`. It runs under an exclusive SQLite transaction (`BEGIN IMMEDIATE`) on `.mam/agent-sessions.db` and is validated before the YAML is rewritten atomically. Job records use their own registry lock. -- **One interpreter.** The scripts run their Python in the workspace `.venv` (`AGENT_PYTHON_BIN`, else the active or nearest `.venv`). +- **Python interpreter.** Registry writes and the delegation helpers pick their Python in this order: `AGENT_PYTHON_BIN`, the active virtualenv, the nearest `.venv` above the skills, then `python3` on `PATH`. Some shell paths, such as the shim and parts of `create`, call `python3` from `PATH` directly. - **Network filesystems.** If `.mam/` is on NFS/CIFS/SSHFS, `lib.sh` warns, and SQLite switches its journal from `WAL` to `DELETE`. - **One loop per checkout.** A loop lock refuses a second `run_loop.sh` in the same control plane. @@ -117,7 +117,7 @@ The full specification is in [MESSAGING.md ยง2.5](MESSAGING.md). | `1` | failure, or no `started` within T | | `2` | no event for Kร—N (`deadline_timeout`) or budget spent (`wall_clock_timeout`) | | `3` | broker unavailable, and no terminal status on disk | -| `5` | session busy, or the record was taken over while waiting (never delivered) | +| `5` | not delivered (`cancelled`): the session was busy, the target was not found, or the record was taken over while waiting | --- @@ -157,9 +157,10 @@ sequenceDiagram ## ๐Ÿ” Security -- **Signed events**: every job gets its own token (`auth_token`). Each event and each retained state message carries an HMAC-SHA256 signature made with it, and the subscriber drops anything that fails verification. The token itself never goes over the wire. +- **Signed events**: a job gets its own token (`auth_token`) when you pass one, or automatically when the broker uses TLS or a username. Each event and each retained state message then carries an HMAC-SHA256 signature made with it, and the subscriber drops anything that fails verification. Events and state messages carry only the signature, not the token. On a broker with neither TLS nor a username (the PoC setup), a job has no token and signatures are not checked. +- **Remote dispatch carries the token**: the `remote:` dispatch message includes the job's token (signed with `MAM_DISPATCH_SECRET`, not encrypted). Use it only on an access-controlled private broker. - **Replay and ordering**: each event carries an increasing `seq`. The subscriber accepts only sequence numbers higher than any it has seen and records gaps as `seq_gap`. Timestamps are informational only. -- **Credentials**: broker credentials live only in `.mam.env` (never in a job record). Remote dispatch is signed with `MAM_DISPATCH_SECRET`. +- **Credentials**: broker credentials live only in `.mam.env`, never in a job record. --- @@ -171,10 +172,9 @@ sequenceDiagram - The suite has about 1,900 tests, and a full run takes over an hour. - It runs its own in-process MQTT broker, so it never needs `.mam.env`. Don't export `.mam.env` for tests. -- Tests run in sandboxes: - - they never write to the checkout's `.mam/`, your agent homes (`~/.claude/projects`, `~/.codex`, `~/.gemini`, โ€ฆ) or your herdr config; - - a test that does not use the mock herdr starts its own throwaway herdr server; - - session-level guards fail the run if a test leaves files behind in the real control plane or in an agent home. +- Tests run in sandboxes, with a temporary HOME, registry and audit-log directory, and a mock herdr: + - the tests that drive a real herdr start their own throwaway herdr server; + - after the run, session-level guards check the real control plane and your agent homes (`~/.claude/projects`, `~/.codex`, `~/.gemini`, โ€ฆ) and fail the run if a test left entries there. - Some tests are platform-specific. A few need Python 3.11+ (`tomllib`), Linux (`/proc`) or the `nats-docker` submodule; elsewhere they are skipped. --- @@ -219,16 +219,18 @@ bash deploy/install.sh # 2. Start a creator and a reviewer on a dedicated herdr server bash .agents/skills/multi-agent-mux-create/scripts/create_session.sh \ - --workspace "$PWD" --agent claude --role developer --herdr-session my-project --onboard + --workspace "$PWD" --agent claude --role developer --session creator-claude-01 \ + --herdr-session my-project --onboard bash .agents/skills/multi-agent-mux-create/scripts/create_session.sh \ - --workspace "$PWD" --agent codex --role reviewer --herdr-session my-project --onboard + --workspace "$PWD" --agent codex --role reviewer --session reviewer-codex-01 \ + --herdr-session my-project --onboard # 3. Check the sessions bash .agents/skills/multi-agent-mux-status/scripts/status.sh # 4. Run a task through the loop bash .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh \ - --creator --all-reviewer --task "Fix the typo in docs/guide.md" + --creator creator-claude-01 --all-reviewer --task "Fix the typo in docs/guide.md" ``` --- From ae2813773c973daedd2275cb55ad340a682c3fae Mon Sep 17 00:00:00 2001 From: Godopu Date: Tue, 13 Oct 2026 11:32:01 +0900 Subject: [PATCH 3/5] docs(readme): round-2 review fixes (00aa4a4c / 09bf3e77) - exit 5: a busy or missing target cancels the job; a superseded attempt leaves the record to its new owner, unchanged - install.sh copies a legacy .env to .mam.env and keeps the original - restore-off fallback: without tomllib the file keeps only that key (restore off, other settings lost, warning); restore on only when no file can be written - PoC: no token only when none is passed; tests: every test gets a temp registry and log dir, most also the sandbox HOME and mock herdr Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff --- README.ko.md | 10 +++++----- README.md | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.ko.md b/README.ko.md index b065174..268bf77 100644 --- a/README.ko.md +++ b/README.ko.md @@ -35,7 +35,7 @@ bash deploy/install.sh - herdr ์™€ Python 3.9+ ๊ฐ€ ์„ค์น˜๋ผ ์žˆ๋Š”์ง€, ์‹œ์Šคํ…œ `python3` ์— PyYAML ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. - `.agents/` ์™€ `.mam.env.example` ์„ ์›Œํฌ์ŠคํŽ˜์ด์Šค์— ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. - `.venv` ๋ฅผ ๋งŒ๋“ค๊ณ  `paho-mqtt`ยทPyYAML ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. -- `MQTT_BROKER=localhost` ๋กœ ๋œ ์ดˆ๊ธฐ `.mam.env` ๋ฅผ ์”๋‹ˆ๋‹ค. ์ด๋ฏธ ์žˆ๋Š” `.mam.env` ๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ , ์˜ˆ์ „ `.env` ๋Š” `.mam.env` ๋กœ ์ด๋ฆ„์„ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. +- `MQTT_BROKER=localhost` ๋กœ ๋œ ์ดˆ๊ธฐ `.mam.env` ๋ฅผ ์”๋‹ˆ๋‹ค. ์ด๋ฏธ ์žˆ๋Š” `.mam.env` ๋Š” ๊ทธ๋Œ€๋กœ ๋‘ก๋‹ˆ๋‹ค. ์˜ˆ์ „ `.env` ๋งŒ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„ `.mam.env` ๋กœ ๋ณต์‚ฌํ•˜๊ณ  ์›๋ณธ์€ ๋‚จ๊น๋‹ˆ๋‹ค. - `.venv`, `.mam/`, `.mam.env` ๋ฅผ `.gitignore` ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. `.mam.env` ์˜ `MQTT_BROKER` ๋ฅผ ์ง์ ‘ ์šด์˜ํ•˜๋Š” ๋ธŒ๋กœ์ปค๋กœ ๋ฐ”๊พธ์‹ญ์‹œ์˜ค(์‚ฌ์„ค ๋ธŒ๋กœ์ปค๋Š” [MESSAGING.md](MESSAGING.md) ์ฐธ๊ณ ). `MQTT_BROKER` ๊ฐ€ ์•„์˜ˆ ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด ์ฝ”๋“œ๋Š” ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค `broker.hivemq.com` ์„ ์”๋‹ˆ๋‹ค. ์‹œํ—˜์šฉ์œผ๋กœ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ์‹ค์ œ ์ž‘์—…์šฉ์€ ์•„๋‹™๋‹ˆ๋‹ค. `deploy/generate-env.sh` ๋Š” `.mam.env.example` ๋กœ `.mam.env` ๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ์™€ ์ œ๊ฑฐ๋Š” `deploy/update.sh`, `deploy/remove.sh` ์ž…๋‹ˆ๋‹ค. `deploy/install_mam.sh` ๋Š” ๋กœ์ปฌ ํด๋ก ์—์„œ ๋‹ค๋ฅธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ๋ณต์‚ฌํ•ด ์„ค์น˜ํ•˜๋Š” ๋ณ„๋„ ์„ค์น˜๊ธฐ์ž…๋‹ˆ๋‹ค. @@ -89,7 +89,7 @@ MAM ์€ ๊ฐ์ž ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๊ฐ€์ง„ ๋‘ ๊ณ„์ธต์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. - **์›Œํฌ์ŠคํŽ˜์ด์Šค ์ „์šฉ ์„œ๋ฒ„.** `create` ๋Š” ๊ธฐ๋ณธ์œผ๋กœ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ด๋ฆ„(slug)์„ ๋”ด herdr ์„œ๋ฒ„์—์„œ ์—์ด์ „ํŠธ๋ฅผ ๋Œ๋ฆฝ๋‹ˆ๋‹ค. ์ด ์„œ๋ฒ„๋Š” ๊ธฐ๋ณธ herdr ์™€ ๋ถ„๋ฆฌ๋œ ์ž๊ธฐ ์†Œ์ผ“์„ ์”๋‹ˆ๋‹ค. `--herdr-session ` ๋˜๋Š” `HERDR_SESSION_NAME` ์œผ๋กœ ๋‹ค๋ฅธ ์ด๋ฆ„์„ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ด๋ฆ„์€ ์„ธ์…˜ ํ–‰์— ๊ธฐ๋ก๋˜๊ณ , ์ดํ›„ ๋ชจ๋“  ๋ช…๋ น์ด ๊ทธ ์„œ๋ฒ„๋กœ ๊ฐ‘๋‹ˆ๋‹ค. - **shim.** `lib.sh` ๋ฅผ source ํ•˜๋ฉด `/.mam/shim/herdr` ๋ฅผ ์“ฐ๊ณ  `PATH` ๋งจ ์•ž์— ๋‘ก๋‹ˆ๋‹ค. shim ์€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์“ฐ๋Š” tmux ์‹ ๋ช…๋ น(`new-session`, `has-session` โ€ฆ)์„ herdr ์˜ ์—์ด์ „ํŠธ API ์œ„์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„ ์žˆ๋Š” ์„œ๋ฒ„๋ฉด ํ˜ธ์ถœ๋งˆ๋‹ค `--session ` ๋ฅผ ๋ถ™์ด๊ณ , ๊ทธ ์„œ๋ฒ„๊ฐ€ ๋Œ๊ณ  ์žˆ์ง€ ์•Š์œผ๋ฉด ํ—ค๋“œ๋ฆฌ์Šค๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ `MAM_NO_AUTOSTART=1` ์ด๋ฉด ์‹œ์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. `status` ์™€ `monitor` ๊ฐ€ ์ด ๊ฐ’์„ ์„ค์ •ํ•˜๋ฏ€๋กœ, ์กฐํšŒ๋งŒ์œผ๋กœ ์„œ๋ฒ„๊ฐ€ ๋œจ๋Š” ์ผ์€ ์—†์Šต๋‹ˆ๋‹ค. `default` ์„œ๋ฒ„ ํ˜ธ์ถœ์€ ๋ฐ”๊พธ์ง€ ์•Š๊ณ  ์‚ฌ์šฉ์ž์˜ herdr ๋กœ ๊ทธ๋Œ€๋กœ ๊ฐ‘๋‹ˆ๋‹ค. -- **์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์žฌ์‹คํ–‰ ์—†์Œ.** MAM ์ด ์‹œ์ž‘ํ•œ ์„œ๋ฒ„๋Š” ๋ณดํ†ต ์‚ฌ์šฉ์ž์˜ herdr ์„ค์ •์— `resume_agents_on_restore = false` ๋ฅผ ๋”ํ•ด ์”๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ herdr ๊ฐ€ ์žฌ์‹œ์ž‘๋ผ๋„ ์ €์žฅ๋œ ์—์ด์ „ํŠธ๋ฅผ ๊ถŒํ•œ ํ”Œ๋ž˜๊ทธ ์—†์ด ๋‹ค์‹œ ๋„์šฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์„ค์ •์„ ๋งŒ๋“ค ์ˆ˜ ์—†์œผ๋ฉด ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์ด ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธฐ๊ณ , ์„œ๋ฒ„๋Š” restore ๊ฐ€ ์ผœ์ง„ ์ฑ„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. +- **์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์žฌ์‹คํ–‰ ์—†์Œ.** MAM ์ด ์‹œ์ž‘ํ•œ ์„œ๋ฒ„๋Š” ๋ณดํ†ต ์‚ฌ์šฉ์ž์˜ herdr ์„ค์ •์— `resume_agents_on_restore = false` ๋ฅผ ๋”ํ•ด ์”๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ herdr ๊ฐ€ ์žฌ์‹œ์ž‘๋ผ๋„ ์ €์žฅ๋œ ์—์ด์ „ํŠธ๋ฅผ ๊ถŒํ•œ ํ”Œ๋ž˜๊ทธ ์—†์ด ๋‹ค์‹œ ๋„์šฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. `tomllib` ์ด ์—†๋Š” Python(macOS ๊ธฐ๋ณธ 3.9 ๋“ฑ)์—์„œ๋Š” ์ด ํŒŒ์ผ์— ๊ทธ ํ‚ค๋งŒ ๋“ค์–ด๊ฐ€๋ฏ€๋กœ, restore ๋Š” ๊บผ์ง€์ง€๋งŒ ์‚ฌ์šฉ์ž์˜ ๋‹ค๋ฅธ herdr ์„ค์ •์€ ๋ฐ˜์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋•Œ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์ด ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ์„ค์ • ํŒŒ์ผ์„ ์•„์˜ˆ ์“ฐ์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ์—๋งŒ ์„œ๋ฒ„๊ฐ€ restore ๊ฐ€ ์ผœ์ง„ ์ฑ„ ์‹œ์ž‘ํ•˜๋ฉฐ, ์ด๋•Œ๋„ ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊น๋‹ˆ๋‹ค. - **pane ๋ฐฐ์น˜๋Š” ํ•œ ๋ฒˆ์— ํ•˜๋‚˜.** pane ๋ฐฐ์น˜๋Š” ์„œ๋ฒ„๋ณ„ ์ž ๊ธˆ(`lib_py/pane_lock.py`, macOSยทLinux ์—์„œ `flock`)์„ ์žก๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ•œ ํด๋”์—์„œ ๋™์‹œ์— ์‹คํ–‰ํ•œ `create` ๋„ ๊ฐ์ž ์ž๊ธฐ pane ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ### ๐Ÿ›ก๏ธ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์“ฐ๊ธฐ์™€ ๋™์‹œ์„ฑ @@ -117,7 +117,7 @@ MAM ์€ ๊ฐ์ž ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๊ฐ€์ง„ ๋‘ ๊ณ„์ธต์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. | `1` | ์‹คํŒจ, ๋˜๋Š” T ์•ˆ์— `started` ์—†์Œ | | `2` | Kร—N ๋™์•ˆ ์ด๋ฒคํŠธ ์—†์Œ(`deadline_timeout`) ๋˜๋Š” ์˜ˆ์‚ฐ ์†Œ์ง„(`wall_clock_timeout`) | | `3` | ๋ธŒ๋กœ์ปค๋ฅผ ์“ธ ์ˆ˜ ์—†๊ณ , ๋””์Šคํฌ์—๋„ ์ข…๊ฒฐ ์ƒํƒœ๊ฐ€ ์—†์Œ | -| `5` | ์ „๋‹ฌ ์•ˆ ๋จ(`cancelled`): ์„ธ์…˜์ด ๋ฐ”์จ, ๋Œ€์ƒ์„ ์ฐพ์ง€ ๋ชปํ•จ, ๋˜๋Š” ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ์ชฝ์ด ๊ฐ€์ ธ๊ฐ | +| `5` | ์ด๋ฒˆ ์‹œ๋„๋Š” ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š์Œ: ์„ธ์…˜์ด ๋ฐ”์˜๊ฑฐ๋‚˜ ๋Œ€์ƒ์„ ์ฐพ์ง€ ๋ชปํ•จ(์žก์€ `cancelled`), ๋˜๋Š” ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์‹œ๋„๊ฐ€ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ๊ฐ(๋ ˆ์ฝ”๋“œ๋Š” ์ƒˆ ์†Œ์œ ์ž์—๊ฒŒ ๊ทธ๋Œ€๋กœ ๋‘ ) | --- @@ -157,7 +157,7 @@ sequenceDiagram ## ๐Ÿ” ๋ณด์•ˆ -- **์„œ๋ช…๋œ ์ด๋ฒคํŠธ**: ํ† ํฐ์„ ์ง์ ‘ ๋„˜๊ธฐ๊ฑฐ๋‚˜ ๋ธŒ๋กœ์ปค๊ฐ€ TLS ๋˜๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ์“ฐ๋ฉด, ์žก์€ ๊ณ ์œ  ํ† ํฐ(`auth_token`)์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ๋•Œ ๋ชจ๋“  ์ด๋ฒคํŠธ์™€ retained ์ƒํƒœ ๋ฉ”์‹œ์ง€์— ๊ทธ ํ† ํฐ์œผ๋กœ ๋งŒ๋“  HMAC-SHA256 ์„œ๋ช…์ด ๋ถ™๊ณ , ๊ตฌ๋…์ž๋Š” ๊ฒ€์ฆ์— ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ์™€ ์ƒํƒœ ๋ฉ”์‹œ์ง€์—๋Š” ํ† ํฐ์ด ์•„๋‹ˆ๋ผ ์„œ๋ช…๋งŒ ์‹ค๋ฆฝ๋‹ˆ๋‹ค. TLS ๋„ ์‚ฌ์šฉ์ž ์ด๋ฆ„๋„ ์—†๋Š” ๋ธŒ๋กœ์ปค(PoC ๊ตฌ์„ฑ)์—์„œ๋Š” ์žก์— ํ† ํฐ์ด ์—†์–ด ์„œ๋ช…์„ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +- **์„œ๋ช…๋œ ์ด๋ฒคํŠธ**: ํ† ํฐ์„ ์ง์ ‘ ๋„˜๊ธฐ๊ฑฐ๋‚˜ ๋ธŒ๋กœ์ปค๊ฐ€ TLS ๋˜๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ์“ฐ๋ฉด, ์žก์€ ๊ณ ์œ  ํ† ํฐ(`auth_token`)์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ๋•Œ ๋ชจ๋“  ์ด๋ฒคํŠธ์™€ retained ์ƒํƒœ ๋ฉ”์‹œ์ง€์— ๊ทธ ํ† ํฐ์œผ๋กœ ๋งŒ๋“  HMAC-SHA256 ์„œ๋ช…์ด ๋ถ™๊ณ , ๊ตฌ๋…์ž๋Š” ๊ฒ€์ฆ์— ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ์™€ ์ƒํƒœ ๋ฉ”์‹œ์ง€์—๋Š” ํ† ํฐ์ด ์•„๋‹ˆ๋ผ ์„œ๋ช…๋งŒ ์‹ค๋ฆฝ๋‹ˆ๋‹ค. ํ† ํฐ์„ ๋„˜๊ธฐ์ง€ ์•Š์•˜๊ณ  ๋ธŒ๋กœ์ปค์— TLS ๋„ ์‚ฌ์šฉ์ž ์ด๋ฆ„๋„ ์—†์œผ๋ฉด(PoC ๊ตฌ์„ฑ), ์žก์— ํ† ํฐ์ด ์—†์–ด ์„œ๋ช…์„ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. - **์›๊ฒฉ ๋””์ŠคํŒจ์น˜์—๋Š” ํ† ํฐ์ด ์‹ค๋ฆฐ๋‹ค**: `remote:` ๋””์ŠคํŒจ์น˜ ๋ฉ”์‹œ์ง€์—๋Š” ์žก์˜ ํ† ํฐ์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค(`MAM_DISPATCH_SECRET` ์œผ๋กœ ์„œ๋ช…๋  ๋ฟ ์•”ํ˜ธํ™”๋˜์ง€๋Š” ์•Š์Œ). ์ ‘๊ทผ์ด ํ†ต์ œ๋œ ์‚ฌ์„ค ๋ธŒ๋กœ์ปค์—์„œ๋งŒ ์“ฐ์‹ญ์‹œ์˜ค. - **์žฌ์ „์†ก๊ณผ ์ˆœ์„œ**: ์ด๋ฒคํŠธ๋งˆ๋‹ค ์ฆ๊ฐ€ํ•˜๋Š” `seq` ๊ฐ€ ๋ถ™์Šต๋‹ˆ๋‹ค. ๊ตฌ๋…์ž๋Š” ์ง€๊ธˆ๊นŒ์ง€ ๋ณธ ๊ฒƒ๋ณด๋‹ค ํฐ ๋ฒˆํ˜ธ๋งŒ ๋ฐ›๊ณ , ๋นˆ ๋ฒˆํ˜ธ๋Š” `seq_gap` ์œผ๋กœ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž„์Šคํƒฌํ”„๋Š” ์ฐธ๊ณ ์šฉ์ž…๋‹ˆ๋‹ค. - **์ž๊ฒฉ ์ฆ๋ช…**: ๋ธŒ๋กœ์ปค ์ž๊ฒฉ ์ฆ๋ช…์€ `.mam.env` ์—๋งŒ ์žˆ๊ณ , ์žก ๋ ˆ์ฝ”๋“œ์—๋Š” ์—†์Šต๋‹ˆ๋‹ค. @@ -172,7 +172,7 @@ sequenceDiagram - ํ…Œ์ŠคํŠธ๋Š” ์•ฝ 1,900 ๊ฐœ์ด๊ณ , ์ „์ฒด ์‹คํ–‰์— ํ•œ ์‹œ๊ฐ„ ๋„˜๊ฒŒ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. - ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ์ž์ฒด MQTT ๋ธŒ๋กœ์ปค๋ฅผ ๋„์šฐ๋ฏ€๋กœ `.mam.env` ๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ `.mam.env` ๋ฅผ export ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. -- ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ HOMEยท๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท๊ฐ์‚ฌ ๋กœ๊ทธ ๋””๋ ‰ํ„ฐ๋ฆฌ์™€ mock herdr ๋ฅผ ์“ฐ๋Š” ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ๋•๋‹ˆ๋‹ค. +- ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ ์žก ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์™€ ๊ฐ์‚ฌ ๋กœ๊ทธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์”๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ HOME ๊ณผ mock herdr ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ƒŒ๋“œ๋ฐ•์Šค ํ”ฝ์Šค์ฒ˜๋„ ์”๋‹ˆ๋‹ค. - ์‹ค์ œ herdr ๋ฅผ ๋‹ค๋ฃจ๋Š” ํ…Œ์ŠคํŠธ๋Š” ์ผํšŒ์šฉ herdr ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๋„์›๋‹ˆ๋‹ค. - ์‹คํ–‰์ด ๋๋‚˜๋ฉด ์„ธ์…˜ ๋‹จ์œ„ ๊ฐ€๋“œ๊ฐ€ ์‹ค์ œ ์ œ์–ด ํ‰๋ฉด๊ณผ ์‚ฌ์šฉ์ž์˜ ์—์ด์ „ํŠธ ํ™ˆ(`~/.claude/projects`, `~/.codex`, `~/.gemini` โ€ฆ)์„ ํ™•์ธํ•˜๊ณ , ํ…Œ์ŠคํŠธ๊ฐ€ ๋‚จ๊ธด ํ•ญ๋ชฉ์ด ์žˆ์œผ๋ฉด ์‹คํ–‰์„ ์‹คํŒจ์‹œํ‚ต๋‹ˆ๋‹ค. - ์ผ๋ถ€ ํ…Œ์ŠคํŠธ๋Š” ํ”Œ๋žซํผ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. Python 3.11+(`tomllib`), Linux(`/proc`), `nats-docker` ์„œ๋ธŒ๋ชจ๋“ˆ์ด ํ•„์š”ํ•œ ํ…Œ์ŠคํŠธ๋Š” ๊ทธ ๋ฐ–์˜ ํ™˜๊ฒฝ์—์„œ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค. diff --git a/README.md b/README.md index 256284b..321a22a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ bash deploy/install.sh - checks that herdr and Python 3.9+ are installed, and that the system `python3` has PyYAML; - copies `.agents/` and `.mam.env.example` into the workspace; - creates `.venv` and installs `paho-mqtt` and PyYAML into it; -- writes a starter `.mam.env` with `MQTT_BROKER=localhost`. An existing `.mam.env` is kept, and a legacy `.env` is renamed to `.mam.env`; +- writes a starter `.mam.env` with `MQTT_BROKER=localhost`. An existing `.mam.env` is kept. If only a legacy `.env` exists, it is copied to `.mam.env` and the original stays; - adds `.venv`, `.mam/` and `.mam.env` to `.gitignore`. Point `MQTT_BROKER` in `.mam.env` at a broker you run (see [MESSAGING.md](MESSAGING.md) for a private broker). If `MQTT_BROKER` is not set at all, the code falls back to the public `broker.hivemq.com`. That is fine for a trial, but not for real work. `deploy/generate-env.sh` recreates `.mam.env` from `.mam.env.example`. `deploy/update.sh` and `deploy/remove.sh` update and uninstall. `deploy/install_mam.sh` is a separate installer that copies from a local clone into another directory. @@ -89,7 +89,7 @@ MAM has two layers, each with its own registry: - **A dedicated server per workspace.** By default `create` runs the agents on a herdr server named after the workspace (its slug), with its own socket, separate from your default herdr. `--herdr-session ` or `HERDR_SESSION_NAME` picks another name. The server name is recorded on the session row, and every later command routes to it. - **The shim.** Sourcing `lib.sh` writes `/.mam/shim/herdr` and puts it first on `PATH`. The shim provides the tmux-style commands the scripts use (`new-session`, `has-session`, โ€ฆ) on top of herdr's agent API. For a named server it adds `--session ` to each call, and it starts that server headless if it is not running. It does not start one when `MAM_NO_AUTOSTART=1`, which `status` and `monitor` set, so looking never starts a server. Calls for the `default` server go to your ambient herdr unchanged. -- **No surprise relaunches.** A server MAM starts normally uses your herdr config plus `resume_agents_on_restore = false`. A herdr restart therefore does not relaunch saved agents without their permission flags. If that config cannot be built, the bootstrap prints a warning and the server starts with restore on. +- **No surprise relaunches.** A server MAM starts normally uses your herdr config plus `resume_agents_on_restore = false`. A herdr restart therefore does not relaunch saved agents without their permission flags. With a Python that has no `tomllib` (such as macOS's 3.9), the file holds only that key, so restore stays off but your other herdr settings are not carried over; the bootstrap warns about this. Only if no config file can be written at all does the server start with restore on, again with a warning. - **One pane claim at a time.** Pane placement holds a per-server lock (`lib_py/pane_lock.py`, `flock` on macOS and Linux). Concurrent `create` calls in one folder each get their own pane. ### ๐Ÿ›ก๏ธ Registry writes and concurrency @@ -117,7 +117,7 @@ The full specification is in [MESSAGING.md ยง2.5](MESSAGING.md). | `1` | failure, or no `started` within T | | `2` | no event for Kร—N (`deadline_timeout`) or budget spent (`wall_clock_timeout`) | | `3` | broker unavailable, and no terminal status on disk | -| `5` | not delivered (`cancelled`): the session was busy, the target was not found, or the record was taken over while waiting | +| `5` | this attempt did not deliver the prompt: the session was busy or the target was not found (the job is `cancelled`), or another attempt took the record over while this one waited (the record is left to its new owner, unchanged) | --- @@ -157,7 +157,7 @@ sequenceDiagram ## ๐Ÿ” Security -- **Signed events**: a job gets its own token (`auth_token`) when you pass one, or automatically when the broker uses TLS or a username. Each event and each retained state message then carries an HMAC-SHA256 signature made with it, and the subscriber drops anything that fails verification. Events and state messages carry only the signature, not the token. On a broker with neither TLS nor a username (the PoC setup), a job has no token and signatures are not checked. +- **Signed events**: a job gets its own token (`auth_token`) when you pass one, or automatically when the broker uses TLS or a username. Each event and each retained state message then carries an HMAC-SHA256 signature made with it, and the subscriber drops anything that fails verification. Events and state messages carry only the signature, not the token. If no token is passed and the broker has neither TLS nor a username (the PoC setup), a job has no token and signatures are not checked. - **Remote dispatch carries the token**: the `remote:` dispatch message includes the job's token (signed with `MAM_DISPATCH_SECRET`, not encrypted). Use it only on an access-controlled private broker. - **Replay and ordering**: each event carries an increasing `seq`. The subscriber accepts only sequence numbers higher than any it has seen and records gaps as `seq_gap`. Timestamps are informational only. - **Credentials**: broker credentials live only in `.mam.env`, never in a job record. @@ -172,7 +172,7 @@ sequenceDiagram - The suite has about 1,900 tests, and a full run takes over an hour. - It runs its own in-process MQTT broker, so it never needs `.mam.env`. Don't export `.mam.env` for tests. -- Tests run in sandboxes, with a temporary HOME, registry and audit-log directory, and a mock herdr: +- Every test gets a temporary job registry and audit-log directory. Most tests also use the sandbox fixtures, which set a temporary HOME and a mock herdr: - the tests that drive a real herdr start their own throwaway herdr server; - after the run, session-level guards check the real control plane and your agent homes (`~/.claude/projects`, `~/.codex`, `~/.gemini`, โ€ฆ) and fail the run if a test left entries there. - Some tests are platform-specific. A few need Python 3.11+ (`tomllib`), Linux (`/proc`) or the `nats-docker` submodule; elsewhere they are skipped. From 62da8056680fca939a2aff924037ed48b5f74afa Mon Sep 17 00:00:00 2001 From: Godopu Date: Tue, 13 Oct 2026 11:51:32 +0900 Subject: [PATCH 4/5] docs(readme): round-3 review fixes (21063f28) About a third of the tests use the sandbox HOME fixtures (fewer the mock herdr); generate-env.sh creates .mam.env only when missing, --force overwrites with a .bak. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff --- README.ko.md | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.ko.md b/README.ko.md index 268bf77..47f8d40 100644 --- a/README.ko.md +++ b/README.ko.md @@ -38,7 +38,7 @@ bash deploy/install.sh - `MQTT_BROKER=localhost` ๋กœ ๋œ ์ดˆ๊ธฐ `.mam.env` ๋ฅผ ์”๋‹ˆ๋‹ค. ์ด๋ฏธ ์žˆ๋Š” `.mam.env` ๋Š” ๊ทธ๋Œ€๋กœ ๋‘ก๋‹ˆ๋‹ค. ์˜ˆ์ „ `.env` ๋งŒ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„ `.mam.env` ๋กœ ๋ณต์‚ฌํ•˜๊ณ  ์›๋ณธ์€ ๋‚จ๊น๋‹ˆ๋‹ค. - `.venv`, `.mam/`, `.mam.env` ๋ฅผ `.gitignore` ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. -`.mam.env` ์˜ `MQTT_BROKER` ๋ฅผ ์ง์ ‘ ์šด์˜ํ•˜๋Š” ๋ธŒ๋กœ์ปค๋กœ ๋ฐ”๊พธ์‹ญ์‹œ์˜ค(์‚ฌ์„ค ๋ธŒ๋กœ์ปค๋Š” [MESSAGING.md](MESSAGING.md) ์ฐธ๊ณ ). `MQTT_BROKER` ๊ฐ€ ์•„์˜ˆ ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด ์ฝ”๋“œ๋Š” ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค `broker.hivemq.com` ์„ ์”๋‹ˆ๋‹ค. ์‹œํ—˜์šฉ์œผ๋กœ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ์‹ค์ œ ์ž‘์—…์šฉ์€ ์•„๋‹™๋‹ˆ๋‹ค. `deploy/generate-env.sh` ๋Š” `.mam.env.example` ๋กœ `.mam.env` ๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ์™€ ์ œ๊ฑฐ๋Š” `deploy/update.sh`, `deploy/remove.sh` ์ž…๋‹ˆ๋‹ค. `deploy/install_mam.sh` ๋Š” ๋กœ์ปฌ ํด๋ก ์—์„œ ๋‹ค๋ฅธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ๋ณต์‚ฌํ•ด ์„ค์น˜ํ•˜๋Š” ๋ณ„๋„ ์„ค์น˜๊ธฐ์ž…๋‹ˆ๋‹ค. +`.mam.env` ์˜ `MQTT_BROKER` ๋ฅผ ์ง์ ‘ ์šด์˜ํ•˜๋Š” ๋ธŒ๋กœ์ปค๋กœ ๋ฐ”๊พธ์‹ญ์‹œ์˜ค(์‚ฌ์„ค ๋ธŒ๋กœ์ปค๋Š” [MESSAGING.md](MESSAGING.md) ์ฐธ๊ณ ). `MQTT_BROKER` ๊ฐ€ ์•„์˜ˆ ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด ์ฝ”๋“œ๋Š” ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค `broker.hivemq.com` ์„ ์”๋‹ˆ๋‹ค. ์‹œํ—˜์šฉ์œผ๋กœ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ์‹ค์ œ ์ž‘์—…์šฉ์€ ์•„๋‹™๋‹ˆ๋‹ค. `deploy/generate-env.sh` ๋Š” `.mam.env` ๊ฐ€ ์—†์„ ๋•Œ `.mam.env.example` ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค(`--force` ๋Š” `.mam.env.bak` ์„ ๋‚จ๊ธฐ๊ณ  ๋ฎ์–ด์”๋‹ˆ๋‹ค). ์—…๋ฐ์ดํŠธ์™€ ์ œ๊ฑฐ๋Š” `deploy/update.sh`, `deploy/remove.sh` ์ž…๋‹ˆ๋‹ค. `deploy/install_mam.sh` ๋Š” ๋กœ์ปฌ ํด๋ก ์—์„œ ๋‹ค๋ฅธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ๋ณต์‚ฌํ•ด ์„ค์น˜ํ•˜๋Š” ๋ณ„๋„ ์„ค์น˜๊ธฐ์ž…๋‹ˆ๋‹ค. --- @@ -172,7 +172,7 @@ sequenceDiagram - ํ…Œ์ŠคํŠธ๋Š” ์•ฝ 1,900 ๊ฐœ์ด๊ณ , ์ „์ฒด ์‹คํ–‰์— ํ•œ ์‹œ๊ฐ„ ๋„˜๊ฒŒ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. - ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ์ž์ฒด MQTT ๋ธŒ๋กœ์ปค๋ฅผ ๋„์šฐ๋ฏ€๋กœ `.mam.env` ๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ `.mam.env` ๋ฅผ export ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. -- ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ ์žก ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์™€ ๊ฐ์‚ฌ ๋กœ๊ทธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์”๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ HOME ๊ณผ mock herdr ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ƒŒ๋“œ๋ฐ•์Šค ํ”ฝ์Šค์ฒ˜๋„ ์”๋‹ˆ๋‹ค. +- ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ ์žก ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์™€ ๊ฐ์‚ฌ ๋กœ๊ทธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์”๋‹ˆ๋‹ค. ์•ฝ 3๋ถ„์˜ 1 ์€ ์ž„์‹œ HOME ์„ ์„ค์ •ํ•˜๋Š” ์ƒŒ๋“œ๋ฐ•์Šค ํ”ฝ์Šค์ฒ˜๋„ ์“ฐ๊ณ , ๊ทธ๋ณด๋‹ค ์ ์€ ์ˆ˜๋Š” mock herdr ๋„ ์”๋‹ˆ๋‹ค. - ์‹ค์ œ herdr ๋ฅผ ๋‹ค๋ฃจ๋Š” ํ…Œ์ŠคํŠธ๋Š” ์ผํšŒ์šฉ herdr ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๋„์›๋‹ˆ๋‹ค. - ์‹คํ–‰์ด ๋๋‚˜๋ฉด ์„ธ์…˜ ๋‹จ์œ„ ๊ฐ€๋“œ๊ฐ€ ์‹ค์ œ ์ œ์–ด ํ‰๋ฉด๊ณผ ์‚ฌ์šฉ์ž์˜ ์—์ด์ „ํŠธ ํ™ˆ(`~/.claude/projects`, `~/.codex`, `~/.gemini` โ€ฆ)์„ ํ™•์ธํ•˜๊ณ , ํ…Œ์ŠคํŠธ๊ฐ€ ๋‚จ๊ธด ํ•ญ๋ชฉ์ด ์žˆ์œผ๋ฉด ์‹คํ–‰์„ ์‹คํŒจ์‹œํ‚ต๋‹ˆ๋‹ค. - ์ผ๋ถ€ ํ…Œ์ŠคํŠธ๋Š” ํ”Œ๋žซํผ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. Python 3.11+(`tomllib`), Linux(`/proc`), `nats-docker` ์„œ๋ธŒ๋ชจ๋“ˆ์ด ํ•„์š”ํ•œ ํ…Œ์ŠคํŠธ๋Š” ๊ทธ ๋ฐ–์˜ ํ™˜๊ฒฝ์—์„œ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค. diff --git a/README.md b/README.md index 321a22a..ef9efde 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ bash deploy/install.sh - writes a starter `.mam.env` with `MQTT_BROKER=localhost`. An existing `.mam.env` is kept. If only a legacy `.env` exists, it is copied to `.mam.env` and the original stays; - adds `.venv`, `.mam/` and `.mam.env` to `.gitignore`. -Point `MQTT_BROKER` in `.mam.env` at a broker you run (see [MESSAGING.md](MESSAGING.md) for a private broker). If `MQTT_BROKER` is not set at all, the code falls back to the public `broker.hivemq.com`. That is fine for a trial, but not for real work. `deploy/generate-env.sh` recreates `.mam.env` from `.mam.env.example`. `deploy/update.sh` and `deploy/remove.sh` update and uninstall. `deploy/install_mam.sh` is a separate installer that copies from a local clone into another directory. +Point `MQTT_BROKER` in `.mam.env` at a broker you run (see [MESSAGING.md](MESSAGING.md) for a private broker). If `MQTT_BROKER` is not set at all, the code falls back to the public `broker.hivemq.com`. That is fine for a trial, but not for real work. `deploy/generate-env.sh` creates `.mam.env` from `.mam.env.example` when it is missing (`--force` overwrites it, keeping a `.mam.env.bak`). `deploy/update.sh` and `deploy/remove.sh` update and uninstall. `deploy/install_mam.sh` is a separate installer that copies from a local clone into another directory. --- @@ -172,7 +172,7 @@ sequenceDiagram - The suite has about 1,900 tests, and a full run takes over an hour. - It runs its own in-process MQTT broker, so it never needs `.mam.env`. Don't export `.mam.env` for tests. -- Every test gets a temporary job registry and audit-log directory. Most tests also use the sandbox fixtures, which set a temporary HOME and a mock herdr: +- Every test gets a temporary job registry and audit-log directory. About a third also use the sandbox fixtures, which set a temporary HOME (and, for fewer, a mock herdr): - the tests that drive a real herdr start their own throwaway herdr server; - after the run, session-level guards check the real control plane and your agent homes (`~/.claude/projects`, `~/.codex`, `~/.gemini`, โ€ฆ) and fail the run if a test left entries there. - Some tests are platform-specific. A few need Python 3.11+ (`tomllib`), Linux (`/proc`) or the `nats-docker` submodule; elsewhere they are skipped. From e3bcdee834176a97cc1d78d1e6db59ecbcc1f65a Mon Sep 17 00:00:00 2001 From: Godopu Date: Tue, 13 Oct 2026 11:57:33 +0900 Subject: [PATCH 5/5] release(v4.9.2): README rewritten against the code, README.ko.md in step - archive the review reports and bump the lockstep version Review loop (--review-only, --all-reviewer, fact-checked against the code): rounds 1-3 NOT PASS with factual corrections, round 4 (@62da805) 4/4 PASS. Documentation only. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff --- .../report-8b2392ce.identity.json | 14 ++++ .../report-8b2392ce.md | 22 ++++++ .../report-a2716e3b.identity.json | 14 ++++ .../report-a2716e3b.md | 45 +++++++++++++ .../report-f3b2d22c.identity.json | 14 ++++ .../reviewer-agy-01/report-f3b2d22c.md | 67 +++++++++++++++++++ .../report-2311b972.identity.json | 14 ++++ .../reviewer-grok-01/report-2311b972.md | 15 +++++ .agents/skills/lib.sh | 2 +- .agents/skills/lib_py/loop/eager.py | 2 +- .../skills/multi-agent-mux-create/SKILL.md | 2 +- .../multi-agent-mux-delegate-job/SKILL.md | 2 +- .agents/skills/multi-agent-mux-loop/SKILL.md | 2 +- .../skills/multi-agent-mux-monitor/SKILL.md | 2 +- .../multi-agent-mux-orc-onboard/SKILL.md | 2 +- .../skills/multi-agent-mux-resume/SKILL.md | 2 +- .../skills/multi-agent-mux-status/SKILL.md | 2 +- .agents/skills/multi-agent-mux-stop/SKILL.md | 2 +- BOOTSTRAP.ko.md | 2 +- BOOTSTRAP.md | 2 +- MESSAGING.md | 2 +- README.ko.md | 2 +- README.md | 2 +- VERSIONS.md | 32 ++++++--- 24 files changed, 242 insertions(+), 25 deletions(-) create mode 100644 .agents/reports/planner-reviewer-claude-01/report-8b2392ce.identity.json create mode 100644 .agents/reports/planner-reviewer-claude-01/report-8b2392ce.md create mode 100644 .agents/reports/planner-reviewer-codex-01/report-a2716e3b.identity.json create mode 100644 .agents/reports/planner-reviewer-codex-01/report-a2716e3b.md create mode 100644 .agents/reports/reviewer-agy-01/report-f3b2d22c.identity.json create mode 100644 .agents/reports/reviewer-agy-01/report-f3b2d22c.md create mode 100644 .agents/reports/reviewer-grok-01/report-2311b972.identity.json create mode 100644 .agents/reports/reviewer-grok-01/report-2311b972.md diff --git a/.agents/reports/planner-reviewer-claude-01/report-8b2392ce.identity.json b/.agents/reports/planner-reviewer-claude-01/report-8b2392ce.identity.json new file mode 100644 index 0000000..3fe716d --- /dev/null +++ b/.agents/reports/planner-reviewer-claude-01/report-8b2392ce.identity.json @@ -0,0 +1,14 @@ +{ + "loop_id": "loop-20261013T025132Z-60f239", + "base_sha": "ae2813773c973daedd2275cb55ad340a682c3fae", + "head_sha": "62da8056680fca939a2aff924037ed48b5f74afa", + "tree_sha": "f549246ffbe2d5e58cb7e33c212a383cd429dce5", + "review_commit": "62da8056680fca939a2aff924037ed48b5f74afa", + "reviewer": "planner-reviewer-claude-01", + "job_id": "8b2392ce", + "verdict": "PASS", + "transport": "herdr", + "evidence": "review-tree", + "isolation": "worktree", + "verified_at": "2026-10-13T02:56:58Z" +} \ No newline at end of file diff --git a/.agents/reports/planner-reviewer-claude-01/report-8b2392ce.md b/.agents/reports/planner-reviewer-claude-01/report-8b2392ce.md new file mode 100644 index 0000000..f79fa5a --- /dev/null +++ b/.agents/reports/planner-reviewer-claude-01/report-8b2392ce.md @@ -0,0 +1,22 @@ +# README.md / README.ko.md 4์ฐจ ๋ฆฌ๋ทฐ โ€” ์ปค๋ฐ‹ 62da805 (job 8b2392ce) + +- ๋ฆฌ๋ทฐ์–ด: planner-reviewer-claude-01 (Reviewer) +- ๋ฆฌ๋ทฐ identity: loop-20261013T025132Z-60f239 / base ae281377 .. head 62da8056 (์ปค๋ฐ‹ 1๊ฐœ, ๋‘ README ๊ฐ 2์ค„) / tree f549246f +- ๊ฒ€์ฆ ๊ฒฝ๋กœ: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1` โ€” HEADยทtree ์ผ์น˜, `git status --porcelain` 0 ์ค„(์‹œ์ž‘ยท์ข…๋ฃŒ). ๋ณธ ์ฒดํฌ์•„์›ƒ HEAD 2ccf439(main) ๋ณ€๋™ ์—†์Œ. +- ๋ฐฉ๋ฒ•: ๋ฐ”๋€ ๋‘ ๋ฌธ์žฅ๋งŒ ์ฝ”๋“œ์™€ ๋Œ€์กฐ. `generate-env.sh`ยท์„ค์น˜๊ธฐ๋Š” ์‹คํ–‰ํ•˜์ง€ ์•Š์•˜๊ณ , ํ…Œ์ŠคํŠธ๋„ ๋Œ๋ฆฌ์ง€ ์•Š์•˜๋‹ค(ํ”ฝ์Šค์ฒ˜ ์ง‘๊ณ„๋Š” `pytest --co` ์— ์ˆ˜์ง‘ ์ „์šฉ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์–น์–ด `fixturenames` ๋งŒ ์…Œ๋‹ค; `env -i`, basetemp ๋Š” scratchpad). ์‹ค์ œ ์„œ๋ฒ„ยท์„ธ์…˜ยท`.mam`ยท`.mam.env`ยท์—์ด์ „ํŠธ ํ™ˆ ๋ฏธ์ ‘์ด‰. + +## 1. ๋‘ ๋ฌธ์žฅ์˜ ์ฝ”๋“œ ๋Œ€์กฐ + +| ๋ฌธ์žฅ (README.md / README.ko.md ๊ฐ™์€ ์ค„) | ๊ทผ๊ฑฐ | ํŒ์ • | +|---|---|---| +| **:41** `generate-env.sh` ๋Š” `.mam.env` ๊ฐ€ ์—†์„ ๋•Œ `.mam.env.example` ๋กœ ๋งŒ๋“ค๊ณ , `--force` ๋Š” `.mam.env.bak` ์„ ๋‚จ๊ธฐ๊ณ  ๋ฎ์–ด์”€ | `deploy/generate-env.sh:54-64`: `[ -f "$DST" ] && [ "$FORCE" != "1" ]` โ†’ "no-op โ€ฆ (use --force to overwrite)" `exit 0`; `[ -f "$DST" ] && [ "$FORCE" = "1" ]` โ†’ `cp -p "$DST" "$DST.bak"`; ๊ทธ ๋’ค `cp "$SRC" "$DST"`. ๋จธ๋ฆฌ ์ฃผ์„(`:5-7`)๊ณผ๋„ ์ผ์น˜ | โœ“ | +| **:175** ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ ์žก ๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท๊ฐ์‚ฌ ๋กœ๊ทธ; ์•ฝ 3๋ถ„์˜ 1 ์ด ์ž„์‹œ HOME ์ƒŒ๋“œ๋ฐ•์Šค ํ”ฝ์Šค์ฒ˜, ๊ทธ๋ณด๋‹ค ์ ์€ ์ˆ˜๊ฐ€ mock herdr | ์ด head ์—์„œ ์ˆ˜์ง‘ 1901 ๊ฐœ ์ค‘ `fixturenames` ์— `mam_sandbox` ํฌํ•จ **575 (30 %)**, `mock_herdr` ํฌํ•จ **186 (9 %)**(`mock_agents` 125). grok ์ง‘๊ณ„(1708 ์ค‘ 573/196)์™€ ๋ชจ์ˆ˜๋งŒ ๋‹ค๋ฅด๊ณ  ๋น„์œจ์€ ๊ฐ™๋‹ค. "์•ฝ 3๋ถ„์˜ 1" ๊ณผ "๊ทธ๋ณด๋‹ค ์ ์€ ์ˆ˜" ๋ชจ๋‘ ๋งž์Œ. ์ „์ฒด ํ…Œ์ŠคํŠธ์˜ ์ž„์‹œ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท๋กœ๊ทธ๋Š” `conftest.py:170-181` ์˜ autouse ํ”ฝ์Šค์ฒ˜(3์ฐจ์—์„œ ํ™•์ธ) | โœ“ | + +## 2. ๋‘ ์–ธ์–ด์˜ ์ผ์น˜ +- ๋‘ ๋ฌธ์žฅ ๋ชจ๋‘ ์˜๋ฌธยทํ•œ๊ตญ์–ด๊ฐ€ ๊ฐ™์€ ์กฐ๊ฑดยท๊ฐ™์€ ์ˆ˜์น˜๋ฅผ ๋งํ•œ๋‹ค(์—†์„ ๋•Œ ์ƒ์„ฑ / `--force` ๋Š” `.bak` ๋‚จ๊ธฐ๊ณ  ๋ฎ์–ด์”€; ์•ฝ 3๋ถ„์˜ 1 / ๊ทธ๋ณด๋‹ค ์ ์€ ์ˆ˜). +- ๊ตฌ์กฐ(head): ์ œ๋ชฉ 18/18, ํ‘œ ํ–‰ 17/17, ์ฝ”๋“œ ๋ธ”๋ก 7/7(๋ฒˆ์—ญ ์ฃผ์„ ๋ธ”๋ก ์™ธ ๋™์ผ), ์ˆซ์ž ์ง‘ํ•ฉ ๋™์ผ, ๋ฐฑํ‹ฑ ํ† ํฐ ์ฐจ์ด๋Š” `MULTI_AGENT_RULES.md` โ†” `.ko.md` ๋ฟ. + +## ๊ฒฐ๋ก  +grok 21063f28 ์˜ ๋‘ ์ง€์ ์ด ์ฝ”๋“œ์™€ ๋งž๊ฒŒ ๊ณ ์ณ์กŒ๊ณ  ๋‘ ์–ธ์–ด๊ฐ€ ๊ฐ™๋‹ค. ์•ž ๋ผ์šด๋“œ์—์„œ ๋‚ด๊ฐ€ ๋‚จ๊ฒผ๋˜ `generate-env.sh` ๋ฉ”๋ชจ๋„ ์ด ์ปค๋ฐ‹์œผ๋กœ ํ•ด์†Œ๋๋‹ค. ๋‚จ์€ ์ง€์  ์—†์Œ. + +[VERDICT: PASS] diff --git a/.agents/reports/planner-reviewer-codex-01/report-a2716e3b.identity.json b/.agents/reports/planner-reviewer-codex-01/report-a2716e3b.identity.json new file mode 100644 index 0000000..660aa83 --- /dev/null +++ b/.agents/reports/planner-reviewer-codex-01/report-a2716e3b.identity.json @@ -0,0 +1,14 @@ +{ + "loop_id": "loop-20261013T025132Z-60f239", + "base_sha": "ae2813773c973daedd2275cb55ad340a682c3fae", + "head_sha": "62da8056680fca939a2aff924037ed48b5f74afa", + "tree_sha": "f549246ffbe2d5e58cb7e33c212a383cd429dce5", + "review_commit": "62da8056680fca939a2aff924037ed48b5f74afa", + "reviewer": "planner-reviewer-codex-01", + "job_id": "a2716e3b", + "verdict": "PASS", + "transport": "herdr", + "evidence": "review-tree", + "isolation": "worktree", + "verified_at": "2026-10-13T02:56:58Z" +} \ No newline at end of file diff --git a/.agents/reports/planner-reviewer-codex-01/report-a2716e3b.md b/.agents/reports/planner-reviewer-codex-01/report-a2716e3b.md new file mode 100644 index 0000000..5093091 --- /dev/null +++ b/.agents/reports/planner-reviewer-codex-01/report-a2716e3b.md @@ -0,0 +1,45 @@ +# README 4์ฐจ ๋ฆฌ๋ทฐ โ€” a2716e3b + +ํŒ์ •: PASS. ์ง€์ •๋œ ๋‘ ๋ฌธ์žฅ์˜ ์ˆ˜์ •์—์„œ ์ฐจ๋‹จํ•  ์‚ฌ์‹ค ์˜ค๋ฅ˜๋‚˜ ์˜๋ฌธยทํ•œ๊ตญ์–ด ์˜๋ฏธ ๋ถˆ์ผ์น˜๋ฅผ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. + +## ๋ฆฌ๋ทฐ identity ๋ฐ ๋ฒ”์œ„ + +- loop: `loop-20261013T025132Z-60f239` +- base: `ae2813773c973daedd2275cb55ad340a682c3fae` +- head: `62da8056680fca939a2aff924037ed48b5f74afa` +- tree: `f549246ffbe2d5e58cb7e33c212a383cd429dce5` +- ๊ฒ€์ฆ ๊ฒฝ๋กœ: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1` +- HEAD/tree๊ฐ€ ๋ธŒ๋ฆฌํ”„์™€ ์ผ์น˜ํ•˜๊ณ  ์ž‘์—… ํŠธ๋ฆฌ๊ฐ€ clean์ž„์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์ปค๋ฐ‹๋งŒ ๊ฒ€ํ† ํ–ˆ์œผ๋ฉฐ, ๋‘ README์—์„œ ๊ฐ๊ฐ 41ํ–‰๊ณผ 175ํ–‰๋งŒ ๋ณ€๊ฒฝ๋œ ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. + +## ๊ฒ€ํ†  ๊ฒฐ๊ณผ + +### 1. generate-env.sh ์„ค๋ช… โ€” PASS + +`README.md:41`, `README.ko.md:41`์€ ๋Œ€์ƒ ํŒŒ์ผ์ด ์—†์„ ๋•Œ ์ƒ์„ฑํ•˜๊ณ , `--force`๋กœ ๊ธฐ์กด ํŒŒ์ผ์„ ๋ฎ์–ด์“ธ ๋•Œ `.mam.env.bak`์„ ๋‚จ๊ธด๋‹ค๊ณ  ๋™์ผํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. + +- `deploy/generate-env.sh:17โ€“18`: ํ…œํ”Œ๋ฆฟ๊ณผ ๋Œ€์ƒ ๊ฒฝ๋กœ๋ฅผ `.mam.env.example`, `.mam.env`๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. +- 54โ€“56ํ–‰: ๋Œ€์ƒ์ด ์žˆ๊ณ  `--force`๊ฐ€ ์—†์œผ๋ฉด ์„ฑ๊ณต ์ฝ”๋“œ๋กœ ์ข…๋ฃŒํ•˜๋ฉฐ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +- 59โ€“61ํ–‰: ๋Œ€์ƒ์ด ์žˆ๊ณ  `--force`๊ฐ€ ์žˆ์œผ๋ฉด `cp -p "$DST" "$DST.bak"`์œผ๋กœ ๋ฐฑ์—…ํ•ฉ๋‹ˆ๋‹ค. +- 64ํ–‰: ํ…œํ”Œ๋ฆฟ์„ ๋Œ€์ƒ์œผ๋กœ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. + +๋จธ๋ฆฌ ์ฃผ์„ 5โ€“7ํ–‰๋ฟ ์•„๋‹ˆ๋ผ ์‹ค์ œ ๋ถ„๊ธฐ๋ฅผ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ณ„๋„ ์˜ต์…˜์ธ `--migrate-legacy`๋Š” ์ด๋ฒˆ ๋ฌธ๊ตฌ์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ/force ์„ค๋ช…๊ณผ ์ถฉ๋Œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋Š” ์‹คํ–‰ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. + +### 2. ํ…Œ์ŠคํŠธ ๊ฒฉ๋ฆฌ ๋ฒ”์œ„ โ€” PASS + +`README.md:175`, `README.ko.md:175`์€ ๋ชจ๋“  ํ…Œ์ŠคํŠธ์˜ ์ž„์‹œ ์žก ๊ฒฝ๋กœ์™€ ์ผ๋ถ€ ํ…Œ์ŠคํŠธ๊ฐ€ ์“ฐ๋Š” ์ž„์‹œ HOME/mock herdr๋ฅผ ๊ตฌ๋ณ„ํ•ฉ๋‹ˆ๋‹ค. + +- `tests/conftest.py:170โ€“181`: autouse `_isolate_mam_state_dirs`๊ฐ€ ํ…Œ์ŠคํŠธ๋ณ„ ์ž„์‹œ ์žก ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์™€ ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. +- 195โ€“207ํ–‰: autouse ์—์ด์ „ํŠธ ํ™˜๊ฒฝ ์ •๋ฆฌ ์ž์ฒด๋Š” HOME์„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค๊ณ  ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. +- 228โ€“269ํ–‰: ์„ ํƒ์  `mam_sandbox`๊ฐ€ HOME๊ณผ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ์ž„์‹œ ๊ฒฝ๋กœ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. +- 312โ€“315ํ–‰: ๋ณ„๋„ `mock_herdr` ํ”ฝ์Šค์ฒ˜๊ฐ€ `mam_sandbox`์— ์˜์กดํ•˜์—ฌ mock ์‹คํ–‰ ํŒŒ์ผ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ƒŒ๋“œ๋ฐ•์Šค ์‚ฌ์šฉ ์ž์ฒด๊ฐ€ mock ์‚ฌ์šฉ์„ ์˜๋ฏธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +๋ธŒ๋ฆฌํ”„์— ์ œ์‹œ๋œ ์ˆ˜์ง‘ ํ•ญ๋ชฉ ์ง‘๊ณ„๋Š” 1708๊ฐœ ์ค‘ ์ƒŒ๋“œ๋ฐ•์Šค 573๊ฐœ(33.55%), mock 196๊ฐœ(11.48%)์ด๋ฏ€๋กœ ์ƒˆ ํ‘œํ˜„๊ณผ ๋งž์Šต๋‹ˆ๋‹ค. ์ด ์ •ํ™•ํ•œ pytest ์ˆ˜์ง‘ ์ˆ˜๋Š” ์žฌ์ˆ˜์ง‘ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋…๋ฆฝ์ ์ธ AST ์ •์  ํ™•์ธ์—์„œ๋Š” ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ์ •์˜ 1272๊ฐœ ์ค‘ ๋ช…์‹œ์  ์ธ์ž/๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ ํ”ฝ์Šค์ฒ˜ ์˜์กด ๊ฒฝ๋กœ๋กœ `mam_sandbox` 485๊ฐœ, `mock_herdr` 168๊ฐœ๋ฅผ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ˆ˜์น˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ pytest ํ•ญ๋ชฉ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ํด๋ž˜์Šค/๋ชจ๋“ˆ ์ˆ˜์ค€์˜ ๊ฐ„์ ‘ ์ง€์ •๊นŒ์ง€ ์™„์ „ ์žฌํ˜„ํ•œ ์ง‘๊ณ„๋„ ์•„๋‹™๋‹ˆ๋‹ค. โ€œ๋Œ€๋ถ€๋ถ„โ€์ด๋ผ๋Š” ์ด์ „ ๊ณผ์žฅ์„ ์ œ๊ฑฐํ•˜๊ณ  mock ์‚ฌ์šฉ ๋ฒ”์œ„๋ฅผ ๋” ์ขํžŒ ์ˆ˜์ • ๋ฐฉํ–ฅ์„ ๋’ท๋ฐ›์นจํ•˜๋Š” ๋ณด์กฐ ํ™•์ธ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. + +## ๊ฒ€์ฆ ๋ฐ ์ œํ•œ + +- `git diff --check ae28137..HEAD`: ์„ฑ๊ณต. +- ์–‘ ๋ฌธ์„œ์˜ ๋ณ€๊ฒฝ ํ–‰์ด ์ •ํ™•ํžˆ `[41, 175]`์ด๋ฉฐ ์ค„ ์ˆ˜๊ฐ€ ์œ ์ง€๋จ์„ ์ •์  ๊ฒ€์‚ฌ๋กœ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€ ๋ฌธ์žฅยท๋ช…๋ นยท๋‹ค์ด์–ด๊ทธ๋žจ์€ ์ด๋ฒˆ ์ปค๋ฐ‹์—์„œ ๋ฐ”๋€Œ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. +- ๋‘ ๋ณ€๊ฒฝ ๋ฌธ์žฅ์˜ ์กฐ๊ฑด๊ณผ ์ˆ˜๋Ÿ‰ ํ‘œํ˜„์ด EN/KO์—์„œ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. +- ํ…Œ์ŠคํŠธ, ์„ค์น˜๊ธฐ, ํ™˜๊ฒฝ ์ƒ์„ฑ ์Šคํฌ๋ฆฝํŠธ, ์‹ค์ œ herdr/์—์ด์ „ํŠธ/monitor๋Š” ์‹คํ–‰ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ง€์ • ๋ฆฌ๋ทฐ ํŠธ๋ฆฌ์˜ ํŒŒ์ผ๋งŒ ์ฝ์—ˆ๊ณ  ์†Œ์Šคยท๋ฌธ์„œยท์‹ค์ œ ์„ค์ • ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. pytest ์ „์ฒด ํ†ต๊ณผ ๋˜๋Š” ์ •ํ™•ํ•œ ์ˆ˜์ง‘ ์ˆ˜ ์žฌํ˜„์„ ์ฃผ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +[VERDICT: PASS] diff --git a/.agents/reports/reviewer-agy-01/report-f3b2d22c.identity.json b/.agents/reports/reviewer-agy-01/report-f3b2d22c.identity.json new file mode 100644 index 0000000..910741a --- /dev/null +++ b/.agents/reports/reviewer-agy-01/report-f3b2d22c.identity.json @@ -0,0 +1,14 @@ +{ + "loop_id": "loop-20261013T025132Z-60f239", + "base_sha": "ae2813773c973daedd2275cb55ad340a682c3fae", + "head_sha": "62da8056680fca939a2aff924037ed48b5f74afa", + "tree_sha": "f549246ffbe2d5e58cb7e33c212a383cd429dce5", + "review_commit": "62da8056680fca939a2aff924037ed48b5f74afa", + "reviewer": "reviewer-agy-01", + "job_id": "f3b2d22c", + "verdict": "PASS", + "transport": "herdr", + "evidence": "review-tree", + "isolation": "worktree", + "verified_at": "2026-10-13T02:56:58Z" +} \ No newline at end of file diff --git a/.agents/reports/reviewer-agy-01/report-f3b2d22c.md b/.agents/reports/reviewer-agy-01/report-f3b2d22c.md new file mode 100644 index 0000000..671d747 --- /dev/null +++ b/.agents/reports/reviewer-agy-01/report-f3b2d22c.md @@ -0,0 +1,67 @@ +# Code Review Report (4th Round): `docs/readme-refresh` (README.md & README.ko.md Targeted Refinement) + +- **Job ID**: `f3b2d22c` +- **Reviewer**: `agy` (Session: `herdr:reviewer-agy-01`, Role: `Reviewer`) +- **Date**: 2026-10-13 +- **Target Branch**: `docs/readme-refresh` +- **Base Commit**: `ae2813773c973daedd2275cb55ad340a682c3fae` +- **Head Commit**: `62da8056680fca939a2aff924037ed48b5f74afa` +- **Verification Path**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1` +- **Verification Environment**: macOS (Darwin 24.3.0, arm64), Python 3.9.6 + +--- + +## 1. Executive Summary + +This 4th-round review evaluated commit [`62da8056680fca939a2aff924037ed48b5f74afa`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1), which addresses 3rd-round reviewer feedback (grok `21063f28`) regarding two targeted descriptions across [`README.md`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1/README.md) and [`README.ko.md`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1/README.ko.md): +1. Clarification that [`deploy/generate-env.sh`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1/deploy/generate-env.sh) creates `.mam.env` only when missing, and `--force` backs up `.mam.env` to `.mam.env.bak` before overwriting. +2. Accurate quantification of test isolation fixtures: all tests get temporary job registry and audit-log directories, while roughly one-third use sandbox temporary HOME fixtures, and an even smaller subset use mock herdr. + +Both changes have been verified against the codebase and found factually accurate. Bilingual parity between English and Korean is fully preserved. + +**Verdict: PASS**. + +--- + +## 2. Technical Item Verification + +### 2.1 `deploy/generate-env.sh` Behavior +- **Code Inspection** ([`deploy/generate-env.sh:54-64`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1/deploy/generate-env.sh#L54-L64)): + - If `.mam.env` exists and `--force` is not passed, the script exits immediately with no-op: + ```bash + if [ -f "$DST" ] && [ "$FORCE" != "1" ]; then + echo "no-op: $DST already exists (use --force to overwrite)" + exit 0 + fi + ``` + - If `.mam.env` exists and `--force` is passed, it creates a backup copy at `.mam.env.bak` before overwriting: + ```bash + if [ -f "$DST" ] && [ "$FORCE" = "1" ]; then + cp -p "$DST" "$DST.bak" + echo "backed up existing .mam.env -> $DST.bak" + fi + cp "$SRC" "$DST" + ``` +- **Documentation Verification**: + - *EN*: `deploy/generate-env.sh creates .mam.env from .mam.env.example when it is missing (--force overwrites it, keeping a .mam.env.bak).` + - *KO*: `deploy/generate-env.sh ๋Š” .mam.env ๊ฐ€ ์—†์„ ๋•Œ .mam.env.example ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค(--force ๋Š” .mam.env.bak ์„ ๋‚จ๊ธฐ๊ณ  ๋ฎ์–ด์”๋‹ˆ๋‹ค).` +- **Evaluation**: Accurately reflects the conditional creation and backup semantics of `generate-env.sh`. + +### 2.2 Test Isolation Scoping & Proportions +- **Code Inspection** ([`tests/conftest.py`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1/tests/conftest.py)): + - `_isolate_mam_state_dirs` is `autouse=True`, executing for 100% of tests. + - Of 1,272 test functions defined across `tests/`, 418 (~32.8%, roughly one-third) declare sandbox fixtures (`mam_sandbox`, `temp_home`), and only 158 declare `mock_herdr`. +- **Documentation Verification**: + - *EN*: `Every test gets a temporary job registry and audit-log directory. About a third also use the sandbox fixtures, which set a temporary HOME (and, for fewer, a mock herdr):` + - *KO*: `๋ชจ๋“  ํ…Œ์ŠคํŠธ๋Š” ์ž„์‹œ ์žก ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์™€ ๊ฐ์‚ฌ ๋กœ๊ทธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์”๋‹ˆ๋‹ค. ์•ฝ 3๋ถ„์˜ 1 ์€ ์ž„์‹œ HOME ์„ ์„ค์ •ํ•˜๋Š” ์ƒŒ๋“œ๋ฐ•์Šค ํ”ฝ์Šค์ฒ˜๋„ ์“ฐ๊ณ , ๊ทธ๋ณด๋‹ค ์ ์€ ์ˆ˜๋Š” mock herdr ๋„ ์”๋‹ˆ๋‹ค.` +- **Evaluation**: The replacement of "most" with "about a third" (and fewer for mock herdr) accurately aligns the documentation with actual test fixture distribution. + +--- + +## 3. Bilingual Alignment & Integrity +- Both updated lines in [`README.md`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1/README.md) and [`README.ko.md`](file:///var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261013T025132Z-60f239/1/README.ko.md) maintain exact semantic, technical, and structural parity. +- Markdown formatting, links, and code backticks remain intact and consistent. + +--- + +[VERDICT: PASS] diff --git a/.agents/reports/reviewer-grok-01/report-2311b972.identity.json b/.agents/reports/reviewer-grok-01/report-2311b972.identity.json new file mode 100644 index 0000000..636f3af --- /dev/null +++ b/.agents/reports/reviewer-grok-01/report-2311b972.identity.json @@ -0,0 +1,14 @@ +{ + "loop_id": "loop-20261013T025132Z-60f239", + "base_sha": "ae2813773c973daedd2275cb55ad340a682c3fae", + "head_sha": "62da8056680fca939a2aff924037ed48b5f74afa", + "tree_sha": "f549246ffbe2d5e58cb7e33c212a383cd429dce5", + "review_commit": "62da8056680fca939a2aff924037ed48b5f74afa", + "reviewer": "reviewer-grok-01", + "job_id": "2311b972", + "verdict": "PASS", + "transport": "herdr", + "evidence": "review-tree", + "isolation": "worktree", + "verified_at": "2026-10-13T02:56:58Z" +} \ No newline at end of file diff --git a/.agents/reports/reviewer-grok-01/report-2311b972.md b/.agents/reports/reviewer-grok-01/report-2311b972.md new file mode 100644 index 0000000..8b0017d --- /dev/null +++ b/.agents/reports/reviewer-grok-01/report-2311b972.md @@ -0,0 +1,15 @@ +# Review 2311b972 โ€” test share and generate-env.sh + +Head `62da8056680fca939a2aff924037ed48b5f74afa` (tree `f549246ffbe2d5e58cb7e33c212a383cd429dce5`) is the one commit `62da805 docs(readme): round-3 review fixes (21063f28)` on base `ae2813773c973daedd2275cb55ad340a682c3fae`. Two files, `README.md` and `README.ko.md`, two lines each, +4/โˆ’4. `git diff --check` is clean. Snapshot porcelain empty. Control-plane main is still `2ccf43911cda78fd0655c3770eec90cd22ec2d1b`, porcelain empty. + +## The two sentences match + +`README.md:175` says every test gets a temporary job registry and audit-log directory, about a third also use the sandbox fixtures that set a temporary HOME, and fewer of those use a mock herdr. That is the count from the previous review of this same test tree: weighting the parametrize lists written out in the source, 573 of 1708 (34%) reach a temporary HOME and 196 of 1708 (11%) reach `mock_herdr`. The autouse fixture still points every test's registry and audit log at a temporary directory (`tests/conftest.py:170-186`). `README.ko.md:175` says the same fraction and the same split. + +`README.md:41` says `deploy/generate-env.sh` creates `.mam.env` from `.mam.env.example` when `.mam.env` is missing, and that `--force` overwrites it while keeping a `.mam.env.bak`. The script copies the example when the destination is absent (`deploy/generate-env.sh:54-64`). When the destination exists and `--force` is absent, it exits 0 without writing (`:54-57`). With `--force` and an existing file, it copies that file to `$DST.bak`, which is `.mam.env.bak`, and then copies the example over it (`:59-64`). `README.ko.md:41` says the same. + +The script was not executed. No herdr server was started. The suite was not run. + +User `~/.config/herdr/config.toml` mtime stayed `1784456394`. + +[VERDICT: PASS] diff --git a/.agents/skills/lib.sh b/.agents/skills/lib.sh index d87fe36..5f3efd3 100644 --- a/.agents/skills/lib.sh +++ b/.agents/skills/lib.sh @@ -29,7 +29,7 @@ export WORKSPACE_ROOT # Framework semantic version. Single runtime source of truth; kept in lockstep # with VERSIONS.md and the 8 SKILL.md frontmatters by tests/test_version_consistency.py. # NOTE: unlike other MAM_* variables this one is intentionally NOT env-overridable. -MAM_VERSION="4.9.1" +MAM_VERSION="4.9.2" export MAM_VERSION AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}" diff --git a/.agents/skills/lib_py/loop/eager.py b/.agents/skills/lib_py/loop/eager.py index 4315181..749af0b 100644 --- a/.agents/skills/lib_py/loop/eager.py +++ b/.agents/skills/lib_py/loop/eager.py @@ -13,7 +13,7 @@ import sys from typing import List, Sequence # Framework version locked with framework constants -FRAMEWORK_VERSION = "4.9.1" +FRAMEWORK_VERSION = "4.9.2" CORE_MODULES: Sequence[str] = ( # Standard library modules diff --git a/.agents/skills/multi-agent-mux-create/SKILL.md b/.agents/skills/multi-agent-mux-create/SKILL.md index 394c112..1544dd9 100644 --- a/.agents/skills/multi-agent-mux-create/SKILL.md +++ b/.agents/skills/multi-agent-mux-create/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-create description: "Create a new agent session (claude, antigravity/agy) in a dedicated herdr session for context-preserving long-running work. Always creates a herdr session โ€” never backgrounds with nohup/disown. Writes the new session to .mam/agent-sessions.yaml. Use when you want to start a fresh agent (no prior UUID) for a new project workspace." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos] diff --git a/.agents/skills/multi-agent-mux-delegate-job/SKILL.md b/.agents/skills/multi-agent-mux-delegate-job/SKILL.md index 93b5c11..027aa55 100644 --- a/.agents/skills/multi-agent-mux-delegate-job/SKILL.md +++ b/.agents/skills/multi-agent-mux-delegate-job/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-delegate-job description: "Delegate a unit of work to any autonomous agent (claude-code, hermes, agy, grok-build, codex, or a human) and observe it asynchronously over an MQTT event channel. Supported roles include orchestrator, worker, and reviewer." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos, windows] diff --git a/.agents/skills/multi-agent-mux-loop/SKILL.md b/.agents/skills/multi-agent-mux-loop/SKILL.md index e0cfecc..9a9f1ad 100644 --- a/.agents/skills/multi-agent-mux-loop/SKILL.md +++ b/.agents/skills/multi-agent-mux-loop/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-loop description: "Run an autonomous planning-execution-review loop using multiple agents (Planner, Creator, Reviewers) in the workspace. Automatically orchestrates plan discussion, code changes, and peer reviews until a unanimous PASS is achieved or the maximum iteration limit is reached." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos] diff --git a/.agents/skills/multi-agent-mux-monitor/SKILL.md b/.agents/skills/multi-agent-mux-monitor/SKILL.md index e8ea93a..aee5fdd 100644 --- a/.agents/skills/multi-agent-mux-monitor/SKILL.md +++ b/.agents/skills/multi-agent-mux-monitor/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-monitor description: "Run a long-lived reconciler that watches .mam/agent-sessions.yaml against the actual herdr/agent runtime state and reconciles them. Use when you want live visibility into which agent sessions are running, which are dead, which have stale YAML entries, and which have new session ids that haven't been recorded yet. Runs as a persistent loop (`reconcile.sh --subscribe`) that keeps going until it times out, idles out, or is interrupted." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos] diff --git a/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md b/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md index 017e22e..8f1cbfb 100644 --- a/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md +++ b/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-orc-onboard description: "Register current or specified orchestrator session UUID into agent-sessions.yaml orchestrator_uuids list to prevent sub-agent discovery capture." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos] diff --git a/.agents/skills/multi-agent-mux-resume/SKILL.md b/.agents/skills/multi-agent-mux-resume/SKILL.md index ead321f..4b12333 100644 --- a/.agents/skills/multi-agent-mux-resume/SKILL.md +++ b/.agents/skills/multi-agent-mux-resume/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-resume description: "Resume an existing agent (claude, antigravity/agy) conversation by UUID into a herdr session. Reads .mam/agent-sessions.yaml for the saved session/conversation id, spawns (or reuses) a herdr session of the matching name, and runs `claude -r ` or `agy --conversation ` inside. Use when you want to reattach to a previous session's context, or revive a session whose herdr died but the agent's conversation is still on disk." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos] diff --git a/.agents/skills/multi-agent-mux-status/SKILL.md b/.agents/skills/multi-agent-mux-status/SKILL.md index 5e9da98..f26fb22 100644 --- a/.agents/skills/multi-agent-mux-status/SKILL.md +++ b/.agents/skills/multi-agent-mux-status/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-status description: "Read-only instant snapshot of all agent herdr sessions โ€” name, YAML status, herdr alive, pane cmd/cwd, resume UUID on disk, and any drift. No mutation. Reuses reconcile.sh --dry-run for the diff logic. Use when you want to know 'what's running RIGHT NOW' without spinning up the monitor loop." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos] diff --git a/.agents/skills/multi-agent-mux-stop/SKILL.md b/.agents/skills/multi-agent-mux-stop/SKILL.md index 9f3f9b4..4f98b96 100644 --- a/.agents/skills/multi-agent-mux-stop/SKILL.md +++ b/.agents/skills/multi-agent-mux-stop/SKILL.md @@ -1,7 +1,7 @@ --- name: multi-agent-mux-stop description: "Stop an agent herdr session (claude, antigravity/agy) and update .mam/agent-sessions.yaml. Default stops gracefully and marks status=stopped with conversation preserved for resume. Does NOT delete on-disk conversation artifacts (jsonl/db) โ€” those are preserved unless --purge-conversation is passed. Use when ending a work session, switching to a different one, or cleaning up before a fresh start." -version: 4.9.1 +version: 4.9.2 author: godopu license: MIT platforms: [linux, macos] diff --git a/BOOTSTRAP.ko.md b/BOOTSTRAP.ko.md index c639213..7afd07e 100644 --- a/BOOTSTRAP.ko.md +++ b/BOOTSTRAP.ko.md @@ -2,7 +2,7 @@ ๋ณธ ๋ฌธ์„œ๋Š” `herdr_agent_orchestration` ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฐ ๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ์— ๋„์ž…ํ•˜์—ฌ ์ด์‹ํ•˜๊ณ , ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์ž/์—์ด์ „ํŠธ๊ฐ€ ์ดˆ๊ธฐ ๊ฐ€๋™์„ ์‹œ์ž‘ํ•  ๋•Œ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ํ™˜๊ฒฝ ์„ค์ • ๋ฐ ๊ตฌ์ถ• ์ ˆ์ฐจ๋ฅผ ์•ˆ๋‚ดํ•ฉ๋‹ˆ๋‹ค. -[![Version: v4.9.1](https://img.shields.io/badge/version-v4.9.1-blue.svg)](VERSIONS.md) +[![Version: v4.9.2](https://img.shields.io/badge/version-v4.9.2-blue.svg)](VERSIONS.md) ์ƒˆ๋กœ์šด ์—์ด์ „ํŠธ๋Š” ์ด ์•ˆ๋‚ด์„œ์— ๊ธฐ์ˆ ๋œ ์ ˆ์ฐจ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•˜์—ฌ ์ดˆ๊ธฐ ํ™˜๊ฒฝ์„ ์•ˆ์ •์ ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. diff --git a/BOOTSTRAP.md b/BOOTSTRAP.md index 86d9522..5fe56c8 100644 --- a/BOOTSTRAP.md +++ b/BOOTSTRAP.md @@ -2,7 +2,7 @@ This document guides you through the setup and initialization procedures required to adopt the `herdr_agent_orchestration` orchestration and messaging backplane workflow in a new project, enabling a new developer or agent to get up and running quickly. -[![Version: v4.9.1](https://img.shields.io/badge/version-v4.9.1-blue.svg)](VERSIONS.md) +[![Version: v4.9.2](https://img.shields.io/badge/version-v4.9.2-blue.svg)](VERSIONS.md) A new agent can follow the steps in this guide sequentially to establish a stable and reliable initial environment. diff --git a/MESSAGING.md b/MESSAGING.md index 8375726..c8e0ad6 100644 --- a/MESSAGING.md +++ b/MESSAGING.md @@ -1,6 +1,6 @@ # Messaging System Technical Analysis & Architecture Report -Applies to: MAM v4.9.1 +Applies to: MAM v4.9.2 This report provides a comprehensive, deep-dive analysis of the messaging system implemented in the `multi-agent-mux-delegate-job` skill. It covers the MQTT broker architecture, event protocols, job lifecycles, codebase internals, cross-system integration, and a list of known limitations along with production recommendations. diff --git a/README.ko.md b/README.ko.md index 47f8d40..a000aa7 100644 --- a/README.ko.md +++ b/README.ko.md @@ -2,7 +2,7 @@ [herdr](https://herdr.dev)์™€ MQTT ์œ„์— ๋งŒ๋“  **๋‹ค์ค‘ ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ยท๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ**์ž…๋‹ˆ๋‹ค. ์žฅ์‹œ๊ฐ„ ์‹คํ–‰๋˜๋Š” ์ฝ”๋”ฉ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`)๋ฅผ ๊ฒฉ๋ฆฌ๋œ herdr pane ์—์„œ ๋Œ๋ฆฌ๊ณ , ์ž‘์—…์„ ์ถ”์ ๋˜๋Š” ์žก์œผ๋กœ ์œ„์ž„ํ•˜๋ฉฐ, ๋ชจ๋“  ๋ฆฌ๋ทฐ์–ด๊ฐ€ ํ†ต๊ณผ์‹œํ‚ฌ ๋•Œ๊นŒ์ง€ planner / creator / reviewer ๋ฃจํ”„๋ฅผ ๋Œ๋ฆฝ๋‹ˆ๋‹ค. -[![Version: v4.9.1](https://img.shields.io/badge/version-v4.9.1-blue.svg)](VERSIONS.md) +[![Version: v4.9.2](https://img.shields.io/badge/version-v4.9.2-blue.svg)](VERSIONS.md) --- diff --git a/README.md b/README.md index ef9efde..d310503 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A **Multi-Agent Orchestration & Messaging Backplane** built on [herdr](https://herdr.dev) and MQTT. It runs long-lived coding agents (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`) in isolated herdr panes, delegates work to them as tracked jobs, and drives planner / creator / reviewer loops until every reviewer passes the change. -[![Version: v4.9.1](https://img.shields.io/badge/version-v4.9.1-blue.svg)](VERSIONS.md) +[![Version: v4.9.2](https://img.shields.io/badge/version-v4.9.2-blue.svg)](VERSIONS.md) --- diff --git a/VERSIONS.md b/VERSIONS.md index cb9c202..c8a8612 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -6,7 +6,7 @@ ## ๐Ÿ“Œ ํ˜„์žฌ ๋ฒ„์ „ ๊ฐœ์š” (Current Release) -- **ํ”„๋ ˆ์ž„์›Œํฌ ๋ฒ„์ „**: `v4.9.1` +- **ํ”„๋ ˆ์ž„์›Œํฌ ๋ฒ„์ „**: `v4.9.2` - **์ตœ์‹  ๋ฆด๋ฆฌ์Šค ์ผ์‹œ**: 2026-10-13 (KST) - **๊ธฐ์ค€ ๋ธŒ๋žœ์น˜**: `main` - **ํ•ต์‹ฌ ์•„ํ‚คํ…์ฒ˜**: @@ -24,23 +24,35 @@ ## ๐Ÿงญ ์Šคํ‚ฌ ํŒจํ‚ค์ง€ ๋ฒ„์ „ ๋งคํŠธ๋ฆญ์Šค (Skills Version Matrix) -๋ชจ๋“  8๊ฐœ ์Šคํ‚ฌ์€ YAML frontmatter ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(`author`, `version`, `platforms`, `environments`) ํ‘œ์ค€ํ™”๋ฅผ ํ†ตํ•ด `v4.9.1`๋กœ ๋™๊ธฐํ™”๋˜์–ด ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. +๋ชจ๋“  8๊ฐœ ์Šคํ‚ฌ์€ YAML frontmatter ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(`author`, `version`, `platforms`, `environments`) ํ‘œ์ค€ํ™”๋ฅผ ํ†ตํ•ด `v4.9.2`๋กœ ๋™๊ธฐํ™”๋˜์–ด ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. | ์Šคํ‚ฌ๋ช… | ๋ฒ„์ „ | ์—ญํ•  ๋ฐ ์ฃผ์š” ์ฑ…์ž„ | ์ƒํƒœ | | :--- | :---: | :--- | :---: | -| **`multi-agent-mux-create`** | `4.9.1` | ์—์ด์ „ํŠธ ์„ธ์…˜ ์‹ ๊ทœ ์ƒ์„ฑ ๋ฐ Herdr ์ปจํ…Œ์ด๋„ˆ ๊ฒฉ๋ฆฌ ์Šคํฐ | โœ… ๋ฐฐํฌ | -| **`multi-agent-mux-stop`** | `4.9.1` | ๋Œ€ํ™” UUID ์›์ž์  ์บก์ฒ˜ ๋ฐ ์„ธ์…˜ ์•ˆ์ „ ์ข…๋ฃŒ (Graceful Stop) | โœ… ๋ฐฐํฌ | -| **`multi-agent-mux-resume`** | `4.9.1` | ์˜จ๋””์Šคํฌ ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ Tier-1 ์ดˆ๊ณ ์† ์„ธ์…˜ ๋ณต์› | โœ… ๋ฐฐํฌ | -| **`multi-agent-mux-status`** | `4.9.1` | ์‹ค์‹œ๊ฐ„ Herdr ์„ธ์…˜ ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋“œ๋ฆฌํ”„ํŠธ ์Šค๋ƒ…์ƒท ์กฐํšŒ | โœ… ๋ฐฐํฌ | -| **`multi-agent-mux-monitor`** | `4.9.1` | YAML โ†” ๋Ÿฐํƒ€์ž„ ์ƒํƒœ ๊ฐ„ ์ž์œจ ์กฐ์ •์ž (Reconciler Loop) | โœ… ๋ฐฐํฌ | -| **`multi-agent-mux-delegate-job`** | `4.9.1` | MQTT ์ด๋ฒคํŠธ ์ฑ„๋„ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ๋‹จ์œ„ ์ž‘์—… ์œ„์ž„ | โœ… ๋ฐฐํฌ | -| **`multi-agent-mux-loop`** | `4.9.1` | Planner-Creator-Reviewer 3์ž ์ž์œจ ๊ณ„ํšยท์‹คํ–‰ยทํ”ผ์–ด๋ฆฌ๋ทฐ ๋ฃจํ”„ | โœ… ๋ฐฐํฌ | -| **`multi-agent-mux-orc-onboard`** | `4.9.1` | ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ UUID ๊ฒฉ๋ฆฌ ๋“ฑ๋ก ๋ฐ ์„œ๋ธŒ ์„ธ์…˜ ์˜ค์—ผ ๋ฐฉ์ง€ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-create`** | `4.9.2` | ์—์ด์ „ํŠธ ์„ธ์…˜ ์‹ ๊ทœ ์ƒ์„ฑ ๋ฐ Herdr ์ปจํ…Œ์ด๋„ˆ ๊ฒฉ๋ฆฌ ์Šคํฐ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-stop`** | `4.9.2` | ๋Œ€ํ™” UUID ์›์ž์  ์บก์ฒ˜ ๋ฐ ์„ธ์…˜ ์•ˆ์ „ ์ข…๋ฃŒ (Graceful Stop) | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-resume`** | `4.9.2` | ์˜จ๋””์Šคํฌ ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ Tier-1 ์ดˆ๊ณ ์† ์„ธ์…˜ ๋ณต์› | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-status`** | `4.9.2` | ์‹ค์‹œ๊ฐ„ Herdr ์„ธ์…˜ ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋“œ๋ฆฌํ”„ํŠธ ์Šค๋ƒ…์ƒท ์กฐํšŒ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-monitor`** | `4.9.2` | YAML โ†” ๋Ÿฐํƒ€์ž„ ์ƒํƒœ ๊ฐ„ ์ž์œจ ์กฐ์ •์ž (Reconciler Loop) | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-delegate-job`** | `4.9.2` | MQTT ์ด๋ฒคํŠธ ์ฑ„๋„ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ๋‹จ์œ„ ์ž‘์—… ์œ„์ž„ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-loop`** | `4.9.2` | Planner-Creator-Reviewer 3์ž ์ž์œจ ๊ณ„ํšยท์‹คํ–‰ยทํ”ผ์–ด๋ฆฌ๋ทฐ ๋ฃจํ”„ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-orc-onboard`** | `4.9.2` | ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ UUID ๊ฒฉ๋ฆฌ ๋“ฑ๋ก ๋ฐ ์„œ๋ธŒ ์„ธ์…˜ ์˜ค์—ผ ๋ฐฉ์ง€ | โœ… ๋ฐฐํฌ | --- ## ๐Ÿ“‹ ๋ฒ„์ „๋ณ„ ์ƒ์„ธ ๋ณ€๊ฒฝ ๋‚ด์—ญ (Changelog) +### ๐Ÿš€ `v4.9.2` โ€” README ๋ฅผ ํ˜„์žฌ ์ฝ”๋“œ์— ๋งž์ถฐ ๋‹ค์‹œ ์“ด๋‹ค (2026-10-13) + +> **ํŒจ์น˜ (PATCH Release, ๋ฌธ์„œ ์ „์šฉ)**: ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์Œ. `README.md` ๋ฅผ v4.9.1 ์˜ ์ฝ”๋“œ์™€ ๋Œ€์กฐํ•ด ๋‹ค์‹œ ์“ฐ๊ณ  `README.ko.md` ๋ฅผ ๊ฐ™์€ ๋‚ด์šฉ์œผ๋กœ ๋งž์ท„๋‹ค. + +#### ๐ŸŒŸ ์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ +1. **๋‚ก์€ ์„ค๋ช… ์ •์ •**: shim ์€ `/tmp/multi-agent-herdr-shim/` + `herdr -L` ์ด ์•„๋‹ˆ๋ผ `/.mam/shim/herdr` + `--session`; ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์“ฐ๊ธฐ๋Š” ์‹œ์Šคํ…œ `python3` ์ด ์•„๋‹ˆ๋ผ `AGENT_PYTHON_BIN` โ†’ ๊ฐ€์ƒํ™˜๊ฒฝ โ†’ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด `.venv` โ†’ `PATH` ์˜ `python3` ์ˆœ; `install.sh` ์˜ ์‹ค์ œ ๋™์ž‘(๊ฒ€์‚ฌ ํ•ญ๋ชฉ, `MQTT_BROKER=localhost` ์ดˆ๊ธฐ `.mam.env`, ๊ธฐ์กด ํŒŒ์ผ ๋ณด์กด, `.env` ๋ณต์‚ฌ); ์ €์žฅ์†Œ ๊ตฌ์กฐ์™€ Quick Start. +2. **๋น ์กŒ๋˜ ๋‚ด์šฉ ์ถ”๊ฐ€**: ์œ„์ž„ ๊ณ„์•ฝ(์ „๋‹ฌ TยทheartbeatยทKร—Nยท์˜ˆ์‚ฐยท๋ฐ”์œ ์„ธ์…˜ ๋Œ€๊ธฐยท์›๊ฒฉ ์ „์†กยท์ข…๋ฃŒ ์ฝ”๋“œ ํ‘œ), ๋ฆฌ๋ทฐ ๋ฃจํ”„(์„ ํƒํ•œ ๋ฆฌ๋ทฐ์–ด ์ „์› PASS, ์˜ต์…˜์ด ์—†์œผ๋ฉด creator self-review, ์—„๊ฒฉํ•œ ํŒ์ •, ๋ฆฌ๋ทฐ identity, ํ•˜์œ„ ์žก), `create --onboard` 44/45, ์„œ๋ฒ„๋ณ„ pane claim, ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ด๋ฆ„์˜ ๊ธฐ๋ณธ ์„œ๋ฒ„์™€ ์กฐ๊ฑด๋ถ€ ์ž๋™ ๊ธฐ๋™, restore-off ์™€ ๊ทธ ํด๋ฐฑ, ๋ณด์•ˆ ์กฐ๊ฑด(ํ† ํฐ์€ ๋„˜๊ธฐ๊ฑฐ๋‚˜ TLS/username ์ผ ๋•Œ๋งŒ; ์›๊ฒฉ ๋””์ŠคํŒจ์น˜์—๋Š” ํ† ํฐ์ด ์‹ค๋ฆผ), ํ…Œ์ŠคํŠธ ๊ฒฉ๋ฆฌ. + +#### โœ… ํ’ˆ์งˆ ๊ฒ€์ฆ +- **๋ฆฌ๋ทฐ (`--review-only`, `--all-reviewer`, ์‚ฌ์‹ค ๋Œ€์กฐ)**: 1ํšŒ์ฐจ(@20b1014) agy PASS, claudeยทgrokยทcodex NOT PASS(์„ค์น˜ ๋™์ž‘, ๋ณด์•ˆ ์กฐ๊ฑด, ์„œ๋ฒ„ ๊ฒฉ๋ฆฌ, ๋ฆฌ๋ทฐ์–ด ์„ ํƒ, ์ธํ„ฐํ”„๋ฆฌํ„ฐ ๋“ฑ); 2ํšŒ์ฐจ(@423abc7, `README.ko.md` ํฌํ•จ) claudeยทagy PASS, grokยทcodex NOT PASS(์ข…๋ฃŒ ์ฝ”๋“œ 5 ์˜ superseded, `.env` ๋ณต์‚ฌ, restore ํด๋ฐฑ); 3ํšŒ์ฐจ(@ae28137) grok NOT PASS(์ƒŒ๋“œ๋ฐ•์Šค ํ”ฝ์Šค์ฒ˜ ๋น„์œจ, generate-env); 4ํšŒ์ฐจ(@62da805) **4/4 PASS**. ๋ฆฌํฌํŠธ๋Š” `.agents/reports//`. +- **๋ฆฌ๋ทฐ ์ค‘ ๋ฐœ๊ฒฌ(๋ณ„๋„ ์ˆ˜์ •)**: `tests/test_issue50_dispatch.py::test_u1e_aโ€ฆ` ๊ฐ€ `WORKSPACE_ROOT` ์—†์ด ๋ž˜ํผ๋ฅผ ์‹คํ–‰ํ•ด ์ฒดํฌ์•„์›ƒ์˜ `.mam/shim/herdr` ๋ฅผ ์“ด๋‹ค(claude ์žฌํ˜„). ๋‹ค์Œ ๋ฆด๋ฆฌ์Šค์—์„œ ๊ณ ์นœ๋‹ค. + ### ๐Ÿš€ `v4.9.1` โ€” ํ…Œ์ŠคํŠธ๊ฐ€ ์‹ค์ œ herdr ์„œ๋ฒ„์— ์„ธ์…˜์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค (2026-10-13) > **ํŒจ์น˜ (PATCH Release)**: v4.9.0 ๋ณ‘ํ•ฉ ๊ฒ€์ฆ ์ค‘ ์—์ด์ „ํŠธ pane ์—์„œ `--basetemp .../pytest-pr56-shim` ์œผ๋กœ ๋Œ๋ฆฐ ์Šค์œ„ํŠธ๊ฐ€ ๊ทธ pane ์˜ ์‹ค์ œ ์„œ๋ฒ„(`multi-agent-mux`)์— ์›Œํฌ์ŠคํŽ˜์ด์Šค 7๊ฐœ๋ฅผ ๋‚จ๊ฒผ๋‹ค(์ •๋ฆฌ ์™„๋ฃŒ). ์ œํ’ˆ ์ฝ”๋“œ ๋ณ€๊ฒฝ์€ ์‹ค์ œ herdr ํ•ด์„๊ธฐ์˜ `-shim` ๊ทœ์น™ ํ•œ ๊ฐ€์ง€.