From 0937707fe53f74a3dc40b0f5085f6344578f6240 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Apr 2026 18:16:44 +0000 Subject: [PATCH] chore: gardener housekeeping 2026-04-15 --- AGENTS.md | 4 +- gardener/AGENTS.md | 2 +- gardener/pending-actions.json | 90 +++++++++++++++++++---------------- lib/AGENTS.md | 4 +- planner/AGENTS.md | 2 +- predictor/AGENTS.md | 2 +- review/AGENTS.md | 2 +- supervisor/AGENTS.md | 2 +- 8 files changed, 58 insertions(+), 50 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2fafde4..7db1e96 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ - + # Disinto — Agent Instructions ## What this repo is @@ -188,8 +188,6 @@ Humans write these. Agents read and enforce them. - **Dev-agent** reads AGENTS.md before implementing; refuses work that violates ADs. - **AD-002 is a runtime invariant; nothing for the gardener to check at issue-groom time.** OAuth concurrency is handled by per-session `CLAUDE_CONFIG_DIR` isolation (with `CLAUDE_EXTERNAL_LOCK` as a rollback flag). Per-issue work is enforced by `issue_claim`. A violation manifests as a 401 or VRAM OOM in agent logs, not as a malformed issue. ---- - ## Phase-Signaling Protocol When running as a persistent tmux session, Claude must signal the orchestrator diff --git a/gardener/AGENTS.md b/gardener/AGENTS.md index 2661859..b177774 100644 --- a/gardener/AGENTS.md +++ b/gardener/AGENTS.md @@ -1,4 +1,4 @@ - + # Gardener Agent **Role**: Backlog grooming — detect duplicate issues, missing acceptance diff --git a/gardener/pending-actions.json b/gardener/pending-actions.json index 84caa73..e619a80 100644 --- a/gardener/pending-actions.json +++ b/gardener/pending-actions.json @@ -1,52 +1,62 @@ [ + { + "action": "edit_body", + "issue": 784, + "body": "Flagged by AI reviewer in PR #783.\n\n## Problem\n\n`_regen_file()` (added in PR #783, `bin/disinto` ~line 1424) moves the existing target file to a temp stash before calling the generator:\n\n```bash\nmv \"$target\" \"$stashed\"\n\"$generator\" \"$@\"\n```\n\nThe script runs under `set -euo pipefail`. If the generator exits non-zero, bash exits immediately and the original file remains stranded at `${target}.stash.XXXXXX` (never restored). The target file no longer exists, and `docker compose up` is never reached. Recovery requires the operator to manually locate and rename the hidden stash file.\n\n## Fix\n\nAdd an ERR trap inside `_regen_file` to restore the stash on failure, e.g.:\n```bash\n\"$generator\" \"$@\" || { mv \"$stashed\" \"$target\"; return 1; }\n```\n\n---\n*Auto-created from AI review*\n\n## Acceptance criteria\n\n- [ ] If the generator exits non-zero, the original target file is restored from the stash (not stranded at the temp path)\n- [ ] `_regen_file` still removes the stash file after a successful generator run\n- [ ] `docker compose up` is reached when the generator succeeds\n- [ ] ShellCheck passes on `bin/disinto`\n\n## Affected files\n\n- `bin/disinto` — `_regen_file()` function (~line 1424)\n" + }, + { + "action": "add_label", + "issue": 784, + "label": "backlog" + }, { "action": "remove_label", - "issue": 771, - "label": "backlog" - }, - { - "action": "edit_body", - "issue": 771, - "body": "## Symptom\n\n`docker/Caddyfile` is tracked in git with legacy content (`/forgejo/*` path). `lib/generators.sh` has a `generate_caddyfile` function that emits a different Caddyfile with `/forge/*` (post-#704 vision), `/ci/*`, `/staging/*`, and conditional `/chat/*` blocks when `EDGE_TUNNEL_FQDN` is set.\n\nBoth files exist. The edge container's compose block mounts `./docker/Caddyfile:/etc/caddy/Caddyfile`, so the **static** file is what actually serves traffic today. The generated file is written to a different path and effectively unused until someone rewires the mount.\n\nThis means:\n\n- Changes to the generator's Caddy block are invisible to running stacks (same drift class as #C).\n- The static file's `/forgejo/*` naming contradicts #704's `/forge/*` convention — anyone reading the vision will be confused by the real system.\n- Two places for the same configuration invites one-side-only edits.\n\n## Fix\n\nSingle source of truth: the file `generate_caddyfile` produces.\n\n1. Delete tracked `docker/Caddyfile`.\n2. Update `generate_caddyfile` to write to `docker/Caddyfile` (or a well-known path like `state/caddyfile/Caddyfile`, decide based on which side of the ignore/commit line fits the project) — whichever path the edge compose block mounts.\n3. Add the output path to `.gitignore` so it's a generated artifact, not tracked.\n4. Confirm `lib/generators.sh`'s compose block mounts the generator output path.\n5. Update `disinto init` flow: if a fresh init runs `generate_caddyfile` and `generate_compose` in the right order, the first `disinto up` already has a working Caddy. Document this ordering in `docs/commands.md` or equivalent.\n\n## Acceptance criteria\n\n- [ ] `docker/Caddyfile` is removed from git (no tracked static version)\n- [ ] `generate_caddyfile` writes to a single, documented output path; that path is what the edge compose block mounts\n- [ ] `.gitignore` excludes the generated Caddyfile path\n- [ ] After `disinto init` on a fresh clone, the edge container starts and serves the generator's Caddyfile — not a stale static one\n- [ ] `grep -rn \"/forgejo/\\*\" docker/` returns nothing — convention is consistently `/forge/*` everywhere\n- [ ] CI green\n\n## Note\n\nThis is independent of children A / B / C — can land whenever. No blocking dependency.\n\n## Affected files\n- `docker/Caddyfile` — delete (tracked static file to be removed)\n- `lib/generators.sh` — update `generate_caddyfile` to write to the edge-mounted path\n- `.gitignore` — exclude the generated Caddyfile path\n- `bin/disinto` — ensure `disinto init` calls `generate_caddyfile` in correct order\n- `docs/commands.md` — document Caddyfile generation ordering (if file exists)\n" + "issue": 773, + "label": "blocked" }, { "action": "add_label", - "issue": 771, - "label": "backlog" - }, - { - "action": "edit_body", - "issue": 776, - "body": "## Problem\n\n`disinto secrets add NAME` uses `IFS= read -rs value` — TTY-only, cannot be piped. No automation path for multi-line key material (SSH keys, PEM, TLS certs). Every rent-a-human formula that needs to hand a secret to the factory currently requires either the interactive editor (`edit-vault`) or writing a plaintext file to disk first.\n\nConcrete blocker: importing `CADDY_SSH_KEY` for collect-engagement (#745) into the factory's secret store, ahead of starting the edge container.\n\n## Proposed solution\n\nMake stdin detection the dispatch inside `disinto_secrets() → add)`:\n\n- stdin is a TTY → prompt as today (preserves interactive use)\n- stdin is a pipe/redirect → read raw bytes verbatim, no prompt, no echo\n\nInvocations:\n\n```\ncat ~/caddy-collect | disinto secrets add CADDY_SSH_KEY\ndisinto secrets add CADDY_SSH_KEY < ~/caddy-collect\necho 159.89.14.107 | disinto secrets add CADDY_SSH_HOST\n```\n\nNo `--from-file` / `--from-stdin` flag ceremony. One flag exception: `--force` / `-f` to suppress the overwrite prompt for scripted upserts.\n\n## Acceptance criteria\n- [ ] Piped multi-line input stored verbatim; `disinto secrets show CADDY_SSH_KEY` round-trips byte-for-byte (diff against the source file is empty, including trailing newline)\n- [ ] TTY invocation unchanged (prompt + hidden read)\n- [ ] `-f` / `--force` skips overwrite confirmation\n- [ ] Stdin reading uses `cat` / `IFS= read -d ''` — NOT `read -rs` which strips characters\n\n## Affected files\n- `bin/disinto` — `disinto_secrets()` `add)` branch around line 1167\n\n## Context\n- `bin/disinto` → `disinto_secrets()` around line 1167 (`add)` branch).\n- Parent: sprint PR `disinto-admin/disinto-ops#10` (website-observability-wire-up).\n- Unblocks: issue C (#778 rent-a-human-caddy-ssh.toml fix).\n" - }, - { - "action": "add_label", - "issue": 776, - "label": "backlog" - }, - { - "action": "edit_body", - "issue": 777, - "body": "## Problem\n\nTwo parallel secret stores:\n\n1. `secrets/.enc` — per-key, age-encrypted. Populated by `disinto secrets add`. **No runtime consumer today.** Only `disinto secrets show` ever decrypts these.\n2. `.env.vault.enc` — monolithic, sops/dotenv-encrypted. The only store actually loaded into containers (via `docker/edge/dispatcher.sh` → `sops -d --output-type dotenv`).\n\nTwo mental models, redundant subcommands (`edit-vault`, `show-vault`, `migrate-vault`), and today`s `disinto secrets add` silently deposits secrets into a dead-letter directory. Operator runs the command, edge container still logs `CADDY_SSH_KEY not set, skipping` (docker/edge/entrypoint-edge.sh:207).\n\n## Proposed solution\n\nConsolidate on `secrets/.enc` as THE store. One file per secret, granular, small surface.\n\n**1. Wire container dispatchers to load `secrets/*.enc` into env**\n- `docker/edge/dispatcher.sh` (and agent / ops dispatchers) decrypt declared secrets at startup and export them.\n- Granular per-secret — not a bulk dump.\n\n**2. Containers declare required secrets**\n- `secrets.required = [\"CADDY_SSH_KEY\", \"CADDY_SSH_HOST\", ...]` in the container's TOML, or equivalent in compose.\n- Missing required secret → **hard fail** with clear message. Replaces today's silent-skip branch at `entrypoint-edge.sh:207`.\n\n**3. Deprecate the monolithic vault**\n- Remove `.env.vault`, `.env.vault.enc`, and subcommands `edit-vault` / `show-vault` / `migrate-vault` from `bin/disinto`.\n- Remove sops round-trip from `docker/edge/dispatcher.sh` (lines 32-40 currently).\n\n**4. One-shot migration for existing operators**\n- `disinto secrets migrate-from-vault` splits an existing `.env.vault.enc` into `secrets/.enc` files, verifies each, then removes the old vault on success.\n- Idempotent: safe to run multiple times.\n\n## Acceptance criteria\n- [ ] Edge container declares `secrets.required = [\"CADDY_SSH_KEY\", \"CADDY_SSH_HOST\", \"CADDY_SSH_USER\", \"CADDY_ACCESS_LOG\"]`. Dispatcher exports them. `collect-engagement.sh` runs without additional env wiring.\n- [ ] Container refuses to start when a required secret is missing (fail loudly, not skip silently)\n- [ ] `.env.vault*` files and all vault-specific subcommands removed from `bin/disinto` and all formulas / docs\n- [ ] `migrate-from-vault` converts an existing monolithic vault correctly (verified by round-trip test)\n- [ ] `disinto secrets` help text shows one store, four verbs: `add`, `show`, `remove`, `list`\n\n## Affected files\n- `bin/disinto` — `disinto_secrets()`: wire stdin to `secrets/.enc`, add `migrate-from-vault` subcommand, remove `edit-vault`/`show-vault`/`migrate-vault`\n- `docker/edge/dispatcher.sh` — replace sops round-trip (lines 32-40) with per-secret decryption from `secrets/*.enc`\n- `docker/edge/entrypoint-edge.sh` — replace silent-skip branch at line 207 with hard fail on missing required secrets\n\n## Dependencies\n- #776 (piped stdin for `disinto secrets add` must land before deprecating `edit-vault`)\n\n## Context\n- Parent: sprint PR `disinto-admin/disinto-ops#10`.\n- Rationale (operator quote): \"containers should have option to load single secrets, granular. no 2 mental models, only 1 thing that works well and has small surface.\"\n" - }, - { - "action": "add_label", - "issue": 777, - "label": "backlog" - }, - { - "action": "edit_body", - "issue": 778, - "body": "## Problem\n\n`formulas/rent-a-human-caddy-ssh.toml` step 3 tells the operator:\n\n```\necho \"CADDY_SSH_KEY=$(base64 -w0 caddy-collect)\" >> .env.vault.enc\n```\n\n**You cannot append plaintext to a sops-encrypted file.** The append silently corrupts `.env.vault.enc` — subsequent `sops -d` fails, all vault secrets become unrecoverable. Any operator who followed the docs verbatim has broken their vault.\n\nSteps 4 (`CADDY_HOST`) and 5 (`CADDY_ACCESS_LOG`) have the same bug.\n\n## Proposed fix\n\nRewrite the `>>` steps to use the stdin-piped `disinto secrets add` (from issue #776):\n\n```\ncat caddy-collect | disinto secrets add CADDY_SSH_KEY\necho '159.89.14.107' | disinto secrets add CADDY_SSH_HOST\necho 'debian' | disinto secrets add CADDY_SSH_USER\necho '/var/log/caddy/access.log' | disinto secrets add CADDY_ACCESS_LOG\n```\n\nAlso:\n- Remove the `base64 -w0` step — the new `secrets add` stores multi-line keys verbatim.\n- Remove the `shred -u caddy-collect` step from the happy path — let the operator keep the backup until they've verified the edge container picks it up.\n- Add a recovery note: operators with a corrupted vault from the old docs must `rm .env.vault.enc` (or `migrate-from-vault` if issue #777 landed) before re-running.\n\n## Acceptance criteria\n- [ ] Formula runs end-to-end without touching `.env.vault.enc` or `.env.vault` by hand\n- [ ] Re-running is idempotent (upsert via `disinto secrets add -f`)\n- [ ] Edge container starts cleanly with the imported secrets and the daily collect-engagement cron fires without `\"CADDY_SSH_KEY not set, skipping\"`\n- [ ] Recovery note present in formula for operators with corrupted vault\n\n## Affected files\n- `formulas/rent-a-human-caddy-ssh.toml` — rewrite steps 3-5 to use `disinto secrets add` instead of `>>` append to encrypted file\n\n## Dependencies\n- #776 (piped stdin for `disinto secrets add` must land first)\n\n## Context\n- Parent: sprint PR `disinto-admin/disinto-ops#10`.\n- Soft-depends on: #777 (if landed, drop all `.env.vault*` references entirely).\n" - }, - { - "action": "add_label", - "issue": 778, + "issue": 773, "label": "backlog" }, { "action": "comment", - "issue": 758, - "body": "Vault item filed: [disinto-ops#33](http://forgejo:3000/disinto-admin/disinto-ops/pulls/33) — admin action required to unblock ops repo merges. Choose one of: (1) add planner-bot to merge allowlist in branch protection, (2) remove branch protection from disinto-ops main, or (3) create FORGE_ADMIN_TOKEN. See vault PR for details.\n" + "issue": 772, + "body": "All child issues have been resolved:\n- #768 (edge restart policy) — closed\n- #769 (agents-llama generator service) — closed\n- #770 (disinto up regenerate) — closed\n- #771 (deprecate docker/Caddyfile) — closed\n\nClosing tracker as all decomposed work is complete." + }, + { + "action": "close", + "issue": 772, + "reason": "all child issues 768-771 closed" + }, + { + "action": "edit_body", + "issue": 778, + "body": "## Problem\n\n`formulas/rent-a-human-caddy-ssh.toml` step 3 tells the operator:\n\n```\necho \"CADDY_SSH_KEY=$(base64 -w0 caddy-collect)\" >> .env.vault.enc\n```\n\n**You cannot append plaintext to a sops-encrypted file.** The append silently corrupts `.env.vault.enc` — subsequent `sops -d` fails, all vault secrets become unrecoverable. Any operator who followed the docs verbatim has broken their vault.\n\nSteps 4 (`CADDY_HOST`) and 5 (`CADDY_ACCESS_LOG`) have the same bug.\n\n## Proposed fix\n\nRewrite the `>>` steps to use the stdin-piped `disinto secrets add` (from issue A):\n\n```\ncat caddy-collect | disinto secrets add CADDY_SSH_KEY\necho '159.89.14.107' | disinto secrets add CADDY_SSH_HOST\necho 'debian' | disinto secrets add CADDY_SSH_USER\necho '/var/log/caddy/access.log' | disinto secrets add CADDY_ACCESS_LOG\n```\n\nAlso:\n- Remove the `base64 -w0` step — the new `secrets add` stores multi-line keys verbatim.\n- Remove the `shred -u caddy-collect` step from the happy path — let the operator keep the backup until they have verified the edge container picks it up.\n- Add a recovery note: operators with a corrupted vault from the old docs must `rm .env.vault.enc` (or `migrate-from-vault` if issue B landed) before re-running.\n\n## Context\n\n- Parent: sprint PR `disinto-admin/disinto-ops#10`.\n- Depends on: #776 (piped `secrets add`) — now closed.\n- Soft-depends on: #777 (if landed, drop all `.env.vault*` references entirely).\n\n## Acceptance criteria\n\n- [ ] Formula runs end-to-end without touching `.env.vault.enc` or `.env.vault` by hand\n- [ ] Re-running is idempotent (upsert via `disinto secrets add -f`)\n- [ ] Edge container starts cleanly with the imported secrets and the daily collect-engagement cron fires without `\"CADDY_SSH_KEY not set, skipping\"`\n\n## Affected files\n\n- `formulas/rent-a-human-caddy-ssh.toml` — replace `>> .env.vault.enc` steps with `disinto secrets add` calls\n" + }, + { + "action": "remove_label", + "issue": 778, + "label": "blocked" + }, + { + "action": "add_label", + "issue": 778, + "label": "backlog" + }, + { + "action": "edit_body", + "issue": 777, + "body": "## Problem\n\nTwo parallel secret stores:\n\n1. `secrets/.enc` — per-key, age-encrypted. Populated by `disinto secrets add`. **No runtime consumer today.** Only `disinto secrets show` ever decrypts these.\n2. `.env.vault.enc` — monolithic, sops/dotenv-encrypted. The only store actually loaded into containers (via `docker/edge/dispatcher.sh` → `sops -d --output-type dotenv`).\n\nTwo mental models, redundant subcommands (`edit-vault`, `show-vault`, `migrate-vault`), and today's `disinto secrets add` silently deposits secrets into a dead-letter directory. Operator runs the command, edge container still logs `CADDY_SSH_KEY not set, skipping` (docker/edge/entrypoint-edge.sh:207).\n\n## Proposed solution\n\nConsolidate on `secrets/.enc` as THE store. One file per secret, granular, small surface.\n\n**1. Wire container dispatchers to load `secrets/*.enc` into env**\n\n- `docker/edge/dispatcher.sh` (and agent / ops dispatchers) decrypt declared secrets at startup and export them.\n- Granular per-secret — not a bulk dump.\n\n**2. Containers declare required secrets**\n\n- `secrets.required = [\"CADDY_SSH_KEY\", \"CADDY_SSH_HOST\", ...]` in the container's TOML, or equivalent in compose.\n- Missing required secret → **hard fail** with clear message. Replaces today's silent-skip branch at `entrypoint-edge.sh:207`.\n\n**3. Deprecate the monolithic vault**\n\n- Remove `.env.vault`, `.env.vault.enc`, and subcommands `edit-vault` / `show-vault` / `migrate-vault` from `bin/disinto`.\n- Remove sops round-trip from `docker/edge/dispatcher.sh` (lines 32-40 currently).\n\n**4. One-shot migration for existing operators**\n\n- `disinto secrets migrate-from-vault` splits an existing `.env.vault.enc` into `secrets/.enc` files, verifies each, then removes the old vault on success.\n- Idempotent: safe to run multiple times.\n\n## Context\n\n- Parent: sprint PR `disinto-admin/disinto-ops#10`.\n- Depends on: #776 (`secrets add` must accept piped stdin before we can deprecate `edit-vault`) — now closed.\n- Rationale (operator quote): *\"containers should have option to load single secrets, granular. no 2 mental models, only 1 thing that works well and has small surface.\"*\n\n## Acceptance criteria\n\n- [ ] Edge container declares `secrets.required = [\"CADDY_SSH_KEY\", \"CADDY_SSH_HOST\", \"CADDY_SSH_USER\", \"CADDY_ACCESS_LOG\"]`; dispatcher exports them; `collect-engagement.sh` runs without additional env wiring\n- [ ] Container refuses to start when a required secret is missing (fail loudly, not skip silently)\n- [ ] `.env.vault*` files and all vault-specific subcommands removed from `bin/disinto` and all formulas / docs\n- [ ] `migrate-from-vault` converts an existing monolithic vault correctly (verified by round-trip test)\n- [ ] `disinto secrets` help text shows one store, four verbs: `add`, `show`, `remove`, `list`\n\n## Affected files\n\n- `bin/disinto` — remove `edit-vault`, `show-vault`, `migrate-vault` subcommands; add `migrate-from-vault`\n- `docker/edge/dispatcher.sh` — replace sops round-trip with per-secret age decryption (lines 32-40)\n- `docker/edge/entrypoint-edge.sh` — replace silent-skip at line 207 with hard fail on missing required secrets\n- `lib/vault.sh` — update or remove vault-env.sh wiring now that `.env.vault.enc` is deprecated\n" + }, + { + "action": "remove_label", + "issue": 777, + "label": "blocked" + }, + { + "action": "add_label", + "issue": 777, + "label": "backlog" } ] diff --git a/lib/AGENTS.md b/lib/AGENTS.md index ce6d52a..a611313 100644 --- a/lib/AGENTS.md +++ b/lib/AGENTS.md @@ -1,4 +1,4 @@ - + # Shared Helpers (`lib/`) All agents source `lib/env.sh` as their first action. Additional helpers are @@ -30,7 +30,7 @@ sourced as needed. | `lib/git-creds.sh` | Shared git credential helper configuration. `configure_git_creds([HOME_DIR] [RUN_AS_CMD])` — writes a static credential helper script and configures git globally to use password-based HTTP auth (Forgejo 11.x rejects API tokens for `git push`, #361). **Retry on cold boot (#741)**: resolves bot username from `FORGE_TOKEN` with 5 retries (exponential backoff 1-5s); fails loudly and returns 1 if Forgejo is unreachable — never falls back to a wrong hardcoded default (exports `BOT_USER` on success). `repair_baked_cred_urls([--as RUN_AS_CMD] DIR ...)` — rewrites any git remote URLs that have credentials baked in to use clean URLs instead; uses `safe.directory` bypass for root-owned repos (#671). Requires `FORGE_PASS`, `FORGE_URL`, `FORGE_TOKEN`. | entrypoints (agents, edge) | | `lib/ops-setup.sh` | `setup_ops_repo()` — creates ops repo on Forgejo if it doesn't exist, configures bot collaborators, clones/initializes ops repo locally, seeds directory structure (vault, knowledge, evidence, sprints). Evidence subdirectories seeded: engagement/, red-team/, holdout/, evolution/, user-test/. Also seeds sprints/ for architect output. Exports `_ACTUAL_OPS_SLUG`. `migrate_ops_repo(ops_root, [primary_branch])` — idempotent migration helper that seeds missing directories and .gitkeep files on existing ops repos (pre-#407 deployments). | bin/disinto (init) | | `lib/ci-setup.sh` | `_install_cron_impl()` — installs crontab entries for bare-metal deployments (compose mode uses polling loop instead). `_create_forgejo_oauth_app()` — generic helper to create an OAuth2 app on Forgejo (shared by Woodpecker and chat). `_create_woodpecker_oauth_impl()` — creates Woodpecker OAuth2 app (thin wrapper). `_create_chat_oauth_impl()` — creates disinto-chat OAuth2 app, writes `CHAT_OAUTH_CLIENT_ID`/`CHAT_OAUTH_CLIENT_SECRET` to `.env` (#708). `_generate_woodpecker_token_impl()` — auto-generates WOODPECKER_TOKEN via OAuth2 flow. `_activate_woodpecker_repo_impl()` — activates repo in Woodpecker. All gated by `_load_ci_context()` which validates required env vars. | bin/disinto (init) | -| `lib/generators.sh` | Template generation for `disinto init`: `generate_compose()` — docker-compose.yml (uses `codeberg.org/forgejo/forgejo:11.0` tag; adds `security_opt: [apparmor:unconfined]` to all services for rootless container compatibility; Forgejo includes a healthcheck so dependent services use `condition: service_healthy` — fixes cold-start races, #665; adds `chat` service block with isolated `chat-config` named volume and `CHAT_HISTORY_DIR` bind-mount for per-user NDJSON history persistence (#710); injects `FORWARD_AUTH_SECRET` for Caddy↔chat defense-in-depth auth (#709); cost-cap env vars `CHAT_MAX_REQUESTS_PER_HOUR`, `CHAT_MAX_REQUESTS_PER_DAY`, `CHAT_MAX_TOKENS_PER_DAY` (#711); subdomain fallback comment for `EDGE_TUNNEL_FQDN_*` vars (#713); all `depends_on` now use `condition: service_healthy/started` instead of bare service names; all services now include `restart: unless-stopped` including the edge service — #768), `generate_caddyfile()` — Caddyfile (routes: `/forge/*` → forgejo:3000, `/woodpecker/*` → woodpecker:8000, `/staging/*` → staging:80; `/chat/login` and `/chat/oauth/callback` bypass `forward_auth` so unauthenticated users can reach the OAuth flow; `/chat/*` gated by `forward_auth` on `chat:8080/chat/auth/verify` which stamps `X-Forwarded-User` (#709); root `/` redirects to `/forge/`), `generate_staging_index()` — staging index, `generate_deploy_pipelines()` — Woodpecker deployment pipeline configs. Requires `FACTORY_ROOT`, `PROJECT_NAME`, `PRIMARY_BRANCH`. | bin/disinto (init) | +| `lib/generators.sh` | Template generation for `disinto init`: `generate_compose()` — docker-compose.yml (uses `codeberg.org/forgejo/forgejo:11.0` tag; adds `security_opt: [apparmor:unconfined]` to all services for rootless container compatibility; Forgejo includes a healthcheck so dependent services use `condition: service_healthy` — fixes cold-start races, #665; adds `chat` service block with isolated `chat-config` named volume and `CHAT_HISTORY_DIR` bind-mount for per-user NDJSON history persistence (#710); injects `FORWARD_AUTH_SECRET` for Caddy↔chat defense-in-depth auth (#709); cost-cap env vars `CHAT_MAX_REQUESTS_PER_HOUR`, `CHAT_MAX_REQUESTS_PER_DAY`, `CHAT_MAX_TOKENS_PER_DAY` (#711); subdomain fallback comment for `EDGE_TUNNEL_FQDN_*` vars (#713); all `depends_on` now use `condition: service_healthy/started` instead of bare service names; all services now include `restart: unless-stopped` including the edge service — #768; agents service now uses `image: ghcr.io/disinto/agents:${DISINTO_IMAGE_TAG:-latest}` instead of `build:` (#429); `WOODPECKER_PLUGINS_PRIVILEGED` env var added to woodpecker service (#779); agents-llama conditional block gated on `ENABLE_LLAMA_AGENT=1` (#769); agents service gains volume mounts for `./projects`, `./.env`, `./state`), `generate_caddyfile()` — Caddyfile (routes: `/forge/*` → forgejo:3000, `/woodpecker/*` → woodpecker:8000, `/staging/*` → staging:80; `/chat/login` and `/chat/oauth/callback` bypass `forward_auth` so unauthenticated users can reach the OAuth flow; `/chat/*` gated by `forward_auth` on `chat:8080/chat/auth/verify` which stamps `X-Forwarded-User` (#709); root `/` redirects to `/forge/`), `generate_staging_index()` — staging index, `generate_deploy_pipelines()` — Woodpecker deployment pipeline configs. Requires `FACTORY_ROOT`, `PROJECT_NAME`, `PRIMARY_BRANCH`. | bin/disinto (init) | | `lib/sprint-filer.sh` | Post-merge sub-issue filer for sprint PRs. Invoked by the `.woodpecker/ops-filer.yml` pipeline after a sprint PR merges to ops repo `main`. Parses ` ... ` blocks from sprint PR bodies to extract sub-issue definitions, creates them on the project repo using `FORGE_FILER_TOKEN` (narrow-scope `filer-bot` identity with `issues:write` only), adds `in-progress` label to the parent vision issue, and handles vision lifecycle closure when all sub-issues are closed. Uses `filer_api_all()` for paginated fetches. Idempotent: uses `` markers to skip already-filed issues. Requires `FORGE_FILER_TOKEN`, `FORGE_API`, `FORGE_API_BASE`, `FORGE_OPS_REPO`. | `.woodpecker/ops-filer.yml` (CI pipeline on ops repo) | | `lib/hire-agent.sh` | `disinto_hire_an_agent()` — user creation, `.profile` repo setup, formula copying, branch protection, and state marker creation for hiring a new agent. Requires `FORGE_URL`, `FORGE_TOKEN`, `FACTORY_ROOT`, `PROJECT_NAME`. Extracted from `bin/disinto`. | bin/disinto (hire) | | `lib/release.sh` | `disinto_release()` — vault TOML creation, branch setup on ops repo, PR creation, and auto-merge request for a versioned release. `_assert_release_globals()` validates required env vars. Requires `FORGE_URL`, `FORGE_TOKEN`, `FORGE_OPS_REPO`, `FACTORY_ROOT`, `PRIMARY_BRANCH`. Extracted from `bin/disinto`. | bin/disinto (release) | diff --git a/planner/AGENTS.md b/planner/AGENTS.md index 36fabf5..59f54bf 100644 --- a/planner/AGENTS.md +++ b/planner/AGENTS.md @@ -1,4 +1,4 @@ - + # Planner Agent **Role**: Strategic planning using a Prerequisite Tree (Theory of Constraints), diff --git a/predictor/AGENTS.md b/predictor/AGENTS.md index f9fdf4a..98dc8cd 100644 --- a/predictor/AGENTS.md +++ b/predictor/AGENTS.md @@ -1,4 +1,4 @@ - + # Predictor Agent **Role**: Abstract adversary (the "goblin"). Runs a 2-step formula diff --git a/review/AGENTS.md b/review/AGENTS.md index 0d31cdc..f757e22 100644 --- a/review/AGENTS.md +++ b/review/AGENTS.md @@ -1,4 +1,4 @@ - + # Review Agent **Role**: AI-powered PR review — post structured findings and formal diff --git a/supervisor/AGENTS.md b/supervisor/AGENTS.md index 693b3c2..e96bd53 100644 --- a/supervisor/AGENTS.md +++ b/supervisor/AGENTS.md @@ -1,4 +1,4 @@ - + # Supervisor Agent **Role**: Health monitoring and auto-remediation, executed as a formula-driven