Files
multi-agent-mux/.agents/skills/multi-agent-mux-resume/SKILL.md
T
GodopuandClaude Opus 5.5 17eba0904e docs(issue-42): review - attach names the herdr server, --dry-run is not "write nothing", a deleted block stays deleted
Merge-workspace review of PR #46 (codex R1-R3 and C1, claude O1 and O4).

- R1: resume never attaches, and the server it exports does not reach the
  calling shell; the native herdr binary does not route on environment
  variables. The attach advice and the Verification block now name the
  server: `herdr --session <server> agent attach <name>`, with <server> the
  row's herdr_session.
- R2: --dry-run in resume and create skips the spawn and the registry
  update, but the checks before it still run and on macOS remove the
  quarantine attribute from the agent binary. The option rows say so.
- R3: test_no_deleted_body_came_back compares every current block with the
  deleted bodies by exact sha and by a whitespace-insensitive fingerprint
  (stored as base_fingerprint), independently of the inventory, so a
  deleted block cannot return by being listed again under class c.
  Replaying the review's probe (the deleted resume Workflow re-added and
  inventoried as c) fails the new test and passes the old one.
- C1 / O1: the base create call block at 263-266 (class c) folded into the
  Workflow call is recorded under "superseded"; the 37 base blocks are all
  accounted for.
- O4: create exit 42 also covers MAM_KILL_ON_READY_TIMEOUT=1; stop's no-op
  exit 0 does not apply with --purge-conversation.
- The inventory's positions and shas are regenerated for the edited blocks;
  every classification is unchanged.

No product code changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
2026-10-04 08:06:32 +09:00

11 KiB

name, description, version, author, license, platforms, environments, metadata
name description version author license platforms environments metadata
multi-agent-mux-resume Resume an existing agent (claude, antigravity/agy) conversation by UUID into a herdr session. Reads .mam/agent-sessions.yaml for the saved session/conversation id, spawns (or reuses) a herdr session of the matching name, and runs `claude -r <id>` or `agy --conversation <id>` inside. Use when you want to reattach to a previous session's context, or revive a session whose herdr died but the agent's conversation is still on disk. 4.8.2 godopu MIT
linux
macos
terminal
herdr
hermes
tags related_skills prereq_skills
agent
herdr
claude
antigravity
agy
multi-agent
context
resume
session-id
multi-agent-mux-create
multi-agent-mux-stop
multi-agent-mux-monitor
claude-code
multi-agent-mux-create

Multi-Agent Resume — Reattach to a Saved Conversation

Companion skills: multi-agent-mux-create (start a fresh agent), multi-agent-mux-stop (terminate), multi-agent-mux-monitor (live status). Herdr Isolation: HERDR_SESSION_NAME env var를 create에서 설정한 경우, 동일 서버에서 동작합니다. 자세한 격리 패턴은 multi-agent-mux-create/SKILL.md 참조. Single source of truth: ./.mam/agent-sessions.yaml.

What this skill does

Container + data reconstruction: spawn a herdr session (the container), then run the agent inside with a specific session id (the data) so the previous conversation's context is restored.

Three cases this skill handles:

  1. herdr is dead, conversation lives — agent-sessions.yaml has the UUID. The JSONL/db is on disk. Re-spawn the herdr session + run claude -r <id> / agy --conversation <id>.
  2. herdr is alive but empty — You started a session with multi-agent-mux-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 $HOME_DIR/.gemini/antigravity-cli/cache/last_conversations.json (defaults to ~/.gemini/...) for agy, or the latest *.jsonl in $CLAUDE_PROJECT_DIR/<workspace-key>/ (defaults to ~/.claude/projects/) for claude.
  3. herdr is alive AND the agent inside is already running — resume_session.sh only updates the row and exits 0. It does not attach and does not check the agent's permission flags (#45); attach with herdr --session <server> agent attach <name>, where <server> is the row's herdr_session (the server it was resumed on).

Resuming a stopped session (stopped → running)

When a session was ended via multi-agent-mux-stop (which captures the ID and gracefully stops by default), its row is status: stopped with resumable: true and the conversation id already recorded in claude_session_id_own / agy_conversation_id_own. This is the ideal resume path:

  • tier-1, race-free: because the stop command wrote the id into the row at stop time, resolve_session_id.sh resolves it via find_workspace_uuid tier-1 (the per-row own id) — no reliance on the mtime-based disk scan, so a concurrent session in another workspace can never shadow it.
  • On resume, update_yaml_resumed.sh transitions stopped → running and clears the stop metadata (stopped_at, stopped_at_epoch, stop_reason, resumable) along with the usual terminated_at* / termination_mode / archived_at, so the row reflects a clean running state with no stale end-of-session fields.

UUID resolution order

agent-sessions.yaml and on-disk discovery are used to resolve the UUID in this order:

  1. herdr_sessions[] row's per-row own id (claude_session_id_own / agy_conversation_id_own / hermes_conversation_id_own / grok_session_id_own / opencode_session_id_own / codex_session_id_own) — explicitly saved by multi-agent-mux-stop right before teardown (tier-1, race-free).
  2. Workspace-scoped on-disk scan (adapter discover())

If both are empty → for Class A agents (agy, hermes, opencode, codex), resume_session.sh automatically falls back to FRESH_SPAWN=1 (spawn-spec). For Class B agents (claude, grok), fall back to multi-agent-mux-create.

Workflow

bash .agents/skills/multi-agent-mux-resume/scripts/resume_session.sh --workspace <path> --agent <agent> --session <name>

resume_session.sh does the whole flow: original-cwd check, control-plane binding, session-id resolution (resolve_session_id.sh), the herdr-alive check, the agent command (adapter resume-spec, or spawn-spec for a Class A fresh spawn), spawn, start-up dialogs, and the YAML update (update_yaml_resumed.sh, which also publishes a progress "resumed" event when the row has a delegate_job_id). It never attaches; attaching is a separate step that names the server, because the server the script exports does not reach the calling shell and the native herdr binary does not route on environment variables: herdr --session <server> agent attach <name> (<server> = the --herdr-session you passed, or the row's herdr_session).

Option Meaning
--workspace Required. The directory the session ran in (its row's pane.cwd; a different path is exit 2)
--agent Required. claude, agy, hermes, grok, opencode, codex
--session Required. Session name
--herdr-session (--herdr-server) Isolated herdr server name
--herdr-workspace herdr workspace label
--auto-trust / --no-auto-trust Answer a start-up directory-trust dialog or leave it to a human (MAM_AUTO_TRUST; default: answer)
--dry-run Resolve the command and print it; no spawn and no registry (YAML/DB) update. The checks before it still run, and on macOS they remove the quarantine attribute from the agent binary
Exit Meaning
0 Resumed; or already running, so only the row was updated (no attach); or --dry-run
1 From the checks before spawn, nothing was changed: no saved session for claude/grok (use multi-agent-mux-create first), agent binary missing or not executable. The YAML update after spawn (update_yaml_resumed.sh) also exits 1 (YAML not found)
2 From the checks before spawn, nothing was changed: bad arguments, --workspace differs from the original cwd or it no longer exists, control-plane binding refused, whitespace in the control-plane path. The YAML update after spawn also exits 2 (bad arguments)
other A later step failed (herdr spawn, start-up dialogs, YAML update) and its code is passed through. resume does not roll back

A non-zero exit after the spawn can leave the herdr session running while the row is still stopped. Before retrying or creating a new session, check with multi-agent-mux-status. The ERROR: line on stderr tells the two apart: the pre-spawn checks' messages are in resume_session.sh (lines 50-223).

Original cwd only (Issue #21 phase 2)

A session is resumed only in the directory it ran in (its row's pane.cwd): the conversation is keyed by that directory, and a class A agent (agy/hermes/opencode/codex) would otherwise start a new conversation in the wrong tree.

  • --workspace differing from pane.cwd → exit 2 with the path to use (claude/grok used to fail with exit 1 "No saved session").
  • pane.cwd no longer exists (worktree removed) → exit 2; recreate the worktree at that path to resume.
  • Rows without pane.cwd are not checked. The check runs before session-id resolution and also under --dry-run.
  • The control-plane binding is computed before the herdr-alive check, so an already-running session's row gets it too; a binding that cannot be computed is refused (exit 2) for a worktree and warned about for the control root.

Pitfalls

  • 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.
  • 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. resume_session.sh re-passes them through the adapter resume-spec.
  • Don't resume if the session is brand new and empty — multi-agent-mux-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-mux-create.

Verification

# The server the session runs on (its row's herdr_session); the native herdr
# binary needs it as --session, an exported variable is not enough.
SERVER=$(python3 -c "import yaml; d = yaml.safe_load(open('.mam/agent-sessions.yaml')); print([s for s in d['herdr_sessions'] if s['name'] == '$SESSION_NAME'][0].get('herdr_session') or 'default')")

# 1. herdr alive with the right cmd (real native command, no lib.sh needed)
herdr --session "$SERVER" agent get "$SESSION_NAME" | python3 -c "
import sys, json
a = json.load(sys.stdin)['result']['agent']
print(f\"cmd={a['agent']} cwd={a['cwd']}\")
"

# 2. agent-sessions.yaml updated
python3 -c "
import yaml
d = yaml.safe_load(open('.mam/agent-sessions.yaml'))
s = [s for s in d['herdr_sessions'] if s['name'] == '$SESSION_NAME'][0]
print(f'  status: {s[\"status\"]}')
print(f'  pane.cmd_full: {s[\"pane\"][\"cmd_full\"]}')
"

# 3. TUI shows resumed conversation (real native command, no lib.sh needed)
sleep 5
herdr --session "$SERVER" agent read "$SESSION_NAME" --source visible --lines 30
# look for the previous message at top of the buffer (claude) or last_visible_status set (agy)

herdr list-panes / herdr capture-pane are tmux-compat pseudo-commands that only work after source .agents/skills/lib.sh — the real herdr binary doesn't have those subcommands. This block uses only the real herdr agent get/herdr agent read commands, so it works standalone.

When NOT to use this skill

  • No saved session yet → multi-agent-mux-create
  • Killing an existing session → multi-agent-mux-stop
  • Just attaching → herdr --session <server> agent attach <name> (no skill needed; <server> = the row's herdr_session)