mcptools: add bootstrap_session.sh for session handoff

Assembles a bootstrap prompt from a bead: full bead JSON fields,
comments, recent git log (from mount cwd), and any denote documents
referenced in description/notes/comments.

Crash-resilient: state lives in beads + git, no agent snapshot needed.
Documents handoff pattern in anvillm-sessions SKILL.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-14 15:10:58 +01:00
parent d76ccf4979
commit 669f9255a2
2 changed files with 133 additions and 0 deletions

115
mcptools/bootstrap_session.sh Executable file
View File

@ -0,0 +1,115 @@
#!/bin/bash
# capabilities: beads, agents
# description: Build a bootstrap prompt for session continuity from a bead
# Usage: bootstrap_session.sh --mount <mount> --id <bead-id> [--git-lines <n>]
set -euo pipefail
if cat /etc/shadow >/dev/null 2>&1; then
echo "Error: This script must be run via execute_code tool" >&2
exit 1
fi
MOUNT=""
BEAD_ID=""
GIT_LINES=30
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--git-lines) GIT_LINES="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: bootstrap_session.sh --mount <mount> --id <bead-id> [--git-lines <n>]" >&2
exit 1
fi
# Get bead JSON
BEAD_JSON=$(9p read "anvillm/beads/$MOUNT/$BEAD_ID/json" 2>/dev/null) || {
echo "error: bead $BEAD_ID not found in mount $MOUNT" >&2
exit 1
}
# Extract fields
TITLE=$(echo "$BEAD_JSON" | jq -r '.title // ""')
STATUS=$(echo "$BEAD_JSON" | jq -r '.status // ""')
DESCRIPTION=$(echo "$BEAD_JSON" | jq -r '.description // ""')
ACCEPTANCE=$(echo "$BEAD_JSON" | jq -r '.acceptance_criteria // ""')
NOTES=$(echo "$BEAD_JSON" | jq -r '.notes // ""')
ASSIGNEE=$(echo "$BEAD_JSON" | jq -r '.assignee // ""')
COMMENT_COUNT=$(echo "$BEAD_JSON" | jq -r '.comment_count // 0')
PARENT_ID=$(echo "$BEAD_JSON" | jq -r '.parent_id // ""')
# Get comments if any
COMMENTS=""
if [ "$COMMENT_COUNT" -gt 0 ]; then
COMMENTS=$(9p read "anvillm/beads/$MOUNT/$BEAD_ID/comments" 2>/dev/null \
| jq -r '.[] | "[\(.created_at | split("T")[0])] \(.author // "agent"): \(.text)"' 2>/dev/null || true)
fi
# Get mount cwd from mtab
CWD=$(9p read anvillm/beads/mtab 2>/dev/null | awk -v m="$MOUNT" -F'\t' '$1 == m {print $2}')
# Get git log if we have a cwd
GIT_LOG=""
if [ -n "$CWD" ] && [ -d "$CWD/.git" ]; then
GIT_LOG=$(git -C "$CWD" log --oneline -n "$GIT_LINES" 2>/dev/null || true)
fi
# Collect denote references from description, notes, and comments
ALL_TEXT="$DESCRIPTION $NOTES $COMMENTS"
DENOTE_IDS=$(echo "$ALL_TEXT" | grep -oE 'denote:[0-9]{8}T[0-9]{6}' | sed 's/denote://' | sort -u || true)
# Output bootstrap prompt
cat <<BOOTSTRAP
## Bootstrap Context — $BEAD_ID
### Task
**Title:** $TITLE
**Status:** $STATUS
**Mount:** $MOUNT${ASSIGNEE:+
**Assignee:** $ASSIGNEE}${PARENT_ID:+
**Parent:** $PARENT_ID}
${CWD:+**Project:** $CWD}
### Description
${DESCRIPTION:-"(none)"}
${ACCEPTANCE:+### Acceptance Criteria
$ACCEPTANCE
}${NOTES:+### Notes
$NOTES
}BOOTSTRAP
if [ -n "$COMMENTS" ]; then
echo "### Comments"
echo "$COMMENTS"
echo ""
fi
if [ -n "$GIT_LOG" ]; then
echo "### Recent Git History"
echo "$GIT_LOG"
echo ""
fi
# Include referenced denote documents
if [ -n "$DENOTE_IDS" ]; then
echo "### Referenced Documents"
while IFS= read -r did; do
[ -z "$did" ] && continue
FILE=$(find "$HOME/doc" -type f -name "${did}--*" 2>/dev/null | head -1)
if [ -n "$FILE" ]; then
echo ""
echo "#### denote:$did ($(basename "$FILE"))"
echo '```'
cat "$FILE"
echo '```'
fi
done <<< "$DENOTE_IDS"
fi

View File

@ -46,6 +46,14 @@ tool: kill_agent.sh
args: ["--agent-id", "<agent-id>"]
```
Bootstrap session (build context prompt from a bead for handoff):
```
Tool: execute_code
tool: bootstrap_session.sh
args: ["--mount", "<mount>", "--id", "<bead-id>"]
```
Optional: `"--git-lines", "<n>"` (default 30). Output includes bead details, comments, recent git log, and any referenced denote documents. Feed the output as the initial prompt when spawning a replacement agent.
## Backends
- `kiro-cli` - Kiro CLI agent
@ -74,6 +82,16 @@ args: ["--agent-id", "<agent-id>"]
- Need to stop/restart/kill an agent
- Coordinating multi-agent workflows
## Session Handoff Pattern
Agent A finishes or is killed. Agent B picks up where A left off:
1. Agent B (or supervisor) calls `bootstrap_session.sh --mount <mount> --id <bead-id>`
2. Feed the output as B's initial prompt (via `--prompt` in `spawn_agent.sh`, or as the first message in `context`)
3. B reads the bead, claims it, and resumes work
Bootstrap is crash-resilient: state lives in beads + git, not in the agent's memory. No agent-written snapshot required.
## When NOT to Use
- Sending messages to agents (use anvillm-communication skill)