refactor(skills): rename multi-agent-* + agent-sessions-monitor + delegate-job to tmux-agent-orchestrate-*
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).
This commit is contained in:
+2
-2
@@ -14,5 +14,5 @@ __pycache__/
|
|||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
# 빌드/배포 HTML 산출물
|
# 빌드/배포 HTML 산출물
|
||||||
skills/delegate-job/USER_MANUAL.html
|
skills/tmux-agent-orchestrate-delegate-job/USER_MANUAL.html
|
||||||
skills/delegate-job/mqtt-broker-setup.html
|
skills/tmux-agent-orchestrate-delegate-job/mqtt-broker-setup.html
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# delegate-job 스킬
|
|
||||||
|
|
||||||
작업(Job)을 자율 에이전트(claude-code/codex/opencode/human)에게 위임하고 MQTT
|
|
||||||
이벤트 채널로 비동기 관찰하는 Hermes 스킬. **시작점은 [`SKILL.md`](./SKILL.md).**
|
|
||||||
|
|
||||||
- 프로토콜/스키마: [`job-protocol.md`](./job-protocol.md)
|
|
||||||
- 브로커 PoC→운영 전환: [`mqtt-broker-setup.md`](./mqtt-broker-setup.md)
|
|
||||||
- 레지스트리 포맷/동시성: [`registry.md`](./registry.md)
|
|
||||||
- 참조 구현: [`delegate-job`](./delegate-job) (bash wrapper), [`scripts/publish_event.py`](./scripts/publish_event.py), [`scripts/job_subscriber.py`](./scripts/job_subscriber.py), [`scripts/registry.py`](./scripts/registry.py), [`scripts/mqtt_common.py`](./scripts/mqtt_common.py)
|
|
||||||
- 영구 감사 로그: `.hermes/delegate_job_logs/<job_id>/` (`meta.json`·`events.ndjson`·`status.json`)
|
|
||||||
— `delegate-job logs <id>` 또는 `delegate-job logs --list`로 조회 (SKILL.md "Audit Logs" 참조)
|
|
||||||
+7
-7
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# lib.sh — shared library for the multi-agent-* / agent-sessions-* skills.
|
# lib.sh — shared library for the tmux-agent-orchestrate-* skills.
|
||||||
#
|
#
|
||||||
# Single source of truth for the four things that were inconsistently
|
# Single source of truth for the four things that were inconsistently
|
||||||
# re-implemented across create/resume/delete/monitor (REVIEW.md §4.1):
|
# re-implemented across create/resume/delete/monitor (REVIEW.md §4.1):
|
||||||
@@ -362,7 +362,7 @@ PYEOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# delegate-job integration helpers
|
# tmux-agent-orchestrate-delegate-job integration helpers
|
||||||
#
|
#
|
||||||
# All paths are resolved relative to lib.sh's own location (BASH_SOURCE), so the
|
# All paths are resolved relative to lib.sh's own location (BASH_SOURCE), so the
|
||||||
# skill tree is relocatable — no hardcoded absolute paths (review item 6).
|
# skill tree is relocatable — no hardcoded absolute paths (review item 6).
|
||||||
@@ -381,26 +381,26 @@ _delegate_py_bin() {
|
|||||||
printf '%s\n' "python3"
|
printf '%s\n' "python3"
|
||||||
}
|
}
|
||||||
|
|
||||||
# _delegate_script <name> — echo the path to a delegate-job script, resolved
|
# _delegate_script <name> — echo the path to a tmux-agent-orchestrate-delegate-job script, resolved
|
||||||
# relative to skills/ (lib.sh dir). Empty if not found.
|
# relative to skills/ (lib.sh dir). Empty if not found.
|
||||||
_delegate_script() {
|
_delegate_script() {
|
||||||
local name="$1" skill_dir cand
|
local name="$1" skill_dir cand
|
||||||
skill_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
skill_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
cand="$skill_dir/delegate-job/scripts/$name"
|
cand="$skill_dir/tmux-agent-orchestrate-delegate-job/scripts/$name"
|
||||||
if [ -f "$cand" ]; then printf '%s\n' "$cand"; return 0; fi
|
if [ -f "$cand" ]; then printf '%s\n' "$cand"; return 0; fi
|
||||||
printf '%s\n' "$(find "$skill_dir" -name "$name" 2>/dev/null | head -n 1 || true)"
|
printf '%s\n' "$(find "$skill_dir" -name "$name" 2>/dev/null | head -n 1 || true)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# delegate_submit_job <prompt> <agent> <agent_session>
|
# delegate_submit_job <prompt> <agent> <agent_session>
|
||||||
#
|
#
|
||||||
# Register a job in the delegate-job registry. Prints the new JID on stdout.
|
# Register a job in the tmux-agent-orchestrate-delegate-job registry. Prints the new JID on stdout.
|
||||||
delegate_submit_job() {
|
delegate_submit_job() {
|
||||||
local prompt="$1" agent="$2" session="$3"
|
local prompt="$1" agent="$2" session="$3"
|
||||||
local py_bin registry_py
|
local py_bin registry_py
|
||||||
py_bin="$(_delegate_py_bin)"
|
py_bin="$(_delegate_py_bin)"
|
||||||
registry_py="$(_delegate_script registry.py)"
|
registry_py="$(_delegate_script registry.py)"
|
||||||
if [ -z "$registry_py" ] || [ ! -f "$registry_py" ]; then
|
if [ -z "$registry_py" ] || [ ! -f "$registry_py" ]; then
|
||||||
echo "ERROR: delegate-job registry.py not found under skills/" >&2
|
echo "ERROR: tmux-agent-orchestrate-delegate-job registry.py not found under skills/" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
"$py_bin" "$registry_py" register \
|
"$py_bin" "$registry_py" register \
|
||||||
@@ -411,7 +411,7 @@ delegate_submit_job() {
|
|||||||
|
|
||||||
# delegate_publish_event <job_id> <event> [detail]
|
# delegate_publish_event <job_id> <event> [detail]
|
||||||
#
|
#
|
||||||
# Publish a lifecycle event to the delegate-job registry. Consolidates the
|
# Publish a lifecycle event to the tmux-agent-orchestrate-delegate-job registry. Consolidates the
|
||||||
# inline .venv-walk + publish_event.py blocks that were duplicated across
|
# inline .venv-walk + publish_event.py blocks that were duplicated across
|
||||||
# create/delete/resume (review item 7). Non-fatal by contract: an empty job id,
|
# create/delete/resume (review item 7). Non-fatal by contract: an empty job id,
|
||||||
# a missing script, or a broker failure never aborts the caller.
|
# a missing script, or a broker failure never aborts the caller.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-create
|
name: tmux-agent-orchestrate-create
|
||||||
description: "Create a new agent session (claude, antigravity/agy) in a dedicated tmux session for context-preserving long-running work. Always creates a tmux session — never backgrounds with nohup/disown. Writes the new session to ~/PuKi/lab/agent_sessions/agent-sessions.yaml. Use when you want to start a fresh agent (no prior UUID) for a new project workspace."
|
description: "Create a new agent session (claude, antigravity/agy) in a dedicated tmux session for context-preserving long-running work. Always creates a tmux session — never backgrounds with nohup/disown. Writes the new session to ~/PuKi/lab/agent_sessions/agent-sessions.yaml. Use when you want to start a fresh agent (no prior UUID) for a new project workspace."
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
author: godopu
|
author: godopu
|
||||||
@@ -9,18 +9,18 @@ environments: [terminal, tmux]
|
|||||||
metadata:
|
metadata:
|
||||||
hermes:
|
hermes:
|
||||||
tags: [agent, tmux, claude, antigravity, agy, multi-agent, context, session]
|
tags: [agent, tmux, claude, antigravity, agy, multi-agent, context, session]
|
||||||
related_skills: [multi-agent-resume, multi-agent-delete, agent-sessions-monitor, claude-code]
|
related_skills: [tmux-agent-orchestrate-resume, tmux-agent-orchestrate-delete, tmux-agent-orchestrate-monitor, claude-code]
|
||||||
prereq_skills: [claude-code]
|
prereq_skills: [claude-code]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Multi-Agent Create — Start a Fresh Agent in a tmux Session
|
# Multi-Agent Create — Start a Fresh Agent in a tmux Session
|
||||||
|
|
||||||
> **Companion skills**: `multi-agent-resume` (resume an existing UUID), `multi-agent-delete` (terminate), `agent-sessions-monitor` (live status).
|
> **Companion skills**: `tmux-agent-orchestrate-resume` (resume an existing UUID), `tmux-agent-orchestrate-delete` (terminate), `tmux-agent-orchestrate-monitor` (live status).
|
||||||
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml` (this skill writes to it; never read it ad-hoc — go through this skill).
|
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml` (this skill writes to it; never read it ad-hoc — go through this skill).
|
||||||
|
|
||||||
## What this skill does
|
## What this skill does
|
||||||
|
|
||||||
Spawn a new agent (`claude` or `agy`/antigravity-cli) in a **dedicated tmux session** for context-preserving long-running work. The tmux session is the *container*; the agent's session ID is *data* inside the container. **This skill creates the container + starts the agent — but does not resume an old conversation** (use `multi-agent-resume` for that).
|
Spawn a new agent (`claude` or `agy`/antigravity-cli) in a **dedicated tmux session** for context-preserving long-running work. The tmux session is the *container*; the agent's session ID is *data* inside the container. **This skill creates the container + starts the agent — but does not resume an old conversation** (use `tmux-agent-orchestrate-resume` for that).
|
||||||
|
|
||||||
For all agents: the tmux session name is produced by **`lib.sh::derive_session_name`** — the single source of truth shared by create/resume/delete/status/monitor (P0-A). The rule (verbatim from the function):
|
For all agents: the tmux session name is produced by **`lib.sh::derive_session_name`** — the single source of truth shared by create/resume/delete/status/monitor (P0-A). The rule (verbatim from the function):
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ SESSION_NAME="$(derive_session_name "$WORKSPACE" "$AGENT")"
|
|||||||
|
|
||||||
# 1. If session already alive, fail fast
|
# 1. If session already alive, fail fast
|
||||||
tmux has-session -t "$SESSION_NAME" 2>/dev/null && {
|
tmux has-session -t "$SESSION_NAME" 2>/dev/null && {
|
||||||
echo "ERROR: tmux session '$SESSION_NAME' already exists. Use multi-agent-resume to attach or multi-agent-delete first."
|
echo "ERROR: tmux session '$SESSION_NAME' already exists. Use tmux-agent-orchestrate-resume to attach or tmux-agent-orchestrate-delete first."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ After spawn, append a new `tmux_sessions[]` entry to `~/PuKi/lab/agent_sessions/
|
|||||||
Use the `agent-sessions-yaml-edit` script in `scripts/` to safely append (preserves comments + format):
|
Use the `agent-sessions-yaml-edit` script in `scripts/` to safely append (preserves comments + format):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash ~/PuKi/lab/agent_sessions/skills/multi-agent-create/scripts/create_session.sh \
|
bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-create/scripts/create_session.sh \
|
||||||
--workspace "$WORKSPACE" --agent "$AGENT" --session "$SESSION_NAME"
|
--workspace "$WORKSPACE" --agent "$AGENT" --session "$SESSION_NAME"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ The script handles the YAML append, pane capture, and the `last_visible_status`
|
|||||||
- **Don't trust `--session-id <uuid>` flags blindly** — claude/agy may not accept a fixed session id on first spawn. The session id is *assigned* on first user message; you can read it back from `~/.claude/projects/.../session.jsonl` headers or `~/.gemini/.../cache/last_conversations.json` AFTER the first message.
|
- **Don't trust `--session-id <uuid>` flags blindly** — claude/agy may not accept a fixed session id on first spawn. The session id is *assigned* on first user message; you can read it back from `~/.claude/projects/.../session.jsonl` headers or `~/.gemini/.../cache/last_conversations.json` AFTER the first message.
|
||||||
- **Wrapper script MUST NOT be created via `hermes profile alias`** — that command writes a `hermes -p <profile>` wrapper that destroys the tmux behavior. Create wrappers manually (see `lab-landing-page-creator-claude` template).
|
- **Wrapper script MUST NOT be created via `hermes profile alias`** — that command writes a `hermes -p <profile>` wrapper that destroys the tmux behavior. Create wrappers manually (see `lab-landing-page-creator-claude` template).
|
||||||
- **Always use the workspace-relative path** in tmux `cwd` — relative paths break when tmux respawns in a different shell context.
|
- **Always use the workspace-relative path** in tmux `cwd` — relative paths break when tmux respawns in a different shell context.
|
||||||
- **The first `claude` message generates the session id** — `multi-agent-create` only sets up the *container*. If you need a known session id for later resume, send a placeholder message (e.g. "init") and read it back, then call `multi-agent-resume` later.
|
- **The first `claude` message generates the session id** — `tmux-agent-orchestrate-create` only sets up the *container*. If you need a known session id for later resume, send a placeholder message (e.g. "init") and read it back, then call `tmux-agent-orchestrate-resume` later.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ tmux capture-pane -t "$SESSION_NAME" -p -S -20
|
|||||||
|
|
||||||
## When NOT to use this skill
|
## When NOT to use this skill
|
||||||
|
|
||||||
- **Resuming an old conversation** → `multi-agent-resume`
|
- **Resuming an old conversation** → `tmux-agent-orchestrate-resume`
|
||||||
- **Killing an existing session** → `multi-agent-delete`
|
- **Killing an existing session** → `tmux-agent-orchestrate-delete`
|
||||||
- **Just attaching to an existing session** → `tmux attach -t <name>` (no skill needed)
|
- **Just attaching to an existing session** → `tmux attach -t <name>` (no skill needed)
|
||||||
- **One-shot print mode (claude -p "...")** → no tmux needed; use `claude-code` skill's print mode
|
- **One-shot print mode (claude -p "...")** → no tmux needed; use `claude-code` skill's print mode
|
||||||
+7
-7
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# create_session.sh — multi-agent-create 의 부속 스크립트
|
# create_session.sh — tmux-agent-orchestrate-create 의 부속 스크립트
|
||||||
# Usage:
|
# Usage:
|
||||||
# bash create_session.sh --workspace <path> --agent <claude|agy> [--session <name>] [--wrapper]
|
# bash create_session.sh --workspace <path> --agent <claude|agy> [--session <name>] [--wrapper]
|
||||||
#
|
#
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
# 0 = success
|
# 0 = success
|
||||||
# 1 = preflight failure
|
# 1 = preflight failure
|
||||||
# 2 = invalid args
|
# 2 = invalid args
|
||||||
# 3 = tmux session already exists (use multi-agent-resume or delete first)
|
# 3 = tmux session already exists (use tmux-agent-orchestrate-resume or delete first)
|
||||||
# 4 = agent-sessions.yaml append failure
|
# 4 = agent-sessions.yaml append failure
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ Options:
|
|||||||
--wrapper force use of ~/.local/bin/<session> wrapper even if not present
|
--wrapper force use of ~/.local/bin/<session> wrapper even if not present
|
||||||
--dry-run print commands without executing
|
--dry-run print commands without executing
|
||||||
--tmux-server NAME specify isolated tmux server name
|
--tmux-server NAME specify isolated tmux server name
|
||||||
--submit-job PROMPT submit a job to delegate-job registry with the given prompt
|
--submit-job PROMPT submit a job to tmux-agent-orchestrate-delegate-job registry with the given prompt
|
||||||
-h, --help this help
|
-h, --help this help
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ fi
|
|||||||
|
|
||||||
# 이미 살아있으면 실패
|
# 이미 살아있으면 실패
|
||||||
if _tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
if _tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||||
echo "ERROR: tmux session '$SESSION_NAME' already exists. Use multi-agent-resume to attach, or multi-agent-delete first." >&2
|
echo "ERROR: tmux session '$SESSION_NAME' already exists. Use tmux-agent-orchestrate-resume to attach, or tmux-agent-orchestrate-delete first." >&2
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -262,7 +262,7 @@ echo "=== created ==="
|
|||||||
echo "tmux session: $SESSION_NAME (pane pid $PANE_PID, cmd $PANE_CMD, cwd $PANE_CWD)"
|
echo "tmux session: $SESSION_NAME (pane pid $PANE_PID, cmd $PANE_CMD, cwd $PANE_CWD)"
|
||||||
if [ -n "$DELEGATE_JOB_ID" ]; then
|
if [ -n "$DELEGATE_JOB_ID" ]; then
|
||||||
echo "delegate job: $DELEGATE_JOB_ID"
|
echo "delegate job: $DELEGATE_JOB_ID"
|
||||||
delegate_publish_event "$DELEGATE_JOB_ID" started "canary session created"
|
delegate_publish_event "$DELEGATE_JOB_ID" started "tmux-agent-orchestrate session created"
|
||||||
fi
|
fi
|
||||||
echo "agent-sessions.yaml updated"
|
echo "agent-sessions.yaml updated"
|
||||||
echo
|
echo
|
||||||
@@ -271,5 +271,5 @@ if [ -n "${TMUX_SERVER_NAME:-}" ] && [ "$TMUX_SERVER_NAME" != "default" ]; then
|
|||||||
else
|
else
|
||||||
echo "Attach: tmux attach -t $SESSION_NAME"
|
echo "Attach: tmux attach -t $SESSION_NAME"
|
||||||
fi
|
fi
|
||||||
echo "Delete: use multi-agent-delete skill"
|
echo "Delete: use tmux-agent-orchestrate-delete skill"
|
||||||
echo "Resume: use multi-agent-resume skill (after first message creates a session id)"
|
echo "Resume: use tmux-agent-orchestrate-resume skill (after first message creates a session id)"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# tmux-agent-orchestrate-delegate-job 스킬
|
||||||
|
|
||||||
|
작업(Job)을 자율 에이전트(claude-code/codex/opencode/human)에게 위임하고 MQTT
|
||||||
|
이벤트 채널로 비동기 관찰하는 Hermes 스킬. **시작점은 [`SKILL.md`](./SKILL.md).**
|
||||||
|
|
||||||
|
- 프로토콜/스키마: [`job-protocol.md`](./job-protocol.md)
|
||||||
|
- 브로커 PoC→운영 전환: [`mqtt-broker-setup.md`](./mqtt-broker-setup.md)
|
||||||
|
- 레지스트리 포맷/동시성: [`registry.md`](./registry.md)
|
||||||
|
- 참조 구현: [`tmux-agent-orchestrate-delegate-job`](./tmux-agent-orchestrate-delegate-job) (bash wrapper), [`scripts/publish_event.py`](./scripts/publish_event.py), [`scripts/job_subscriber.py`](./scripts/job_subscriber.py), [`scripts/registry.py`](./scripts/registry.py), [`scripts/mqtt_common.py`](./scripts/mqtt_common.py)
|
||||||
|
- 영구 감사 로그: `.hermes/delegate_job_logs/<job_id>/` (`meta.json`·`events.ndjson`·`status.json`)
|
||||||
|
— `tmux-agent-orchestrate-delegate-job logs <id>` 또는 `tmux-agent-orchestrate-delegate-job logs --list`로 조회 (SKILL.md "Audit Logs" 참조)
|
||||||
+19
-19
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: delegate-job
|
name: tmux-agent-orchestrate-delegate-job
|
||||||
description: "Delegate a unit of work to any autonomous agent (claude-code, codex, opencode, or a human) and observe it asynchronously over an MQTT event channel. Each job gets a unique id, a registry record (prompt, broker, status, timeouts), and a single per-job topic that carries started/permission_required/progress/completed/error events as schema-versioned JSON. The delegator starts a subscriber first, runs the agent, and treats a completed/error event or a timeout as the job's terminal state. Ships a working reference implementation (publish_event.py, job_subscriber.py, registry.py, mqtt_common.py, delegate-job wrapper) plus a PoC-to-production path: validate on a public broker, then move to an authenticated TLS broker by changing config only — no code change. Use when you need fire-and-observe delegation, multi-job fan-out across tmux sessions, or a uniform completion-signal protocol shared by several agent types."
|
description: "Delegate a unit of work to any autonomous agent (claude-code, codex, opencode, or a human) and observe it asynchronously over an MQTT event channel. Each job gets a unique id, a registry record (prompt, broker, status, timeouts), and a single per-job topic that carries started/permission_required/progress/completed/error events as schema-versioned JSON. The delegator starts a subscriber first, runs the agent, and treats a completed/error event or a timeout as the job's terminal state. Ships a working reference implementation (publish_event.py, job_subscriber.py, registry.py, mqtt_common.py, tmux-agent-orchestrate-delegate-job wrapper) plus a PoC-to-production path: validate on a public broker, then move to an authenticated TLS broker by changing config only — no code change. Use when you need fire-and-observe delegation, multi-job fan-out across tmux sessions, or a uniform completion-signal protocol shared by several agent types."
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
author: Hermes Agent
|
author: Hermes Agent
|
||||||
license: MIT
|
license: MIT
|
||||||
@@ -11,7 +11,7 @@ metadata:
|
|||||||
related_skills: [claude-code, codex, opencode, hermes-agent-skill-authoring]
|
related_skills: [claude-code, codex, opencode, hermes-agent-skill-authoring]
|
||||||
---
|
---
|
||||||
|
|
||||||
# delegate-job — Async Job Delegation over MQTT
|
# tmux-agent-orchestrate-delegate-job — Async Job Delegation over MQTT
|
||||||
|
|
||||||
Delegate a unit of work to an autonomous agent, then **observe** it instead of
|
Delegate a unit of work to an autonomous agent, then **observe** it instead of
|
||||||
blocking on it. Every job gets a unique id and a registry record; the agent
|
blocking on it. Every job gets a unique id and a registry record; the agent
|
||||||
@@ -73,7 +73,7 @@ you need finer control.
|
|||||||
```bash
|
```bash
|
||||||
# 1) one line: register → start subscriber → launch agent in tmux
|
# 1) one line: register → start subscriber → launch agent in tmux
|
||||||
# (uses public broker by default; last stdout line is the audit-log dir)
|
# (uses public broker by default; last stdout line is the audit-log dir)
|
||||||
delegate-job submit \
|
tmux-agent-orchestrate-delegate-job submit \
|
||||||
--agent claude-code \
|
--agent claude-code \
|
||||||
--prompt "정렬 문제 10개를 만들어 sort_problems.md로 저장" \
|
--prompt "정렬 문제 10개를 만들어 sort_problems.md로 저장" \
|
||||||
--workdir /path/to/project \
|
--workdir /path/to/project \
|
||||||
@@ -86,12 +86,12 @@ delegate-job submit \
|
|||||||
# /path/to/project/.hermes/delegate_job_logs/<JID> ← audit log dir
|
# /path/to/project/.hermes/delegate_job_logs/<JID> ← audit log dir
|
||||||
|
|
||||||
# 2) at any time, query the job or its audit log
|
# 2) at any time, query the job or its audit log
|
||||||
delegate-job status --job <JID>
|
tmux-agent-orchestrate-delegate-job status --job <JID>
|
||||||
delegate-job logs <JID> # pretty timeline
|
tmux-agent-orchestrate-delegate-job logs <JID> # pretty timeline
|
||||||
delegate-job logs --list # every job, live status
|
tmux-agent-orchestrate-delegate-job logs --list # every job, live status
|
||||||
|
|
||||||
# 3) run a user-supplied validator against the job's artifacts
|
# 3) run a user-supplied validator against the job's artifacts
|
||||||
delegate-job verify --job <JID> --validate ./validate.sh
|
tmux-agent-orchestrate-delegate-job verify --job <JID> --validate ./validate.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
The wrapper enforces the **subscribe-before-publish** ordering and **forwards
|
The wrapper enforces the **subscribe-before-publish** ordering and **forwards
|
||||||
@@ -102,7 +102,7 @@ propagated to the agent"). When you need finer control, the manual flow is:
|
|||||||
```bash
|
```bash
|
||||||
# Manual 5-step (same outcome, more knobs)
|
# Manual 5-step (same outcome, more knobs)
|
||||||
PY=.venv/bin/python
|
PY=.venv/bin/python
|
||||||
SKILL=./skills/delegate-job/scripts
|
SKILL=./skills/tmux-agent-orchestrate-delegate-job/scripts
|
||||||
|
|
||||||
# 1) register
|
# 1) register
|
||||||
JID=$($PY "$SKILL/registry.py" register \
|
JID=$($PY "$SKILL/registry.py" register \
|
||||||
@@ -194,8 +194,8 @@ never touched.
|
|||||||
**Reading them:**
|
**Reading them:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
delegate-job logs <job_id> # pretty-print one job's timeline
|
tmux-agent-orchestrate-delegate-job logs <job_id> # pretty-print one job's timeline
|
||||||
delegate-job logs --list # summarise every logged job (with live status)
|
tmux-agent-orchestrate-delegate-job logs --list # summarise every logged job (with live status)
|
||||||
# or directly via the registry CLI:
|
# or directly via the registry CLI:
|
||||||
$PY scripts/registry.py logs <job_id> [--tail N] [--json]
|
$PY scripts/registry.py logs <job_id> [--tail N] [--json]
|
||||||
$PY scripts/registry.py logs --list [--json]
|
$PY scripts/registry.py logs --list [--json]
|
||||||
@@ -239,7 +239,7 @@ agent").
|
|||||||
Your job_id is "$JOB_ID" (read it from the registry record for this delegation —
|
Your job_id is "$JOB_ID" (read it from the registry record for this delegation —
|
||||||
do not reuse any job_id you saw before).
|
do not reuse any job_id you saw before).
|
||||||
|
|
||||||
On start: $PY delegate-job/scripts/publish_event.py --job "$JOB_ID" --event started
|
On start: $PY tmux-agent-orchestrate-delegate-job/scripts/publish_event.py --job "$JOB_ID" --event started
|
||||||
On permission: $PY … --job "$JOB_ID" --event permission_required --detail "<tool>:<what>"
|
On permission: $PY … --job "$JOB_ID" --event permission_required --detail "<tool>:<what>"
|
||||||
On progress: $PY … --job "$JOB_ID" --event progress --detail "<short status>"
|
On progress: $PY … --job "$JOB_ID" --event progress --detail "<short status>"
|
||||||
On success: $PY … --job "$JOB_ID" --event completed --detail "<one-line summary>"
|
On success: $PY … --job "$JOB_ID" --event completed --detail "<one-line summary>"
|
||||||
@@ -261,17 +261,17 @@ agent").
|
|||||||
|
|
||||||
## User Interface
|
## User Interface
|
||||||
|
|
||||||
The [`delegate-job`](./delegate-job) bash wrapper bundles register +
|
The [`tmux-agent-orchestrate-delegate-job`](./tmux-agent-orchestrate-delegate-job) bash wrapper bundles register +
|
||||||
subscribe-first + run-agent + validate:
|
subscribe-first + run-agent + validate:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
delegate-job submit --agent claude-code \
|
tmux-agent-orchestrate-delegate-job submit --agent claude-code \
|
||||||
--prompt "정렬 문제 10개를 만들어 sort_problems.md로 저장" \
|
--prompt "정렬 문제 10개를 만들어 sort_problems.md로 저장" \
|
||||||
--workdir /path/to/project --timeout 600 [--validate ./validate.sh]
|
--workdir /path/to/project --timeout 600 [--validate ./validate.sh]
|
||||||
delegate-job status --job <id> # one record, pretty-printed
|
tmux-agent-orchestrate-delegate-job status --job <id> # one record, pretty-printed
|
||||||
delegate-job list # all jobs, one line each
|
tmux-agent-orchestrate-delegate-job list # all jobs, one line each
|
||||||
delegate-job verify --job <id> --validate ./validate.sh # runs it, reports exit code
|
tmux-agent-orchestrate-delegate-job verify --job <id> --validate ./validate.sh # runs it, reports exit code
|
||||||
delegate-job wait [--job <id>] # block until terminal (else --wait-any)
|
tmux-agent-orchestrate-delegate-job wait [--job <id>] # block until terminal (else --wait-any)
|
||||||
```
|
```
|
||||||
|
|
||||||
`submit` **always starts the subscriber before the agent** (the ordering
|
`submit` **always starts the subscriber before the agent** (the ordering
|
||||||
@@ -340,7 +340,7 @@ business-logic validation — those are hooks you fill (`validate.sh` reads
|
|||||||
logging failure (e.g. read-only log dir) does not break the publish or
|
logging failure (e.g. read-only log dir) does not break the publish or
|
||||||
subscribe path — only a `logger.warning` is emitted.
|
subscribe path — only a `logger.warning` is emitted.
|
||||||
- [ ] **end-to-end demo smoke** — run
|
- [ ] **end-to-end demo smoke** — run
|
||||||
`delegate-job submit --agent claude-code --agent-session tmux:demo-smoke
|
`tmux-agent-orchestrate-delegate-job submit --agent claude-code --agent-session tmux:demo-smoke
|
||||||
--prompt "echo hello and call publish_event.py --job <JID>
|
--prompt "echo hello and call publish_event.py --job <JID>
|
||||||
--event completed" --timeout 120` and confirm
|
--event completed" --timeout 120` and confirm
|
||||||
(a) registered job id echoed, (b) subscriber pid echoed, (c) tmux session
|
(a) registered job id echoed, (b) subscriber pid echoed, (c) tmux session
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Job Event Protocol
|
# Job Event Protocol
|
||||||
|
|
||||||
The wire contract every delegate-job agent (claude-code, codex, opencode,
|
The wire contract every tmux-agent-orchestrate-delegate-job agent (claude-code, codex, opencode,
|
||||||
human, …) speaks. One job → one MQTT topic → JSON event payloads. Stable across
|
human, …) speaks. One job → one MQTT topic → JSON event payloads. Stable across
|
||||||
the PoC (public broker) and production (own broker) stages; only transport
|
the PoC (public broker) and production (own broker) stages; only transport
|
||||||
hardening changes, never the payload shape.
|
hardening changes, never the payload shape.
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# MQTT Broker Setup — PoC → Production
|
# MQTT Broker Setup — PoC → Production
|
||||||
|
|
||||||
The delegate-job scripts read **all** broker settings from environment
|
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,
|
variables (or a job record's `broker.*` block) through a single helper,
|
||||||
`broker_config_from_env()` in
|
`broker_config_from_env()` in
|
||||||
[`./scripts/mqtt_common.py`](./scripts/mqtt_common.py). The design goal:
|
[`./scripts/mqtt_common.py`](./scripts/mqtt_common.py). The design goal:
|
||||||
@@ -152,7 +152,7 @@ export MQTT_PASSWORD=… # subscriber side
|
|||||||
mosquitto_sub -h "$MQTT_BROKER" -p 8883 --cafile "$MQTT_CA_CERTS" \
|
mosquitto_sub -h "$MQTT_BROKER" -p 8883 --cafile "$MQTT_CA_CERTS" \
|
||||||
-u hermes -P "$MQTT_PASSWORD" -t 'python/mqtt/jobs/+/events' -v &
|
-u hermes -P "$MQTT_PASSWORD" -t 'python/mqtt/jobs/+/events' -v &
|
||||||
|
|
||||||
# 3) run the unchanged delegate-job loop
|
# 3) run the unchanged tmux-agent-orchestrate-delegate-job loop
|
||||||
PY=.venv/bin/python
|
PY=.venv/bin/python
|
||||||
JID=$($PY scripts/registry.py register --prompt "broker cutover smoke")
|
JID=$($PY scripts/registry.py register --prompt "broker cutover smoke")
|
||||||
$PY scripts/job_subscriber.py --job "$JID" --timeout 30 &
|
$PY scripts/job_subscriber.py --job "$JID" --timeout 30 &
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""Shared MQTT + registry helpers for the delegate-job skill.
|
"""Shared MQTT + registry helpers for the tmux-agent-orchestrate-delegate-job skill.
|
||||||
|
|
||||||
Single entry point for:
|
Single entry point for:
|
||||||
- broker configuration (env -> dataclass),
|
- broker configuration (env -> dataclass),
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
"""Job registry for the delegate-job skill.
|
"""Job registry for the tmux-agent-orchestrate-delegate-job skill.
|
||||||
|
|
||||||
A job record is the single source of truth for one delegated unit of work:
|
A job record is the single source of truth for one delegated unit of work:
|
||||||
its id, prompt, owning agent session, broker connection, timeouts, and status.
|
its id, prompt, owning agent session, broker connection, timeouts, and status.
|
||||||
@@ -9,7 +9,7 @@ Concurrency is handled via the fcntl lock in :mod:`mqtt_common` (PoC). For
|
|||||||
multi-host delegation, migrate to SQLite WAL — see references/registry.md.
|
multi-host delegation, migrate to SQLite WAL — see references/registry.md.
|
||||||
|
|
||||||
Importable as a library and runnable as a CLI (``register``/``list``/``get``/
|
Importable as a library and runnable as a CLI (``register``/``list``/``get``/
|
||||||
``status``/``pick``) so the ``delegate-job`` bash wrapper can shell out.
|
``status``/``pick``) so the ``tmux-agent-orchestrate-delegate-job`` bash wrapper can shell out.
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ def _iter_records(registry_dir: str):
|
|||||||
# CLI (so the bash wrapper can shell out without inline python)
|
# CLI (so the bash wrapper can shell out without inline python)
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
def _build_parser() -> argparse.ArgumentParser:
|
def _build_parser() -> argparse.ArgumentParser:
|
||||||
parser = argparse.ArgumentParser(description="delegate-job registry CLI")
|
parser = argparse.ArgumentParser(description="tmux-agent-orchestrate-delegate-job registry CLI")
|
||||||
parser.add_argument("--registry-dir", default=DEFAULT_REGISTRY_DIR)
|
parser.add_argument("--registry-dir", default=DEFAULT_REGISTRY_DIR)
|
||||||
sub = parser.add_subparsers(dest="command", required=True)
|
sub = parser.add_subparsers(dest="command", required=True)
|
||||||
|
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# delegate-job — user-facing orchestrator for the delegate-job skill.
|
# tmux-agent-orchestrate-delegate-job — user-facing orchestrator for the tmux-agent-orchestrate-delegate-job skill.
|
||||||
#
|
#
|
||||||
# Subcommands:
|
# Subcommands:
|
||||||
# submit register a job, start the subscriber FIRST, then run the agent,
|
# submit register a job, start the subscriber FIRST, then run the agent,
|
||||||
@@ -41,7 +41,7 @@ REGISTRY_DIR_DEFAULT=".hermes/jobs"
|
|||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
delegate-job <command> [options]
|
tmux-agent-orchestrate-delegate-job <command> [options]
|
||||||
|
|
||||||
submit --agent <name> --prompt <text> [--workdir <dir>] [--agent-session <label>]
|
submit --agent <name> --prompt <text> [--workdir <dir>] [--agent-session <label>]
|
||||||
[--timeout <sec>] [--idle-timeout <sec>] [--validate <script>]
|
[--timeout <sec>] [--idle-timeout <sec>] [--validate <script>]
|
||||||
+18
-18
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-delete
|
name: tmux-agent-orchestrate-delete
|
||||||
description: "Terminate an agent tmux session (claude, antigravity/agy) and update ~/PuKi/lab/agent_sessions/agent-sessions.yaml to mark it terminated with timestamp. Does NOT delete on-disk conversation artifacts (jsonl/db) — those are preserved for future resume. Use when ending a work session, switching to a different one, or cleaning up before a fresh start."
|
description: "Terminate an agent tmux session (claude, antigravity/agy) and update ~/PuKi/lab/agent_sessions/agent-sessions.yaml to mark it terminated with timestamp. Does NOT delete on-disk conversation artifacts (jsonl/db) — those are preserved for future resume. Use when ending a work session, switching to a different one, or cleaning up before a fresh start."
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
author: godopu
|
author: godopu
|
||||||
@@ -9,13 +9,13 @@ environments: [terminal, tmux]
|
|||||||
metadata:
|
metadata:
|
||||||
hermes:
|
hermes:
|
||||||
tags: [agent, tmux, claude, antigravity, agy, multi-agent, delete, terminate, cleanup]
|
tags: [agent, tmux, claude, antigravity, agy, multi-agent, delete, terminate, cleanup]
|
||||||
related_skills: [multi-agent-create, multi-agent-resume, agent-sessions-monitor]
|
related_skills: [tmux-agent-orchestrate-create, tmux-agent-orchestrate-resume, tmux-agent-orchestrate-monitor]
|
||||||
prereq_skills: [multi-agent-create, multi-agent-resume]
|
prereq_skills: [tmux-agent-orchestrate-create, tmux-agent-orchestrate-resume]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Multi-Agent Delete — Terminate an Agent tmux Session
|
# Multi-Agent Delete — Terminate an Agent tmux Session
|
||||||
|
|
||||||
> **Companion skills**: `multi-agent-create` (start), `multi-agent-resume` (re-attach), `agent-sessions-monitor` (live status).
|
> **Companion skills**: `tmux-agent-orchestrate-create` (start), `tmux-agent-orchestrate-resume` (re-attach), `tmux-agent-orchestrate-monitor` (live status).
|
||||||
> **Tmux Isolation**: `delete` 명령은 YAML의 `tmux_server` 필드를 자동으로 파싱하여 해당 격리 서버의 세션을 안전하게 종료(kill)하므로, `TMUX_SERVER_NAME` 환경변수를 수동으로 지정할 필요가 없습니다.
|
> **Tmux Isolation**: `delete` 명령은 YAML의 `tmux_server` 필드를 자동으로 파싱하여 해당 격리 서버의 세션을 안전하게 종료(kill)하므로, `TMUX_SERVER_NAME` 환경변수를 수동으로 지정할 필요가 없습니다.
|
||||||
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
||||||
|
|
||||||
@@ -24,8 +24,8 @@ metadata:
|
|||||||
Stop an agent's tmux session and **mark the YAML entry as terminated**. Preserves:
|
Stop an agent's tmux session and **mark the YAML entry as terminated**. Preserves:
|
||||||
|
|
||||||
- The tmux session's recorded `pane.pid / cmd / cwd / mcp_attachments` for audit
|
- The tmux session's recorded `pane.pid / cmd / cwd / mcp_attachments` for audit
|
||||||
- The agent's on-disk conversation (claude `*.jsonl`, agy `conversations/*.db`) — so the user can `multi-agent-resume` later
|
- The agent's on-disk conversation (claude `*.jsonl`, agy `conversations/*.db`) — so the user can `tmux-agent-orchestrate-resume` later
|
||||||
- The `start_command` so a future `multi-agent-create --session <name>` reproduces the same tmux spec
|
- The `start_command` so a future `tmux-agent-orchestrate-create --session <name>` reproduces the same tmux spec
|
||||||
|
|
||||||
The user explicitly chooses:
|
The user explicitly chooses:
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ import yaml
|
|||||||
d = yaml.safe_load(open('$AGENT_SESSIONS_YAML'))
|
d = yaml.safe_load(open('$AGENT_SESSIONS_YAML'))
|
||||||
names = [s['name'] for s in d.get('tmux_sessions', [])]
|
names = [s['name'] for s in d.get('tmux_sessions', [])]
|
||||||
if '$SESSION_NAME' not in names:
|
if '$SESSION_NAME' not in names:
|
||||||
print('NOT in YAML — refusing to delete (no audit trail). Use multi-agent-create first, or pass --force-no-yaml.')
|
print('NOT in YAML — refusing to delete (no audit trail). Use tmux-agent-orchestrate-create first, or pass --force-no-yaml.')
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
"
|
"
|
||||||
|
|
||||||
@@ -65,27 +65,27 @@ fi
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. soft delete (YAML only — tmux left running)
|
# 1. soft delete (YAML only — tmux left running)
|
||||||
bash ~/PuKi/lab/agent_sessions/skills/multi-agent-delete/scripts/delete_session.sh \
|
bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-delete/scripts/delete_session.sh \
|
||||||
--session "$SESSION_NAME" --mode soft
|
--session "$SESSION_NAME" --mode soft
|
||||||
|
|
||||||
# 2. hard delete (default — kill tmux + update YAML)
|
# 2. hard delete (default — kill tmux + update YAML)
|
||||||
bash ~/PuKi/lab/agent_sessions/skills/multi-agent-delete/scripts/delete_session.sh \
|
bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-delete/scripts/delete_session.sh \
|
||||||
--session "$SESSION_NAME" --mode hard
|
--session "$SESSION_NAME" --mode hard
|
||||||
|
|
||||||
# 3. hard delete + clean up on-disk conversation (DANGEROUS)
|
# 3. hard delete + clean up on-disk conversation (DANGEROUS)
|
||||||
# — this prevents any future resume. Use only when user is certain.
|
# — this prevents any future resume. Use only when user is certain.
|
||||||
bash ~/PuKi/lab/agent_sessions/skills/multi-agent-delete/scripts/delete_session.sh \
|
bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-delete/scripts/delete_session.sh \
|
||||||
--session "$SESSION_NAME" --mode hard --purge-conversation
|
--session "$SESSION_NAME" --mode hard --purge-conversation
|
||||||
```
|
```
|
||||||
|
|
||||||
The script:
|
The script:
|
||||||
1. Verifies the session is in agent-sessions.yaml
|
1. Verifies the session is in agent-sessions.yaml
|
||||||
2. If `delegate_job_id` is set, automatically publishes a `progress --detail "terminating"` event to the delegate-job registry
|
2. If `delegate_job_id` is set, automatically publishes a `progress --detail "terminating"` event to the tmux-agent-orchestrate-delegate-job registry
|
||||||
3. Captures the `last_visible_status` from `tmux capture-pane` (so we have a final TUI snapshot for audit)
|
3. Captures the `last_visible_status` from `tmux capture-pane` (so we have a final TUI snapshot for audit)
|
||||||
4. For `hard` mode: `tmux kill-session -t <name>` (which auto-SIGTERMs children including the agent)
|
4. For `hard` mode: `tmux kill-session -t <name>` (which auto-SIGTERMs children including the agent)
|
||||||
5. For `purge-conversation`: deletes `~/.claude/projects/.../jsonl` (claude) or `~/.gemini/antigravity-cli/conversations/...db` + `brain/...` (agy)
|
5. For `purge-conversation`: deletes `~/.claude/projects/.../jsonl` (claude) or `~/.gemini/antigravity-cli/conversations/...db` + `brain/...` (agy)
|
||||||
6. Updates the YAML entry
|
6. Updates the YAML entry
|
||||||
7. If `delegate_job_id` is set, publishes a `completed` event to the delegate-job registry
|
7. If `delegate_job_id` is set, publishes a `completed` event to the tmux-agent-orchestrate-delegate-job registry
|
||||||
8. Updates the YAML entry:
|
8. Updates the YAML entry:
|
||||||
```yaml
|
```yaml
|
||||||
- name: <SESSION_NAME>
|
- name: <SESSION_NAME>
|
||||||
@@ -98,10 +98,10 @@ The script:
|
|||||||
## Pitfalls
|
## Pitfalls
|
||||||
|
|
||||||
- **`tmux kill-session` doesn't just kill the session — it sends SIGHUP to the pane's child processes too.** This is usually what you want (the agent process dies, no zombie reparenting to init). But if you wanted to keep the agent running outside tmux for some reason, use `soft` mode.
|
- **`tmux kill-session` doesn't just kill the session — it sends SIGHUP to the pane's child processes too.** This is usually what you want (the agent process dies, no zombie reparenting to init). But if you wanted to keep the agent running outside tmux for some reason, use `soft` mode.
|
||||||
- **Don't delete on-disk artifacts by default** — the agent's `*.jsonl` / `conversations/*.db` is the data that `multi-agent-resume` needs. `--purge-conversation` is for when the user is genuinely done with the conversation and wants zero recovery chance.
|
- **Don't delete on-disk artifacts by default** — the agent's `*.jsonl` / `conversations/*.db` is the data that `tmux-agent-orchestrate-resume` needs. `--purge-conversation` is for when the user is genuinely done with the conversation and wants zero recovery chance.
|
||||||
- **YAML is append-only until you write a delete** — if a previous run left the entry as `running` but tmux is actually dead (crash, host reboot), the YAML is stale. Running `multi-agent-delete --mode hard` will detect "tmux already dead, just update YAML" and proceed.
|
- **YAML is append-only until you write a delete** — if a previous run left the entry as `running` but tmux is actually dead (crash, host reboot), the YAML is stale. Running `tmux-agent-orchestrate-delete --mode hard` will detect "tmux already dead, just update YAML" and proceed.
|
||||||
- **Don't delete the `claude_session_id_own: null` placeholder** — when the user creates a fresh session with `multi-agent-create` and never sent a message, the entry has `claude_session_id_own: null`. Deletion must preserve that field (it's the audit trail showing "this tmux session never produced a session id of its own").
|
- **Don't delete the `claude_session_id_own: null` placeholder** — when the user creates a fresh session with `tmux-agent-orchestrate-create` and never sent a message, the entry has `claude_session_id_own: null`. Deletion must preserve that field (it's the audit trail showing "this tmux session never produced a session id of its own").
|
||||||
- **Monitor skill may still be tracking** — if `agent-sessions-monitor` is running a heartbeat loop, deleting a session while it watches will trigger its `tmux ls != yaml` reconciliation. That's expected — let the monitor run, it will mark the entry as `terminated` on its own. Don't fight it.
|
- **Monitor skill may still be tracking** — if `tmux-agent-orchestrate-monitor` is running a heartbeat loop, deleting a session while it watches will trigger its `tmux ls != yaml` reconciliation. That's expected — let the monitor run, it will mark the entry as `terminated` on its own. Don't fight it.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
@@ -127,5 +127,5 @@ print(f' preserved: pane.pid={s[\"pane\"][\"pid\"]}, cmd={s[\"pane\"][\"cmd\"]}
|
|||||||
## When NOT to use this skill
|
## When NOT to use this skill
|
||||||
|
|
||||||
- **Just detaching** → `tmux detach` (Ctrl-B d) or just close the terminal. The tmux session keeps running.
|
- **Just detaching** → `tmux detach` (Ctrl-B d) or just close the terminal. The tmux session keeps running.
|
||||||
- **Stopping the agent inside but keeping tmux** → send `Ctrl-C` or `/exit` (claude) / `Ctrl-D` (agy) via `tmux send-keys`. The tmux session stays but the agent process is gone; you can then `multi-agent-create` again to spawn a fresh agent in the same tmux session.
|
- **Stopping the agent inside but keeping tmux** → send `Ctrl-C` or `/exit` (claude) / `Ctrl-D` (agy) via `tmux send-keys`. The tmux session stays but the agent process is gone; you can then `tmux-agent-orchestrate-create` again to spawn a fresh agent in the same tmux session.
|
||||||
- **Replacing an existing session with a new one** → `multi-agent-delete --mode hard` first, then `multi-agent-create`.
|
- **Replacing an existing session with a new one** → `tmux-agent-orchestrate-delete --mode hard` first, then `tmux-agent-orchestrate-create`.
|
||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# delete_session.sh — multi-agent-delete 의 부속 스크립트
|
# delete_session.sh — tmux-agent-orchestrate-delete 의 부속 스크립트
|
||||||
# Usage:
|
# Usage:
|
||||||
# bash delete_session.sh --session <name> [--agent claude|agy] \
|
# bash delete_session.sh --session <name> [--agent claude|agy] \
|
||||||
# [--mode soft|hard] [--purge-conversation] [--yes]
|
# [--mode soft|hard] [--purge-conversation] [--yes]
|
||||||
@@ -88,7 +88,7 @@ DELEGATE_JOB_ID=$(printf '%s' "$MAPPED_DATA" | python3 -c 'import sys,json; prin
|
|||||||
if [ "$PURGE" = "1" ] && [ "$YES" != "1" ]; then
|
if [ "$PURGE" = "1" ] && [ "$YES" != "1" ]; then
|
||||||
echo "DANGER: --purge-conversation will DELETE this workspace's on-disk conversation."
|
echo "DANGER: --purge-conversation will DELETE this workspace's on-disk conversation."
|
||||||
echo " workspace: ${TARGET_CWD:-<unknown>}"
|
echo " workspace: ${TARGET_CWD:-<unknown>}"
|
||||||
echo " This means: no future multi-agent-resume for this session."
|
echo " This means: no future tmux-agent-orchestrate-resume for this session."
|
||||||
echo " Re-run with --yes to confirm."
|
echo " Re-run with --yes to confirm."
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
@@ -205,5 +205,5 @@ echo " mode: $MODE"
|
|||||||
echo " purge: $PURGE${PURGE_UUID:+ (uuid $PURGE_UUID)}"
|
echo " purge: $PURGE${PURGE_UUID:+ (uuid $PURGE_UUID)}"
|
||||||
echo " time: $NOW_ISO"
|
echo " time: $NOW_ISO"
|
||||||
echo
|
echo
|
||||||
echo "Recovery: multi-agent-create + multi-agent-resume 로 동일 컨텍스트 복원 가능"
|
echo "Recovery: tmux-agent-orchestrate-create + tmux-agent-orchestrate-resume 로 동일 컨텍스트 복원 가능"
|
||||||
echo " (단 --purge-conversation 사용 시 복원 불가)"
|
echo " (단 --purge-conversation 사용 시 복원 불가)"
|
||||||
+16
-16
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: agent-sessions-monitor
|
name: tmux-agent-orchestrate-monitor
|
||||||
description: "Run a long-lived Kanban worker that polls ~/PuKi/lab/agent_sessions/agent-sessions.yaml against the actual tmux/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. Designed to be dispatched as a Kanban goal_mode task (--goal) so it keeps running until the user stops it."
|
description: "Run a long-lived Kanban worker that polls ~/PuKi/lab/agent_sessions/agent-sessions.yaml against the actual tmux/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. Designed to be dispatched as a Kanban goal_mode task (--goal) so it keeps running until the user stops it."
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
author: godopu
|
author: godopu
|
||||||
@@ -9,13 +9,13 @@ environments: [kanban, terminal, tmux]
|
|||||||
metadata:
|
metadata:
|
||||||
hermes:
|
hermes:
|
||||||
tags: [agent, tmux, claude, antigravity, agy, monitor, kanban, observation, reconciliation]
|
tags: [agent, tmux, claude, antigravity, agy, monitor, kanban, observation, reconciliation]
|
||||||
related_skills: [multi-agent-create, multi-agent-resume, multi-agent-delete, kanban-orchestrator]
|
related_skills: [tmux-agent-orchestrate-create, tmux-agent-orchestrate-resume, tmux-agent-orchestrate-delete, kanban-orchestrator]
|
||||||
prereq_skills: [kanban-worker, multi-agent-create]
|
prereq_skills: [kanban-worker, tmux-agent-orchestrate-create]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Agent Sessions Monitor — Live Reconciliation via Kanban Worker
|
# Agent Sessions Monitor — Live Reconciliation via Kanban Worker
|
||||||
|
|
||||||
> **Companion skills**: `multi-agent-create` / `multi-agent-resume` / `multi-agent-delete` (mutators); this skill is the **observer**.
|
> **Companion skills**: `tmux-agent-orchestrate-create` / `tmux-agent-orchestrate-resume` / `tmux-agent-orchestrate-delete` (mutators); this skill is the **observer**.
|
||||||
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
||||||
|
|
||||||
## What this skill does
|
## What this skill does
|
||||||
@@ -59,12 +59,12 @@ hermes kanban create \
|
|||||||
--title "agent-sessions monitor (live reconcile)" \
|
--title "agent-sessions monitor (live reconcile)" \
|
||||||
--assignee default \
|
--assignee default \
|
||||||
--workspace worktree \
|
--workspace worktree \
|
||||||
--branch wt/agent-sessions-monitor \
|
--branch wt/tmux-agent-orchestrate-monitor \
|
||||||
--goal \
|
--goal \
|
||||||
--goal-max-turns 100 \
|
--goal-max-turns 100 \
|
||||||
--max-runtime 8h \
|
--max-runtime 8h \
|
||||||
--max-retries 1 \
|
--max-retries 1 \
|
||||||
--skill agent-sessions-monitor \
|
--skill tmux-agent-orchestrate-monitor \
|
||||||
--body "$(cat <<'EOF'
|
--body "$(cat <<'EOF'
|
||||||
You are the agent-sessions monitor. Every 30 seconds, do:
|
You are the agent-sessions monitor. Every 30 seconds, do:
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ If the user comments `stop` or `stop monitoring` on this card, call `kanban_bloc
|
|||||||
|
|
||||||
If you find that a Claude session's `claude_session_id_own` is null but there's a new *.jsonl in the project dir, read the sessionId from the first line and update the YAML.
|
If you find that a Claude session's `claude_session_id_own` is null but there's a new *.jsonl in the project dir, read the sessionId from the first line and update the YAML.
|
||||||
|
|
||||||
Use the helper script at ~/PuKi/lab/agent_sessions/skills/agent-sessions-monitor/scripts/reconcile.sh for the YAML updates — it handles all the merge logic and writes a structured comment to this card.
|
Use the helper script at ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh for the YAML updates — it handles all the merge logic and writes a structured comment to this card.
|
||||||
EOF
|
EOF
|
||||||
)"
|
)"
|
||||||
```
|
```
|
||||||
@@ -94,17 +94,17 @@ The worker calls this script every 30s. It:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Reconcile + auto-update YAML (atomic, flock-guarded). Emits JSON drift to stdout.
|
# Reconcile + auto-update YAML (atomic, flock-guarded). Emits JSON drift to stdout.
|
||||||
bash skills/agent-sessions-monitor/scripts/reconcile.sh --once --emit-diff
|
bash skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh --once --emit-diff
|
||||||
|
|
||||||
# Read-only: compute drift WITHOUT writing the YAML (use for "what's running?" checks).
|
# Read-only: compute drift WITHOUT writing the YAML (use for "what's running?" checks).
|
||||||
bash skills/agent-sessions-monitor/scripts/reconcile.sh --once --emit-diff --dry-run
|
bash skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh --once --emit-diff --dry-run
|
||||||
|
|
||||||
# Push-based MQTT Monitor: listen to delegated job events on the broker and update the YAML instantly.
|
# Push-based MQTT Monitor: listen to delegated job events on the broker and update the YAML instantly.
|
||||||
# Bounded run that exits after 5 min idle, or 1 h wall-clock; falls back to polling if the broker is down.
|
# Bounded run that exits after 5 min idle, or 1 h wall-clock; falls back to polling if the broker is down.
|
||||||
bash skills/agent-sessions-monitor/scripts/reconcile.sh --subscribe --idle-timeout 300 --timeout 3600
|
bash skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh --subscribe --idle-timeout 300 --timeout 3600
|
||||||
|
|
||||||
# Persistent monitor (no timeouts): runs until interrupted; still polls if the broker is unreachable.
|
# Persistent monitor (no timeouts): runs until interrupted; still polls if the broker is unreachable.
|
||||||
bash skills/agent-sessions-monitor/scripts/reconcile.sh --subscribe --idle-timeout 0
|
bash skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh --subscribe --idle-timeout 0
|
||||||
```
|
```
|
||||||
|
|
||||||
Flags: `--once` (single pass), `--emit-diff` (print JSON), `--dry-run` (P1-E — no mutation), `--subscribe` (push-based MQTT subscription monitoring). `--subscribe` sub-flags: `--timeout N` (exit after N seconds of wall-clock; `0` = no limit, default), `--idle-timeout N` (exit after N seconds with no message; default `600`, `0` = never idle-out). On a broker connection failure (connect error **or** non-zero CONNACK), `--subscribe` falls back to a polling loop that re-runs `--once --emit-diff` every `RECONCILE_POLL_INTERVAL` (default 15) seconds until `--timeout`. Terminal-event YAML updates are written through `lib.sh::atomic_dump_yaml` (flock + schema-validate + `.bak`). There are **no** `--workspace` / `--agent` / `--comment-card` flags; the worker turns the emitted JSON `drifts[]` into `kanban_comment` calls itself.
|
Flags: `--once` (single pass), `--emit-diff` (print JSON), `--dry-run` (P1-E — no mutation), `--subscribe` (push-based MQTT subscription monitoring). `--subscribe` sub-flags: `--timeout N` (exit after N seconds of wall-clock; `0` = no limit, default), `--idle-timeout N` (exit after N seconds with no message; default `600`, `0` = never idle-out). On a broker connection failure (connect error **or** non-zero CONNACK), `--subscribe` falls back to a polling loop that re-runs `--once --emit-diff` every `RECONCILE_POLL_INTERVAL` (default 15) seconds until `--timeout`. Terminal-event YAML updates are written through `lib.sh::atomic_dump_yaml` (flock + schema-validate + `.bak`). There are **no** `--workspace` / `--agent` / `--comment-card` flags; the worker turns the emitted JSON `drifts[]` into `kanban_comment` calls itself.
|
||||||
@@ -154,8 +154,8 @@ disk: ~/.claude/projects/.../87dc548e-...jsonl: missing
|
|||||||
|
|
||||||
- **Don't run the monitor without `--goal`** — without goal mode, a single turn will spawn, do one reconcile, and complete. Goal mode keeps the worker alive across many turns.
|
- **Don't run the monitor without `--goal`** — without goal mode, a single turn will spawn, do one reconcile, and complete. Goal mode keeps the worker alive across many turns.
|
||||||
- **The 30s poll is a default** — workers may override if they detect heavy churn. A workspace with 5+ agent sessions should bump to 60s to avoid noise.
|
- **The 30s poll is a default** — workers may override if they detect heavy churn. A workspace with 5+ agent sessions should bump to 60s to avoid noise.
|
||||||
- **`kanban_comment` rate limits** — Kanban may throttle if you comment too fast. Coalesce: only comment when the diff is *new* (not the same drift on every poll). The script tracks a state file at `~/.cache/agent-sessions-monitor/<workspace>.state` for this.
|
- **`kanban_comment` rate limits** — Kanban may throttle if you comment too fast. Coalesce: only comment when the diff is *new* (not the same drift on every poll). The script tracks a state file at `~/.cache/tmux-agent-orchestrate-monitor/<workspace>.state` for this.
|
||||||
- **Don't fight the user's explicit action** — if `multi-agent-delete` is mid-flight and the monitor sees the same session in two states within 5s, prefer the user's most recent action. The monitor should not auto-revert a fresh `terminated` to `running` because of a stale `tmux has-session` check.
|
- **Don't fight the user's explicit action** — if `tmux-agent-orchestrate-delete` is mid-flight and the monitor sees the same session in two states within 5s, prefer the user's most recent action. The monitor should not auto-revert a fresh `terminated` to `running` because of a stale `tmux has-session` check.
|
||||||
- **The monitor should never modify the conversation artifacts** (jsonl, db) — only the YAML. If you see a stale UUID, comment about it but don't delete the file.
|
- **The monitor should never modify the conversation artifacts** (jsonl, db) — only the YAML. If you see a stale UUID, comment about it but don't delete the file.
|
||||||
- **TUI capture-pane is expensive** — only capture when you need to update `last_visible_status`, not every poll.
|
- **TUI capture-pane is expensive** — only capture when you need to update `last_visible_status`, not every poll.
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ The `--body` of the dispatched task IS the worker's behavior spec. Here's a test
|
|||||||
## Loop (every 30s)
|
## Loop (every 30s)
|
||||||
|
|
||||||
1. Read agent-sessions.yaml
|
1. Read agent-sessions.yaml
|
||||||
2. Bash: `bash ~/PuKi/lab/agent_sessions/skills/agent-sessions-monitor/scripts/reconcile.sh --emit-diff`
|
2. Bash: `bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh --emit-diff`
|
||||||
3. Parse the JSON diff from stdout
|
3. Parse the JSON diff from stdout
|
||||||
4. If `drifts` is non-empty:
|
4. If `drifts` is non-empty:
|
||||||
- For each drift, call `kanban_comment` with the diff message
|
- For each drift, call `kanban_comment` with the diff message
|
||||||
@@ -192,7 +192,7 @@ If `$HERMES_KANBAN_TASK` card has any comment containing "stop" or "stop monitor
|
|||||||
|
|
||||||
- Do NOT modify conversation artifacts (jsonl, db, brain/)
|
- Do NOT modify conversation artifacts (jsonl, db, brain/)
|
||||||
- Do NOT spawn/delete tmux sessions — that's the create/delete skills' job
|
- Do NOT spawn/delete tmux sessions — that's the create/delete skills' job
|
||||||
- Do NOT call multi-agent-create or multi-agent-delete — only the user initiates those
|
- Do NOT call tmux-agent-orchestrate-create or tmux-agent-orchestrate-delete — only the user initiates those
|
||||||
- Do NOT call `git commit` / `git push`
|
- Do NOT call `git commit` / `git push`
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ If `$HERMES_KANBAN_TASK` card has any comment containing "stop" or "stop monitor
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run reconcile once and inspect output
|
# Run reconcile once and inspect output
|
||||||
bash ~/PuKi/lab/agent_sessions/skills/agent-sessions-monitor/scripts/reconcile.sh --emit-diff --once \
|
bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-monitor/scripts/reconcile.sh --emit-diff --once \
|
||||||
| python3 -m json.tool
|
| python3 -m json.tool
|
||||||
```
|
```
|
||||||
|
|
||||||
+7
-7
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# reconcile.sh — agent-sessions-monitor 의 부속 스크립트
|
# reconcile.sh — tmux-agent-orchestrate-monitor 의 부속 스크립트
|
||||||
# YAML ↔ tmux ↔ 디스크 artifact 간 drift 감지 (+ YAML 자동 갱신).
|
# YAML ↔ tmux ↔ 디스크 artifact 간 drift 감지 (+ YAML 자동 갱신).
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
# bash reconcile.sh --once --emit-diff --dry-run # drift 만 계산, 쓰기 안 함 (P1-E)
|
# bash reconcile.sh --once --emit-diff --dry-run # drift 만 계산, 쓰기 안 함 (P1-E)
|
||||||
#
|
#
|
||||||
# --dry-run: 부수효과 없는 read-only. "지금 뭐 돌고 있지?" 질문에 안전.
|
# --dry-run: 부수효과 없는 read-only. "지금 뭐 돌고 있지?" 질문에 안전.
|
||||||
# multi-agent-status 스킬이 이걸 재사용.
|
# tmux-agent-orchestrate-status 스킬이 이걸 재사용.
|
||||||
#
|
#
|
||||||
# 출력 (JSON): {timestamp, yaml_path, tmux_sessions_alive, tmux_confirmed, drifts, actions}
|
# 출력 (JSON): {timestamp, yaml_path, tmux_sessions_alive, tmux_confirmed, drifts, actions}
|
||||||
#
|
#
|
||||||
@@ -16,7 +16,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib.sh"
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib.sh"
|
||||||
|
|
||||||
STATE_DIR="${AGENT_SESSIONS_STATE_DIR:-$HOME/.cache/agent-sessions-monitor}"
|
STATE_DIR="${AGENT_SESSIONS_STATE_DIR:-$HOME/.cache/tmux-agent-orchestrate-monitor}"
|
||||||
|
|
||||||
ONCE=0
|
ONCE=0
|
||||||
EMIT_DIFF=0
|
EMIT_DIFF=0
|
||||||
@@ -65,16 +65,16 @@ skills_dir = os.environ.get('SKILLS_DIR', '')
|
|||||||
timeout = int(os.environ.get('SUB_TIMEOUT', '0') or '0') # 0 = no overall timeout
|
timeout = int(os.environ.get('SUB_TIMEOUT', '0') or '0') # 0 = no overall timeout
|
||||||
idle_timeout = int(os.environ.get('SUB_IDLE_TIMEOUT', '600') or '0') # 0 = no idle timeout
|
idle_timeout = int(os.environ.get('SUB_IDLE_TIMEOUT', '600') or '0') # 0 = no idle timeout
|
||||||
|
|
||||||
# Locate skills/delegate-job/scripts to import mqtt_common — relative first, then
|
# Locate skills/tmux-agent-orchestrate-delegate-job/scripts to import mqtt_common — relative first, then
|
||||||
# an upward walk from cwd. No hardcoded absolute path (review item 6).
|
# an upward walk from cwd. No hardcoded absolute path (review item 6).
|
||||||
cand = os.path.join(skills_dir, 'delegate-job', 'scripts') if skills_dir else ''
|
cand = os.path.join(skills_dir, 'tmux-agent-orchestrate-delegate-job', 'scripts') if skills_dir else ''
|
||||||
if cand and os.path.isdir(cand):
|
if cand and os.path.isdir(cand):
|
||||||
sys.path.append(cand)
|
sys.path.append(cand)
|
||||||
else:
|
else:
|
||||||
d = os.getcwd()
|
d = os.getcwd()
|
||||||
while d and d != '/':
|
while d and d != '/':
|
||||||
hit = None
|
hit = None
|
||||||
for sub in (('skills', 'delegate-job', 'scripts'), ('delegate-job', 'scripts')):
|
for sub in (('skills', 'tmux-agent-orchestrate-delegate-job', 'scripts'), ('tmux-agent-orchestrate-delegate-job', 'scripts')):
|
||||||
p = os.path.join(d, *sub)
|
p = os.path.join(d, *sub)
|
||||||
if os.path.isdir(p):
|
if os.path.isdir(p):
|
||||||
hit = p
|
hit = p
|
||||||
@@ -204,7 +204,7 @@ PYEOF
|
|||||||
|
|
||||||
if [ "$sub_rc" = "3" ]; then
|
if [ "$sub_rc" = "3" ]; then
|
||||||
echo "MQTT Monitor: broker unavailable — falling back to polling (interval ${POLL_INTERVAL}s)" >&2
|
echo "MQTT Monitor: broker unavailable — falling back to polling (interval ${POLL_INTERVAL}s)" >&2
|
||||||
_self="$SKILLS_DIR/agent-sessions-monitor/scripts/reconcile.sh"
|
_self="$SKILLS_DIR/tmux-agent-orchestrate-monitor/scripts/reconcile.sh"
|
||||||
_start=$(date +%s)
|
_start=$(date +%s)
|
||||||
while :; do
|
while :; do
|
||||||
bash "$_self" --once --emit-diff >/dev/null 2>&1 || true
|
bash "$_self" --once --emit-diff >/dev/null 2>&1 || true
|
||||||
+16
-16
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-resume
|
name: tmux-agent-orchestrate-resume
|
||||||
description: "Resume an existing agent (claude, antigravity/agy) conversation by UUID into a tmux session. Reads ~/PuKi/lab/agent_sessions/agent-sessions.yaml for the saved session/conversation id, spawns (or reuses) a tmux session of the matching name, and runs `claude -r <id>` or `agy --conversation <id>` inside. Use when you want to reattach to a previous session's context, or revive a session whose tmux died but the agent's conversation is still on disk."
|
description: "Resume an existing agent (claude, antigravity/agy) conversation by UUID into a tmux session. Reads ~/PuKi/lab/agent_sessions/agent-sessions.yaml for the saved session/conversation id, spawns (or reuses) a tmux session of the matching name, and runs `claude -r <id>` or `agy --conversation <id>` inside. Use when you want to reattach to a previous session's context, or revive a session whose tmux died but the agent's conversation is still on disk."
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
author: godopu
|
author: godopu
|
||||||
@@ -9,14 +9,14 @@ environments: [terminal, tmux]
|
|||||||
metadata:
|
metadata:
|
||||||
hermes:
|
hermes:
|
||||||
tags: [agent, tmux, claude, antigravity, agy, multi-agent, context, resume, session-id]
|
tags: [agent, tmux, claude, antigravity, agy, multi-agent, context, resume, session-id]
|
||||||
related_skills: [multi-agent-create, multi-agent-delete, agent-sessions-monitor, claude-code]
|
related_skills: [tmux-agent-orchestrate-create, tmux-agent-orchestrate-delete, tmux-agent-orchestrate-monitor, claude-code]
|
||||||
prereq_skills: [multi-agent-create]
|
prereq_skills: [tmux-agent-orchestrate-create]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Multi-Agent Resume — Reattach to a Saved Conversation
|
# Multi-Agent Resume — Reattach to a Saved Conversation
|
||||||
|
|
||||||
> **Companion skills**: `multi-agent-create` (start a fresh agent), `multi-agent-delete` (terminate), `agent-sessions-monitor` (live status).
|
> **Companion skills**: `tmux-agent-orchestrate-create` (start a fresh agent), `tmux-agent-orchestrate-delete` (terminate), `tmux-agent-orchestrate-monitor` (live status).
|
||||||
> **Tmux Isolation**: `TMUX_SERVER_NAME` env var를 create에서 설정한 경우, 동일 서버에서 동작합니다. 자세한 격리 패턴은 [multi-agent-create/SKILL.md](file:///home/godopu16/PuKi/laa/canary_projects/advanced_multi_agent/skills/multi-agent-create/SKILL.md) 참조.
|
> **Tmux Isolation**: `TMUX_SERVER_NAME` env var를 create에서 설정한 경우, 동일 서버에서 동작합니다. 자세한 격리 패턴은 [tmux-agent-orchestrate-create/SKILL.md](file:///home/godopu16/PuKi/laa/canary_projects/advanced_multi_agent/skills/tmux-agent-orchestrate-create/SKILL.md) 참조.
|
||||||
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
||||||
|
|
||||||
## What this skill does
|
## What this skill does
|
||||||
@@ -26,7 +26,7 @@ metadata:
|
|||||||
Three cases this skill handles:
|
Three cases this skill handles:
|
||||||
|
|
||||||
1. **tmux is dead, conversation lives** — `agent-sessions.yaml` has the UUID. The JSONL/db is on disk. Re-spawn the tmux session + run `claude -r <id>` / `agy --conversation <id>`.
|
1. **tmux is dead, conversation lives** — `agent-sessions.yaml` has the UUID. The JSONL/db is on disk. Re-spawn the tmux session + run `claude -r <id>` / `agy --conversation <id>`.
|
||||||
2. **tmux is alive but empty** — You started a session with `multi-agent-create` but haven't sent a message yet (so no session id was assigned). The user can either send their first message (and the id is auto-assigned), or you can read the *workspace's* most recent conversation from `~/.gemini/antigravity-cli/cache/last_conversations.json` for agy, or the latest `*.jsonl` in `~/.claude/projects/<workspace-key>/` for claude.
|
2. **tmux is alive but empty** — You started a session with `tmux-agent-orchestrate-create` but haven't sent a message yet (so no session id was assigned). The user can either send their first message (and the id is auto-assigned), or you can read the *workspace's* most recent conversation from `~/.gemini/antigravity-cli/cache/last_conversations.json` for agy, or the latest `*.jsonl` in `~/.claude/projects/<workspace-key>/` for claude.
|
||||||
3. **tmux is alive AND the agent inside is already running** — Just attach. No re-spawn needed.
|
3. **tmux is alive AND the agent inside is already running** — Just attach. No re-spawn needed.
|
||||||
|
|
||||||
## UUID resolution order
|
## UUID resolution order
|
||||||
@@ -39,21 +39,21 @@ Three cases this skill handles:
|
|||||||
- claude: `ls -t ~/.claude/projects/<workspace-key>/*.jsonl | head -1` and parse the `sessionId` from the first line
|
- claude: `ls -t ~/.claude/projects/<workspace-key>/*.jsonl | head -1` and parse the `sessionId` from the first line
|
||||||
- agy: `jq -r '."<workspace>"' ~/.gemini/antigravity-cli/cache/last_conversations.json`
|
- agy: `jq -r '."<workspace>"' ~/.gemini/antigravity-cli/cache/last_conversations.json`
|
||||||
|
|
||||||
If all three are empty → the workspace has no conversation yet. Fall back to `multi-agent-create`.
|
If all three are empty → the workspace has no conversation yet. Fall back to `tmux-agent-orchestrate-create`.
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
WORKSPACE=/path/to/project
|
WORKSPACE=/path/to/project
|
||||||
AGENT=claude # or agy
|
AGENT=claude # or agy
|
||||||
SESSION_NAME=<workspace>-creator-<agent> # same convention as multi-agent-create
|
SESSION_NAME=<workspace>-creator-<agent> # same convention as tmux-agent-orchestrate-create
|
||||||
|
|
||||||
# 1. Resolve the session id
|
# 1. Resolve the session id
|
||||||
UUID=$(bash ~/PuKi/lab/agent_sessions/skills/multi-agent-resume/scripts/resolve_session_id.sh \
|
UUID=$(bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-resume/scripts/resolve_session_id.sh \
|
||||||
--workspace "$WORKSPACE" --agent "$AGENT")
|
--workspace "$WORKSPACE" --agent "$AGENT")
|
||||||
|
|
||||||
if [ -z "$UUID" ]; then
|
if [ -z "$UUID" ]; then
|
||||||
echo "No saved session for $WORKSPACE ($AGENT). Use multi-agent-create first."
|
echo "No saved session for $WORKSPACE ($AGENT). Use tmux-agent-orchestrate-create first."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -87,8 +87,8 @@ case "$AGENT" in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
# 4. Update agent-sessions.yaml: status running, last_visible_status
|
# 4. Update agent-sessions.yaml: status running, last_visible_status
|
||||||
# (Also automatically publishes a `progress --detail "resumed"` event to the delegate-job registry if a delegate_job_id exists)
|
# (Also automatically publishes a `progress --detail "resumed"` event to the tmux-agent-orchestrate-delegate-job registry if a delegate_job_id exists)
|
||||||
bash ~/PuKi/lab/agent_sessions/skills/multi-agent-resume/scripts/update_yaml_resumed.sh \
|
bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-resume/scripts/update_yaml_resumed.sh \
|
||||||
--session "$SESSION_NAME" --uuid "$UUID"
|
--session "$SESSION_NAME" --uuid "$UUID"
|
||||||
|
|
||||||
# 5. Attach
|
# 5. Attach
|
||||||
@@ -100,8 +100,8 @@ tmux attach -t "$SESSION_NAME"
|
|||||||
- **`claude -r` requires the SAME project directory** — if the workspace path differs from when the session was created, claude will create a new project dir key (`-home-...-different-name`) and put the resume in a different location. Always `-c` (cd to workspace) before running.
|
- **`claude -r` requires the SAME project directory** — if the workspace path differs from when the session was created, claude will create a new project dir key (`-home-...-different-name`) and put the resume in a different location. Always `-c` (cd to workspace) before running.
|
||||||
- **agy's `--conversation` flag name varies by version** — older versions used `--resume` or `-r`. Check `agy --help | grep -E "conversation|resume"` and use the right flag. v1.0.x: `--conversation`.
|
- **agy's `--conversation` flag name varies by version** — older versions used `--resume` or `-r`. Check `agy --help | grep -E "conversation|resume"` and use the right flag. v1.0.x: `--conversation`.
|
||||||
- **The first message after resume might re-trigger TUI dialogs** — if the original session was created with `--dangerously-skip-permissions`, those flags are NOT persisted; you must re-apply them on resume. The script above re-passes them.
|
- **The first message after resume might re-trigger TUI dialogs** — if the original session was created with `--dangerously-skip-permissions`, those flags are NOT persisted; you must re-apply them on resume. The script above re-passes them.
|
||||||
- **Don't resume if the session is brand new and empty** — `multi-agent-create` already set up an empty container; sending a probe message ("init") is the right way to materialize a session id, NOT `claude -r` with a placeholder.
|
- **Don't resume if the session is brand new and empty** — `tmux-agent-orchestrate-create` already set up an empty container; sending a probe message ("init") is the right way to materialize a session id, NOT `claude -r` with a placeholder.
|
||||||
- **`agy --conversation <id>` will fail if the conversation was deleted from disk** — check `~/.gemini/antigravity-cli/conversations/<uuid>.db` exists before attempting resume. If missing, the conversation is gone; you need a fresh session via `multi-agent-create`.
|
- **`agy --conversation <id>` will fail if the conversation was deleted from disk** — check `~/.gemini/antigravity-cli/conversations/<uuid>.db` exists before attempting resume. If missing, the conversation is gone; you need a fresh session via `tmux-agent-orchestrate-create`.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
@@ -126,6 +126,6 @@ tmux capture-pane -t "$SESSION_NAME" -p -S -30
|
|||||||
|
|
||||||
## When NOT to use this skill
|
## When NOT to use this skill
|
||||||
|
|
||||||
- **No saved session yet** → `multi-agent-create`
|
- **No saved session yet** → `tmux-agent-orchestrate-create`
|
||||||
- **Killing an existing session** → `multi-agent-delete`
|
- **Killing an existing session** → `tmux-agent-orchestrate-delete`
|
||||||
- **Just attaching** → `tmux attach -t <name>` (no skill needed)
|
- **Just attaching** → `tmux attach -t <name>` (no skill needed)
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# resolve_session_id.sh — multi-agent-resume 의 부속 스크립트
|
# resolve_session_id.sh — tmux-agent-orchestrate-resume 의 부속 스크립트
|
||||||
# Usage:
|
# Usage:
|
||||||
# bash resolve_session_id.sh --workspace <path> --agent <claude|agy>
|
# bash resolve_session_id.sh --workspace <path> --agent <claude|agy>
|
||||||
# 출력: stdout 으로 UUID 한 줄 (없으면 빈 줄 + exit 0)
|
# 출력: stdout 으로 UUID 한 줄 (없으면 빈 줄 + exit 0)
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# update_yaml_resumed.sh — multi-agent-resume 의 부속 스크립트
|
# update_yaml_resumed.sh — tmux-agent-orchestrate-resume 의 부속 스크립트
|
||||||
# Resume 한 세션의 agent-sessions.yaml 엔트리를 status=running + resume 메타로 갱신.
|
# Resume 한 세션의 agent-sessions.yaml 엔트리를 status=running + resume 메타로 갱신.
|
||||||
# resume UUID 를 per-row own id (claude_session_id_own / agy_conversation_id_own)
|
# resume UUID 를 per-row own id (claude_session_id_own / agy_conversation_id_own)
|
||||||
# 에 박는다 — agent_identities 전역은 더 이상 primary 아님 (cache 로 강등, P0-C/단계 e).
|
# 에 박는다 — agent_identities 전역은 더 이상 primary 아님 (cache 로 강등, P0-C/단계 e).
|
||||||
+16
-16
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-status
|
name: tmux-agent-orchestrate-status
|
||||||
description: "Read-only instant snapshot of all agent tmux sessions — name, YAML status, tmux alive, pane cmd/cwd, resume UUID on disk, and any drift. No Kanban, 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 a Kanban monitor worker."
|
description: "Read-only instant snapshot of all agent tmux sessions — name, YAML status, tmux alive, pane cmd/cwd, resume UUID on disk, and any drift. No Kanban, 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 a Kanban monitor worker."
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
author: godopu
|
author: godopu
|
||||||
@@ -9,13 +9,13 @@ environments: [terminal, tmux]
|
|||||||
metadata:
|
metadata:
|
||||||
hermes:
|
hermes:
|
||||||
tags: [agent, tmux, claude, antigravity, agy, status, read-only, snapshot]
|
tags: [agent, tmux, claude, antigravity, agy, status, read-only, snapshot]
|
||||||
related_skills: [multi-agent-create, multi-agent-resume, multi-agent-delete, agent-sessions-monitor]
|
related_skills: [tmux-agent-orchestrate-create, tmux-agent-orchestrate-resume, tmux-agent-orchestrate-delete, tmux-agent-orchestrate-monitor]
|
||||||
prereq_skills: [multi-agent-create, agent-sessions-monitor]
|
prereq_skills: [tmux-agent-orchestrate-create, tmux-agent-orchestrate-monitor]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Multi-Agent Status — Read-Only Instant Snapshot
|
# Multi-Agent Status — Read-Only Instant Snapshot
|
||||||
|
|
||||||
> **Companion skills**: `multi-agent-create` (start), `multi-agent-resume` (re-attach), `multi-agent-delete` (terminate), `agent-sessions-monitor` (live polling).
|
> **Companion skills**: `tmux-agent-orchestrate-create` (start), `tmux-agent-orchestrate-resume` (re-attach), `tmux-agent-orchestrate-delete` (terminate), `tmux-agent-orchestrate-monitor` (live polling).
|
||||||
> **Tmux Isolation**: `status` 명령은 YAML에 등록된 모든 세션의 격리 서버(`tmux_server` 필드)를 자동으로 조회하여 상태를 확인하므로, `TMUX_SERVER_NAME` 환경변수를 수동으로 지정하지 않아도 모든 격리 서버의 세션 상태를 통합 조회합니다.
|
> **Tmux Isolation**: `status` 명령은 YAML에 등록된 모든 세션의 격리 서버(`tmux_server` 필드)를 자동으로 조회하여 상태를 확인하므로, `TMUX_SERVER_NAME` 환경변수를 수동으로 지정하지 않아도 모든 격리 서버의 세션 상태를 통합 조회합니다.
|
||||||
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
> **Single source of truth**: `~/PuKi/lab/agent_sessions/agent-sessions.yaml`.
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ metadata:
|
|||||||
|
|
||||||
Print a single table of every agent tmux session, comparing YAML state to actual tmux state. **No mutation. No Kanban. No polling loop.**
|
Print a single table of every agent tmux session, comparing YAML state to actual tmux state. **No mutation. No Kanban. No polling loop.**
|
||||||
|
|
||||||
This is the "what's running right now?" answer — faster than dispatching `agent-sessions-monitor` (which polls every 30s) and safer than `reconcile.sh --once --emit-diff` (which mutates as a side effect).
|
This is the "what's running right now?" answer — faster than dispatching `tmux-agent-orchestrate-monitor` (which polls every 30s) and safer than `reconcile.sh --once --emit-diff` (which mutates as a side effect).
|
||||||
|
|
||||||
## Pre-flight
|
## Pre-flight
|
||||||
|
|
||||||
@@ -33,12 +33,12 @@ command -v python3
|
|||||||
test -f ~/PuKi/lab/agent_sessions/agent-sessions.yaml
|
test -f ~/PuKi/lab/agent_sessions/agent-sessions.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
If `agent-sessions.yaml` doesn't exist or is malformed → print clear error, exit 1. **Do not create it.** (Use `multi-agent-create` first.)
|
If `agent-sessions.yaml` doesn't exist or is malformed → print clear error, exit 1. **Do not create it.** (Use `tmux-agent-orchestrate-create` first.)
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash ~/PuKi/lab/agent_sessions/skills/multi-agent-status/scripts/status.sh [--json]
|
bash ~/PuKi/lab/agent_sessions/skills/tmux-agent-orchestrate-status/scripts/status.sh [--json]
|
||||||
```
|
```
|
||||||
|
|
||||||
The script:
|
The script:
|
||||||
@@ -98,17 +98,17 @@ lab-paper-pdf2md-creator-claude default running alive clau
|
|||||||
|
|
||||||
| Class | Detection | Meaning |
|
| Class | Detection | Meaning |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `A` | YAML `running`, tmux dead | session died without going through `multi-agent-delete`. *Could* auto-terminate but won't — that's `agent-sessions-monitor`'s job. |
|
| `A` | YAML `running`, tmux dead | session died without going through `tmux-agent-orchestrate-delete`. *Could* auto-terminate but won't — that's `tmux-agent-orchestrate-monitor`'s job. |
|
||||||
| `B` | tmux alive, not in YAML | ad-hoc session someone started without `multi-agent-create`. Suggest: "use multi-agent-create to register, or tmux kill-session to clean up." |
|
| `B` | tmux alive, not in YAML | ad-hoc session someone started without `tmux-agent-orchestrate-create`. Suggest: "use tmux-agent-orchestrate-create to register, or tmux kill-session to clean up." |
|
||||||
| `C` | YAML has `claude_session_id_own: null` AND a new *.jsonl exists | new session id materialized; suggest: "run multi-agent-resume or reconcile to register it." |
|
| `C` | YAML has `claude_session_id_own: null` AND a new *.jsonl exists | new session id materialized; suggest: "run tmux-agent-orchestrate-resume or reconcile to register it." |
|
||||||
| `D` | YAML has UUID in `agent_identities`, but the on-disk artifact is gone | stale UUID; user should `multi-agent-delete --purge-conversation` to clean up. |
|
| `D` | YAML has UUID in `agent_identities`, but the on-disk artifact is gone | stale UUID; user should `tmux-agent-orchestrate-delete --purge-conversation` to clean up. |
|
||||||
|
|
||||||
## Pitfalls
|
## Pitfalls
|
||||||
|
|
||||||
- **Do NOT use this skill to drive mutations** — the output is a snapshot, not a call to action. If you need to fix drifts, dispatch `agent-sessions-monitor` (Kanban worker) or run `multi-agent-resume` / `multi-agent-delete` manually.
|
- **Do NOT use this skill to drive mutations** — the output is a snapshot, not a call to action. If you need to fix drifts, dispatch `tmux-agent-orchestrate-monitor` (Kanban worker) or run `tmux-agent-orchestrate-resume` / `tmux-agent-orchestrate-delete` manually.
|
||||||
- **Read-only is enforced by script** — `status.sh` opens the YAML with `open(path)` (no `'w'`), never calls `tmux kill-session`, never writes anywhere. The `reconcile.sh --dry-run` mode is the same path.
|
- **Read-only is enforced by script** — `status.sh` opens the YAML with `open(path)` (no `'w'`), never calls `tmux kill-session`, never writes anywhere. The `reconcile.sh --dry-run` mode is the same path.
|
||||||
- **If `agent-sessions.yaml` is malformed** — print the YAML error verbatim and exit 1. Do NOT attempt recovery (that's `multi-agent-delete --purge-conversation` or manual edit's job).
|
- **If `agent-sessions.yaml` is malformed** — print the YAML error verbatim and exit 1. Do NOT attempt recovery (that's `tmux-agent-orchestrate-delete --purge-conversation` or manual edit's job).
|
||||||
- **Sessions outside the `<workspace>-creator-*` naming convention** are still shown but tagged `ad-hoc` — they didn't go through `multi-agent-create` and aren't tracked in YAML.
|
- **Sessions outside the `<workspace>-creator-*` naming convention** are still shown but tagged `ad-hoc` — they didn't go through `tmux-agent-orchestrate-create` and aren't tracked in YAML.
|
||||||
|
|
||||||
## When to use
|
## When to use
|
||||||
|
|
||||||
@@ -119,6 +119,6 @@ lab-paper-pdf2md-creator-claude default running alive clau
|
|||||||
|
|
||||||
## When NOT to use
|
## When NOT to use
|
||||||
|
|
||||||
- Continuous live tracking → `agent-sessions-monitor` (Kanban worker)
|
- Continuous live tracking → `tmux-agent-orchestrate-monitor` (Kanban worker)
|
||||||
- Recovering from corruption → manual edit + `.bak` restore
|
- Recovering from corruption → manual edit + `.bak` restore
|
||||||
- Polling more than once a minute → `agent-sessions-monitor` (it dedupes)
|
- Polling more than once a minute → `tmux-agent-orchestrate-monitor` (it dedupes)
|
||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# status.sh — multi-agent-status 의 부속 스크립트 (READ-ONLY)
|
# status.sh — tmux-agent-orchestrate-status 의 부속 스크립트 (READ-ONLY)
|
||||||
# 한 번 호출로 현재 agent 세션 상태표를 출력. 부수효과 없음.
|
# 한 번 호출로 현재 agent 세션 상태표를 출력. 부수효과 없음.
|
||||||
# reconcile.sh --dry-run 을 재사용해 drift 를 계산하고 (P1-E), YAML/디스크에서
|
# reconcile.sh --dry-run 을 재사용해 drift 를 계산하고 (P1-E), YAML/디스크에서
|
||||||
# 보강한 표를 그린다. YAML 을 절대 수정하지 않는다.
|
# 보강한 표를 그린다. YAML 을 절대 수정하지 않는다.
|
||||||
@@ -9,12 +9,12 @@ set -euo pipefail
|
|||||||
|
|
||||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib.sh"
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib.sh"
|
||||||
|
|
||||||
RECONCILE="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/agent-sessions-monitor/scripts/reconcile.sh"
|
RECONCILE="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/tmux-agent-orchestrate-monitor/scripts/reconcile.sh"
|
||||||
|
|
||||||
JSON=0
|
JSON=0
|
||||||
[ "${1:-}" = "--json" ] && JSON=1
|
[ "${1:-}" = "--json" ] && JSON=1
|
||||||
|
|
||||||
[ -f "$AGENT_SESSIONS_YAML" ] || { echo "ERROR: $AGENT_SESSIONS_YAML not found. Run multi-agent-create first." >&2; exit 1; }
|
[ -f "$AGENT_SESSIONS_YAML" ] || { echo "ERROR: $AGENT_SESSIONS_YAML not found. Run tmux-agent-orchestrate-create first." >&2; exit 1; }
|
||||||
|
|
||||||
# read-only drift snapshot — reconcile.sh --dry-run (no side effects)
|
# read-only drift snapshot — reconcile.sh --dry-run (no side effects)
|
||||||
DRIFT_JSON="$(bash "$RECONCILE" --once --emit-diff --dry-run)"
|
DRIFT_JSON="$(bash "$RECONCILE" --once --emit-diff --dry-run)"
|
||||||
@@ -24,7 +24,7 @@ if [ "$JSON" = "1" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Project root (parent of skills/) holds the delegate-job .hermes registry.
|
# Project root (parent of skills/) holds the tmux-agent-orchestrate-delegate-job .hermes registry.
|
||||||
# Resolved relative to this script — no hardcoded absolute path (review item 6).
|
# Resolved relative to this script — no hardcoded absolute path (review item 6).
|
||||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
||||||
|
|
||||||
Reference in New Issue
Block a user