diff --git a/hooks/opencode/coordinator.sh b/hooks/opencode/coordinator.sh new file mode 100644 index 000000000..c4b580a6d --- /dev/null +++ b/hooks/opencode/coordinator.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# AutoShip Coordinator — entry point that runs the coordinator agent skill +# The coordinator agent handles scanning, dispatching, and monitoring. +# +# Usage: +# bash hooks/opencode/coordinator.sh [--once] +# +# Options: +# --once Process queued workspaces then exit (no re-scan loop) + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +AUTOSHIP_DIR="${AUTOSHIP_DIR:-.autoship}" +REPO_ROOT="${AUTOSHIP_REPO_ROOT:-$(cd "$SCRIPT_DIR/../../.." && pwd)}" +LOG_FILE="$REPO_ROOT/$AUTOSHIP_DIR/coordinator.log" +SKILL_FILE="$SCRIPT_DIR/../../skills/autoship-coordinator/SKILL.md" +COORDINATOR_MODEL="${AUTOSHIP_COORDINATOR_MODEL:-kimi-for-coding/k2p6}" + +ONCE=false +[[ "${1:-}" == "--once" ]] && ONCE=true + +log() { echo "$(date -u '+%Y-%m-%dT%H:%M:%SZ') $1" | tee -a "$LOG_FILE"; } + +log "Coordinator starting (model=$COORDINATOR_MODEL)" +cd "$REPO_ROOT" +opencode run --model "$COORDINATOR_MODEL" "$SKILL_FILE" 2>&1 | tee -a "$LOG_FILE" + +coordinator_exit=$? +log "Coordinator exited with code $coordinator_exit" + +[[ "$ONCE" == "false" ]] && { log "Re-scanning..."; exec bash "$0" --once; } +exit $coordinator_exit diff --git a/skills/autoship-coordinator/SKILL.md b/skills/autoship-coordinator/SKILL.md new file mode 100644 index 000000000..4683f443b --- /dev/null +++ b/skills/autoship-coordinator/SKILL.md @@ -0,0 +1,55 @@ +# AutoShip Coordinator + +You are the AutoShip Coordinator for this repository. You manage queued AutoShip issues by spawning implementer subagents. + +## Mission + +Process all workspaces in `.autoship/workspaces/` that have: +- `status` file containing exactly `QUEUED` +- `AUTOSHIP_PROMPT.md` file present + +## Workflow + +1. **Scan** — List all workspace directories, read their `status` and check for `AUTOSHIP_PROMPT.md` +2. **Filter** — Only process workspaces where status == "QUEUED" AND AUTOSHIP_PROMPT.md exists +3. **Dispatch** — For each qualifying workspace (up to concurrency limit): + a. Read `AUTOSHIP_PROMPT.md` for the task prompt + b. Read `model` file for target model (default: kimi-for-coding/k2p6) + c. Write "RUNNING" to `/status` + d. Write current UTC timestamp to `/started_at` + e. Call `task(subagent_type="general", prompt=)` + f. On task return, write the task_id to `/task_id` + g. Read final `/status` — expect COMPLETE, BLOCKED, or STUCK +4. **Report** — When all done, output a summary table: workspace, model, final_status + +## Concurrency + +Read `.autoship/config.json` for `max_workers` or `max_concurrent` field. Default: 5. +Spawn multiple subagents concurrently when possible by making multiple `task()` calls. + +## Status Tracking + +- RUNNING: subagent is active +- COMPLETE: task finished successfully +- BLOCKED: subagent reported it cannot proceed +- STUCK: subagent timed out or crashed +- QUEUED: ready for pickup (do not re-process RUNNING ones) + +## Error Handling + +If a workspace has no AUTOSHIP_PROMPT.md, log it and skip. +If a workspace status file is missing or unreadable, log it and skip. +If task() throws an error, write "STUCK" to status and continue. + +## Final Output Format + +``` +AutoShip Coordinator Summary +============================ +Processed: N workspaces +- issue-XXXX: COMPLETE (model: kimi-for-coding/k2p6) +- issue-YYYY: BLOCKED (model: kimi-for-coding/k2p6) +- issue-ZZZZ: STUCK (model: kimi-for-coding/k2p6) +``` + +Do not modify source code yourself — your only job is to scan, dispatch, and report.