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>
This commit is contained in:
johba 2026-03-26 19:55:12 +01:00
parent a899fd0733
commit 71fe89cdd0
55 changed files with 421 additions and 932 deletions

View file

@ -96,7 +96,7 @@ The dev-agent is completely starved until they are promoted or resolved.
For each tier-0 issue:
- Read the full body: curl -sf -H "Authorization: token $FORGE_TOKEN" "$FORGE_API/issues/{number}"
- If resolvable: promote to backlog add acceptance criteria, affected files, relabel
- If needs human decision: file a vault procurement item (vault/pending/<id>.md)
- If needs human decision: file a vault procurement item ($OPS_REPO_ROOT/vault/pending/<id>.md)
- If invalid / wontfix: close with explanation comment
After completing all tier-0, re-fetch to check for new blockers:
@ -136,7 +136,7 @@ DUPLICATE (>80% overlap after reading both bodies — confirm before closing):
Write: echo "ACTION: closed #NNN as duplicate of #OLDER" >> "$RESULT_FILE"
VAULT (ambiguous scope, architectural question, needs human decision):
File a vault procurement item at $PROJECT_REPO_ROOT/vault/pending/<id>.md:
File a vault procurement item at $OPS_REPO_ROOT/vault/pending/<id>.md:
# <What decision or resource is needed>
## What
<description>
@ -144,7 +144,7 @@ VAULT (ambiguous scope, architectural question, needs human decision):
<which issue this unblocks>
## Unblocks
- #NNN — <title>
Log: echo "VAULT: filed vault/pending/<id>.md for #NNN — <reason>" >> "$RESULT_FILE"
Log: echo "VAULT: filed $OPS_REPO_ROOT/vault/pending/<id>.md for #NNN — <reason>" >> "$RESULT_FILE"
Dust vs ore rules:
Dust: comment fix, variable rename, whitespace/formatting, single-line edit, trivial cleanup with no behavior change

View file

@ -63,7 +63,7 @@ Do NOT flag:
## 4. Vault item quality (conditional)
If the PR adds or modifies files in `vault/pending/*.md`, apply these
If the PR adds or modifies vault item files (`vault/pending/*.md` in the ops repo), apply these
additional checks. These criteria apply ON TOP of the normal review
a vault PR must also pass the standard checklist above.
@ -102,9 +102,9 @@ propose a specific action.
### Dedup check
Check whether `vault/pending/`, `vault/approved/`, or `vault/fired/`
Check whether `$OPS_REPO_ROOT/vault/pending/`, `$OPS_REPO_ROOT/vault/approved/`, or `$OPS_REPO_ROOT/vault/fired/`
already contains a similar item (same resource, same ask). List the
vault directories to inspect existing items. If a duplicate or
vault directories in the ops repo to inspect existing items. If a duplicate or
near-duplicate exists, REQUEST_CHANGES and reference the existing item.
## 5. External action detection (token separation)
@ -112,7 +112,7 @@ near-duplicate exists, REQUEST_CHANGES and reference the existing item.
Agents must NEVER execute external actions directly. Any action that touches
an external system (publish, deploy, post, push to external registry, API
calls to third-party services) MUST go through vault dispatch i.e., the
agent files a vault item (`vault/pending/*.json`) and the vault-runner
agent files a vault item (`$OPS_REPO_ROOT/vault/pending/*.json`) and the vault-runner
container executes it with injected secrets.
Scan the diff for these patterns:
@ -128,7 +128,7 @@ Scan the diff for these patterns:
If ANY of these patterns appear in agent code (scripts in `dev/`, `action/`,
`planner/`, `gardener/`, `supervisor/`, `predictor/`, `review/`, `formulas/`,
`lib/`) WITHOUT routing through vault dispatch (`vault/pending/`, `vault-fire.sh`,
`lib/`) WITHOUT routing through vault dispatch (`$OPS_REPO_ROOT/vault/pending/`, `vault-fire.sh`,
`vault-run-action.sh`), **REQUEST_CHANGES**.
Explain that external actions must use vault dispatch per AD-006. The agent

View file

@ -120,7 +120,7 @@ DUST (trivial — single-line edit, rename, comment, style, whitespace):
of 3+ into one backlog issue.
VAULT (needs human decision or external resource):
File a vault procurement item at $PROJECT_REPO_ROOT/vault/pending/<id>.md:
File a vault procurement item at $OPS_REPO_ROOT/vault/pending/<id>.md:
# <What decision or resource is needed>
## What
<description>
@ -128,7 +128,7 @@ VAULT (needs human decision or external resource):
<which issue this unblocks>
## Unblocks
- #NNN — <title>
Log: echo "VAULT: filed vault/pending/<id>.md for #NNN — <reason>" >> "$RESULT_FILE"
Log: echo "VAULT: filed $OPS_REPO_ROOT/vault/pending/<id>.md for #NNN — <reason>" >> "$RESULT_FILE"
CLEAN (only if truly nothing to do):
echo 'CLEAN' >> "$RESULT_FILE"

View file

@ -21,8 +21,9 @@ version = 4
model = "opus"
[context]
files = ["VISION.md", "AGENTS.md", "RESOURCES.md", "planner/prerequisite-tree.md"]
# Recent planner/journal/*.md files + graph report loaded by planner-run.sh
files = ["VISION.md", "AGENTS.md"]
# RESOURCES.md and prerequisites.md loaded from ops repo (ops: prefix)
# Recent journal/planner/*.md files + graph report loaded by planner-run.sh
[[steps]]
id = "preflight"
@ -40,10 +41,10 @@ description = """
HEAD_SHA=$(git rev-parse HEAD)
echo "$HEAD_SHA" > /tmp/planner-head-sha
4. Read the planner memory file at: $PROJECT_REPO_ROOT/planner/MEMORY.md
4. Read the planner memory file at: $OPS_REPO_ROOT/knowledge/planner-memory.md
If it does not exist, this is the first planning run.
5. Read the prerequisite tree at: $PROJECT_REPO_ROOT/planner/prerequisite-tree.md
5. Read the prerequisite tree at: $OPS_REPO_ROOT/prerequisites.md
If it does not exist, create an initial tree from VISION.md in the next step.
6. Read the graph report injected into the prompt (## Structural analysis).
@ -121,7 +122,7 @@ Update the tree:
2. Recalculate objective status (READY/BLOCKED/DONE)
3. Add new prerequisites discovered from graph report
4. Add new objectives from VISION.md not yet in tree
5. Check vault state: vault/pending/*.md + vault/approved/*.md (blocked-on-vault), vault/fired/*.md (resolved?)
5. Check vault state: $OPS_REPO_ROOT/vault/pending/*.md + $OPS_REPO_ROOT/vault/approved/*.md (blocked-on-vault), $OPS_REPO_ROOT/vault/fired/*.md (resolved?)
6. Check RESOURCES.md for newly available capabilities
Bounce/stuck detection for issues in the tree, fetch recent comments:
@ -141,7 +142,7 @@ Tree format:
## Objective: <name> (#issue or description)
- [x] Resolved prerequisite (reference)
- [ ] Unresolved prerequisite (#issue or description)
- [ ] Resource need blocked-on-vault (vault/pending/<id>.md)
- [ ] Resource need blocked-on-vault ($OPS_REPO_ROOT/vault/pending/<id>.md)
Status: READY | BLOCKED <reason> | DONE
### Part C: File at constraints
@ -157,7 +158,7 @@ Stuck issue handling:
procurement item instead of skipping. First check for duplicates across ALL
vault directories (pending/, approved/, fired/) if a file with the same
slug already exists in any of them, do NOT create a new one.
Naming: vault/pending/<project>-<slug>.md (e.g. disinto-github-org.md).
Naming: $OPS_REPO_ROOT/vault/pending/<project>-<slug>.md (e.g. disinto-github-org.md).
Write with this template:
# Request: <short description>
@ -181,7 +182,7 @@ Stuck issue handling:
## Unblocks
- #<issue> — <title>
Then mark the prerequisite in the tree as "blocked-on-vault (vault/pending/<id>.md)".
Then mark the prerequisite in the tree as "blocked-on-vault ($OPS_REPO_ROOT/vault/pending/<id>.md)".
Do NOT skip or mark as "awaiting human decision" the vault owns the human interface.
Filing gate (for non-stuck constraints):
@ -197,9 +198,9 @@ Priority label sync:
"$FORGE_API/issues/<num>/labels/<priority_label_id>"
Vault procurement: if a constraint needs a resource not in RESOURCES.md with
recurring cost, create vault/pending/<project>-<slug>.md instead of an issue.
recurring cost, create $OPS_REPO_ROOT/vault/pending/<project>-<slug>.md instead of an issue.
Use the same template as HUMAN_BLOCKED above (What/Why/Human action/Factory will then/Unblocks).
Dedup: check vault/pending/ + vault/approved/ + vault/fired/ before creating.
Dedup: check $OPS_REPO_ROOT/vault/pending/ + $OPS_REPO_ROOT/vault/approved/ + $OPS_REPO_ROOT/vault/fired/ before creating.
Rules:
- Action budget: the planner may create at most (predictions_addressed + 1)
@ -220,10 +221,10 @@ id = "journal-and-commit"
title = "Write tree, journal, optional memory; commit and PR"
description = """
### 1. Write prerequisite tree
Write to: $PROJECT_REPO_ROOT/planner/prerequisite-tree.md
Write to: $OPS_REPO_ROOT/prerequisites.md
### 2. Write journal entry
Create/append to: $PROJECT_REPO_ROOT/planner/journal/$(date -u +%Y-%m-%d).md
Create/append to: $OPS_REPO_ROOT/journal/planner/$(date -u +%Y-%m-%d).md
Format:
# Planner run — YYYY-MM-DD HH:MM UTC
@ -242,7 +243,7 @@ Format:
(or "No stuck issues detected")
## Vault items filed
- vault/pending/<id>.md <what> blocks #NNN
- $OPS_REPO_ROOT/vault/pending/<id>.md <what> blocks #NNN
(or "No vault items filed")
## Issues created
@ -261,28 +262,21 @@ Keep concise — 30-50 lines max.
### 3. Memory update (every 5th run)
Count "# Planner run —" headers across all journal files.
Check "<!-- summarized-through-run: N -->" in MEMORY.md.
If (count - N) >= 5 or MEMORY.md missing, write to:
$PROJECT_REPO_ROOT/planner/MEMORY.md
Check "<!-- summarized-through-run: N -->" in planner-memory.md.
If (count - N) >= 5 or planner-memory.md missing, write to:
$OPS_REPO_ROOT/knowledge/planner-memory.md
Include: run counter marker, date, constraint focus, patterns, direction.
Keep under 100 lines. Replace entire file.
### 4. Commit and PR
If no file changes (git status --porcelain), skip.
Otherwise:
BRANCH="chore/planner-$(date -u +%Y%m%d-%H%M)"
git checkout -B "$BRANCH"
git add planner/prerequisite-tree.md planner/journal/ planner/MEMORY.md vault/pending/
### 4. Commit ops repo changes
Commit the ops repo changes (prerequisites, journal, memory, vault items):
cd "$OPS_REPO_ROOT"
git add prerequisites.md journal/planner/ knowledge/planner-memory.md vault/pending/
git add -u
git diff --cached --quiet && skip
git commit -m "chore: planner run $(date -u +%Y-%m-%d)"
git push -u origin "$BRANCH"
Create PR via forge API:
curl -sf -X POST -H "Authorization: token $FORGE_TOKEN" \
-H "Content-Type: application/json" "$FORGE_API/pulls" \
-d '{"title":"chore: planner run — prerequisite tree update",
"head":"<branch>","base":"<primary-branch>",
"body":"Automated planner run — prerequisite tree update and journal entry."}'
git checkout "$PRIMARY_BRANCH"
if ! git diff --cached --quiet; then
git commit -m "chore: planner run $(date -u +%Y-%m-%d)"
git push origin "$PRIMARY_BRANCH"
fi
cd "$PROJECT_REPO_ROOT"
"""
needs = ["triage-and-plan"]

View file

@ -18,7 +18,8 @@ version = 3
model = "sonnet"
[context]
files = ["AGENTS.md", "RESOURCES.md", "VISION.md", "planner/prerequisite-tree.md"]
files = ["AGENTS.md", "VISION.md"]
# RESOURCES.md and prerequisites.md loaded from ops repo (ops: prefix)
graph_report = "Structural analysis JSON from lib/build-graph.py — orphans, cycles, thin objectives, bottlenecks"
[[steps]]
@ -48,12 +49,12 @@ Set up the working environment and load your prediction history.
unreviewed (planner hasn't seen it yet)
3. Read the prerequisite tree:
cat "$PROJECT_REPO_ROOT/planner/prerequisite-tree.md"
cat "$OPS_REPO_ROOT/prerequisites.md"
4. Count evidence per claim area:
for dir in evidence/red-team evidence/holdout evidence/evolution evidence/user-test; do
echo "=== $dir ===$(find "$PROJECT_REPO_ROOT/$dir" -name '*.json' 2>/dev/null | wc -l) files"
find "$PROJECT_REPO_ROOT/$dir" -name '*.json' -printf '%T+ %p\n' 2>/dev/null | sort -r | head -3
echo "=== $dir ===$(find "$OPS_REPO_ROOT/$dir" -name '*.json' 2>/dev/null | wc -l) files"
find "$OPS_REPO_ROOT/$dir" -name '*.json' -printf '%T+ %p\n' 2>/dev/null | sort -r | head -3
done
5. Check current system state (lightweight don't over-collect):

View file

@ -209,7 +209,7 @@ Check 2 — collect-engagement.sh is present in the repo:
fi
Check 3 engagement evidence has been collected at least once:
EVIDENCE_DIR="$FACTORY_ROOT/evidence/engagement"
EVIDENCE_DIR="$OPS_REPO_ROOT/evidence/engagement"
LATEST=$(ls -1t "$EVIDENCE_DIR"/*.json 2>/dev/null | head -1 || true)
if [ -n "$LATEST" ]; then
echo "OK: Latest engagement report: $LATEST"
@ -222,7 +222,7 @@ Check 3 — engagement evidence has been collected at least once:
Summary:
echo ""
echo "Observable status: addressable=disinto.ai measurement=caddy-access-logs"
echo "Evidence path: evidence/engagement/YYYY-MM-DD.json"
echo "Consumer: planner reads evidence/engagement/ during gap analysis"
echo "Evidence path: \$OPS_REPO_ROOT/evidence/engagement/YYYY-MM-DD.json"
echo "Consumer: planner reads ops repo evidence/engagement/ during gap analysis"
"""
needs = ["verify"]

View file

@ -34,12 +34,12 @@ and injected into your prompt above. Review them now.
(24h grace period). Check the "Stale Phase Cleanup" section for any
files cleaned or in grace period this run.
2. Check vault state: read vault/pending/*.md for any procurement items
2. Check vault state: read $OPS_REPO_ROOT/vault/pending/*.md for any procurement items
the planner has filed. Note items relevant to the health assessment
(e.g. a blocked resource that explains why the pipeline is stalled).
3. Read the supervisor journal for recent history:
JOURNAL_FILE="$FACTORY_ROOT/supervisor/journal/$(date -u +%Y-%m-%d).md"
JOURNAL_FILE="$OPS_REPO_ROOT/journal/supervisor/$(date -u +%Y-%m-%d).md"
if [ -f "$JOURNAL_FILE" ]; then cat "$JOURNAL_FILE"; fi
4. Note any values that cross these thresholds:
@ -151,7 +151,7 @@ For each finding from the health assessment, decide and execute an action.
For P0-P2 issues that persist after auto-fix attempts, or issues requiring
human judgment, file a vault procurement item:
Write $PROJECT_REPO_ROOT/vault/pending/supervisor-<issue-slug>.md:
Write $OPS_REPO_ROOT/vault/pending/supervisor-<issue-slug>.md:
# <What is needed>
## What
<description of the problem and why the supervisor cannot fix it>
@ -162,11 +162,11 @@ human judgment, file a vault procurement item:
The vault-poll will notify the human and track the request.
Read the relevant best-practices file before taking action:
cat "$FACTORY_ROOT/supervisor/best-practices/memory.md" # P0
cat "$FACTORY_ROOT/supervisor/best-practices/disk.md" # P1
cat "$FACTORY_ROOT/supervisor/best-practices/ci.md" # P2 CI
cat "$FACTORY_ROOT/supervisor/best-practices/dev-agent.md" # P2 agent
cat "$FACTORY_ROOT/supervisor/best-practices/git.md" # P2 git
cat "$OPS_REPO_ROOT/knowledge/memory.md" # P0
cat "$OPS_REPO_ROOT/knowledge/disk.md" # P1
cat "$OPS_REPO_ROOT/knowledge/ci.md" # P2 CI
cat "$OPS_REPO_ROOT/knowledge/dev-agent.md" # P2 agent
cat "$OPS_REPO_ROOT/knowledge/git.md" # P2 git
Track what you fixed and what vault items you filed for the report step.
"""
@ -208,7 +208,7 @@ description = """
Append a timestamped entry to the supervisor journal.
File path:
$FACTORY_ROOT/supervisor/journal/$(date -u +%Y-%m-%d).md
$OPS_REPO_ROOT/journal/supervisor/$(date -u +%Y-%m-%d).md
If the file already exists (multiple runs per day), append a new section.
If it does not exist, create it.