From 38bcd41338ff610ba12f95cc60f14a321616cea0 Mon Sep 17 00:00:00 2001 From: CleverAgents Build Agent Date: Mon, 13 Apr 2026 23:36:34 -0400 Subject: [PATCH] Build: Better protection against agents editing the main working directory --- .opencode/agents/agent-evolution-worker.md | 6 +++++- .opencode/agents/architecture-worker.md | 6 +++++- .opencode/agents/asv-benchmarker.md | 6 +++++- .opencode/agents/behave-tester.md | 6 +++++- .opencode/agents/coverage-improver.md | 6 +++++- .opencode/agents/documentation-worker.md | 6 +++++- .opencode/agents/fix-pr.md | 7 ++++++- .opencode/agents/implementation-worker.md | 6 +++++- .opencode/agents/implementer.md | 6 +++++- .opencode/agents/integration-test-runner.md | 6 +++++- .opencode/agents/lint-fixer.md | 6 +++++- .opencode/agents/pr-ci-test-fixer.md | 8 ++++++-- .opencode/agents/pr-merge-pool-supervisor.md | 14 ++++++++++---- .opencode/agents/pr-merge-worker.md | 10 +++++++--- .opencode/agents/project-bootstrapper.md | 13 ++++++++++--- .opencode/agents/repo-isolator.md | 6 +++++- .opencode/agents/robot-tester.md | 6 +++++- .opencode/agents/spec-update-worker.md | 6 +++++- .opencode/agents/subtask-loop.md | 6 +++++- .opencode/agents/test-fixer.md | 6 +++++- .opencode/agents/tier-codex.md | 6 +++++- .opencode/agents/tier-haiku.md | 6 +++++- .opencode/agents/tier-opus.md | 6 +++++- .opencode/agents/tier-sonnet.md | 6 +++++- .opencode/agents/timeline-update-worker.md | 7 ++++++- .opencode/agents/typecheck-fixer.md | 6 +++++- .opencode/agents/unit-test-runner.md | 6 +++++- 27 files changed, 150 insertions(+), 35 deletions(-) diff --git a/.opencode/agents/agent-evolution-worker.md b/.opencode/agents/agent-evolution-worker.md index f00077a52..feb6b426d 100644 --- a/.opencode/agents/agent-evolution-worker.md +++ b/.opencode/agents/agent-evolution-worker.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.2 model: anthropic/claude-sonnet-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/architecture-worker.md b/.opencode/agents/architecture-worker.md index cebb8de4a..40ba90a92 100644 --- a/.opencode/agents/architecture-worker.md +++ b/.opencode/agents/architecture-worker.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.3 model: anthropic/claude-sonnet-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/asv-benchmarker.md b/.opencode/agents/asv-benchmarker.md index 5df4f8d69..828d7f7be 100644 --- a/.opencode/agents/asv-benchmarker.md +++ b/.opencode/agents/asv-benchmarker.md @@ -8,7 +8,11 @@ temperature: 0.2 model: anthropic/claude-sonnet-4-6 color: success permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/behave-tester.md b/.opencode/agents/behave-tester.md index 016dbc93e..d39e46735 100644 --- a/.opencode/agents/behave-tester.md +++ b/.opencode/agents/behave-tester.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.2 # NO MODEL SPECIFIED - inherits from caller (tier selector) permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/coverage-improver.md b/.opencode/agents/coverage-improver.md index 5942ff34f..c95d2027d 100644 --- a/.opencode/agents/coverage-improver.md +++ b/.opencode/agents/coverage-improver.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.2 # NO MODEL SPECIFIED - inherits from caller (tier selector) permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/documentation-worker.md b/.opencode/agents/documentation-worker.md index c819a6351..5c17db2e5 100644 --- a/.opencode/agents/documentation-worker.md +++ b/.opencode/agents/documentation-worker.md @@ -7,7 +7,11 @@ hidden: true temperature: 0.3 model: anthropic/claude-sonnet-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/fix-pr.md b/.opencode/agents/fix-pr.md index 8c6ff04eb..495d64c5f 100644 --- a/.opencode/agents/fix-pr.md +++ b/.opencode/agents/fix-pr.md @@ -7,7 +7,11 @@ temperature: 0.2 model: anthropic/claude-sonnet-4-6 color: "#059669" permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny @@ -61,6 +65,7 @@ You manually fix a specific pull request. The user tells you which PR to fix. Yo 4. Fix the code — address both CI failures and review feedback. 5. Run quality gates locally (`nox -e lint`, `nox -e typecheck`, `nox -e unit_tests`, `nox -e integration_tests`). 6. Commit and push using `git-commit-helper`. +7. Clean up the isolated clone using `repo-isolator`. ## Rules diff --git a/.opencode/agents/implementation-worker.md b/.opencode/agents/implementation-worker.md index 2f1ed59c4..63c34e847 100644 --- a/.opencode/agents/implementation-worker.md +++ b/.opencode/agents/implementation-worker.md @@ -9,7 +9,11 @@ hidden: true temperature: 0.1 # No model specified — tier is set by the supervisor via tier selectors permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/implementer.md b/.opencode/agents/implementer.md index 07941e624..018404456 100644 --- a/.opencode/agents/implementer.md +++ b/.opencode/agents/implementer.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.2 # NO MODEL SPECIFIED - inherits from caller (tier selector) permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/integration-test-runner.md b/.opencode/agents/integration-test-runner.md index faafad528..49e72e5a1 100644 --- a/.opencode/agents/integration-test-runner.md +++ b/.opencode/agents/integration-test-runner.md @@ -8,7 +8,11 @@ temperature: 0.2 # NO MODEL SPECIFIED - inherits from caller (tier selector) color: warning permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/lint-fixer.md b/.opencode/agents/lint-fixer.md index 120170532..51b1a65ae 100644 --- a/.opencode/agents/lint-fixer.md +++ b/.opencode/agents/lint-fixer.md @@ -8,7 +8,11 @@ temperature: 0.1 # NO MODEL SPECIFIED - inherits from caller (tier selector) color: warning permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/pr-ci-test-fixer.md b/.opencode/agents/pr-ci-test-fixer.md index 94f13bfd1..3a75dcd04 100644 --- a/.opencode/agents/pr-ci-test-fixer.md +++ b/.opencode/agents/pr-ci-test-fixer.md @@ -9,7 +9,11 @@ temperature: 0.1 model: anthropic/claude-sonnet-4-6 color: warning permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny @@ -46,7 +50,7 @@ permission: # PR CI Test Fixer -You fix failing CI checks on a PR branch. You work in an isolated clone directory. +You fix failing CI checks on a PR branch. You work in an isolated clone directory — `$WORK_DIR` is always a path inside `/tmp/` created by `repo-isolator`. All file edits and every git operation (`add`, `commit`, `push`, branch switching) must be performed inside `$WORK_DIR`, never against `/app`. ## What You Do diff --git a/.opencode/agents/pr-merge-pool-supervisor.md b/.opencode/agents/pr-merge-pool-supervisor.md index 1eed8b6f0..20b9065bf 100644 --- a/.opencode/agents/pr-merge-pool-supervisor.md +++ b/.opencode/agents/pr-merge-pool-supervisor.md @@ -10,7 +10,11 @@ temperature: 0.1 model: anthropic/claude-sonnet-4-6 color: "#059669" permission: - edit: deny + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: deny bash: "*": deny @@ -99,6 +103,8 @@ Before merging any PR, the following must be true: 5. **No `needs feedback` label** — the PR is not waiting for human input 6. **Not blocked** — no `Blocked` label +**Note:** The above criteria do not need to be satisfied before dispatching a `pr-merge-worker`. While they must be satisfied before the actual merge, the rebasing and conflict resolution steps are still useful even if it isnt ready to be merged. + ## Workers You call `pr-merge-worker` as a **blocking subagent** (via the Task tool) for rebase operations with conflict resolution when PRs are behind the base branch. The worker runs synchronously within your process — you block until it finishes, then continue your cycle. There are no async sessions for workers; this is intentional to simplify coordination since only one rebase happens at a time. @@ -109,9 +115,9 @@ Poll every 5 minutes using `bash("sleep 300", timeout=360000)`. Each cycle: 1. List all open PRs. (the forgejo task paginates so be sure to go through every page) -2. for each PR that is marked as mergable attempt to do a fast-forward or rebase merge, as always do the mandatory post-merge verification. -2. For all other PR (including those you attempted to merge but were unsuccessful), filter such that only those that have passing CI quality gates/tests remain. -4. For each PR that needs rebasing, regardless of if it has conflicts, (prioritized by: milestone order lowest first, then priority label, then MoSCoW label, then issue number), call `pr-merge-worker` as a **blocking subagent** via the Task tool. Pass the PR number, repository info, and credentials in the prompt. The worker will rebase onto the latest master, resolve conflicts, wait for CI, and attempt a fast-forward or rebase merge. You block until the worker finishes before processing the next PR. +2. for each PR that can be merged (has a passing CI,, isn't stale, and has at least 1 approval review) do a fast-forward or rebase merge, as always do the mandatory post-merge verification. +3. For all other PR (including those you attempted to merge but were unsuccessful) order them as follows: 1) CI passes and has one or more review approval 2) CI is failing without conflicts and has one or more review approval 3) CI is failing with conflicts and has one or more review approval 4) All other PRs, within each of those four categories sort by priority label with the most critical label ("Priority/CI Blocking") coming first. +4. For each PR, in the order specified in step 2 above, call `pr-merge-worker` as a **blocking subagent** via the Task tool. Pass the PR number, repository info, and credentials in the prompt. The worker will rebase onto the latest master, resolve conflicts, wait for CI, and attempt a fast-forward or rebase merge. You block until the worker finishes before processing the next PR. 5. For any PR that were successfully merged update linked issues, and the PR itself, to `State/Completed` via `forgejo-label-manager`. ## Tracking diff --git a/.opencode/agents/pr-merge-worker.md b/.opencode/agents/pr-merge-worker.md index c8243c33f..912babf5e 100644 --- a/.opencode/agents/pr-merge-worker.md +++ b/.opencode/agents/pr-merge-worker.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.1 model: anthropic/claude-sonnet-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + "external_directory": + "/tmp/**": allow webfetch: allow bash: "*": deny @@ -46,7 +50,7 @@ You perform a single rebase operation on a PR branch, resolve any conflicts, and ## Procedure Your prompt tells you which PR to rebase. You must: -1. Create an isolated clone using the `repo-isolator` subagent ensuring you pass it the branch used by the PR. +1. Create an isolated clone using the `repo-isolator` subagent ensuring you pass it the branch used by the PR. Make sure all work is done within this clone's directory. 2. Rebase it onto the base branch (usually `master`). 3. Resolve any conflicts that arise by reviewing the recent git history and using that to fix the conflicts 4. Force-push with lease using `git-commit-helper` @@ -59,6 +63,6 @@ Your prompt tells you which PR to rebase. You must: 1. **One task, then exit.** Do not loop. Do not sleep. Do not look for more work. 2. **Force-push with lease only.** Never use `--force` without `--lease`. -3. **Clean up your clone.** Delete the temporary directory before exiting. +3. **Clean up your clone.** Delete the temporary clone directory before exiting. 4. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`. 5. **Exhaustive pagination for all list results.** Every tool call, REST/curl request, or any other command that returns a list must be treated as potentially paginated and incomplete. Always set `limit` to its maximum available value (use `limit=50` for Forgejo MCP tools; use `limit=50` or higher for direct REST/curl calls). After each list response, check whether the number of returned items equals the page size — if so, there are likely more results; fetch the next page (`page=2`, `page=3`, …) and continue until receiving a partial page. Never assume the first response is the complete result. This rule applies to every list-returning call without exception. *Examples specific to this agent (not exhaustive):* `git log` listing commits during conflict resolution must be fully read; any future REST/curl calls returning JSON arrays must be paginated. diff --git a/.opencode/agents/project-bootstrapper.md b/.opencode/agents/project-bootstrapper.md index 666c9ad8b..4eff5d366 100644 --- a/.opencode/agents/project-bootstrapper.md +++ b/.opencode/agents/project-bootstrapper.md @@ -9,7 +9,11 @@ temperature: 0.2 model: anthropic/claude-sonnet-4-6 color: primary permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny @@ -29,6 +33,8 @@ permission: task: "*": deny "forgejo-label-manager": allow + "repo-isolator": allow + "git-commit-helper": allow "forgejo_*": allow # CRITICAL: Never list repo-level labels — use org labels via forgejo-label-manager "forgejo_list_repo_labels": deny @@ -60,5 +66,6 @@ You set up project infrastructure from scratch. Your caller provides the product 1. **Detect before creating.** Always check if something exists before creating it. 2. **Never overwrite.** If a file or label already exists, skip it. 3. **Credentials from prompt.** All Forgejo PAT, git identity, etc. come from the caller's prompt. -4. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`. -5. **Exhaustive pagination for all list results.** Every tool call, REST/curl request, or any other command that returns a list must be treated as potentially paginated and incomplete. Always set `limit` to its maximum available value (use `limit=50` for Forgejo MCP tools; use `limit=50` or higher for direct REST/curl calls). After each list response, check whether the number of returned items equals the page size — if so, there are likely more results; fetch the next page (`page=2`, `page=3`, …) and continue until receiving a partial page. Never assume the first response is the complete result. This rule applies to every list-returning call without exception. *Examples specific to this agent (not exhaustive):* any `forgejo_list_*` calls used when checking for existing labels, milestones, or workflows must be paginated — missing one means re-creating something that already exists. +4. **Work in an isolated clone.** Use `repo-isolator` to create an isolated clone of the target repository in `/tmp/`. All file creation and edits must be done in the clone — never directly in `/app`. Use `git-commit-helper` to commit and push changes. Clean up the isolated clone using `repo-isolator` when done. +5. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`. +6. **Exhaustive pagination for all list results.** Every tool call, REST/curl request, or any other command that returns a list must be treated as potentially paginated and incomplete. Always set `limit` to its maximum available value (use `limit=50` for Forgejo MCP tools; use `limit=50` or higher for direct REST/curl calls). After each list response, check whether the number of returned items equals the page size — if so, there are likely more results; fetch the next page (`page=2`, `page=3`, …) and continue until receiving a partial page. Never assume the first response is the complete result. This rule applies to every list-returning call without exception. *Examples specific to this agent (not exhaustive):* any `forgejo_list_*` calls used when checking for existing labels, milestones, or workflows must be paginated — missing one means re-creating something that already exists. diff --git a/.opencode/agents/repo-isolator.md b/.opencode/agents/repo-isolator.md index 647ad08f3..4488b8c82 100644 --- a/.opencode/agents/repo-isolator.md +++ b/.opencode/agents/repo-isolator.md @@ -9,7 +9,9 @@ temperature: 0.1 model: openai/gpt-5-codex color: "#6B7280" permission: - edit: deny + edit: + "*": deny + "/tmp/**": allow webfetch: deny bash: "*": deny @@ -37,6 +39,8 @@ permission: # CRITICAL: DO NOT use forgejo_add_issue_labels directly # Always delegate to forgejo-label-manager for label operations "forgejo_add_issue_labels": deny + "external_directory": + "/tmp/**": allow --- # Repository Isolator diff --git a/.opencode/agents/robot-tester.md b/.opencode/agents/robot-tester.md index 5b6d5508c..d0bdcdaaf 100644 --- a/.opencode/agents/robot-tester.md +++ b/.opencode/agents/robot-tester.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.2 # NO MODEL SPECIFIED - inherits from caller (tier selector) permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/spec-update-worker.md b/.opencode/agents/spec-update-worker.md index 3d5ec86b9..b21f5fbc3 100644 --- a/.opencode/agents/spec-update-worker.md +++ b/.opencode/agents/spec-update-worker.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.2 model: anthropic/claude-sonnet-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/subtask-loop.md b/.opencode/agents/subtask-loop.md index d3b4f44e7..079b89fe8 100644 --- a/.opencode/agents/subtask-loop.md +++ b/.opencode/agents/subtask-loop.md @@ -11,7 +11,11 @@ temperature: 0.1 model: openai/gpt-5-codex color: accent permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/test-fixer.md b/.opencode/agents/test-fixer.md index fe1a38890..802926a8f 100644 --- a/.opencode/agents/test-fixer.md +++ b/.opencode/agents/test-fixer.md @@ -9,7 +9,11 @@ temperature: 0.2 # NO MODEL SPECIFIED - inherits from caller (tier selector) color: warning permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/tier-codex.md b/.opencode/agents/tier-codex.md index a59e1ce30..a750b1711 100644 --- a/.opencode/agents/tier-codex.md +++ b/.opencode/agents/tier-codex.md @@ -7,7 +7,11 @@ hidden: true temperature: 0.0 model: openai/gpt-5-codex permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: deny bash: "*": deny diff --git a/.opencode/agents/tier-haiku.md b/.opencode/agents/tier-haiku.md index 429b4f8ab..2d1a964d6 100644 --- a/.opencode/agents/tier-haiku.md +++ b/.opencode/agents/tier-haiku.md @@ -7,7 +7,11 @@ hidden: true temperature: 0.0 model: anthropic/claude-haiku-4-5 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: deny bash: "*": deny diff --git a/.opencode/agents/tier-opus.md b/.opencode/agents/tier-opus.md index 7181fa7df..a00f0eda5 100644 --- a/.opencode/agents/tier-opus.md +++ b/.opencode/agents/tier-opus.md @@ -7,7 +7,11 @@ hidden: true temperature: 0.0 model: anthropic/claude-opus-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: deny bash: "*": deny diff --git a/.opencode/agents/tier-sonnet.md b/.opencode/agents/tier-sonnet.md index f620b928a..fd57741fe 100644 --- a/.opencode/agents/tier-sonnet.md +++ b/.opencode/agents/tier-sonnet.md @@ -7,7 +7,11 @@ hidden: true temperature: 0.0 model: anthropic/claude-sonnet-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: deny bash: "*": deny diff --git a/.opencode/agents/timeline-update-worker.md b/.opencode/agents/timeline-update-worker.md index 2547a7166..0c525042e 100644 --- a/.opencode/agents/timeline-update-worker.md +++ b/.opencode/agents/timeline-update-worker.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.1 model: anthropic/claude-sonnet-4-6 permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny @@ -53,6 +57,7 @@ Your prompt provides the current milestone status data and the timeline file for 3. Add new entries — never overwrite existing ones. 4. Commit using `git-commit-helper` with a Conventional Changelog message. 5. Push and exit. (No PR needed — timeline updates go directly to master.) +6. Clean up the isolated clone using `repo-isolator`. ## Rules diff --git a/.opencode/agents/typecheck-fixer.md b/.opencode/agents/typecheck-fixer.md index da25c8932..b5205a8c0 100644 --- a/.opencode/agents/typecheck-fixer.md +++ b/.opencode/agents/typecheck-fixer.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.1 # NO MODEL SPECIFIED - inherits from caller (tier selector) permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny diff --git a/.opencode/agents/unit-test-runner.md b/.opencode/agents/unit-test-runner.md index ee3f0f1c3..96b95d8e3 100644 --- a/.opencode/agents/unit-test-runner.md +++ b/.opencode/agents/unit-test-runner.md @@ -8,7 +8,11 @@ hidden: true temperature: 0.2 # NO MODEL SPECIFIED - inherits from caller (tier selector) permission: - edit: allow + edit: + "*": deny + "/tmp/**": allow + external_directory: + "/tmp/**": allow webfetch: allow bash: "*": deny