2026-03-20 13:40:09 +00:00
#!/usr/bin/env bash
# =============================================================================
# planner-run.sh — Cron wrapper: direct planner execution via Claude + formula
#
2026-03-20 17:21:33 +00:00
# Runs daily (or on-demand). Guards against concurrent runs and low memory.
2026-03-20 13:40:09 +00:00
# Creates a tmux session with Claude (opus) reading formulas/run-planner.toml.
# No action issues — the planner is a nervous system component, not work.
#
2026-03-20 17:21:33 +00:00
# Usage:
# planner-run.sh [projects/disinto.toml] # project config (default: disinto)
2026-03-20 13:40:09 +00:00
# =============================================================================
set -euo pipefail
SCRIPT_DIR = " $( cd " $( dirname " $0 " ) " && pwd ) "
FACTORY_ROOT = " $( dirname " $SCRIPT_DIR " ) "
2026-03-20 17:21:33 +00:00
# Accept project config from argument; default to disinto (planner is disinto infrastructure)
export PROJECT_TOML = " ${ 1 :- $FACTORY_ROOT /projects/disinto.toml } "
2026-03-20 13:40:09 +00:00
# shellcheck source=../lib/env.sh
source " $FACTORY_ROOT /lib/env.sh "
fix: Per-agent Forgejo accounts — identity and permissions via authorship (#747)
Each agent now gets its own Forgejo account (dev-bot, review-bot,
planner-bot, gardener-bot, vault-bot, supervisor-bot, predictor-bot,
action-bot) with a dedicated API token. This enables:
- Audit trail: every forge action attributable to a specific agent
- Permission boundaries: agents act under their own identity
- Vault authorization model: vault-bot comments = proof of approval
Changes:
- bin/disinto: setup_forge() creates all 8 bot accounts during init,
stores per-agent tokens (FORGE_*_TOKEN) in .env, adds all bots as
repo collaborators
- lib/env.sh: exports per-agent token vars with fallback to FORGE_TOKEN
for backwards compat; sets FORGE_BOT_USERNAMES default to all 8 bots
- Agent scripts: each agent overrides FORGE_TOKEN with its per-agent
token after sourcing env.sh (gardener, planner, supervisor, predictor,
vault, action)
- .env.example: documents all per-agent token fields
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:16:13 +00:00
# Use planner-bot's own Forgejo identity (#747)
FORGE_TOKEN = " ${ FORGE_PLANNER_TOKEN :- ${ FORGE_TOKEN } } "
2026-03-20 13:40:09 +00:00
# shellcheck source=../lib/agent-session.sh
source " $FACTORY_ROOT /lib/agent-session.sh "
2026-03-20 13:53:33 +00:00
# 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 13:40:09 +00:00
LOG_FILE = " $SCRIPT_DIR /planner.log "
2026-03-20 17:41:52 +00:00
# shellcheck disable=SC2034 # consumed by run_formula_and_monitor
2026-03-20 13:40:09 +00:00
SESSION_NAME = " planner- ${ PROJECT_NAME } "
PHASE_FILE = " /tmp/planner-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/planner- ${ PROJECT_NAME } -scratch.md "
2026-03-20 13:40:09 +00:00
log( ) { echo " [ $( date -u +%Y-%m-%dT%H:%M:%S) Z] $* " >> " $LOG_FILE " ; }
2026-03-20 13:53:33 +00:00
# ── Guards ────────────────────────────────────────────────────────────────
2026-03-23 21:46:59 +00:00
check_active planner
2026-03-20 13:53:33 +00:00
acquire_cron_lock "/tmp/planner-run.lock"
check_memory 2000
2026-03-20 13:40:09 +00:00
log "--- Planner run start ---"
2026-03-20 13:53:33 +00:00
# ── Load formula + context ───────────────────────────────────────────────
load_formula " $FACTORY_ROOT /formulas/run-planner.toml "
fix: {project}-ops repo — separate operations from code (#757) (#767)
Fixes #757
## Changes
Separate operations from code into {project}-ops repo pattern. Added OPS_REPO_ROOT infrastructure (env.sh, load-project.sh, formula-session.sh with ensure_ops_repo helper). Updated all 8 agent scripts and 7 formulas to read/write vault items, journals, evidence, prerequisites, RESOURCES.md, and knowledge from the ops repo. Added setup_ops_repo() to disinto init for automatic ops repo creation and seeding. Removed migrated data from code repo (vault data dirs, planner journal/memory/prerequisites, supervisor journal/best-practices, evidence, RESOURCES.md). Updated all documentation. 55 files changed, ShellCheck clean, all 38 phase tests pass.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/767
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-26 19:55:12 +01:00
build_context_block VISION.md AGENTS.md ops:RESOURCES.md ops:prerequisites.md
2026-03-20 13:40:09 +00:00
2026-03-25 13:47:48 +00:00
# ── Build structural analysis graph ──────────────────────────────────────
2026-03-25 13:50:33 +00:00
build_graph_section
2026-03-25 13:47:48 +00:00
fix: {project}-ops repo — separate operations from code (#757) (#767)
Fixes #757
## Changes
Separate operations from code into {project}-ops repo pattern. Added OPS_REPO_ROOT infrastructure (env.sh, load-project.sh, formula-session.sh with ensure_ops_repo helper). Updated all 8 agent scripts and 7 formulas to read/write vault items, journals, evidence, prerequisites, RESOURCES.md, and knowledge from the ops repo. Added setup_ops_repo() to disinto init for automatic ops repo creation and seeding. Removed migrated data from code repo (vault data dirs, planner journal/memory/prerequisites, supervisor journal/best-practices, evidence, RESOURCES.md). Updated all documentation. 55 files changed, ShellCheck clean, all 38 phase tests pass.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/767
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-26 19:55:12 +01:00
# ── Ensure ops repo is available ───────────────────────────────────────
ensure_ops_repo
2026-03-20 13:40:09 +00:00
# ── Read planner memory ─────────────────────────────────────────────────
MEMORY_BLOCK = ""
fix: {project}-ops repo — separate operations from code (#757) (#767)
Fixes #757
## Changes
Separate operations from code into {project}-ops repo pattern. Added OPS_REPO_ROOT infrastructure (env.sh, load-project.sh, formula-session.sh with ensure_ops_repo helper). Updated all 8 agent scripts and 7 formulas to read/write vault items, journals, evidence, prerequisites, RESOURCES.md, and knowledge from the ops repo. Added setup_ops_repo() to disinto init for automatic ops repo creation and seeding. Removed migrated data from code repo (vault data dirs, planner journal/memory/prerequisites, supervisor journal/best-practices, evidence, RESOURCES.md). Updated all documentation. 55 files changed, ShellCheck clean, all 38 phase tests pass.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/767
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-26 19:55:12 +01:00
MEMORY_FILE = " $OPS_REPO_ROOT /knowledge/planner-memory.md "
2026-03-20 13:40:09 +00:00
if [ -f " $MEMORY_FILE " ] ; then
MEMORY_BLOCK = "
fix: {project}-ops repo — separate operations from code (#757) (#767)
Fixes #757
## Changes
Separate operations from code into {project}-ops repo pattern. Added OPS_REPO_ROOT infrastructure (env.sh, load-project.sh, formula-session.sh with ensure_ops_repo helper). Updated all 8 agent scripts and 7 formulas to read/write vault items, journals, evidence, prerequisites, RESOURCES.md, and knowledge from the ops repo. Added setup_ops_repo() to disinto init for automatic ops repo creation and seeding. Removed migrated data from code repo (vault data dirs, planner journal/memory/prerequisites, supervisor journal/best-practices, evidence, RESOURCES.md). Updated all documentation. 55 files changed, ShellCheck clean, all 38 phase tests pass.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/767
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-26 19:55:12 +01:00
### knowledge/planner-memory.md (persistent memory from prior runs)
2026-03-20 13:40:09 +00:00
$( cat " $MEMORY_FILE " )
"
fi
2026-03-21 08:57:06 +00:00
# ── Read recent journal files ──────────────────────────────────────────
JOURNAL_BLOCK = ""
fix: {project}-ops repo — separate operations from code (#757) (#767)
Fixes #757
## Changes
Separate operations from code into {project}-ops repo pattern. Added OPS_REPO_ROOT infrastructure (env.sh, load-project.sh, formula-session.sh with ensure_ops_repo helper). Updated all 8 agent scripts and 7 formulas to read/write vault items, journals, evidence, prerequisites, RESOURCES.md, and knowledge from the ops repo. Added setup_ops_repo() to disinto init for automatic ops repo creation and seeding. Removed migrated data from code repo (vault data dirs, planner journal/memory/prerequisites, supervisor journal/best-practices, evidence, RESOURCES.md). Updated all documentation. 55 files changed, ShellCheck clean, all 38 phase tests pass.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/767
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-26 19:55:12 +01:00
JOURNAL_DIR = " $OPS_REPO_ROOT /journal/planner "
2026-03-21 08:57:06 +00:00
if [ -d " $JOURNAL_DIR " ] ; then
# Load last 5 journal files (most recent first) for run history context
JOURNAL_FILES = $( find " $JOURNAL_DIR " -name '*.md' -type f | sort -r | head -5)
if [ -n " $JOURNAL_FILES " ] ; then
JOURNAL_BLOCK = "
fix: {project}-ops repo — separate operations from code (#757) (#767)
Fixes #757
## Changes
Separate operations from code into {project}-ops repo pattern. Added OPS_REPO_ROOT infrastructure (env.sh, load-project.sh, formula-session.sh with ensure_ops_repo helper). Updated all 8 agent scripts and 7 formulas to read/write vault items, journals, evidence, prerequisites, RESOURCES.md, and knowledge from the ops repo. Added setup_ops_repo() to disinto init for automatic ops repo creation and seeding. Removed migrated data from code repo (vault data dirs, planner journal/memory/prerequisites, supervisor journal/best-practices, evidence, RESOURCES.md). Updated all documentation. 55 files changed, ShellCheck clean, all 38 phase tests pass.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/767
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-26 19:55:12 +01:00
### Recent journal entries (journal/planner/)
2026-03-21 08:57:06 +00:00
"
while IFS = read -r jf; do
JOURNAL_BLOCK = " ${ JOURNAL_BLOCK }
#### $(basename "$jf")
$( cat " $jf " )
"
done <<< " $JOURNAL_FILES "
fi
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 13:40:09 +00:00
# ── Build prompt ─────────────────────────────────────────────────────────
2026-03-20 17:41:52 +00:00
build_prompt_footer "
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
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\"}'
2026-03-20 17:41:52 +00:00
"
# 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 strategic planner 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 13:40:09 +00:00
## Project context
2026-03-21 08:57:06 +00:00
${ CONTEXT_BLOCK } ${ MEMORY_BLOCK } ${ JOURNAL_BLOCK }
2026-03-25 13:47:48 +00:00
${ GRAPH_SECTION }
2026-03-20 20:12:45 +00:00
${ SCRATCH_CONTEXT : + ${ SCRATCH_CONTEXT }
}
2026-03-20 13:40:09 +00:00
## Formula
${ FORMULA_CONTENT }
2026-03-20 20:12:45 +00:00
${ SCRATCH_INSTRUCTION }
2026-03-20 17:41:52 +00:00
${ PROMPT_FOOTER } "
2026-03-20 13:40:09 +00:00
2026-03-20 17:41:52 +00:00
# ── Run session ──────────────────────────────────────────────────────────
2026-03-20 13:40:09 +00:00
export CLAUDE_MODEL = "opus"
2026-03-20 17:41:52 +00:00
run_formula_and_monitor "planner"
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