Renamed 6 skills directories to tmux-agent-orchestrate-* prefix: - multi-agent-create → tmux-agent-orchestrate-create - multi-agent-resume → tmux-agent-orchestrate-resume - multi-agent-delete → tmux-agent-orchestrate-delete - multi-agent-status → tmux-agent-orchestrate-status - agent-sessions-monitor → tmux-agent-orchestrate-monitor - delegate-job → tmux-agent-orchestrate-delegate-job Updated: - skills/lib.sh internal paths (delegate_submit_job etc.) - skills/tmux-agent-orchestrate-status/scripts/status.sh (monitor path) - skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh - .gitignore (HTML ignore patterns) - 6 SKILL.md frontmatter (name, related_skills, prereq_skills) and body - All script headers and Korean comments Notes: - tmux session naming convention unchanged (<slug>-creator-<agent>) — workspace identifier based, kept for backward compatibility - Existing 2 sessions in -L multi-agent-canary untouched - YAML delegate_job_id / agent-session (tmux:canary-...) preserved for log history compatibility Verified on isolated server -L agy-rename-test (kill-server after).
5.6 KiB
MQTT Broker Setup — PoC → Production
The tmux-agent-orchestrate-delegate-job scripts read all broker settings from environment
variables (or a job record's broker.* block) through a single helper,
broker_config_from_env() in
./scripts/mqtt_common.py. The design goal:
switch from the public PoC broker to your own broker with config only — no
code change.
| Env var | Meaning | PoC default | Production |
|---|---|---|---|
MQTT_BROKER |
host | broker.hivemq.com |
internal hostname/IP |
MQTT_PORT |
port | 1883 |
8883 (TLS) |
MQTT_TLS |
TLS on/off (1/0) |
0 |
1 |
MQTT_USERNAME / MQTT_PASSWORD |
auth | (none) | broker-issued |
MQTT_CA_CERTS |
CA bundle path | (none) | private CA path |
MQTT_CERTFILE / MQTT_KEYFILE |
client cert (optional mTLS) | (none) | per-client |
MQTT_CLIENT_ID_PREFIX |
client id prefix | hermes |
per-environment |
1. PoC: public broker (broker.hivemq.com)
Pros — zero setup, reachable from anywhere, perfect for wiring up the publish/subscribe loop and the timeout/state-machine logic.
Cons / accepted assumptions — no auth, no integrity, shared with the world:
- no secrets in payloads;
started/completed/errorare advisory signals only;- non-retained messages are not queued for absent subscribers, so the subscriber must start before the agent;
- a re-subscribing client cannot recover past (non-retained) events.
Use it only to validate the protocol, never for real decisions.
2. Production: self-hosted Mosquitto (or EMQX)
Both support MQTT 5 + ACL + TLS. Mosquitto shown below; EMQX is a drop-in for the same env vars.
2.1 Install
# macOS
brew install mosquitto
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y mosquitto mosquitto-clients
# Docker
docker run -d --name mosquitto -p 8883:8883 \
-v "$PWD/mosquitto.conf:/mosquitto/config/mosquitto.conf" \
-v "$PWD/certs:/mosquitto/certs" \
-v "$PWD/auth:/mosquitto/auth" \
eclipse-mosquitto:2
2.2 mosquitto.conf (key lines)
persistence true
persistence_location /mosquitto/data/
password_file /mosquitto/auth/passwd
acl_file /mosquitto/auth/acl
allow_anonymous false
listener 8883
cafile /mosquitto/certs/ca.crt
certfile /mosquitto/certs/server.crt
keyfile /mosquitto/certs/server.key
persistence true + QoS 1 + retained terminal events means a subscriber that
joins after a job finished still sees the final completed/error.
2.3 Users (username/password)
# create the file with the first user, then add more with -b
mosquitto_passwd -c /mosquitto/auth/passwd hermes # subscriber/delegator
mosquitto_passwd /mosquitto/auth/passwd claude-worker # publisher/agent
# (omit -c after the first; -c truncates the file)
2.4 ACL — least privilege
The worker only publishes events; Hermes only subscribes:
# /mosquitto/auth/acl
# claude-worker: may publish job events, may not read others' streams
user claude-worker
topic write python/mqtt/jobs/+/events
# hermes: observes every job's events
user hermes
topic read python/mqtt/jobs/+/events
# keep the legacy demo topic usable for both, if desired
pattern readwrite python/mqtt/sample
2.5 TLS certificates
Quick self-signed (single host, internal only):
mkdir -p certs && cd certs
openssl req -x509 -newkey rsa:2048 -nodes -days 825 \
-keyout server.key -out server.crt \
-subj "/CN=mqtt.internal"
cp server.crt ca.crt # clients trust this as the CA bundle
Private CA (recommended — separate CA from server cert):
# 1) CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -days 3650 -out ca.crt -subj "/CN=Hermes-CA"
# 2) server cert signed by the CA
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=mqtt.internal"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -days 825
Clients trust ca.crt via MQTT_CA_CERTS=/path/to/ca.crt.
3. Cut-over verification (config-only, no code change)
Goal: prove the same scripts talk to your broker by changing only env/registry.
# 1) point the env at the new broker
export MQTT_BROKER=mqtt.internal
export MQTT_PORT=8883
export MQTT_TLS=1
export MQTT_CA_CERTS=$PWD/certs/ca.crt
export MQTT_USERNAME=hermes
export MQTT_PASSWORD=… # subscriber side
# (publisher side uses claude-worker creds via the job record's broker block)
# 2) sanity-check with the mosquitto CLI first
mosquitto_sub -h "$MQTT_BROKER" -p 8883 --cafile "$MQTT_CA_CERTS" \
-u hermes -P "$MQTT_PASSWORD" -t 'python/mqtt/jobs/+/events' -v &
# 3) run the unchanged tmux-agent-orchestrate-delegate-job loop
PY=.venv/bin/python
JID=$($PY scripts/registry.py register --prompt "broker cutover smoke")
$PY scripts/job_subscriber.py --job "$JID" --timeout 30 &
sleep 3
$PY scripts/publish_event.py --job "$JID" --event started
$PY scripts/publish_event.py --job "$JID" --event completed # auto-retained
Expected:
- subscriber prints the
startedandcompletedlines and exits 0; mosquitto_subshows the same events (ACL allowshermesto read);- publishing as a credential without write ACL is rejected by the broker;
- a subscriber started after
completedstill receives it (retained).
If all four hold, the migration is config-only. Persist the broker block into
each job record so publish_event.py connects from the registry alone:
"broker": { "host": "mqtt.internal", "port": 8883, "tls": true,
"username": "claude-worker", "password": "…" }