Merge pull request 'chore: gardener housekeeping' (#463) from chore/gardener-20260409-0005 into main
All checks were successful
ci/woodpecker/push/ci Pipeline was successful

This commit is contained in:
dev-bot 2026-04-09 00:09:02 +00:00
commit c52e5d35a2
10 changed files with 31 additions and 35 deletions

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: 60086973550d5f6a7ea0774efee5614da6b0de9f -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Disinto — Agent Instructions
## What this repo is
@ -67,8 +67,6 @@ disinto-ops/ (ops repo — {project}-ops)
└── RESOURCES.md accounts, tokens (refs), infra inventory
```
> **Note:** Journal directories (`journal/planner/` and `journal/supervisor/`) still exist in the ops repo. Agent journals are now stored in each agent's `.profile` repo on Forgejo.
## Agent .profile Model
Each agent has a `.profile` repository on Forgejo storing `knowledge/lessons-learned.md` (injected into each session prompt) and `journal/` reflection entries (digested into lessons). Pre-session: `formula_prepare_profile_context()` loads lessons. Post-session: `profile_write_journal` records reflections. See `lib/formula-session.sh`.
@ -152,23 +150,13 @@ Issues flow: `backlog` → `in-progress` → PR → CI → review → merge →
### Dependency conventions
Issues declare dependencies in their body using a `## Dependencies` or
`## Depends on` section listing `#N` references. The dev-poll scheduler uses
`lib/parse-deps.sh` to extract these and only picks issues whose dependencies
are all closed.
### Single-threaded pipeline
Each project processes one issue at a time. Dev-poll will not start new work
while an open PR is waiting for CI or review. This keeps context clear and
prevents merge conflicts between concurrent changes.
Issues declare dependencies via `## Dependencies` / `## Depends on` sections listing `#N` refs. `lib/parse-deps.sh` extracts these; dev-poll only picks issues whose deps are all closed. See AD-002 for single-threaded pipeline rules.
---
## Addressables
## Addressables and Observables
Concrete artifacts the factory has produced or is building. The gardener
maintains this table during grooming — see `formulas/run-gardener.toml`.
Concrete artifacts the factory has produced or is building. Observables have measurement wired — the gardener promotes addressables once an evidence process is connected.
| Artifact | Location | Observable? |
|----------|----------|-------------|
@ -177,14 +165,6 @@ maintains this table during grooming — see `formulas/run-gardener.toml`.
| Skill | ClawHub (in progress) | No |
| GitHub org | github.com/Disinto | No |
## Observables
Addressables with measurement wired — the factory can read structured
feedback from these. The gardener promotes addressables here once an
evidence process is connected.
None yet.
---
## Architecture Decisions

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Architect — Agent Instructions
## What this agent is
@ -40,11 +40,16 @@ the steps for:
Run via `architect/architect-run.sh`, which:
- Acquires a cron lock and checks available memory
- Cleans up per-issue scratch files from previous runs (`/tmp/architect-{project}-scratch-*.md`)
- Sources shared libraries (env.sh, formula-session.sh)
- Uses FORGE_ARCHITECT_TOKEN for authentication
- Loads the formula and builds context from VISION.md, AGENTS.md, and ops repo
- Executes the formula via `agent_run`
**Multi-sprint pitching**: The architect pitches up to 3 sprints per run. The pitch budget is `3 <open architect PRs>`. After handling existing PRs (accept/reject/answer parsing), the architect selects up to `pitch_budget` vision issues (skipping any already with an open architect PR or `in-progress` label), then writes one per-issue scratch file (`/tmp/architect-{project}-scratch-{issue_number}.md`) and creates one sprint PR per scratch file.
**Session resumption (answer_parsing)**: When processing human answers on a PR in the `questions` phase (PR body has `## Design forks` + question comments), `architect-run.sh` resumes the prior Claude session (from `SID_FILE`) rather than starting fresh. This preserves deep codebase understanding from the research phase so sub-issues include specific file references.
## Cron
Suggested cron entry (every 6 hours):

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Dev Agent
**Role**: Implement issues autonomously — write code, push branches, address
@ -14,7 +14,7 @@ in-progress issues are also picked up. The direct-merge scan runs before the loc
check so approved PRs get merged even while a dev-agent session is active.
**Key files**:
- `dev/dev-poll.sh` — Cron scheduler: finds next ready issue, handles merge/rebase of approved PRs, tracks CI fix attempts. `BOT_USER` is resolved once at startup via the Forge `/user` API and cached for all assignee checks. Formula guard skips issues labeled `formula`, `prediction/dismissed`, or `prediction/unreviewed`. **Race prevention**: checks issue assignee before claiming — skips if assigned to a different bot user. **Stale branch abandonment**: closes PRs and deletes branches that are behind `$PRIMARY_BRANCH` (restarts poll cycle for a fresh start). **Stale in-progress recovery**: on each poll cycle, scans for issues labeled `in-progress`. If the issue is assigned to `$BOT_USER` (this agent), checks for pending review feedback first — if an open PR has `REQUEST_CHANGES`, spawns the dev-agent to address it before setting `BLOCKED_BY_INPROGRESS=true`; otherwise just sets blocked. If assigned to another agent, logs and falls through (does not block). If no assignee, no open PR, and no agent lock file — removes `in-progress`, adds `blocked` with a human-triage comment. **Per-agent open-PR gate**: before starting new work, filters open waiting PRs to only those assigned to this agent (`$BOT_USER`). Other agents' PRs do not block this agent's pipeline (#358, #369). **Pre-lock merge scan own-PRs only**: the direct-merge scan only merges PRs whose linked issue is assigned to this agent — skips PRs owned by other bot users (#374).
- `dev/dev-poll.sh` — Cron scheduler: finds next ready issue, handles merge/rebase of approved PRs, tracks CI fix attempts. `BOT_USER` is resolved once at startup via the Forge `/user` API and cached for all assignee checks. Formula guard skips issues labeled `formula`, `prediction/dismissed`, or `prediction/unreviewed`. **Race prevention**: checks issue assignee before claiming — skips if assigned to a different bot user. **Stale branch abandonment**: closes PRs and deletes branches that are behind `$PRIMARY_BRANCH` (restarts poll cycle for a fresh start). **Stale in-progress recovery**: on each poll cycle, scans for issues labeled `in-progress`. If the issue has a `vision` label, sets `BLOCKED_BY_INPROGRESS=true` and skips further stale checks (vision issues are managed by the architect). If the issue is assigned to `$BOT_USER` (this agent), checks for pending review feedback first — if an open PR has `REQUEST_CHANGES`, spawns the dev-agent to address it before setting `BLOCKED_BY_INPROGRESS=true`; otherwise just sets blocked. If assigned to another agent, logs and falls through (does not block). If no assignee, no open PR, and no agent lock file — removes `in-progress`, adds `blocked` with a human-triage comment. **Per-agent open-PR gate**: before starting new work, filters open waiting PRs to only those assigned to this agent (`$BOT_USER`). Other agents' PRs do not block this agent's pipeline (#358, #369). **Pre-lock merge scan own-PRs only**: the direct-merge scan only merges PRs whose linked issue is assigned to this agent — skips PRs owned by other bot users (#374).
- `dev/dev-agent.sh` — Orchestrator: claims issue, creates worktree + tmux session with interactive `claude`, monitors phase file, injects CI results and review feedback, merges on approval
- `dev/phase-test.sh` — Integration test for the phase protocol

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Gardener Agent
**Role**: Backlog grooming — detect duplicate issues, missing acceptance

View file

@ -1 +1,12 @@
[]
[
{
"action": "edit_body",
"issue": 454,
"body": "Flagged by AI reviewer in PR #453.\n\n## Problem\n\n`vault/vault-env.sh` `validate_vault_action` (line 70-73) validates field names against an allowlist that does NOT include `blast_radius`:\n\n```\nid|formula|context|secrets|model|tools|timeout_minutes\n```\n\nIf an operator adds `blast_radius = \"low\"` to a vault action TOML (as documented in `vault/SCHEMA.md` and supported by `vault/classify.sh`), the validator rejects it with \"ERROR: Unknown fields in TOML: blast_radius\". The feature is documented and implemented but cannot be exercised without triggering a validation error.\n\n## Fix\n\nAdd `blast_radius` to the allowed fields list in `validate_vault_action` in `vault/vault-env.sh`.\n\n---\n*Auto-created from AI review*\n\n## Affected files\n\n- `vault/vault-env.sh` (line 76 — `id|formula|context|secrets|model|tools|timeout_minutes|dispatch_mode` allowlist)\n\n## Acceptance criteria\n\n- [ ] `blast_radius` is added to the allowed fields list in `validate_vault_action` in `vault/vault-env.sh`\n- [ ] A vault action TOML containing `blast_radius = \"low\"` passes `validate_vault_action` without error\n- [ ] A vault action TOML containing an unrecognised field (e.g. `bogus_field = \"x\"`) still fails validation\n- [ ] `vault/validate.sh` and existing tests continue to pass after the change"
},
{
"action": "add_label",
"issue": 454,
"label": "backlog"
}
]

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Shared Helpers (`lib/`)
All agents source `lib/env.sh` as their first action. Additional helpers are
@ -22,7 +22,7 @@ sourced as needed.
| `lib/worktree.sh` | Reusable git worktree management: `worktree_create(path, branch, [base_ref])` — create worktree, checkout base, fetch submodules. `worktree_recover(path, branch, [remote])` — detect existing worktree, reuse if on correct branch (sets `_WORKTREE_REUSED`), otherwise clean and recreate. `worktree_cleanup(path)``git worktree remove --force`, clear Claude Code project cache (`~/.claude/projects/` matching path). `worktree_cleanup_stale([max_age_hours])` — scan `/tmp` for orphaned worktrees older than threshold, skip preserved and active tmux worktrees, prune. `worktree_preserve(path, reason)` — mark worktree as preserved for debugging (writes `.worktree-preserved` marker, skipped by stale cleanup). | dev-agent.sh, supervisor-run.sh, planner-run.sh, predictor-run.sh, gardener-run.sh |
| `lib/pr-lifecycle.sh` | Reusable PR lifecycle library: `pr_create()`, `pr_find_by_branch()`, `pr_poll_ci()`, `pr_poll_review()`, `pr_merge()`, `pr_is_merged()`, `pr_walk_to_merge()`, `build_phase_protocol_prompt()`. Requires `lib/ci-helpers.sh`. | dev-agent.sh (future) |
| `lib/issue-lifecycle.sh` | Reusable issue lifecycle library: `issue_claim()` (add in-progress, remove backlog), `issue_release()` (remove in-progress, add backlog), `issue_block()` (post diagnostic comment with secret redaction, add blocked label), `issue_close()`, `issue_check_deps()` (parse deps, check transitive closure; sets `_ISSUE_BLOCKED_BY`, `_ISSUE_SUGGESTION`), `issue_suggest_next()` (find next unblocked backlog issue; sets `_ISSUE_NEXT`), `issue_post_refusal()` (structured refusal comment with dedup). Label IDs cached in globals on first lookup. Sources `lib/secret-scan.sh`. | dev-agent.sh (future) |
| `lib/vault.sh` | **Vault PR helper** — create vault action PRs on ops repo via Forgejo API (works from containers without SSH). `vault_request <action_id> <toml_content>` validates TOML (using `validate_vault_action` from `vault/vault-env.sh`), creates branch `vault/<action-id>`, writes `vault/actions/<action-id>.toml`, creates PR targeting `main` with title `vault: <action-id>` and body from context field, returns PR number. Idempotent: if PR exists, returns existing number. Requires `FORGE_TOKEN`, `FORGE_URL`, `FORGE_REPO`, `FORGE_OPS_REPO`. Uses the calling agent's own token (saves/restores `FORGE_TOKEN` around sourcing `vault-env.sh`), so approval workflow respects individual agent identities. | dev-agent (vault actions), future vault dispatcher |
| `lib/vault.sh` | **Vault PR helper** — create vault action PRs on ops repo via Forgejo API (works from containers without SSH). `vault_request <action_id> <toml_content>` validates TOML (using `validate_vault_action` from `vault/vault-env.sh`), creates branch `vault/<action-id>`, writes `vault/actions/<action-id>.toml`, creates PR targeting `main` with title `vault: <action-id>` and body from context field, returns PR number. Idempotent: if PR exists, returns existing number. **Low-tier bypass**: if the action's `blast_radius` classifies as `low` (via `vault/classify.sh`), `vault_request` calls `_vault_commit_direct()` which commits directly to ops `main` using `FORGE_ADMIN_TOKEN` — no PR, no approval wait. Returns `0` (not a PR number) for direct commits. Requires `FORGE_TOKEN`, `FORGE_ADMIN_TOKEN` (low-tier only), `FORGE_URL`, `FORGE_REPO`, `FORGE_OPS_REPO`. Uses the calling agent's own token (saves/restores `FORGE_TOKEN` around sourcing `vault-env.sh`), so approval workflow respects individual agent identities. | dev-agent (vault actions), future vault dispatcher |
| `lib/branch-protection.sh` | Branch protection helpers for Forgejo repos. `setup_vault_branch_protection()` — configures admin-only merge protection on main (require 1 approval, restrict merge to admin role, block direct pushes). `setup_profile_branch_protection()` — same protection for `.profile` repos. `verify_branch_protection()` — checks protection is correctly configured. `remove_branch_protection()` — removes protection (cleanup/testing). Handles race condition after initial push: retries with backoff if Forgejo hasn't processed the branch yet. Requires `FORGE_TOKEN`, `FORGE_URL`, `FORGE_OPS_REPO`. | bin/disinto (hire-an-agent) |
| `lib/agent-sdk.sh` | `agent_run([--resume SESSION_ID] [--worktree DIR] PROMPT)` — one-shot `claude -p` invocation with session persistence. Saves session ID to `SID_FILE`, reads it back on resume. `agent_recover_session()` — restore previous session ID from `SID_FILE` on startup. **Nudge guard**: skips nudge injection if the worktree is clean and no push is expected, preventing spurious re-invocations. Callers must define `SID_FILE`, `LOGFILE`, and `log()` before sourcing. | formula-driven agents (dev-agent, planner-run, predictor-run, gardener-run) |
| `lib/forge-setup.sh` | `setup_forge()` — Forgejo instance provisioning: creates admin user, bot accounts, org, repos (code + ops), configures webhooks, sets repo topics. Extracted from `bin/disinto`. Requires `FORGE_URL`, `FORGE_TOKEN`, `FACTORY_ROOT`. **Password storage (#361)**: after creating each bot account, stores its password in `.env` as `FORGE_<BOT>_PASS` (e.g. `FORGE_PASS`, `FORGE_REVIEW_PASS`, etc.) for use by `forge-push.sh`. | bin/disinto (init) |

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Planner Agent
**Role**: Strategic planning using a Prerequisite Tree (Theory of Constraints),

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Predictor Agent
**Role**: Abstract adversary (the "goblin"). Runs a 2-step formula

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Review Agent
**Role**: AI-powered PR review — post structured findings and formal

View file

@ -1,4 +1,4 @@
<!-- last-reviewed: ebadff09a1ce3c0140e4975985d383136a9a5504 -->
<!-- last-reviewed: d5e63a801ed48f9bd54c77e4915bc076b7490958 -->
# Supervisor Agent
**Role**: Health monitoring and auto-remediation, executed as a formula-driven