Files
multi-agent-mux/.agents/skills/multi-agent-mux-delegate-job/SKILL.md
T
GodopuandClaude Opus 5 387479732e release(v4.4.0): bump framework and eight skills to 4.4.0 in lockstep
Issue #5 (Python core migration, CAS state transitions, shadow watcher,
auto-completion gate, eager-import immutable runtime, B-13 freeze removal)
is complete and merged to main. This stamps the release.

SemVer: MINOR, not MAJOR. The change is large but breaks nothing. Across the
whole Issue #5 range there are zero file deletions and zero renames, the event
wire schema stays at SCHEMA_VERSION 1, all four literal script paths survive as
compatibility shims, the 968-line legacy shell loop is still in run_loop.sh,
and every default change reverts through a single environment variable
(MAM_DELEGATION_PY / MAM_ENGINE_CAS / MAM_LOOP_PY / MAM_LOOP_FREEZE). The
riskiest new feature, auto-completion, ships default-off. No operator has
anything to migrate, which is the decisive reason not to call it 5.0.0. The
reasoning is recorded in the VERSIONS.md release notes, not just here.

Close a gap in the lockstep guard. lib.sh exports MAM_VERSION and eager_load()
refuses to start the loop when it disagrees with FRAMEWORK_VERSION, so eager.py
is a load-bearing fourth leg — but test_version_consistency.py only checked
three, and the sole check on eager.py was a hardcoded literal in the phase 4
test that a release bump has to edit anyway. The lockstep test now covers
eager.py, a new test pins the fail-closed gate itself, and the phase 4 test no
longer carries a version literal.

Fix a latent test-isolation defect the bump exposed. The first full run failed
four tests with "MAM_VERSION mismatch: expected 4.4.0, got 4.3.0 in
environment" — 4.3.0 was not in the tree, it was inherited from the shell that
launched pytest and had sourced the pre-bump lib.sh. Those tests were measuring
the runner's shell rather than the tree under test, and only passed until now
because the two values always happened to agree. A session-scoped fixture drops
the ambient value. Production is unaffected: run_loop.sh:17 sources lib.sh
before anything else and lib.sh re-exports MAM_VERSION unconditionally, so a
stale inherited value is always overwritten before Python starts.

Full suite: 750 passed in 912.50s, 0 failed, 0 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
2026-09-07 15:55:26 +09:00

139 lines
8.2 KiB
Markdown

---
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.4.0
author: godopu
license: MIT
platforms: [linux, macos, windows]
environments: [terminal, herdr]
metadata:
hermes:
tags: [agent, herdr, multi-agent, delegate, mqtt, async, job]
related_skills: [multi-agent-mux-create, multi-agent-mux-resume, multi-agent-mux-loop]
prereq_skills: [multi-agent-mux-create]
---
# multi-agent-mux-delegate-job — Async Job Delegation over MQTT
Delegate a unit of work to any autonomous agent, then **observe** it asynchronously instead of blocking. Every job gets a unique ID and a registry record. The worker agent publishes lifecycle events (`started`, `permission_required`, `progress`, `completed`, `error`) to a per-job MQTT topic, and the delegator/orchestrator subscribes to verify the final state.
This skill allows any agent (`claude-code`, `hermes`, `agy`, `grok-build`, etc.) to play any role: **Orchestrator/Delegator**, **Worker/Implementer**, or **Reviewer**.
---
## Roles in Multi-Agent Mux
- **Orchestrator (Delegator)**: Initiates the job, coordinates other agents, handles loops and reviews, and commits final changes.
- **Worker (Implementer)**: Receives the brief file or task prompt, performs the implementation, and emits started/completed/error events.
- **Reviewer**: Evaluates git diffs or artifacts produced by the worker, and responds with a `completed` event containing `"PASS"` or feedback.
---
## Core Commands (CLI)
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. herdr session name 'demo')
multi-agent-mux-delegate-job submit \
--agent <claude-code|hermes-agent|agy-agent|grok-build|human> \
--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 herdr:<worker_session> \
--type loop --reviewer <reviewer_agent> --reviewer-session herdr:<reviewer_session> \
--prompt "Task description"
# 3) Check job status and audit logs
multi-agent-mux-delegate-job status --job <JOB_ID>
multi-agent-mux-delegate-job logs <JOB_ID> # Chronological log of events
multi-agent-mux-delegate-job list # Summary of all registered jobs
# 4) Verify job artifacts with a validation script
multi-agent-mux-delegate-job verify --job <JOB_ID> --validate ./validate.sh
```
---
## Task Delegation Types
Supported job types include:
- `direct` (default): Single agent execution (direct tasking).
- `loop` (Worker-Reviewer Loop): Alternates worker execution and reviewer evaluation until reviewer approves (`PASS`) or iterations run out.
- `discuss` (Research & Discussion): Collaboration between two agents to reach a consensus (e.g., agreeing on a design or plan).
For detailed state machine diagrams and configurations, see [DELEGATION_TYPES.md](./DELEGATION_TYPES.md).
---
## Where the Implementation Lives (v4.3.0)
The implementation moved to the `lib_py.delegation` package in issue #5 phase 1.
`scripts/{mqtt_common,registry,publish_event,job_subscriber}.py` remain as
compatibility shims and **their paths are unchanged** -- every command in this
document still works verbatim. Each shim binds the `lib_py.delegation` package
to the tree next to itself, once per process, without touching `sys.path`, so
`import mqtt_common` yields the same module object as
`lib_py.delegation.mqtt_common`.
Which tree wins, by execution context:
| Context | Resolved by | Tree that wins |
|---|---|---|
| Loop process and its children (frozen `lib.sh` sourced) | the helper's explicit bootstrap from `SKILL_DIR` | the frozen snapshot |
| Agent session running a **frozen** script path while `PYTHONPATH` still points live | the shim, from its own location | the frozen snapshot (B-13 preserved) |
| Live helpers (create/stop/resume/reconcile) | `PYTHONPATH` or the shim (same tree) | the live tree |
| Standalone, no `PYTHONPATH` | the shim's fallback append | the shim's own tree |
`lib.sh` calls the package through `_delegation_py`, which inserts its own
`SKILL_DIR` at the front of the import path. It deliberately does **not** use
`python -m`: for `-m` the current directory precedes `PYTHONPATH`, so a frozen
loop whose working directory happened to contain a `lib_py` package would have
silently executed live code. The working directory is left untouched, because
the registry and audit-log paths are relative to it.
Setting `MAM_DELEGATION_PY=0` switches the shell helpers back to their preserved
legacy bodies with no redeploy.
One in-process caveat: the package binds once per process and is never rebound,
so do not import a frozen shim after a live `lib_py.delegation` is already bound
inside the same interpreter. Production never does this — each delegated job is
a fresh interpreter — but a test harness could.
---
## The Event Protocol Contract
Every agent participating in the delegation contract must follow the same lifecycle publishing protocol using `publish_event.py`:
1. **On Start**: Publish `started` event.
`python3 .agents/skills/multi-agent-mux-delegate-job/scripts/publish_event.py --job "$JOB_ID" --event started`
2. **On Tool/Permission Prompt**: Publish `permission_required` event.
`python3 ... --job "$JOB_ID" --event permission_required --detail "<tool>:<reason>"`
3. **On Progress Update (Optional)**: Publish `progress` event.
`python3 ... --job "$JOB_ID" --event progress --detail "<status_update>"`
4. **On Success**: Publish `completed` event.
`python3 ... --job "$JOB_ID" --event completed --detail "<summary>"` (Reviewer should include `"PASS"` in the detail to approve).
5. **On Failure/Feedback**: Publish `error` event.
`python3 ... --job "$JOB_ID" --event error --detail "<reason_or_feedback>"`
---
## Audit Logs
Job lifecycle execution events are persistently mirrored to an append-only log under `.mam/delegate_job_logs/<job_id>/` (containing `meta.json`, `events.ndjson`, and `status.json`). Use `multi-agent-mux-delegate-job logs <job_id>` to view the timeline.
---
## Best Practices and Pitfalls
- **Subscribe-Before-Publish**: The subscriber must be running before the agent starts publishing. The `submit` command handles this automatically by launching the subscriber in the background first.
- **Fresh job_id Propagation**: Make sure the worker agent receives the correct `JOB_ID` generated for the current run, rather than reusing stale IDs from previous sessions.
- **Brief delivery via file path**: For long or complex prompts, write the instructions to a file (e.g. `/tmp/task-brief.md`) and pass a short prompt pointing to the file path to prevent terminal buffer overflows.
- **Prompts injected into a live agent session MUST be English, ASCII-only, and short** — this is exactly what `--prompt`/the `instructions` string sent to `run_agent()` end up as. Any Korean (or other non-ASCII) content the task needs to convey must go in a markdown brief file (e.g. `.mam/jobs/<id>/brief.md`, written in Korean is fine) that the injected prompt merely tells the agent to read. Two independent bugs in `send_keys_safe`'s paste-verification (in `lib.sh`) made this matter in practice: (a) its marker was taken with a byte-based `tail -c 24`, which can slice a multi-byte UTF-8 (e.g. Korean) character in half; (b) the rendered pane soft-wraps long lines at the terminal width, which can split the marker across two visual lines. Both are now fixed at the source (character-safe truncation + newline-stripped matching before comparison), but keeping injected prompts short/English/file-referencing is still the cheapest way to avoid ever exercising this edge case at all — it's also simply what `submit`'s own default instruction template already does (see `Core Commands` above).
- **Batch Grouping**: Group non-overlapping tasks into batches to parallelize execution across multiple agent sessions, reducing overhead.