CodingOpen SourceFreeActiveMachine-verified· intermediate · ~5 min setup

OpenCode: a reviewer subagent gated to exactly the git commands you allow

Define a Markdown agent whose bash access is scoped per command (git diff and grep yes, everything else no) and that can never write.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 2/2 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

Anyone who wants a read-only reviewer with surgical bash permissions. CI parses the Markdown agent's YAML frontmatter and asserts edit=deny and a bash map with the catch-all wildcard ordered first then git diff allowed. No key. The review itself is a fenced model step.

Not for

  • Putting the specific allows before the "*" wildcard, last match wins so the wildcard must come first or it overrides your allows
  • Expecting CI to run the review, only that the permission frontmatter is well-formed

The Stack

Tested Against

opencode@1.17.4opencode.ai/docs (2026-06)ruby@3.x (YAML stdlib)

Side effects & data flow

Network
none, local only
Writes
./.opencode/agents/review.md
Credentials
none required

Prerequisites

  • OpenCode installed
  • A provider logged in to actually run it

Steps

  1. 1

    Write the gated reviewer agent and validate the frontmatter

    Drop review.md in .opencode/agents/ (per project) or ~/.config/opencode/agents/ (global). Keep the "*" catch-all first and the specific allows after it, since the last matching rule wins. CI parses the YAML frontmatter and asserts edit=deny, wildcard-first, and git diff allowed.

    mkdir -p .opencode/agents
    cat > .opencode/agents/review.md <<'MD'
    ---
    description: Reviews code without making changes
    mode: subagent
    model: provider/your-cheap-model
    permission:
      edit: deny
      webfetch: deny
      bash:
        "*": ask
        "git diff": allow
        "git log*": allow
        "grep *": allow
    ---
    
    You are in review mode. Inspect the diff and flag bugs, security issues, and
    risky changes. Do not modify files. Suggest fixes as comments only.
    MD
    ruby -ryaml -e '
    lines = File.read(".opencode/agents/review.md").lines
    i1 = lines.index { |l| l.strip == "---" }
    abort "BAD: no frontmatter start" if i1.nil?
    rest = lines[(i1 + 1)..]
    i2 = rest.index { |l| l.strip == "---" }
    abort "BAD: no frontmatter end" if i2.nil?
    fm = YAML.load(rest[0...i2].join)
    perm = fm["permission"] || {}
    abort "BAD: edit not deny" unless perm["edit"] == "deny"
    bash = perm["bash"] || {}
    abort "BAD: wildcard not first" unless bash.keys.first == "*"
    abort "BAD: git diff not allowed" unless bash["git diff"] == "allow"
    puts "config OK: @review frontmatter parses, edit=deny, bash wildcard-first then git diff=allow"
    '
  2. 2

    Use @review on a diff (the model step, not checked by CI)

    Mention @review in a message; it can run git diff/log and grep to inspect, but never write. It suggests fixes as comments only. The review runs the model, so CI never claims its content.

Eval, 2 fixtures

Last passed: verified today
  • frontmatter-okcontainstimeout 30s · max $0

    Expected: config OK: @review frontmatter parses, edit=deny, bash wildcard-first then git diff=allow

  • clean-exitexit_codetimeout 30s · max $0

    Expected: 0

Results

The setup that shows off OpenCode's permission system: surgical, per-command bash, not all-or-nothing. The filename becomes the agent name, so this creates @review.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).