#!/bin/sh # Claude Code Stop hook — fires on every turn boundary, not just completion. # Convention: the agent signals "this task is done" by writing a report file # named .orchestra-report.md at the worktree root before stopping. If that # marker is present, report completion. If it is absent, this is an ordinary # turn boundary — ask the unified turn-decision endpoint (AUDIT.md B3, Phase # 2 items 1-2) what to do instead of no-op'ing. # # Requires: ORCHESTRA_TASK_ID and ORCHESTRA_URL set in the pane's env. # Optional: ORCHESTRA_HARNESS_TOKEN if the server requires one. # # Reads the Stop hook's JSON payload from stdin (has "transcript_path" and # "cwd"); needs jq. set -eu payload="$(cat)" transcript_path="$(printf '%s' "$payload" | jq -r '.transcript_path // empty')" cwd="$(printf '%s' "$payload" | jq -r '.cwd // empty')" [ -z "$transcript_path" ] && exit 0 [ -z "${ORCHESTRA_TASK_ID:-}" ] && exit 0 [ -z "${ORCHESTRA_URL:-}" ] && exit 0 auth_header="" if [ -n "${ORCHESTRA_HARNESS_TOKEN:-}" ]; then auth_header="Authorization: Bearer ${ORCHESTRA_HARNESS_TOKEN}" fi report_file="${cwd:-.}/.orchestra-report.md" if [ -f "$report_file" ]; then report="$(cat "$report_file")" body="$(jq -n \ --arg task_id "$ORCHESTRA_TASK_ID" \ --arg transcript_path "$transcript_path" \ --arg report "$report" \ '{task_id: $task_id, harness: "claude", transcript_path: $transcript_path, report: $report}')" if curl -fsS -X POST "${ORCHESTRA_URL%/}/v1/harness/complete" \ -H "Content-Type: application/json" \ ${auth_header:+-H "$auth_header"} \ -d "$body" >/dev/null 2>&1; then rm -f "$report_file" else echo "orchestra-stop: failed to report completion" >&2 exit 2 fi exit 0 fi body="$(jq -n --arg task_id "$ORCHESTRA_TASK_ID" '{task_id: $task_id}')" response="$(curl -fsS -X POST "${ORCHESTRA_URL%/}/v1/harness/turn" \ -H "Content-Type: application/json" \ ${auth_header:+-H "$auth_header"} \ -d "$body" 2>/dev/null)" || { echo "orchestra-stop: failed to reach turn-decision endpoint" >&2 exit 0 } decision="$(printf '%s' "$response" | jq -r '.decision // empty')" if [ "$decision" = "refuse" ]; then echo "orchestra-stop: turn decision is refuse — this turn boundary is not safe to stop at" >&2 exit 2 fi exit 0