diff --git a/docker/agents/entrypoint.sh b/docker/agents/entrypoint.sh index 42119a6..ea0a85a 100644 --- a/docker/agents/entrypoint.sh +++ b/docker/agents/entrypoint.sh @@ -18,7 +18,7 @@ log() { # Build crontab from project TOMLs and install for the agent user. install_project_crons() { - local cron_lines="" + local cron_lines="DISINTO_CONTAINER=1" for toml in "${DISINTO_DIR}"/projects/*.toml; do [ -f "$toml" ] || continue local pname @@ -30,9 +30,9 @@ with open(sys.argv[1], 'rb') as f: cron_lines="${cron_lines} # disinto: ${pname} -2,7,12,17,22,27,32,37,42,47,52,57 * * * * ${DISINTO_DIR}/review/review-poll.sh ${toml} >/dev/null 2>&1 -4,9,14,19,24,29,34,39,44,49,54,59 * * * * ${DISINTO_DIR}/dev/dev-poll.sh ${toml} >/dev/null 2>&1 -0 0,6,12,18 * * * cd ${DISINTO_DIR} && bash gardener/gardener-run.sh ${toml} >/dev/null 2>&1" +2,7,12,17,22,27,32,37,42,47,52,57 * * * * ${DISINTO_DIR}/review/review-poll.sh ${toml} >>/home/agent/data/logs/cron.log 2>&1 +4,9,14,19,24,29,34,39,44,49,54,59 * * * * ${DISINTO_DIR}/dev/dev-poll.sh ${toml} >>/home/agent/data/logs/cron.log 2>&1 +0 0,6,12,18 * * * cd ${DISINTO_DIR} && bash gardener/gardener-run.sh ${toml} >>/home/agent/data/logs/cron.log 2>&1" done if [ -n "$cron_lines" ]; then diff --git a/gardener/gardener-run.sh b/gardener/gardener-run.sh index 6c964dc..31aa8c0 100755 --- a/gardener/gardener-run.sh +++ b/gardener/gardener-run.sh @@ -92,11 +92,8 @@ Supported actions: The commit-and-pr step converts JSONL to JSON array. The orchestrator executes actions after the PR merges. Do NOT call mutation APIs directly during the run." -# Reuse shared footer (API reference + environment), replace phase protocol -# shellcheck disable=SC2034 # consumed by build_prompt_footer -PHASE_FILE="" # not used in SDK mode -build_prompt_footer "$GARDENER_API_EXTRA" -PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}## Completion protocol (REQUIRED) +build_sdk_prompt_footer "$GARDENER_API_EXTRA" +PROMPT_FOOTER="${PROMPT_FOOTER}## Completion protocol (REQUIRED) When the commit-and-pr step creates a PR, write the PR number and stop: echo \"\$PR_NUMBER\" > '${GARDENER_PR_FILE}' Then STOP. Do NOT write PHASE: signals — the orchestrator handles CI, review, and merge. diff --git a/lib/formula-session.sh b/lib/formula-session.sh index 670da95..7f200c5 100644 --- a/lib/formula-session.sh +++ b/lib/formula-session.sh @@ -291,6 +291,33 @@ build_graph_section() { fi } +# ── SDK helpers ─────────────────────────────────────────────────────────── + +# build_sdk_prompt_footer [EXTRA_API_LINES] +# Like build_prompt_footer but omits the phase protocol section (SDK mode). +# Sets PROMPT_FOOTER. +build_sdk_prompt_footer() { + # shellcheck disable=SC2034 # consumed by build_prompt_footer + PHASE_FILE="" # not used in SDK mode + build_prompt_footer "${1:-}" + PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}" +} + +# formula_worktree_setup WORKTREE +# Creates an isolated worktree for synchronous formula execution. +# Fetches primary branch, cleans stale worktree, creates new one, and +# sets an EXIT trap for cleanup. +# Requires globals: PROJECT_REPO_ROOT, PRIMARY_BRANCH. +formula_worktree_setup() { + local worktree="$1" + cd "$PROJECT_REPO_ROOT" + git fetch origin "$PRIMARY_BRANCH" 2>/dev/null || true + worktree_cleanup "$worktree" + git worktree add "$worktree" "origin/${PRIMARY_BRANCH}" --detach 2>/dev/null + # shellcheck disable=SC2064 # expand worktree now, not at trap time + trap "worktree_cleanup '$worktree'" EXIT +} + # ── Prompt + monitor helpers ────────────────────────────────────────────── # build_prompt_footer [EXTRA_API_LINES] diff --git a/planner/planner-run.sh b/planner/planner-run.sh index 265e6bc..313f6ef 100755 --- a/planner/planner-run.sh +++ b/planner/planner-run.sh @@ -96,16 +96,11 @@ SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") # ── Build prompt ───────────────────────────────────────────────────────── -# Reuse shared footer (API reference + environment), replace phase protocol -# shellcheck disable=SC2034 # consumed by build_prompt_footer -PHASE_FILE="" # not used in SDK mode -build_prompt_footer " +build_sdk_prompt_footer " Relabel: curl -sf -H \"Authorization: token \${FORGE_TOKEN}\" -X PUT -H 'Content-Type: application/json' '${FORGE_API}/issues/{number}/labels' -d '{\"labels\":[LABEL_ID]}' Comment: curl -sf -H \"Authorization: token \${FORGE_TOKEN}\" -X POST -H 'Content-Type: application/json' '${FORGE_API}/issues/{number}/comments' -d '{\"body\":\"...\"}' Close: curl -sf -H \"Authorization: token \${FORGE_TOKEN}\" -X PATCH -H 'Content-Type: application/json' '${FORGE_API}/issues/{number}' -d '{\"state\":\"closed\"}' " -# Strip phase protocol — not used in SDK mode -PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}" PROMPT="You are the strategic planner for ${FORGE_REPO}. Work through the formula below. @@ -122,15 +117,7 @@ ${SCRATCH_INSTRUCTION} ${PROMPT_FOOTER}" # ── Create worktree ────────────────────────────────────────────────────── -cd "$PROJECT_REPO_ROOT" -git fetch origin "$PRIMARY_BRANCH" 2>/dev/null || true -worktree_cleanup "$WORKTREE" -git worktree add "$WORKTREE" "origin/${PRIMARY_BRANCH}" --detach 2>/dev/null - -cleanup() { - worktree_cleanup "$WORKTREE" -} -trap cleanup EXIT +formula_worktree_setup "$WORKTREE" # ── Run agent ───────────────────────────────────────────────────────────── export CLAUDE_MODEL="opus" diff --git a/predictor/predictor-run.sh b/predictor/predictor-run.sh index 6a48493..fb9bf51 100755 --- a/predictor/predictor-run.sh +++ b/predictor/predictor-run.sh @@ -65,12 +65,8 @@ SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") # ── Build prompt ───────────────────────────────────────────────────────── -# Reuse shared footer (API reference + environment), replace phase protocol -# shellcheck disable=SC2034 # consumed by build_prompt_footer -PHASE_FILE="" # not used in SDK mode -build_prompt_footer -# Strip phase protocol — not used in SDK mode -PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}" +build_sdk_prompt_footer +export CLAUDE_MODEL="sonnet" PROMPT="You are the prediction agent (goblin) for ${FORGE_REPO}. Work through the formula below. @@ -96,19 +92,9 @@ ${SCRATCH_INSTRUCTION} ${PROMPT_FOOTER}" # ── Create worktree ────────────────────────────────────────────────────── -cd "$PROJECT_REPO_ROOT" -git fetch origin "$PRIMARY_BRANCH" 2>/dev/null || true -worktree_cleanup "$WORKTREE" -git worktree add "$WORKTREE" "origin/${PRIMARY_BRANCH}" --detach 2>/dev/null - -cleanup() { - worktree_cleanup "$WORKTREE" -} -trap cleanup EXIT +formula_worktree_setup "$WORKTREE" # ── Run agent ───────────────────────────────────────────────────────────── -export CLAUDE_MODEL="sonnet" - agent_run --worktree "$WORKTREE" "$PROMPT" log "agent_run complete" diff --git a/supervisor/supervisor-run.sh b/supervisor/supervisor-run.sh index 5ffbbc9..129666f 100755 --- a/supervisor/supervisor-run.sh +++ b/supervisor/supervisor-run.sh @@ -76,12 +76,11 @@ SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") # ── Build prompt ───────────────────────────────────────────────────────── -# Reuse shared footer (API reference + environment), replace phase protocol -# shellcheck disable=SC2034 # consumed by build_prompt_footer -PHASE_FILE="" # not used in SDK mode -build_prompt_footer -# Strip phase protocol — not used in SDK mode -PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}" +build_sdk_prompt_footer +export CLAUDE_MODEL="sonnet" + +# ── Create worktree (before prompt assembly so trap is set early) ──────── +formula_worktree_setup "$WORKTREE" PROMPT="You are the supervisor agent for ${FORGE_REPO}. Work through the formula below. @@ -102,20 +101,7 @@ ${FORMULA_CONTENT} ${SCRATCH_INSTRUCTION} ${PROMPT_FOOTER}" -# ── Create worktree ────────────────────────────────────────────────────── -cd "$PROJECT_REPO_ROOT" -git fetch origin "$PRIMARY_BRANCH" 2>/dev/null || true -worktree_cleanup "$WORKTREE" -git worktree add "$WORKTREE" "origin/${PRIMARY_BRANCH}" --detach 2>/dev/null - -cleanup() { - worktree_cleanup "$WORKTREE" -} -trap cleanup EXIT - # ── Run agent ───────────────────────────────────────────────────────────── -export CLAUDE_MODEL="sonnet" - agent_run --worktree "$WORKTREE" "$PROMPT" log "agent_run complete"