2026-03-20 17:29:49 +00:00
#!/usr/bin/env bash
# =============================================================================
# predictor-run.sh — Cron wrapper: predictor execution via Claude + formula
#
# Runs daily (or on-demand). Guards against concurrent runs and low memory.
# Creates a tmux session with Claude (sonnet) reading formulas/run-predictor.toml.
# Files prediction/unreviewed issues for the planner to triage.
#
# Usage:
# predictor-run.sh [projects/disinto.toml] # project config (default: disinto)
#
# Cron: 0 6 * * * cd /path/to/dark-factory && bash predictor/predictor-run.sh
# =============================================================================
set -euo pipefail
SCRIPT_DIR = " $( cd " $( dirname " $0 " ) " && pwd ) "
FACTORY_ROOT = " $( dirname " $SCRIPT_DIR " ) "
# Accept project config from argument; default to disinto
export PROJECT_TOML = " ${ 1 :- $FACTORY_ROOT /projects/disinto.toml } "
# shellcheck source=../lib/env.sh
source " $FACTORY_ROOT /lib/env.sh "
# shellcheck source=../lib/agent-session.sh
source " $FACTORY_ROOT /lib/agent-session.sh "
# shellcheck source=../lib/formula-session.sh
source " $FACTORY_ROOT /lib/formula-session.sh "
LOG_FILE = " $SCRIPT_DIR /predictor.log "
2026-03-20 17:41:52 +00:00
# shellcheck disable=SC2034 # consumed by run_formula_and_monitor
2026-03-20 17:29:49 +00:00
SESSION_NAME = " predictor- ${ PROJECT_NAME } "
PHASE_FILE = " /tmp/predictor-session- ${ PROJECT_NAME } .phase "
# shellcheck disable=SC2034 # read by monitor_phase_loop in lib/agent-session.sh
PHASE_POLL_INTERVAL = 15
2026-03-20 20:12:45 +00:00
SCRATCH_FILE = " /tmp/predictor- ${ PROJECT_NAME } -scratch.md "
2026-03-20 17:29:49 +00:00
log( ) { echo " [ $( date -u +%Y-%m-%dT%H:%M:%S) Z] $* " >> " $LOG_FILE " ; }
# ── Guards ────────────────────────────────────────────────────────────────
acquire_cron_lock "/tmp/predictor-run.lock"
check_memory 2000
log "--- Predictor run start ---"
# ── Load formula + context ───────────────────────────────────────────────
load_formula " $FACTORY_ROOT /formulas/run-predictor.toml "
build_context_block AGENTS.md RESOURCES.md
2026-03-20 20:12:45 +00:00
# ── Read scratch file (compaction survival) ───────────────────────────────
SCRATCH_CONTEXT = $( read_scratch_context " $SCRATCH_FILE " )
SCRATCH_INSTRUCTION = $( build_scratch_instruction " $SCRATCH_FILE " )
2026-03-20 17:29:49 +00:00
# ── Build prompt ─────────────────────────────────────────────────────────
2026-03-20 17:41:52 +00:00
build_prompt_footer
# shellcheck disable=SC2034 # consumed by run_formula_and_monitor
2026-03-20 17:29:49 +00:00
PROMPT = " You are the prediction agent (goblin) for ${ CODEBERG_REPO } . Work through the formula below. You MUST write PHASE:done to ' ${ PHASE_FILE } ' when finished — the orchestrator will time you out if you return to the prompt without signalling.
Your role: spot patterns in infrastructure signals and file them as prediction issues.
The planner ( adult) will triage every prediction before acting.
You MUST NOT emit feature work or implementation issues — only predictions
about CI health, issue staleness, agent status, and system conditions.
## Project context
${ CONTEXT_BLOCK }
2026-03-20 20:58:32 +00:00
${ SCRATCH_CONTEXT }
2026-03-20 17:29:49 +00:00
## Formula
${ FORMULA_CONTENT }
2026-03-20 20:58:32 +00:00
${ SCRATCH_INSTRUCTION }
2026-03-20 17:41:52 +00:00
${ PROMPT_FOOTER } "
2026-03-20 17:29:49 +00:00
2026-03-20 17:41:52 +00:00
# ── Run session ──────────────────────────────────────────────────────────
2026-03-20 17:29:49 +00:00
export CLAUDE_MODEL = "sonnet"
2026-03-20 17:41:52 +00:00
run_formula_and_monitor "predictor"
2026-03-20 20:12:45 +00:00
# ── Cleanup scratch file on normal exit ──────────────────────────────────
2026-03-20 20:58:32 +00:00
# FINAL_PHASE already set by run_formula_and_monitor
if [ " ${ FINAL_PHASE :- } " = "PHASE:done" ] ; then
2026-03-20 20:12:45 +00:00
rm -f " $SCRATCH_FILE "
fi