# formulas/run-gardener.toml — Gardener housekeeping formula # # Defines the gardener's complete run: grooming (Claude session via # gardener-agent.sh) + blocked-review + AGENTS.md maintenance + final # commit-and-pr. # # No memory, no journal. The gardener does mechanical housekeeping # based on current state — it doesn't need to remember past runs. # # Steps: preflight → grooming → blocked-review → agents-update → commit-and-pr name = "run-gardener" description = "Mechanical housekeeping: grooming, blocked review, docs update" version = 1 [context] files = ["AGENTS.md", "VISION.md", "README.md"] # ───────────────────────────────────────────────────────────────────── # Step 1: preflight # ───────────────────────────────────────────────────────────────────── [[steps]] id = "preflight" title = "Pull latest code" description = """ Set up the working environment for this gardener run. 1. Change to the project repository: cd "$PROJECT_REPO_ROOT" 2. Pull the latest code: git fetch origin "$PRIMARY_BRANCH" --quiet git checkout "$PRIMARY_BRANCH" --quiet git pull --ff-only origin "$PRIMARY_BRANCH" --quiet 3. Record the current HEAD SHA for AGENTS.md watermarks: HEAD_SHA=$(git rev-parse HEAD) echo "$HEAD_SHA" > /tmp/gardener-head-sha """ # ───────────────────────────────────────────────────────────────────── # Step 2: grooming — Claude-driven backlog grooming # ───────────────────────────────────────────────────────────────────── [[steps]] id = "grooming" title = "Backlog grooming — triage all open issues" description = """ Groom the open issue backlog. This step is the core Claude-driven analysis (currently implemented in gardener-agent.sh with bash pre-checks). Pre-checks (bash, zero tokens — detect problems before invoking Claude): 1. Fetch all open issues: curl -sf -H "Authorization: token $CODEBERG_TOKEN" \ "$CODEBERG_API/issues?state=open&type=issues&limit=50&sort=updated&direction=desc" 2. Duplicate detection: compare issue titles pairwise. Normalize (lowercase, strip prefixes like feat:/fix:/refactor:, collapse whitespace) and flag pairs with >60% word overlap as possible duplicates. 3. Missing acceptance criteria: flag issues with body < 100 chars and no checkboxes (- [ ] or - [x]). 4. Stale issues: flag issues with no update in 14+ days. 5. Blockers starving the factory (HIGHEST PRIORITY): find issues that block backlog items but are NOT themselves labeled backlog. These starve the dev-agent completely. Extract deps from ## Dependencies / ## Depends on / ## Blocked by sections of backlog issues and check if each dependency is open + not backlog-labeled. 6. Tech-debt promotion: list all tech-debt labeled issues — goal is to process them all (promote to backlog or classify as dust). For each issue, choose ONE action and write to result file: ACTION (substantial — promote, close duplicate, add acceptance criteria): echo "ACTION: promoted #NNN to backlog — " >> "$RESULT_FILE" echo "ACTION: closed #NNN as duplicate of #OLDER" >> "$RESULT_FILE" DUST (trivial — single-line edit, rename, comment, style, whitespace): echo 'DUST: {"issue": NNN, "group": "", "title": "...", "reason": "..."}' >> "$RESULT_FILE" Group by file or subsystem (e.g. "gardener", "lib/env.sh", "dev-poll"). Do NOT close dust issues — the script auto-bundles groups of 3+ into one backlog issue. ESCALATE (needs human decision): printf 'ESCALATE\n1. #NNN "title" — reason (a) option1 (b) option2\n' >> "$RESULT_FILE" CLEAN (only if truly nothing to do): echo 'CLEAN' >> "$RESULT_FILE" Dust vs ore rules: Dust: comment fix, variable rename, whitespace/formatting, single-line edit, trivial cleanup with no behavior change Ore: multi-file changes, behavioral fixes, architectural improvements, security/correctness issues Sibling dependency rule (CRITICAL): Issues from the same PR review or code audit are SIBLINGS — independent work items. NEVER add bidirectional ## Dependencies between siblings (creates deadlocks). Use ## Related for cross-references: "## Related\n- #NNN (sibling)" Processing order: 1. Handle PRIORITY_blockers_starving_factory first — promote or resolve 2. Process tech-debt issues by score (impact/effort) 3. Classify remaining items as dust or escalate After processing, dust items are collected into gardener/dust.jsonl. When a group accumulates 3+ distinct issues, create one bundled backlog issue, close the source issues with cross-reference comments, and remove bundled items from the staging file. CRITICAL: If this step fails for any reason, log the failure and move on. """ needs = ["preflight"] # ───────────────────────────────────────────────────────────────────── # Step 3: blocked-review — triage blocked issues # ───────────────────────────────────────────────────────────────────── [[steps]] id = "blocked-review" title = "Review issues labeled blocked" description = """ Review all issues labeled 'blocked' and decide their fate. (See issue #352 for the blocked label convention.) 1. Look up the 'blocked' label ID (Gitea needs integer IDs for label removal): BLOCKED_LABEL_ID=$(curl -sf -H "Authorization: token $CODEBERG_TOKEN" \ "$CODEBERG_API/labels" | jq -r '.[] | select(.name == "blocked") | .id') If the lookup fails, skip label removal and just post comments. 2. Fetch all blocked issues: curl -sf -H "Authorization: token $CODEBERG_TOKEN" \ "$CODEBERG_API/issues?state=open&type=issues&labels=blocked&limit=50" 3. For each blocked issue, read the full body and comments: curl -sf -H "Authorization: token $CODEBERG_TOKEN" \ "$CODEBERG_API/issues/" curl -sf -H "Authorization: token $CODEBERG_TOKEN" \ "$CODEBERG_API/issues//comments" 4. Check dependencies — extract issue numbers from ## Dependencies / ## Depends on / ## Blocked by sections. For each dependency: curl -sf -H "Authorization: token $CODEBERG_TOKEN" \ "$CODEBERG_API/issues/" Check if the dependency is now closed. 5. For each blocked issue, choose ONE action: UNBLOCK — all dependencies are now closed or the blocking condition resolved: a. Remove the 'blocked' label (using ID from step 1): curl -sf -X DELETE -H "Authorization: token $CODEBERG_TOKEN" \ "$CODEBERG_API/issues//labels/$BLOCKED_LABEL_ID" b. Add context comment explaining what changed: curl -sf -X POST -H "Authorization: token $CODEBERG_TOKEN" \ -H "Content-Type: application/json" \ "$CODEBERG_API/issues//comments" \ -d '{"body":"Unblocked: "}' NEEDS HUMAN — blocking condition is ambiguous, requires architectural decision, or involves external factors: a. Post a diagnostic comment explaining what you found and what decision is needed b. Leave the 'blocked' label in place CLOSE — issue is stale (blocked 30+ days with no progress on blocker), the blocker is wontfix, or the issue is no longer relevant: a. Post a comment explaining why: curl -sf -X POST -H "Authorization: token $CODEBERG_TOKEN" \ -H "Content-Type: application/json" \ "$CODEBERG_API/issues//comments" \ -d '{"body":"Closing: "}' b. Close the issue: curl -sf -X PATCH -H "Authorization: token $CODEBERG_TOKEN" \ -H "Content-Type: application/json" \ "$CODEBERG_API/issues/" \ -d '{"state":"closed"}' CRITICAL: If this step fails, log the failure and move on. """ needs = ["grooming"] # ───────────────────────────────────────────────────────────────────── # Step 4: agents-update — AGENTS.md watermark staleness check # ───────────────────────────────────────────────────────────────────── [[steps]] id = "agents-update" title = "Check AGENTS.md watermarks, update stale files" description = """ Check all AGENTS.md files for staleness and update any that are outdated. This keeps documentation fresh — runs 2x/day so drift stays small. 1. Read the HEAD SHA from preflight: HEAD_SHA=$(cat /tmp/gardener-head-sha) 2. Find all AGENTS.md files: find "$PROJECT_REPO_ROOT" -name "AGENTS.md" -not -path "*/.git/*" 3. For each file, read the watermark from line 1: 4. Check for changes since the watermark: git log --oneline ..HEAD -- If zero changes, the file is current — skip it. 5. For stale files: - Read the AGENTS.md and the source files in that directory - Update the documentation to reflect code changes since the watermark - Set the watermark to the HEAD SHA from the preflight step - Conventions: max ~200 lines, architecture and WHY not implementation details 6. Stage ONLY the AGENTS.md files you changed — do NOT commit yet. All git writes happen in the commit-and-pr step at the end. 7. If no AGENTS.md files need updating, skip this step entirely. CRITICAL: If this step fails for any reason, log the failure and move on. Do NOT let an AGENTS.md failure prevent the commit-and-pr step. """ needs = ["blocked-review"] # ───────────────────────────────────────────────────────────────────── # Step 6: commit-and-pr — single commit with all file changes # ───────────────────────────────────────────────────────────────────── [[steps]] id = "commit-and-pr" title = "One commit with all file changes, push, create PR" description = """ Collect all file changes from this run (AGENTS.md updates) into a single commit. API calls (issue creation, PR comments, closures) already happened during the run — only file changes need the PR. 1. Check for staged or unstaged changes: cd "$PROJECT_REPO_ROOT" git status --porcelain If there are no file changes, skip this entire step — no commit, no PR. 2. If there are changes: a. Create a branch: BRANCH="chore/gardener-$(date -u +%Y%m%d-%H%M)" git checkout -B "$BRANCH" b. Stage all modified AGENTS.md files: find . -name "AGENTS.md" -not -path "./.git/*" -exec git add {} + c. Also stage any other files the gardener modified (if any): git add -u d. Commit: git commit -m "chore: gardener housekeeping $(date -u +%Y-%m-%d)" e. Push: git push -u origin "$BRANCH" f. Create a PR: curl -sf -X POST \ -H "Authorization: token $CODEBERG_TOKEN" \ -H "Content-Type: application/json" \ "$CODEBERG_API/pulls" \ -d '{"title":"chore: gardener housekeeping", "head":"","base":"", "body":"Automated gardener housekeeping — AGENTS.md updates.\n\nReview-agent fast-tracks doc-only PRs."}' g. Return to primary branch: git checkout "$PRIMARY_BRANCH" 3. If the PR creation fails (e.g. no changes after staging), log and continue. """ needs = ["agents-update"]