chore: gardener housekeeping 2026-03-27
- Update AGENTS.md watermarks to current HEAD across all 10 files - dev/AGENTS.md: document rebase-before-push and _inject_into_session - review/AGENTS.md: document formal forge review fallback in review-poll - gardener/pending-actions.json: close #3 (already implemented in PR #2) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9b91c6a5bd
commit
daf08fe62d
11 changed files with 20 additions and 38 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Disinto — Agent Instructions
|
# Disinto — Agent Instructions
|
||||||
|
|
||||||
## What this repo is
|
## What this repo is
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Action Agent
|
# Action Agent
|
||||||
|
|
||||||
**Role**: Execute operational tasks described by action formulas — run scripts,
|
**Role**: Execute operational tasks described by action formulas — run scripts,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Dev Agent
|
# Dev Agent
|
||||||
|
|
||||||
**Role**: Implement issues autonomously — write code, push branches, address
|
**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.
|
check so approved PRs get merged even while a dev-agent session is active.
|
||||||
|
|
||||||
**Key files**:
|
**Key files**:
|
||||||
- `dev/dev-poll.sh` — Cron scheduler: finds next ready issue, handles merge/rebase of approved PRs, tracks CI fix attempts. Formula guard skips issues labeled `formula`, `action`, `prediction/dismissed`, or `prediction/unreviewed` (replaced `prediction/backlog` — that label no longer exists)
|
- `dev/dev-poll.sh` — Cron scheduler: finds next ready issue, handles merge/rebase of approved PRs, tracks CI fix attempts. Formula guard skips issues labeled `formula`, `action`, `prediction/dismissed`, or `prediction/unreviewed`. Also injects CI failures and review feedback into active tmux sessions via `_inject_into_session()` (uses `tmux load-buffer` + `paste-buffer` to handle multi-line text safely).
|
||||||
- `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/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-handler.sh` — Phase callback functions: `post_refusal_comment()`, `_on_phase_change()`, `build_phase_protocol_prompt()`. `do_merge()` detects already-merged PRs on HTTP 405 (race with dev-poll's pre-lock scan) and returns success instead of escalating. Sources `lib/mirrors.sh` and calls `mirror_push()` after every successful merge.
|
- `dev/phase-handler.sh` — Phase callback functions: `post_refusal_comment()`, `_on_phase_change()`, `build_phase_protocol_prompt()`. `do_merge()` detects already-merged PRs on HTTP 405 (race with dev-poll's pre-lock scan) and returns success instead of escalating. Sources `lib/mirrors.sh` and calls `mirror_push()` after every successful merge.
|
||||||
- `dev/phase-test.sh` — Integration test for the phase protocol
|
- `dev/phase-test.sh` — Integration test for the phase protocol
|
||||||
|
|
@ -33,6 +33,8 @@ check so approved PRs get merged even while a dev-agent session is active.
|
||||||
|
|
||||||
**Crash recovery**: on `PHASE:crashed` or non-zero exit, the worktree is **preserved** (not destroyed) for debugging. Location logged. Supervisor housekeeping removes stale crashed worktrees older than 24h.
|
**Crash recovery**: on `PHASE:crashed` or non-zero exit, the worktree is **preserved** (not destroyed) for debugging. Location logged. Supervisor housekeeping removes stale crashed worktrees older than 24h.
|
||||||
|
|
||||||
|
**Rebase-before-push**: the phase protocol instructs Claude to `git fetch && git rebase` on `$PRIMARY_BRANCH` before every push (initial, CI fix, and review address). This avoids merge conflicts when main has advanced since branch creation. Uses `--force-with-lease` on CI/review fix pushes.
|
||||||
|
|
||||||
**Lifecycle**: dev-poll.sh (`check_active dev`) → dev-agent.sh → tmux `dev-{project}-{issue}` → phase file
|
**Lifecycle**: dev-poll.sh (`check_active dev`) → dev-agent.sh → tmux `dev-{project}-{issue}` → phase file
|
||||||
drives CI/review loop → merge + `mirror_push()` → close issue. On respawn after
|
drives CI/review loop → merge + `mirror_push()` → close issue. On respawn after
|
||||||
`PHASE:escalate`, the stale phase file is cleared first so the session starts
|
`PHASE:escalate`, the stale phase file is cleared first so the session starts
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Gardener Agent
|
# Gardener Agent
|
||||||
|
|
||||||
**Role**: Backlog grooming — detect duplicate issues, missing acceptance
|
**Role**: Backlog grooming — detect duplicate issues, missing acceptance
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,12 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"action": "edit_body",
|
"action": "comment",
|
||||||
"issue": 765,
|
"issue": 3,
|
||||||
"body": "Depends on: none\n\n## Goal\n\nThe disinto website becomes a versioned artifact: built by CI, published to Codeberg's generic package registry, deployed to staging automatically. Version visible in footer.\n\n## Files to add/change\n\n### `site/VERSION`\n```\n0.1.0\n```\n\n### `site/build.sh`\n```bash\n#!/bin/bash\nVERSION=$(cat VERSION)\nmkdir -p dist\ncp *.html *.jpg *.webp *.png *.ico *.xml robots.txt dist/\nsed -i \"s|Built from scrap, powered by a single battery.|v${VERSION} · Built from scrap, powered by a single battery.|\" dist/index.html\necho \"$VERSION\" > dist/VERSION\n```\n\n### `site/index.html`\nNo template placeholder needed — `build.sh` does the sed replacement on the existing footer text.\n\n### `.woodpecker/site.yml`\n```yaml\nwhen:\n path: \"site/**\"\n event: push\n branch: main\n\nsteps:\n - name: build\n image: alpine\n commands:\n - cd site && sh build.sh\n - VERSION=$(cat site/VERSION)\n - tar czf site-${VERSION}.tar.gz -C site/dist .\n\n - name: publish\n image: alpine\n commands:\n - apk add curl\n - VERSION=$(cat site/VERSION)\n - >-\n curl -sf --user \"johba:$$FORGE_TOKEN\"\n --upload-file site-${VERSION}.tar.gz\n \"https://codeberg.org/api/packages/johba/generic/disinto-site/${VERSION}/site-${VERSION}.tar.gz\"\n environment:\n FORGE_TOKEN:\n from_secret: forge_token\n\n - name: deploy-staging\n image: alpine\n commands:\n - apk add curl\n - VERSION=$(cat site/VERSION)\n - >-\n curl -sf --user \"johba:$$FORGE_TOKEN\"\n \"https://codeberg.org/api/packages/johba/generic/disinto-site/${VERSION}/site-${VERSION}.tar.gz\"\n -o site.tar.gz\n - rm -rf /srv/staging/*\n - tar xzf site.tar.gz -C /srv/staging/\n environment:\n FORGE_TOKEN:\n from_secret: forge_token\n volumes:\n - /home/debian/staging-site:/srv/staging\n```\n\n## Infra setup (manual, before first run)\n- `mkdir -p /home/debian/staging-site`\n- Add to Caddyfile: `staging.disinto.ai { root * /home/debian/staging-site; file_server }`\n- DNS: `staging.disinto.ai` A record → same IP as `disinto.ai`\n- Reload Caddy: `sudo systemctl reload caddy`\n- Add `forge_token` as Woodpecker repo secret for johba/disinto (if not already set)\n- Add `/home/debian/staging-site` to `WOODPECKER_BACKEND_DOCKER_VOLUMES`\n\n## Verification\n- [ ] Merge PR that touches `site/` → CI runs site pipeline\n- [ ] Package appears at `codeberg.org/johba/-/packages/generic/disinto-site/0.1.0`\n- [ ] `staging.disinto.ai` serves the site with `v0.1.0` in footer\n- [ ] `disinto.ai` (production) unchanged\n\n## Related\n- #764 — docker stack edge proxy + staging (future: this moves inside the stack)\n- #755 — vault-gated production promotion (production deploy comes later)\n\n## Affected files\n- `site/VERSION` — new, holds current version string\n- `site/build.sh` — new, builds dist/ with version injected into footer\n- `.woodpecker/site.yml` — new, CI pipeline for build/publish/deploy-staging"
|
"body": "Closing: this issue was fully implemented by PR #2 (commit `723167d`). All acceptance criteria are met:\n- `edge` (Caddy) service added to docker-compose\n- `staging` Caddy static file server configured\n- `docker/Caddyfile` template generated by `disinto init`\n- Default \"Nothing shipped yet\" staging page in `docker/staging-seed/`\n\nThe dev-agent sessions recorded here crashed after the implementation was already merged into `main`. Closing as implemented."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"action": "edit_body",
|
"action": "close",
|
||||||
"issue": 764,
|
"issue": 3,
|
||||||
"body": "Depends on: none (builds on existing docker-compose generation in `bin/disinto`)\n\n## Design\n\n`disinto init` + `disinto up` starts two additional containers as base factory infrastructure:\n\n### Edge proxy (Caddy)\n- Reverse proxies to Forgejo and Woodpecker\n- Serves staging site\n- Runs on ports 80/443\n- At bootstrap: IP-only, self-signed TLS or HTTP\n- Domain + Let's Encrypt added later via vault resource request\n\n### Staging container (Caddy)\n- Static file server for the project's staging artifacts\n- Starts with a default \"Nothing shipped yet\" page\n- CI pipelines write to a shared volume to update staging content\n- No vault approval needed — staging is the factory's sandbox\n\n### docker-compose addition\n```yaml\nservices:\n edge:\n image: caddy:alpine\n ports:\n - \"80:80\"\n - \"443:443\"\n volumes:\n - ./Caddyfile:/etc/caddy/Caddyfile\n - caddy_data:/data\n depends_on:\n - forgejo\n - woodpecker-server\n - staging\n\n staging:\n image: caddy:alpine\n volumes:\n - staging-site:/srv/site\n # Not exposed directly — edge proxies to it\n\nvolumes:\n caddy_data:\n staging-site:\n```\n\n### Caddyfile (generated by `disinto init`)\n```\n# IP-only at bootstrap, domain added later\n:80 {\n handle /forgejo/* {\n reverse_proxy forgejo:3000\n }\n handle /ci/* {\n reverse_proxy woodpecker-server:8000\n }\n handle {\n reverse_proxy staging:80\n }\n}\n```\n\n### Staging update flow\n1. CI builds artifact (site tarball, etc.)\n2. CI step writes to `staging-site` volume\n3. Staging container serves updated content immediately\n4. No restart needed — Caddy serves files directly\n\n### Domain lifecycle\n- Bootstrap: no domain, edge serves on IP\n- Later: factory files vault resource request for domain\n- Human buys domain, sets DNS\n- Caddyfile updated with domain, Let's Encrypt auto-provisions TLS\n\n## Affected files\n- `bin/disinto` — `generate_compose()` adds edge + staging services\n- New: default staging page (\"Nothing shipped yet\")\n- New: Caddyfile template in `docker/`\n\n## Related\n- #755 — vault-gated deployment promotion (production comes later)\n- #757 — ops repo (domain is a resource requested through vault)\n\n## Acceptance criteria\n- [ ] `disinto init` generates a `docker-compose.yml` that includes `edge` (Caddy) and `staging` containers\n- [ ] Edge proxy routes `/forgejo/*` → Forgejo, `/ci/*` → Woodpecker, default → staging container\n- [ ] Staging container serves a default \"Nothing shipped yet\" page on first boot\n- [ ] `docker/` directory contains a Caddyfile template generated by `disinto init`\n- [ ] `disinto up` starts all containers including edge and staging without manual steps"
|
"reason": "already implemented in PR #2 (commit 723167d)"
|
||||||
},
|
|
||||||
{
|
|
||||||
"action": "edit_body",
|
|
||||||
"issue": 761,
|
|
||||||
"body": "Depends on: #747\n\n## Design\n\nEach agent account on the bundled Forgejo gets a `.profile` repo. This repo holds the agent's formula (copied from disinto at creation time) and its journal.\n\n### Structure\n```\n{agent-bot}/.profile/\n├── formula.toml # snapshot of the formula at agent creation time\n├── journal/ # daily logs of what the agent did\n│ ├── 2026-03-26.md\n│ └── ...\n└── knowledge/ # learned patterns, best-practices (optional, agent can evolve)\n```\n\n### Lifecycle\n1. **Create agent** — `disinto init` or `disinto spawn-agent` creates Forgejo account + `.profile` repo\n2. **Copy formula** — current `formulas/{role}.toml` from disinto repo is copied to `.profile/formula.toml`\n3. **Agent reads its own formula** — at session start, agent reads from its `.profile`, not from the disinto repo\n4. **Agent writes journal** — daily entries pushed to `.profile/journal/`\n5. **Agent can evolve knowledge** — best-practices, heuristics, patterns written to `.profile/knowledge/`\n\n### What this enables\n\n**A/B testing formulas:** Create two agents from different formula versions, run both against the same backlog, compare results (cycle time, CI pass rate, review rejection rate).\n\n**Rollback:** New formula worse? Kill agent, spawn from older formula version.\n\n**Audit:** What formula was this agent running when it produced that PR? Check its `.profile` at that git commit.\n\n**Drift tracking:** Diff what an agent learned (`.profile/knowledge/`) vs what it started with. Measure formula evolution over time.\n\n**Portability:** Move agent to different box — `git clone` its `.profile`.\n\n### Disinto repo becomes the template\n\n```\ndisinto repo:\n formulas/dev-agent.toml ← canonical template, evolves\n formulas/review-agent.toml\n formulas/planner.toml\n ...\n\nRunning agents:\n dev-bot-v2/.profile/formula.toml ← snapshot from formulas/dev-agent.toml@v2\n dev-bot-v3/.profile/formula.toml ← snapshot from formulas/dev-agent.toml@v3\n review-bot/.profile/formula.toml ← snapshot from formulas/review-agent.toml\n```\n\nThe formula in the disinto repo is the template. The `.profile` copy is the instance. They can diverge — that's a feature, not a bug.\n\n## Affected files\n- `bin/disinto` — agent creation copies formula to .profile\n- Agent session scripts — read formula from .profile instead of local formulas/ dir\n- Planner/supervisor — can read other agents' journals from their .profile repos\n\n## Related\n- #747 — per-agent Forgejo accounts (prerequisite)\n- #757 — ops repo (shared concerns stay there: vault, portfolio, resources)\n\n## Acceptance criteria\n- [ ] `disinto spawn-agent` (or `disinto init`) creates a Forgejo account + `.profile` repo for each agent bot\n- [ ] Current `formulas/{role}.toml` is copied to `.profile/formula.toml` at agent creation time\n- [ ] Agent session script reads its formula from `.profile/formula.toml`, not from the repo's `formulas/` directory\n- [ ] Agent writes daily journal entries to `.profile/journal/YYYY-MM-DD.md`"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"action": "edit_body",
|
|
||||||
"issue": 742,
|
|
||||||
"body": "## Problem\n\n`gardener/recipes/*.toml` (4 files: cascade-rebase, chicken-egg-ci, flaky-test, shellcheck-violations) are an older pattern predating `formulas/*.toml`. Two systems for the same thing.\n\n## Fix\n\nMigrate any unique content from recipes to the gardener formula or to new formulas. Delete the recipes directory.\n\n## Affected files\n- `gardener/recipes/*.toml` — delete after migration\n- `formulas/run-gardener.toml` — absorb relevant content\n- Gardener scripts that reference recipes/\n\n## Acceptance criteria\n- [ ] Contents of `gardener/recipes/*.toml` are diff'd against `formulas/run-gardener.toml` — any unique content is migrated\n- [ ] `gardener/recipes/` directory is deleted\n- [ ] No scripts in `gardener/` reference the `recipes/` path after migration\n- [ ] ShellCheck passes on all modified scripts"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"action": "add_label",
|
|
||||||
"issue": 742,
|
|
||||||
"label": "backlog"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"action": "add_label",
|
|
||||||
"issue": 741,
|
|
||||||
"label": "backlog"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Shared Helpers (`lib/`)
|
# Shared Helpers (`lib/`)
|
||||||
|
|
||||||
All agents source `lib/env.sh` as their first action. Additional helpers are
|
All agents source `lib/env.sh` as their first action. Additional helpers are
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Planner Agent
|
# Planner Agent
|
||||||
|
|
||||||
**Role**: Strategic planning using a Prerequisite Tree (Theory of Constraints),
|
**Role**: Strategic planning using a Prerequisite Tree (Theory of Constraints),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Predictor Agent
|
# Predictor Agent
|
||||||
|
|
||||||
**Role**: Abstract adversary (the "goblin"). Runs a 2-step formula
|
**Role**: Abstract adversary (the "goblin"). Runs a 2-step formula
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Review Agent
|
# Review Agent
|
||||||
|
|
||||||
**Role**: AI-powered PR review — post structured findings and formal
|
**Role**: AI-powered PR review — post structured findings and formal
|
||||||
|
|
@ -9,7 +9,7 @@ whose CI has passed and that lack a review for the current HEAD SHA, then
|
||||||
spawns `review-pr.sh <pr-number>`.
|
spawns `review-pr.sh <pr-number>`.
|
||||||
|
|
||||||
**Key files**:
|
**Key files**:
|
||||||
- `review/review-poll.sh` — Cron scheduler: finds unreviewed PRs with passing CI. Sources `lib/guard.sh` and calls `check_active reviewer` — skips if `$FACTORY_ROOT/state/.reviewer-active` is absent.
|
- `review/review-poll.sh` — Cron scheduler: finds unreviewed PRs with passing CI. Sources `lib/guard.sh` and calls `check_active reviewer` — skips if `$FACTORY_ROOT/state/.reviewer-active` is absent. When injecting review into a dev session, first looks for a bot comment containing `<!-- reviewed: SHA -->`, then falls back to formal Forgejo PR reviews (state `APPROVED` or `REQUEST_CHANGES`) — ensures the dev-agent receives the verdict even when bot comments are absent.
|
||||||
- `review/review-pr.sh` — Creates/reuses a tmux session (`review-{project}-{pr}`), injects PR diff, waits for Claude to write structured JSON output, posts markdown review + formal forge review, auto-creates follow-up issues for pre-existing tech debt. Before starting the session, runs `lib/build-graph.py --changed-files <PR files>` and appends the JSON structural analysis (affected objectives, orphaned prerequisites, thin evidence) to the review prompt. Graph failures are non-fatal — review proceeds without it.
|
- `review/review-pr.sh` — Creates/reuses a tmux session (`review-{project}-{pr}`), injects PR diff, waits for Claude to write structured JSON output, posts markdown review + formal forge review, auto-creates follow-up issues for pre-existing tech debt. Before starting the session, runs `lib/build-graph.py --changed-files <PR files>` and appends the JSON structural analysis (affected objectives, orphaned prerequisites, thin evidence) to the review prompt. Graph failures are non-fatal — review proceeds without it.
|
||||||
|
|
||||||
**Environment variables consumed**:
|
**Environment variables consumed**:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Supervisor Agent
|
# Supervisor Agent
|
||||||
|
|
||||||
**Role**: Health monitoring and auto-remediation, executed as a formula-driven
|
**Role**: Health monitoring and auto-remediation, executed as a formula-driven
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- last-reviewed: f32707ba659de278a3af434e3549fb8a8dce9d3a -->
|
<!-- last-reviewed: 9b91c6a5bdd83513ca262dd468ea14db675971c1 -->
|
||||||
# Vault Agent
|
# Vault Agent
|
||||||
|
|
||||||
**Role**: Three-pipeline gate — action safety classification, resource procurement, and human-action drafting.
|
**Role**: Three-pipeline gate — action safety classification, resource procurement, and human-action drafting.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue