feat: r0 coordinator tooling for orchestrator protocol

Implements the manual coordinator workflow for multi-session agent
orchestration. Agents stop after one milestone (confirmed limitation);
these tools let the human coordinator check status, generate continuation
prompts, and chain sessions together.

New:
- tools/orchestrator/ — 5 scripts + shared library (_lib.sh)
  - mission-init.sh: initialize mission with milestones and state files
  - mission-status.sh: dashboard showing milestones, tasks, sessions
  - session-status.sh: check if agent is running/stale/dead
  - continue-prompt.sh: generate paste-ready continuation prompt
  - session-resume.sh: crash recovery with dirty state detection
- guides/ORCHESTRATOR-PROTOCOL.md: agent-facing mission lifecycle guide
- templates/docs/: mission manifest, scratchpad, continuation templates
- templates/repo/.mosaic/orchestrator/mission.json: state file template

Modified:
- bin/mosaic: add 'coord' subcommand + resume advisory on launch
- AGENTS.md: conditional loading for protocol guide + rule 37
- bin/mosaic-doctor: checks for new coordinator files
- session hooks: mission detection on start, cleanup on end

Usage: mosaic coord init|mission|status|continue|resume

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-22 17:22:50 -06:00
parent a8e580e1a3
commit 5ba531e2d0
16 changed files with 1944 additions and 0 deletions

View File

@@ -0,0 +1,153 @@
#!/usr/bin/env bash
set -euo pipefail
#
# continue-prompt.sh — Generate continuation prompt for next orchestrator session
#
# Usage:
# continue-prompt.sh [--project <path>] [--milestone <id>] [--copy]
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_lib.sh"
# ─── Parse arguments ─────────────────────────────────────────────────────────
PROJECT="."
MILESTONE=""
COPY=false
while [[ $# -gt 0 ]]; do
case "$1" in
--project) PROJECT="$2"; shift 2 ;;
--milestone) MILESTONE="$2"; shift 2 ;;
--copy) COPY=true; shift ;;
-h|--help)
echo "Usage: continue-prompt.sh [--project <path>] [--milestone <id>] [--copy]"
exit 0
;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
_require_jq
require_mission "$PROJECT"
# ─── Load mission data ──────────────────────────────────────────────────────
mission="$(load_mission "$PROJECT")"
mission_name="$(echo "$mission" | jq -r '.name')"
mission_id="$(echo "$mission" | jq -r '.mission_id')"
quality_gates="$(echo "$mission" | jq -r '.quality_gates // "—"')"
project_path="$(echo "$mission" | jq -r '.project_path')"
# Determine current milestone
if [[ -n "$MILESTONE" ]]; then
current_ms_id="$MILESTONE"
else
current_ms_id="$(current_milestone_id "$PROJECT")"
fi
current_ms_name=""
if [[ -n "$current_ms_id" ]]; then
current_ms_name="$(milestone_name "$PROJECT" "$current_ms_id")"
fi
# Task counts
task_counts="$(count_tasks_md "$PROJECT")"
tasks_total="$(echo "$task_counts" | jq '.total')"
tasks_done="$(echo "$task_counts" | jq '.done')"
pct=0
(( tasks_total > 0 )) && pct=$(( (tasks_done * 100) / tasks_total ))
# Next task
next_task="$(find_next_task "$PROJECT")"
# Current branch
current_branch=""
if git -C "$PROJECT" rev-parse --is-inside-work-tree &>/dev/null; then
current_branch="$(git -C "$PROJECT" branch --show-current 2>/dev/null || echo "—")"
fi
# Previous session info
session_count="$(echo "$mission" | jq '.sessions | length')"
prev_session_id="—"
prev_runtime="—"
prev_duration="—"
prev_ended_reason="—"
prev_last_task="—"
if (( session_count > 0 )); then
last_idx=$(( session_count - 1 ))
prev_session_id="$(echo "$mission" | jq -r ".sessions[$last_idx].session_id // \"—\"")"
prev_runtime="$(echo "$mission" | jq -r ".sessions[$last_idx].runtime // \"—\"")"
prev_ended_reason="$(echo "$mission" | jq -r ".sessions[$last_idx].ended_reason // \"—\"")"
prev_last_task="$(echo "$mission" | jq -r ".sessions[$last_idx].last_task_id // \"—\"")"
s_start="$(echo "$mission" | jq -r ".sessions[$last_idx].started_at // \"\"")"
s_end="$(echo "$mission" | jq -r ".sessions[$last_idx].ended_at // \"\"")"
if [[ -n "$s_start" && -n "$s_end" && "$s_end" != "" ]]; then
s_epoch="$(iso_to_epoch "$s_start")"
e_epoch="$(iso_to_epoch "$s_end")"
if (( e_epoch > 0 && s_epoch > 0 )); then
prev_duration="$(format_duration $(( e_epoch - s_epoch )))"
fi
fi
fi
# ─── Generate prompt ────────────────────────────────────────────────────────
prompt="$(cat <<EOF
## Continuation Mission
Continue **$mission_name** from existing state.
## Setup
- **Project:** $project_path
- **State:** docs/TASKS.md (already populated — ${tasks_done}/${tasks_total} tasks complete)
- **Manifest:** docs/MISSION-MANIFEST.md
- **Scratchpad:** docs/scratchpads/${mission_id}.md
- **Protocol:** ~/.config/mosaic/guides/ORCHESTRATOR.md
- **Quality gates:** $quality_gates
## Resume Point
- **Current milestone:** ${current_ms_name:-—} (${current_ms_id:-—})
- **Next task:** ${next_task:-—}
- **Progress:** ${tasks_done}/${tasks_total} tasks (${pct}%)
- **Branch:** ${current_branch:-—}
## Previous Session Context
- **Session:** $prev_session_id ($prev_runtime, $prev_duration)
- **Ended:** $prev_ended_reason
- **Last completed task:** $prev_last_task
## Instructions
1. Read \`~/.config/mosaic/guides/ORCHESTRATOR.md\` for full protocol
2. Read \`docs/MISSION-MANIFEST.md\` for mission scope and status
3. Read \`docs/scratchpads/${mission_id}.md\` for session history and decisions
4. Read \`docs/TASKS.md\` for current task state
5. \`git pull --rebase\` to sync latest changes
6. Continue execution from task **${next_task:-next-pending}**
7. Follow Two-Phase Completion Protocol
8. You are the SOLE writer of \`docs/TASKS.md\`
EOF
)"
# ─── Output ──────────────────────────────────────────────────────────────────
if [[ "$COPY" == true ]]; then
if command -v wl-copy &>/dev/null; then
echo "$prompt" | wl-copy
echo -e "${C_GREEN}Continuation prompt copied to clipboard (wl-copy)${C_RESET}" >&2
elif command -v xclip &>/dev/null; then
echo "$prompt" | xclip -selection clipboard
echo -e "${C_GREEN}Continuation prompt copied to clipboard (xclip)${C_RESET}" >&2
else
echo -e "${C_YELLOW}No clipboard tool found (wl-copy or xclip). Printing to stdout.${C_RESET}" >&2
echo "$prompt"
fi
else
echo "$prompt"
fi