Compare commits

..

3 commits

Author SHA1 Message Date
Claude
01f62c4d3f fix: Migrate planner, predictor, supervisor to SDK (#6)
Some checks failed
ci/woodpecker/pr/ci Pipeline is pending
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/push/smoke-init Pipeline failed
Replace tmux-based run_formula_and_monitor() with synchronous agent_run()
from lib/agent-sdk.sh, matching the pattern established in gardener-run.sh.

Key changes per agent:
- Drop agent-session.sh, use agent-sdk.sh (SID_FILE, LOGFILE)
- Remove SESSION_NAME, PHASE_FILE, PHASE_POLL_INTERVAL (tmux/phase artifacts)
- Strip phase protocol from prompt footer (SDK mode needs no phase signals)
- Preserve all prompt composition: context blocks, memory, journal, preflight

Shared helpers added to lib/formula-session.sh:
- build_sdk_prompt_footer(): build_prompt_footer minus phase protocol
- formula_worktree_setup(): fetch + cleanup + create worktree + EXIT trap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 11:46:01 +00:00
johba
afeb50fc18 fix: cron env missing DISINTO_CONTAINER=1, logs go to ro mount
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/smoke-init Pipeline failed
Cron jobs run with minimal environment — no Docker compose env vars.
Without DISINTO_CONTAINER=1, env.sh falls back to FACTORY_ROOT for
log paths, which is the read-only disinto mount. Polls silently fail.

Fix: set DISINTO_CONTAINER=1 as crontab environment variable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 11:42:34 +00:00
johba
a054e0791d fix: cron entries log to cron.log instead of /dev/null
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/smoke-init Pipeline failed
Cron poll errors were silently swallowed, making it impossible to
diagnose why agents stopped picking up issues. Now logs to
/home/agent/data/logs/cron.log.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 11:37:50 +00:00
6 changed files with 43 additions and 60 deletions

View file

@ -18,7 +18,7 @@ log() {
# Build crontab from project TOMLs and install for the agent user. # Build crontab from project TOMLs and install for the agent user.
install_project_crons() { install_project_crons() {
local cron_lines="" local cron_lines="DISINTO_CONTAINER=1"
for toml in "${DISINTO_DIR}"/projects/*.toml; do for toml in "${DISINTO_DIR}"/projects/*.toml; do
[ -f "$toml" ] || continue [ -f "$toml" ] || continue
local pname local pname
@ -30,9 +30,9 @@ with open(sys.argv[1], 'rb') as f:
cron_lines="${cron_lines} cron_lines="${cron_lines}
# disinto: ${pname} # 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 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} >/dev/null 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} >/dev/null 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 done
if [ -n "$cron_lines" ]; then if [ -n "$cron_lines" ]; then

View file

@ -92,11 +92,8 @@ Supported actions:
The commit-and-pr step converts JSONL to JSON array. The orchestrator executes 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." actions after the PR merges. Do NOT call mutation APIs directly during the run."
# Reuse shared footer (API reference + environment), replace phase protocol build_sdk_prompt_footer "$GARDENER_API_EXTRA"
# shellcheck disable=SC2034 # consumed by build_prompt_footer PROMPT_FOOTER="${PROMPT_FOOTER}## Completion protocol (REQUIRED)
PHASE_FILE="" # not used in SDK mode
build_prompt_footer "$GARDENER_API_EXTRA"
PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}## Completion protocol (REQUIRED)
When the commit-and-pr step creates a PR, write the PR number and stop: When the commit-and-pr step creates a PR, write the PR number and stop:
echo \"\$PR_NUMBER\" > '${GARDENER_PR_FILE}' echo \"\$PR_NUMBER\" > '${GARDENER_PR_FILE}'
Then STOP. Do NOT write PHASE: signals — the orchestrator handles CI, review, and merge. Then STOP. Do NOT write PHASE: signals — the orchestrator handles CI, review, and merge.

View file

@ -291,6 +291,33 @@ build_graph_section() {
fi 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 ────────────────────────────────────────────── # ── Prompt + monitor helpers ──────────────────────────────────────────────
# build_prompt_footer [EXTRA_API_LINES] # build_prompt_footer [EXTRA_API_LINES]

View file

@ -96,16 +96,11 @@ SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE")
# ── Build prompt ───────────────────────────────────────────────────────── # ── Build prompt ─────────────────────────────────────────────────────────
# Reuse shared footer (API reference + environment), replace phase protocol build_sdk_prompt_footer "
# shellcheck disable=SC2034 # consumed by build_prompt_footer
PHASE_FILE="" # not used in SDK mode
build_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]}' 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\":\"...\"}' 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\"}' 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. PROMPT="You are the strategic planner for ${FORGE_REPO}. Work through the formula below.
@ -122,15 +117,7 @@ ${SCRATCH_INSTRUCTION}
${PROMPT_FOOTER}" ${PROMPT_FOOTER}"
# ── Create worktree ────────────────────────────────────────────────────── # ── Create worktree ──────────────────────────────────────────────────────
cd "$PROJECT_REPO_ROOT" formula_worktree_setup "$WORKTREE"
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 ───────────────────────────────────────────────────────────── # ── Run agent ─────────────────────────────────────────────────────────────
export CLAUDE_MODEL="opus" export CLAUDE_MODEL="opus"

View file

@ -65,12 +65,8 @@ SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE")
# ── Build prompt ───────────────────────────────────────────────────────── # ── Build prompt ─────────────────────────────────────────────────────────
# Reuse shared footer (API reference + environment), replace phase protocol build_sdk_prompt_footer
# shellcheck disable=SC2034 # consumed by build_prompt_footer export CLAUDE_MODEL="sonnet"
PHASE_FILE="" # not used in SDK mode
build_prompt_footer
# Strip phase protocol — not used in SDK mode
PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}"
PROMPT="You are the prediction agent (goblin) for ${FORGE_REPO}. Work through the formula below. PROMPT="You are the prediction agent (goblin) for ${FORGE_REPO}. Work through the formula below.
@ -96,19 +92,9 @@ ${SCRATCH_INSTRUCTION}
${PROMPT_FOOTER}" ${PROMPT_FOOTER}"
# ── Create worktree ────────────────────────────────────────────────────── # ── Create worktree ──────────────────────────────────────────────────────
cd "$PROJECT_REPO_ROOT" formula_worktree_setup "$WORKTREE"
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 ───────────────────────────────────────────────────────────── # ── Run agent ─────────────────────────────────────────────────────────────
export CLAUDE_MODEL="sonnet"
agent_run --worktree "$WORKTREE" "$PROMPT" agent_run --worktree "$WORKTREE" "$PROMPT"
log "agent_run complete" log "agent_run complete"

View file

@ -76,12 +76,11 @@ SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE")
# ── Build prompt ───────────────────────────────────────────────────────── # ── Build prompt ─────────────────────────────────────────────────────────
# Reuse shared footer (API reference + environment), replace phase protocol build_sdk_prompt_footer
# shellcheck disable=SC2034 # consumed by build_prompt_footer export CLAUDE_MODEL="sonnet"
PHASE_FILE="" # not used in SDK mode
build_prompt_footer # ── Create worktree (before prompt assembly so trap is set early) ────────
# Strip phase protocol — not used in SDK mode formula_worktree_setup "$WORKTREE"
PROMPT_FOOTER="${PROMPT_FOOTER%%## Phase protocol*}"
PROMPT="You are the supervisor agent for ${FORGE_REPO}. Work through the formula below. PROMPT="You are the supervisor agent for ${FORGE_REPO}. Work through the formula below.
@ -102,20 +101,7 @@ ${FORMULA_CONTENT}
${SCRATCH_INSTRUCTION} ${SCRATCH_INSTRUCTION}
${PROMPT_FOOTER}" ${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 ───────────────────────────────────────────────────────────── # ── Run agent ─────────────────────────────────────────────────────────────
export CLAUDE_MODEL="sonnet"
agent_run --worktree "$WORKTREE" "$PROMPT" agent_run --worktree "$WORKTREE" "$PROMPT"
log "agent_run complete" log "agent_run complete"