---
name: multi-agent-mux-resume
description: "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."
version: 4.1.3
author: godopu
license: MIT
platforms: [linux, macos]
environments: [terminal, herdr]
metadata:
  hermes:
    tags: [agent, herdr, claude, antigravity, agy, multi-agent, context, resume, session-id]
    related_skills: [multi-agent-mux-create, multi-agent-mux-stop, multi-agent-mux-monitor, claude-code]
    prereq_skills: [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](../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** — Just attach. No re-spawn needed.

### 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`) — 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`), `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
WORKSPACE=/path/to/project
AGENT=claude  # claude | agy | hermes | grok | opencode — pass it explicitly
SESSION_NAME=<workspace>-creator-<agent>  # same convention as multi-agent-mux-create

# Resolve the isolated herdr server name & load common utils
source .agents/skills/lib.sh

# 1. Resolve the session id (pass session name to prefer target-row recorded id)
UUID=$(bash .agents/skills/multi-agent-mux-resume/scripts/resolve_session_id.sh \
  --workspace "$WORKSPACE" --agent "$AGENT" --session "$SESSION_NAME")

if [ -z "$UUID" ]; then
  # For Class A, resume_session.sh handles fresh-spawn fallback automatically.
  echo "No saved session for $WORKSPACE ($AGENT). Class B agents must use multi-agent-mux-create first."
  exit 1
fi

export HERDR_SESSION_NAME="$(resolve_herdr_session "$SESSION_NAME" "$WORKSPACE")"
export MAM_WS_LABEL="${HERDR_WORKSPACE_OPT:-$(resolve_herdr_workspace "$SESSION_NAME" "$WORKSPACE")}"

# 2. If herdr is alive, attach. Done.
if herdr has-session -t "$SESSION_NAME" 2>/dev/null; then
  echo "herdr '$SESSION_NAME' already running. Attaching..."
  exec herdr agent attach "$SESSION_NAME"
fi

# 3. Determine CMD_FULL
# For claude: if assigned UUID transcript .jsonl is unmaterialized on disk, use --session-id <uuid>; otherwise use -r <uuid>
case "$AGENT" in
  claude) CMD_FULL="claude --dangerously-skip-permissions $CLAUDE_ID_FLAG $UUID" ;;
  agy)    CMD_FULL="agy --dangerously-skip-permissions --conversation $UUID" ;;
  hermes) CMD_FULL="hermes --resume $UUID --no-restore-cwd --yolo --accept-hooks" ;;
  grok)   CMD_FULL="grok --resume $UUID --permission-mode bypassPermissions" ;;
esac

# 4. Spawn new herdr session + run agent with the saved id
case "$AGENT" in
  claude)
    START_CMD="herdr new-session -d -s \"$SESSION_NAME\" -x 140 -y 40 -c \"$WORKSPACE\" \"$CMD_FULL\""
    eval "$START_CMD"
    # auto-handle trust / bypass dialogs
    handle_startup_dialogs "$SESSION_NAME" 20
    ;;
  agy|hermes|grok)
    eval "herdr new-session -d -s \"$SESSION_NAME\" -x 140 -y 40 -c \"$WORKSPACE\" \"$CMD_FULL\""
    ;;
esac

# 4. Update agent-sessions.yaml: status running, last_visible_status
# (Also automatically publishes a `progress --detail "resumed"` event to the multi-agent-mux-delegate-job registry if a delegate_job_id exists)
bash .agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh \
  --session "$SESSION_NAME" --uuid "$UUID"

# 5. Attach (real native command — "attach" isn't in the lib.sh tmux-compat shim,
#    and real herdr has no `-t` flag here, only a positional target)
herdr agent attach "$SESSION_NAME"
```

## 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. The script above re-passes them.
- **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

```bash
# 1. herdr alive with the right cmd (real native command, no lib.sh needed)
herdr 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 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` here are tmux-compat pseudo-commands that only
> work after `source .agents/skills/lib.sh` (as done in `Workflow` above) — the real `herdr`
> binary doesn't have those subcommands. This block uses the real `herdr agent get`/`herdr agent read`
> equivalents instead so it also 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 agent attach <name>` (no skill needed)
