Clean up all tmux occurrences from dev skills and integrate herdr wrapper translation shim with dynamic env and workspace ID parsing
This commit is contained in:
@@ -45,7 +45,7 @@ multi-agent-mux-delegate-job submit \
|
||||
### 신규 옵션 상세:
|
||||
* `--type`: 작업 위임 타입을 지정합니다. (`direct`, `loop`, `discuss`)
|
||||
* `--reviewer`: 리뷰를 담당할 에이전트 이름입니다 (기본값: `hermes`).
|
||||
* `--reviewer-session`: 리뷰어 에이전트가 돌고 있는 tmux 세션 이름입니다 (기본값: `tmux:hermes`).
|
||||
* `--reviewer-session`: 리뷰어 에이전트가 돌고 있는 herdr 세션 이름입니다 (기본값: `herdr:hermes`).
|
||||
* `--max-iterations`: 루프 또는 토론의 최대 반복 횟수입니다 (기본값: `5`).
|
||||
|
||||
---
|
||||
@@ -73,10 +73,10 @@ stateDiagram-v2
|
||||
### 단계별 상세 동작 프로토콜:
|
||||
|
||||
1. **작업자(Worker) 실행**:
|
||||
* 오케스트레이터는 작업을 `pending`으로 등록하고, `agent_session`을 작업자 세션(예: `tmux:claude`)으로 설정하여 전달합니다.
|
||||
* 오케스트레이터는 작업을 `pending`으로 등록하고, `agent_session`을 작업자 세션(예: `herdr:claude`)으로 설정하여 전달합니다.
|
||||
* 작업자가 수행을 완료하고 `completed` 이벤트를 발행하면 오케스트레이터가 이를 가로챕니다.
|
||||
2. **리뷰어(Reviewer)로 스위칭**:
|
||||
* 오케스트레이터는 전체 작업을 종료하지 않고, 작업 레코드의 `agent_session`을 리뷰어 세션(예: `tmux:hermes`)으로 변경합니다.
|
||||
* 오케스트레이터는 전체 작업을 종료하지 않고, 작업 레코드의 `agent_session`을 리뷰어 세션(예: `herdr:hermes`)으로 변경합니다.
|
||||
* 리뷰어에게 전달할 프롬프트를 자동으로 조립합니다:
|
||||
> *"Review the changes/artifacts generated for job $JOB_ID. Check if they meet the requirements. If correct, publish completed event with 'PASS'. If there are issues, publish error event with detailed feedback/nits."*
|
||||
* 상태를 다시 `pending`으로 리셋하여 리뷰어 세션이 잡을 집어갈 수 있도록 합니다.
|
||||
|
||||
@@ -28,18 +28,18 @@ This skill allows any agent (`claude-code`, `hermes`, `agy`, `cline`, etc.) to p
|
||||
The `multi-agent-mux-delegate-job` bash wrapper handles job registration, subscriber management, agent session targeting, and validation hooks:
|
||||
|
||||
```bash
|
||||
# 1) Submit a new job to a targeted agent session (e.g. tmux session name 'demo')
|
||||
# 1) Submit a new job to a targeted agent session (e.g. herdr session name 'demo')
|
||||
multi-agent-mux-delegate-job submit \
|
||||
--agent <claude-code|hermes-agent|agy-agent|cline-agent|human> \
|
||||
--agent-session tmux:<session_name> \
|
||||
--agent-session herdr:<session_name> \
|
||||
--prompt "Task description or instructions here" \
|
||||
--role <Worker|Planner|Reviewer> \
|
||||
--timeout 3600 --idle-timeout 120
|
||||
|
||||
# 2) Submit a job with a feedback loop (Worker-Reviewer Loop)
|
||||
multi-agent-mux-delegate-job submit \
|
||||
--agent <worker_agent> --agent-session tmux:<worker_session> \
|
||||
--type loop --reviewer <reviewer_agent> --reviewer-session tmux:<reviewer_session> \
|
||||
--agent <worker_agent> --agent-session herdr:<worker_session> \
|
||||
--type loop --reviewer <reviewer_agent> --reviewer-session herdr:<reviewer_session> \
|
||||
--prompt "Task description"
|
||||
|
||||
# 3) Check job status and audit logs
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The registry is the **single source of truth** for delegated work. Job metadata
|
||||
(id, prompt, broker, status, timeouts) lives in files, **not** environment
|
||||
variables — so one tmux session can handle many jobs sequentially or in
|
||||
variables — so one herdr session can handle many jobs sequentially or in
|
||||
parallel without collisions, and `publish_event.py` / `job_subscriber.py` can
|
||||
reconstruct everything they need from the registry alone.
|
||||
|
||||
@@ -37,7 +37,7 @@ Reference implementation: [`./scripts/registry.py`](./scripts/registry.py)
|
||||
"updated_at": "2026-06-19T09:32:00Z",
|
||||
"prompt": "정렬 문제 10개를 만들어 sort_problems.md로 저장…",
|
||||
"agent": "claude-code",
|
||||
"agent_session": "tmux:claude",
|
||||
"agent_session": "herdr:claude",
|
||||
"broker": {
|
||||
"host": "broker.hivemq.com",
|
||||
"port": 1883,
|
||||
@@ -69,7 +69,7 @@ Reference implementation: [`./scripts/registry.py`](./scripts/registry.py)
|
||||
|
||||
Every read-modify-write (`register_job`, `pick_pending`, `update_status`,
|
||||
`next_seq`) runs inside `registry_lock(registry_dir)`, an exclusive
|
||||
`fcntl.flock` over `.lock`. Single-host, good enough for many tmux sessions on
|
||||
`fcntl.flock` over `.lock`. Single-host, good enough for many herdr sessions on
|
||||
one machine.
|
||||
|
||||
### Production — SQLite WAL
|
||||
@@ -83,8 +83,8 @@ signatures stay identical; only the storage backend changes.
|
||||
|
||||
## 4. How multiple sessions take only their own work
|
||||
|
||||
Each tmux session carries an `agent_session` label (`tmux:claude`,
|
||||
`tmux:claude-a`, `tmux:claude-b`, …). `pick_pending(agent_session)`:
|
||||
Each herdr session carries an `agent_session` label (`herdr:claude`,
|
||||
`herdr:claude-a`, `herdr:claude-b`, …). `pick_pending(agent_session)`:
|
||||
|
||||
1. acquires the registry lock,
|
||||
2. scans for the **oldest** record with `status == "pending"` **and**
|
||||
@@ -99,7 +99,7 @@ the job already `running` and moves on.
|
||||
|
||||
```bash
|
||||
# session A only ever runs its own pending jobs
|
||||
PY scripts/registry.py pick --agent-session tmux:claude-a # prints id or exits 3
|
||||
PY scripts/registry.py pick --agent-session herdr:claude-a # prints id or exits 3
|
||||
```
|
||||
|
||||
---
|
||||
@@ -127,12 +127,12 @@ SQLite transaction when you migrate.
|
||||
```bash
|
||||
PY=.venv/bin/python
|
||||
$PY scripts/registry.py register --prompt "…" --agent claude-code \
|
||||
--agent-session tmux:claude --timeout 3600 --idle-timeout 120 # → prints job_id
|
||||
--agent-session herdr:claude --timeout 3600 --idle-timeout 120 # → prints job_id
|
||||
$PY scripts/registry.py list # human table
|
||||
$PY scripts/registry.py list --json # full records
|
||||
$PY scripts/registry.py get --job <id> # one record
|
||||
$PY scripts/registry.py status --job <id> --set completed # set status
|
||||
$PY scripts/registry.py pick --agent-session tmux:claude # claim → running
|
||||
$PY scripts/registry.py pick --agent-session herdr:claude # claim → running
|
||||
```
|
||||
|
||||
Exit codes: `0` ok, `1` not found / bad status, `3` (`pick`) no pending job for
|
||||
|
||||
@@ -266,7 +266,7 @@ def _lock_path(registry_dir: str) -> Path:
|
||||
def registry_lock(registry_dir: str):
|
||||
"""Advisory exclusive lock over the whole registry dir via fcntl.
|
||||
|
||||
PoC-grade single-host concurrency control. Multiple tmux sessions / scripts
|
||||
PoC-grade single-host concurrency control. Multiple herdr sessions / scripts
|
||||
serialise their read-modify-write of job records through this lock so two
|
||||
sessions never claim the same pending job. For multi-host delegation move
|
||||
to SQLite WAL (see references/registry.md)."""
|
||||
|
||||
@@ -16,7 +16,7 @@ Exit codes:
|
||||
|
||||
Usage:
|
||||
publish_event.py --job <id> --event started [--detail "..."] [--data '{...}']
|
||||
publish_event.py --pick-pending --agent-session tmux:claude --event completed
|
||||
publish_event.py --pick-pending --agent-session herdr:claude --event completed
|
||||
publish_event.py --job <id> --event completed --retained
|
||||
"""
|
||||
from __future__ import annotations
|
||||
@@ -135,7 +135,7 @@ def main(argv=None) -> int:
|
||||
target.add_argument("--job", help="job id to publish for")
|
||||
target.add_argument("--pick-pending", action="store_true",
|
||||
help="auto-select a pending job for --agent-session")
|
||||
parser.add_argument("--agent-session", default="tmux:claude",
|
||||
parser.add_argument("--agent-session", default="herdr:claude",
|
||||
help="session label used with --pick-pending")
|
||||
parser.add_argument("--event", default="progress", choices=VALID_EVENTS)
|
||||
parser.add_argument("--detail", default="")
|
||||
|
||||
@@ -50,7 +50,7 @@ def generate_job_id(bits: int = 32) -> str:
|
||||
def register_job(
|
||||
prompt: str,
|
||||
agent: str = "claude-code",
|
||||
agent_session: str = "tmux:claude",
|
||||
agent_session: str = "herdr:claude",
|
||||
role: str = "Worker",
|
||||
broker: Optional[Dict[str, Any]] = None,
|
||||
timeout_sec: int = 3600,
|
||||
@@ -116,7 +116,7 @@ def register_job(
|
||||
def pick_pending(agent_session: str, registry_dir: str = DEFAULT_REGISTRY_DIR) -> Optional[str]:
|
||||
"""Claim the oldest ``pending`` job for ``agent_session``, flipping it to
|
||||
``running`` atomically under the lock. Returns the job id, or None if no
|
||||
pending job matches. This is how each tmux session takes only its own work
|
||||
pending job matches. This is how each herdr session takes only its own work
|
||||
without two sessions grabbing the same job."""
|
||||
with registry_lock(registry_dir):
|
||||
candidates = []
|
||||
@@ -240,7 +240,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
p_reg = sub.add_parser("register", help="create a pending job; prints the job id")
|
||||
p_reg.add_argument("--prompt", required=True)
|
||||
p_reg.add_argument("--agent", default="claude-code")
|
||||
p_reg.add_argument("--agent-session", default="tmux:claude")
|
||||
p_reg.add_argument("--agent-session", default="herdr:claude")
|
||||
p_reg.add_argument("--role", default="Worker", help="logical role for the delegated agent (e.g. Worker, Planner, Reviewer)")
|
||||
p_reg.add_argument("--timeout", type=int, default=3600)
|
||||
p_reg.add_argument("--idle-timeout", type=int, default=120)
|
||||
@@ -275,7 +275,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
p_feedback.add_argument("--job", required=True)
|
||||
|
||||
p_pick = sub.add_parser("pick", help="claim a pending job for a session; prints id")
|
||||
p_pick.add_argument("--agent-session", default="tmux:claude")
|
||||
p_pick.add_argument("--agent-session", default="herdr:claude")
|
||||
|
||||
p_logs = sub.add_parser(
|
||||
"logs",
|
||||
|
||||
Reference in New Issue
Block a user