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 "
2026-03-23 21:46:59 +00:00
# shellcheck source=../lib/guard.sh
source " $FACTORY_ROOT /lib/guard.sh "
2026-03-20 17:29:49 +00:00
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 ────────────────────────────────────────────────────────────────
2026-03-23 21:46:59 +00:00
check_active predictor
2026-03-20 17:29:49 +00:00
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 "
2026-03-23 13:56:59 +00:00
build_context_block AGENTS.md RESOURCES.md VISION.md planner/prerequisite-tree.md
2026-03-20 17:29:49 +00:00
2026-03-24 21:24:20 +00:00
# ── Build structural analysis graph ──────────────────────────────────────
GRAPH_REPORT = " /tmp/ ${ PROJECT_NAME } -graph-report.json "
GRAPH_SECTION = ""
if python3 " $FACTORY_ROOT /lib/build-graph.py " \
--project-root " $PROJECT_REPO_ROOT " \
--output " $GRAPH_REPORT " 2>>" $LOG_FILE " ; then
GRAPH_SECTION = $( printf '\n## Structural analysis\n```json\n%s\n```\n' \
" $( cat " $GRAPH_REPORT " ) " )
log " graph report generated: $( jq -r '.stats | "\(.nodes) nodes, \(.edges) edges"' " $GRAPH_REPORT " ) "
else
log "WARN: build-graph.py failed — continuing without structural analysis"
fi
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
fix: Replace Codeberg dependency with local Forgejo instance (#611)
- Add setup_forge() to bin/disinto: provisions Forgejo via Docker,
creates admin + bot users (dev-bot, review-bot), generates API
tokens, creates repo, and pushes code — all automated
- Rename env vars: CODEBERG_TOKEN→FORGE_TOKEN, REVIEW_BOT_TOKEN→
FORGE_REVIEW_TOKEN, CODEBERG_REPO→FORGE_REPO, CODEBERG_API→
FORGE_API, CODEBERG_WEB→FORGE_WEB, CODEBERG_BOT_USERNAMES→
FORGE_BOT_USERNAMES (with backwards-compat fallbacks)
- Rename API helpers: codeberg_api()→forge_api(), codeberg_api_all()
→forge_api_all() (with compat aliases)
- Add forge_url field to project TOML; load-project.sh derives
FORGE_API/FORGE_WEB from forge_url + repo
- Update parse_repo_slug() to accept any host URL, not just codeberg
- Forgejo data stored under ~/.disinto/forgejo/ (not in factory repo)
- Update all 58 files: agent scripts, formulas, docs, site HTML
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 16:57:12 +00:00
PROMPT = " You are the prediction agent (goblin) for ${ FORGE_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.
2026-03-20 17:29:49 +00:00
2026-03-23 13:56:59 +00:00
Your role: abstract adversary. Find the project' s biggest weakness, challenge
planner claims, and generate evidence. Explore when uncertain ( file a prediction) ,
exploit when confident ( file a prediction AND dispatch a formula via an action issue) .
2026-03-22 11:47:13 +00:00
2026-03-23 13:56:59 +00:00
Your prediction history IS your memory — review it to decide where to focus.
2026-03-20 17:29:49 +00:00
The planner ( adult) will triage every prediction before acting.
You MUST NOT emit feature work or implementation issues — only predictions
2026-03-23 13:56:59 +00:00
challenging claims, exposing gaps, and surfacing risks.
2026-03-22 11:47:13 +00:00
Use WebSearch for external signal scanning — be targeted ( project dependencies
2026-03-23 13:56:59 +00:00
and tools only, not general news) . Limit to 3 web searches per run.
2026-03-20 17:29:49 +00:00
## Project context
${ CONTEXT_BLOCK }
2026-03-24 21:24:20 +00:00
${ GRAPH_SECTION }
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