Files
6krrt/docs/agent-guardrails.md
adlee-was-taken a0362d3f5c docs: record the guardrail gaps that are accepted on purpose
Add a Known gaps section to docs/agent-guardrails.md and tighten the
bash_protected_port row. Each gap was probed at the hook boundary:

- the plugin inspects only task, call_omo_agent, edit, write and bash, so
  webfetch of localhost:8080 passes (seen live 2026-10-04)
- bash_protected_port matches literal host:port text, so [::1], the
  machine address and URLs held in variables are missed
- bash -c / sh -c wrappers evade bash_banned and bash_main_checkout
  (the port rule still sees inside them)
- a relative cd chain after an absolute one can be mis-anchored

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkCGRantZsSwmcFpet6FTa
2026-10-04 21:31:44 -04:00

3.7 KiB

Agent guardrails

An opencode plugin (deploy/opencode-plugin/guardrails.js) that intercepts tool.execute calls and blocks or warns on patterns that have caused expensive failures on this repo.

Install

command cp -f deploy/opencode-plugin/guardrails.js ~/.config/opencode/plugins/
cp -n deploy/opencode-plugin/guardrails.example.json .omo/guardrails.json

Restart opencode. Check ~/.local/share/opencode/log/opencode.log for failed to load plugin.

Uninstall

Delete .omo/guardrails.json (plugin goes inert) or remove guardrails.js from ~/.config/opencode/plugins/.

Rule modes

Each rule can be "block" (default), "warn" (logs only, allows the call), or "off" (no check). Edit in .omo/guardrails.json.

Rules

Rule Blocks Evidence
task_needs_agent task()/call_omo_agent with no category, subagent_type, AND task_id 2026-09-26..28: three such calls reported "completed" with zero work
task_banned_agent task()/call_omo_agent to oh-my-claudecode:* agents 2026-09-26: 12 dispatches to oh-my-claudecode:writer did zero work (pinned Anthropic model)
task_worktree_line task prompt without WORKTREE: line when boulder has worktree_path, or mismatch 2026-09-28: worker rewrote the main checkout's live config.yaml
write_outside_worktree writes to files outside the worktree scope same 2026-09-28 incident
bash_main_checkout git/redirect ops targeting the main checkout from a worktree task same class as 2026-09-28 main-checkout rewrite
bash_banned pkill, git stash, kill, systemctl 2026-09-26: unasked PR; 2026-09-29: git stash in wrong checkout
bash_protected_port bash commands containing localhost, 127.0.0.1 or 0.0.0.0 followed by :8080 (list: protected_ports) 8080 is the production router and opencode's own model traffic runs through it (CLAUDE.md); 2026-08-29 incident #1: an agent pkilled it to free the port for a throwaway, which belongs on 8081
plan_tick_gate tick gate blocks a todo tick while verify_commit fails 2026-09-28: todo committed 3 failing tests and was reported done

Known gaps

Accepted on purpose; each was probed at the hook boundary. Revisit when an agent is seen doing real damage through one of them, not before.

  • The plugin inspects only task, call_omo_agent, edit, write and bash. bash_protected_port therefore does not see webfetch (or any MCP fetch tool): on 2026-10-04 a blocked curl localhost:8080/health was retried through webfetch and succeeded. A fetch is a GET; the calls that spend or change production (/dispatch, admin POSTs) normally go through bash, which is covered.
  • bash_protected_port matches literal text. It misses [::1]:8080, the machine's own address, a URL held in a variable, and a script file that calls 8080 internally. In the other direction, a commit message or argument that names localhost:8080 is blocked. Text-only commands (echo, grep, cat, ...) and heredoc bodies are skipped unless fed to an interpreter. It does see inside bash -c '...' and python3 -c '...', because it reads the raw string.
  • bash -c '...' and sh -c '...' wrappers are not inspected by bash_banned or bash_main_checkout. bash -c 'pkill -f foo' and bash -c 'git stash' both pass.
  • bash_main_checkout can mis-anchor a relative cd chain that follows an absolute one (one block in the replay report).

Log

Blocks, warnings, and internal errors go to .omo/guardrails.log (JSON lines, relative to the project root).

Upstream

scripts/verify_commit.py and scripts/oc_dispatch_audit.py are the two audit scripts the plugin and the agent procedures rely on.