Skip to content
Back to skills

Opencode Adversarial Review

ASecurity

Run an adversarial (red-team) review through the OpenCode CLI's free model pool (muse-spark, Nemotron, stealth models) under a machine-enforced read-only permission config. Use when a HIGH-risk change needs a second cross-family reviewer without spending paid quota, or as the cheap extra pair of eyes beside a primary review.

  • 3 stars
  • 0 votes
  • 3 copies
  • 11 views
  • Added September 19, 2026
ai-agentspythongoshellbashawstestingcode-reviewgitapisecurity

Works with

  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add aarontzeng/dev-lead --skill opencode-adversarial-review --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Opencode Adversarial Review?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Opencode Adversarial Review
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aarontzeng-opencode-adversarial-review/badge)](https://www.skillsdirectory.com/skills/aarontzeng-opencode-adversarial-review)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: opencode-adversarial-review
description: Run an adversarial (red-team) review through the OpenCode CLI's free model pool (muse-spark, Nemotron, stealth models) under a machine-enforced read-only permission config. Use when a HIGH-risk change needs a second cross-family reviewer without spending paid quota, or as the cheap extra pair of eyes beside a primary review.
---

# Adversarial review via `opencode` (free pool)

The value here is an **additional model family at zero quota cost**:
muse-spark (Meta) and Nemotron are neither GPT, Gemini, nor Claude, so this
is the cheapest way to satisfy the cross-family rule's second reviewer on
HIGH-risk work. The
trade-off is best-effort capacity — congestion is normal, so this leg is the
*additional* opinion or the unhurried gate, never the time-critical one.

## Before the first run of a session

Read **[`references/opencode-runtime.md`](references/opencode-runtime.md)**
(same directory). It holds the
family mechanics — the free-model catalogue and the stealth-model
family-unknown caveat, the two silent permission traps (zero-commit project
binding, last-match-wins ordering), congestion behavior, and the audit log
lines. This file assumes them and covers only the review role.

## Choosing the model for this leg — by LENS, not a fixed favourite

**The owner ruled this on 2026-09-16 and it now lives in their roster**
(`roster.json`, located per [`/dev-lead:config`](../config/SKILL.md); it was
in their `CLAUDE.md` before the roster existed); what follows is the same
rule with the numbers behind it,
and this file is where those numbers belong. The division is now explicit in
both directions — the roster names which leg, dev-lead holds prices, buckets
and calibration rows. (The earlier attempt to write a single model in here as
"the default" was mine, on a peer's recommendation, and was retracted in
0.6.8; the rule below is the owner's, not a plugin preference.)

| lens | model | why |
|---|---|---|
| mechanical — consistency, is-it-still-true, convention, falsifiability | `opencode-go/muse-spark-1.3-contributor`; `opencode/muse-spark-1.3-contributor-free` only when the go plan is not available | owner, 2026-10-04: on the go plan this model has no rate limit and draws no quota, while the free twin is a rate-limited pool. Measured strong on fact-checking and line accuracy. (Before that statement this file priced the Go twin at ~$0.014 a leg; take the owner's word for your own plan, and measure if yours differs.) |
| judgement — challenge, design rulings, sequences | `opencode-go/glm-5.3` | an independent family, ~$0.20 a leg against the large ($12 / 5 h) bucket. **No calibration row yet — treat as unproven until one exists** |
| top-tier judgement only | `opencode-go/kimi-k3`, `opencode-go/qwen3.8-max` | 1–2 legs per 5-hour window at most, and the buckets are shared across sessions, so probe immediately before dispatch |

**Effort follows the lens, never the model.** There is no per-variant price;
reasoning tokens bill as output. So `xhigh` on a cheap model is nearly free
and `xhigh` on a dear one can double the leg.

**The terms question, and how it was settled.** Both
`muse-spark-*-contributor` variants, free and paid, put the prompt into a
training set, and a review leg is handed the frozen tree: source, design
documents, sometimes a spec. That is a disclosure decision, not a cost one,
so it went to the owner rather than being settled here. **Ruled 2026-09-16:
accepted for review legs — with the exception carried per change.** If a
change carries material that must not reach a training set, say so and run
the fourth leg on `opencode-go/glm-5.3` instead. The judgement stays with
whoever knows what is in the diff; the default no longer has to be guessed.

**And the owner delegated the judgement itself to this layer (2026-09-16):
dev-lead decides what may go to a contributor tier.** So it needs criteria
that can be CHECKED, not a feeling. Three rules:

**1. Decide per REPOSITORY, once, and write it down — not per change.** A
repo's disclosure class is stable; a change's is not knowable at a glance,
and a judgement re-made every round is one that decays exactly like a STOP
rule that keeps firing on benign causes. Record the class beside the repo's
other dispatch facts. Re-open it only when the repo gains a new kind of
content, not when a change looks unusual.

**2. The stop classes.** A repo is NOT eligible for a contributor tier if its
tracked tree carries any of: credential material of any kind; a customer's or
third party's confidential material; personal data beyond work identifiers;
or specifications for an unannounced product. Everything else — this
account's own infrastructure code, its ADRs, its tooling — is eligible.

**3. Screen the frozen target before the first dispatch, not from memory.**
The tree is what the leg receives, so look at it:

```bash
git ls-files | wc -l; git ls-files -z | xargs -0 cat | wc -c   # what is actually handed over
grep -rlEi 'BEGIN (RSA|OPENSSH|EC) PRIVATE KEY|api[_-]?key *= *["'"'"'][A-Za-z0-9]{16}' .
grep -rhoE '[A-Za-z][A-Za-z.]+@[a-z]+\.com' . | sort -u      # people, not roles
```

Measured on one of the owner's infrastructure repositories 2026-09-16: no
credential material; 153 files and 6.7 MB handed to each leg; colleague work
addresses and internal project codenames present. That is
the residual the owner accepted — **named, not assumed absent.** Eligible.

**The brief is a prompt too.** The claims file and lens text are authored by
the lead and go to the model with the tree, so they can disclose material the
repo does not contain — an audit excerpt with real actor ids, a quoted mail,
a customer's words from a ticket. Screen what you WRITE by the same rules;
this is the half no check on the repository can see.

When any of this trips, the fourth leg runs on `opencode-go/glm-5.3` and the
report says why. A leg not run is always available too: three legs and a
stated reason beat four legs and a disclosure nobody decided.

## Establish an immutable review target

**One frozen directory per reviewer, at the exact commit, that nothing else
touches — no lead activity inside it.** Not "whenever possible": a reviewer
reads the WORKING TREE, not your commit. Measured — a round ran mutation
testing in the same worktree mid-review and the reviewer opened a CRITICAL on
a mutated, non-compiling file it was never meant to see.

Freeze it with the suite's tested helpers instead of hand-rolling the shell;
every bug ever found in this step was in a hand-rolled copy. The suite-root
resolver and both calls — `freeze-target.sh` to create it, `verify-target.sh`
before AND after the run — are in
[dev-lead Phase 2](../dev-lead/SKILL.md), and the reasoning is in
[methodology.md](../../docs/methodology.md) §7. Everything below assumes
`$REVIEW_TARGET_DIR` is that frozen directory and `$REVIEW_HEAD` is the SHA it
was frozen at.

## The read-only boundary is a config file, not a mode

**If the target already has an `opencode.json`, save it first** — writing
ours over a project's real config and then deleting "ours" at teardown
destroys the project's file:

```bash
RUN_DIR=$(mktemp -d "${TMPDIR:-/tmp}/opencode-review.XXXXXX")   # created here; every later step reuses it
[ -f "$REVIEW_TARGET_DIR/opencode.json" ] && \
  mv "$REVIEW_TARGET_DIR/opencode.json" "$RUN_DIR/opencode.json.orig"
# ... run ...; at teardown, restore:
#   mv "$RUN_DIR/opencode.json.orig" "$REVIEW_TARGET_DIR/opencode.json"
```

(The frozen worktree above does NOT make this step optional: it is a checkout
of the same repo, so a project that tracks its own `opencode.json` has one
there too. The backup is what stops teardown deleting it.)

Then write this as `opencode.json` in the target (wildcard FIRST — last
match wins; see runtime):

```json
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "bash": {
      "*": "deny",
      "git status*": "allow",
      "git log*": "allow",
      "git diff*": "allow",
      "git show*": "allow",
      "git rev-parse*": "allow"
    },
    "edit": "deny"
  }
}
```

Call this what it is: a **machine-enforced guardrail against a fallible
delegate, not a security boundary against an adversarial one.** File edits
denied, shell denied except five git reads (`git branch*` is deliberately
NOT on the list — `git branch -d` writes refs, and
`rev-parse --abbrev-ref HEAD` answers the read-only question) — stronger
than a behavioral plan mode, and stronger than opencode's own plan agent
(whose edit-deny a shared config can override and whose bash is
unrestricted — measured; see runtime). But command wildcards match command
*prefixes*, not effects: `git diff --output=<path>` and `git log
--output=<path>` write files while matching the allowed patterns. The
threat model here is an honest model taking a lazy shortcut — which the
denials catch — and the post-run bracket below is what catches everything
else; a hostile-input review needs an OS-level read-only sandbox instead.
Verify what actually governs before spending a run: `opencode debug agent`
prints the merged rule array in evaluation order (runtime file). Use the
default agent with this config. A denied call comes back to the model as a
message, so an over-curious reviewer reports MACHINE-DENIED and keeps
reviewing instead of dying.

The config file itself appears as untracked in the target, and this leg cannot
move it out — it must sit at the project root to bind. **Declare it** to the
certification instead of excusing it:

```bash
set -o pipefail          # without it the digest below survives a MISSING file:
                         # sha256sum reports the bad operand on stderr, the
                         # second sha256sum still exits 0 and hashes whatever
                         # arrived, and the same omission after the run
                         # reproduces the same digest — certifying a run that
                         # never had the claims file. Measured.
for f in opencode.json REVIEW-CLAIMS.md; do
  [ -f "$REVIEW_TARGET_DIR/$f" ] || { echo "scaffold missing: $f"; exit 1; }
done

# Immutable FOR THE DURATION, not merely equal at the endpoints — the third of
# the four properties in the materializing-evidence reference, which this flow
# violated by relying on the digest alone. A before/after digest cannot see the
# edit → read → restore sequence, and this
# leg's own allow-list documents the write: `git diff --output=<path>`. Measured
# that a-w blocks it at the source: "fatal: could not open 'REVIEW-CLAIMS.md'
# for writing: Permission denied".
chmod a-w "$REVIEW_TARGET_DIR"/opencode.json "$REVIEW_TARGET_DIR"/REVIEW-CLAIMS.md

SCAFFOLD_SHA=$(sha256sum "$REVIEW_TARGET_DIR"/{opencode.json,REVIEW-CLAIMS.md} | sha256sum)
```

`a-w` on the files stops a rewrite through the allow-listed `git … --output=`.
Unlinking and recreating them would need write on the *directory* rather than
on the files, and no allow-listed command can do it: `bash` is `deny` except
five git reads, and none of those five unlinks a file. The two layers are what
make the digest meaningful — keep both, and `chmod u+w` before restoring.

Then pass those two paths as trailing arguments to the `verify-target.sh`
bracket the section above already requires — `… "$REVIEW_HEAD" opencode.json
REVIEW-CLAIMS.md` — and compare `SCAFFOLD_SHA` after the run.

Declaring a path permits **that entry and no other**, and fails if it has
vanished — but it permits an entry, **not its content**: `?? opencode.json`
reads the same after a rewrite, and this leg's allow-list reaches
`git diff --output=<path>` (see above). So keep the `SCAFFOLD_SHA` comparison
in the lead as well; the two answer different questions. Remove the claims file
and restore any original config after the run.

**A declaration only works when the config is untracked.** If the target's own
repo tracks `opencode.json`, the `mv`-and-write above produces ` M
opencode.json`, and `verify-target.sh` rejects a declared tracked path by
design — a modified tracked file is a mutation of the reviewed tree, never
scaffolding, and loosening that would reopen exactly the hole the rule closes.
Bracket **outside** the scaffold window instead, which is strictly stronger
than a declaration would have been:

| step | tracked `opencode.json` | untracked |
|---|---|---|
| after freeze, before writing the config | `verify-target.sh "$REVIEW_TARGET_DIR" "$REVIEW_HEAD"` — no declarations, must be fully clean | same |
| write scaffold, record `SCAFFOLD_SHA`, run the leg | — | — |
| after the run | compare `SCAFFOLD_SHA` — meaningful only because the files were `a-w` for the whole window; a digest alone samples two endpoints and cannot see edit → read → restore | same |
| then restore | `chmod u+w` both, then `mv "$RUN_DIR/opencode.json.orig"` back and `rm REVIEW-CLAIMS.md` | `chmod u+w` both, then `rm opencode.json REVIEW-CLAIMS.md` |
| after restoring | `verify-target.sh "$REVIEW_TARGET_DIR" "$REVIEW_HEAD"` — no declarations, must be fully clean | same |

The closing bracket proving clean is what proves the restore was byte-exact:
a `mv`-back that produced anything other than the committed content would
still show ` M opencode.json`. Order matters — compare `SCAFFOLD_SHA` **before**
restoring, or the restore erases the evidence of a rewrite and cleanup's
success gets reported as the run's.

## Run it

Capture `REVIEW_HEAD` **when you freeze the target**, not immediately before
the launch assertion — captured at launch time the check compares HEAD
against itself and can only pass (see the same note in
`claude-adversarial-review`).

**Since 0.6.30 the brief is a LENS inside this leg's framing**
([`references/adversarial-framing.md`](references/adversarial-framing.md)):
the frame carries the general discipline -- read the base revision, label
inherited defects instead of dropping them, a per-claim HOLDS / BROKEN /
NOT REACHED, one plain verdict line -- and your brief says what this round is
about. Adopted on measurement: on three frozen targets with known answers,
three runs per arm, the plain brief found 4 of the known defects and this
frame 7; the plain brief answered broken claims "HOLDS" ([runtime
file](references/opencode-runtime.md), calibration table).

Before this recipe, complete the frozen-target triage step in dev-lead Phase 2;
the review launcher requires its record for this exact commit.

```bash
REVIEW_HEAD=$(git -C "$REVIEW_TARGET_DIR" rev-parse HEAD)   # at freeze time

# ... later, at launch (RUN_DIR was created in the boundary step above):
# Write the lens to "$RUN_DIR/prompt.md" in its own FOREGROUND step.
DEV_LEAD=${DEV_LEAD_ROOT:-$(ls -d "$HOME"/.claude/plugins/cache/dev-lead/dev-lead/* 2>/dev/null | sort -V | tail -1)}
[ "$(git -C "$REVIEW_TARGET_DIR" rev-parse HEAD)" = "$REVIEW_HEAD" ] && \
  eval "$("$DEV_LEAD/scripts/leg-cmd.sh" opencode review --model opencode/<free-model> --effort <effort> \
            --base "$BASE" --target "$REVIEW_TARGET_DIR" --run-dir "$RUN_DIR")" > "$RUN_DIR/review.log" 2>&1
```

What it runs, spelled out (for a lead without the script): the builder, then
the leg inside the frozen target, in a subshell so your own cwd is kept:

```bash
python3 "$DEV_LEAD/scripts/review-prompt.py" --adapter opencode --base "$BASE" \
  --target "$REVIEW_TARGET_DIR" < "$RUN_DIR/prompt.md" > "$RUN_DIR/framed-prompt.md" && \
( cd "$REVIEW_TARGET_DIR" && opencode run --print-logs --log-level INFO \
    -m opencode/<free-model> --variant <effort> \
    < "$RUN_DIR/framed-prompt.md" ) > "$RUN_DIR/review.log" 2>&1
```

`$RUN_DIR` must be absolute (leg-cmd exports it that way) and outside the
target; the lock-down `opencode.json` must already be in the target.

- **`--variant` is the effort knob** — this family's `--effort`. Pass it
  explicitly; omitting it takes the provider default, and there is no
  `reasoningEffort` key in `opencode.json` to set instead (runtime file).
  The free pool costs no quota, so this is the one leg where you can spend
  the top tier without a budget argument.

- **"In its own step" means its own FOREGROUND step.** Measured: a prompt
  file written by a heredoc inside a backgrounded compound command raced the
  read in a second background command — opencode received 168 bytes of a
  5 KB prompt and, sensibly, asked what the session was for. It looks
  exactly like a model ignoring instructions. Compare the size of what you
  piped against the size of what you wrote before believing anything about
  the run.
- **The prompt goes on STDIN, not in argv.** An argv prompt over ~1–2 KB
  hangs before the session is even created — `message=init` then silence,
  forever, in every model (measured; size sweep in the runtime file).
- **Put the claims IN a file inside the repo, not outside it.** Anything
  outside the project trips `permission=external_directory`, which
  auto-rejects headless, and the model treats the refusal as fatal
  (measured: died in seven seconds having read nothing). State the repo
  root explicitly in the prompt ("your cwd is EXACTLY <path>; use relative
  paths") — the same run later hallucinated a neighboring absolute path and
  died identically.
- **Check the log mechanically before reading it as a verdict:**

  ```bash
  DEV_LEAD=${DEV_LEAD_ROOT:-$(ls -d "$HOME"/.claude/plugins/cache/dev-lead/dev-lead/* 2>/dev/null | sort -V | tail -1)}
  "$DEV_LEAD/scripts/leg-log-check.sh" "opencode" "$RUN_DIR/review.log"
  ```

  It passes only a log whose report carries a per-claim verdict word
  (HOLDS / BROKEN / NOT REACHED / FIXED, or `--expect <regex>` for another
  format), so an empty log, an error dump and a refused read with nothing
  after it all exit 1. A leg it fails is a MISSING leg, never "no
  findings" -- measured 2026-09-22 (a peer session): two refused out-of-cwd reads
  and one 20-minute timeout each left a file that looked like a clean run. It
  catches "nothing"; the diagnosis below is still yours.
- **Five terminal failures look alike in the log and are not.** Ending with
  `auto-rejecting` is the permission wall — YOUR bug; fix the prompt and
  rerun. `Streaming response failed: [502]/[503] … ResourceExhausted` or
  `queue is full` is the provider out of capacity. A clean exit with
  `tokens.output=0` USUALLY means nothing was produced — but not always;
  see the retraction below. `Error: unknown certificate verification error`
  after a `> build · <model>` line is TLS failing before any token —
  transport; plain rerun. And a fifth shape that carries no error line at
  all: **a clean exit that read every file, ran its greps, and then simply
  stopped.** Observed 2026-08-19, opencode 1.18.18: two consecutive
  `deepseek-v4-flash-free` legs on the same prompt each worked through the
  evidence pack and exited 0 without writing a word, while
  `nemotron-3-ultra-free` on that identical prompt returned a full table
  minutes later — and a second session on this machine was concurrently
  running `deepseek-v4-flash-free`.

  **That model id no longer resolves** (measured 2026-09-16: zero hits in
  `opencode models`; this account's free pool is `big-pickle`,
  `ling-3.0-flash-fin-free`, `mimo-v2.5-free`,
  `muse-spark-1.2/1.3-contributor-free`, `nemotron-3-ultra-free`,
  `nemotron-3.5-lightning-free`). The incident above is kept because the
  FAILURE SHAPE is what matters and it recurs on other models; the id is
  history, not a dispatch target. Why it left the catalogue is unknown — do
  not infer it from the workspace switches, which provably do not touch the
  listing (runtime file).

  Check before editing anything, and **in this order** — the error greps
  first, because every one of them names a cause that a model switch would
  only reproduce:
  `grep -c auto-rejecting`, `grep -E '50[0-9]\]'`,
  `grep -c 'certificate verification'`,
  `grep -o 'tokens.output=[0-9]*' | tail -1`.

  Only once all four come back clean — a run that errored nowhere and simply
  stopped — is the fifth shape in play. **Per-model contention is a
  hypothesis there, not an established cause**: one uncontrolled observation
  cannot separate it from provider state, a model-specific fault, or account
  quota, and `pgrep` cannot prove the other process holds the *same* model.
  What the episode does establish is two cheap steps that cost nothing and
  settle it either way:

  ```bash
  pgrep -af "opencode run"    # another local session? which model?
  ```

  Mind the self-match — a guard whose own command line contains the pattern
  always finds itself, so read the PIDs rather than counting them. Then rerun
  the same prompt on a different free model — **as a recovery attempt, not as
  a diagnostic.** Two runs separated in time confound the model with
  everything else that moves between them: provider state, quota, routing,
  and the model's own nondeterminism. So a second model returning a report
  buys you a report; it does not establish that the first failure was
  model-specific, and a second model failing too does not establish
  provider-wide congestion. If you actually need the cause — usually you do
  not, you need a review — the cheap next step is to re-run the *original*
  model once the switch succeeds: a failure that reproduces on A after B
  worked is worth believing, one that does not was transient and is not worth
  more of your afternoon.

  Getting this order wrong has a cost beyond the wasted rerun: a permission
  wall gets rediagnosed as a dead provider pool, or the empty run gets written
  up as a model-behaviour finding — and that claim then outlives the session
  in whatever notes the lead keeps.

  **Retraction worth keeping: `tokens.output=0` is a broken accounting
  metric, not a verdict.** Measured: two runs with that fingerprint were
  genuinely empty; a third with the identical fingerprint contained a
  complete review with quoted evidence, verified 4/4 against the real
  files' line counts and last lines.

  **The header grep is a ONE-WAY signal, and reading it as two-way cost a
  round.** A hit (`grep -c '^## '`, or your prompt's required section
  headers) does mean the review is real regardless of the token counter.
  **A zero does NOT mean the run was empty.** Measured: a leg returned a
  full report — a citation table, four findings, two of them that round's
  only catches — written entirely in bold labels and tables with no
  markdown headings at all, so the header count was 0. On that count alone
  it was called a silent-empty run, reported as such to the user, and its
  findings were nearly dropped. Nothing in the prompt had required `##`.

  So the discard decision needs more than one signal. In cost order:

  ```bash
  wc -c "$RUN_DIR/review.log"                              # a real report is rarely tiny
  grep -o 'step=[0-9]*' "$RUN_DIR/review.log" | tail -1    # loop depth: did it work at all?
  grep -cE '^#{1,4} |^\*\*|^\| |NOT REACHED|HOLDS|BROKEN' "$RUN_DIR/review.log"
  grep -v '^timestamp=' "$RUN_DIR/review.log" | tail -200  # then just read the tail
  ```

  The last line is what actually settles it. A 150 KB log whose final
  screen is `git status` output is empty; one whose final screen is prose
  carrying `file:line` citations is not — and no counter substitutes for
  looking. Reading 200 lines is cheaper than re-running the leg, and much
  cheaper than telling the user a leg produced nothing when it did.
- **The tell that it is the provider and not your prompt: did this SHAPE
  work recently?** Measured: three consecutive failures on a
  six-property prompt made the shape look like the cause — but five reviews
  earlier the same day used exactly that shape and all returned full
  reports; the pool had simply degraded that afternoon. A prompt that
  worked in the morning did not become malformed by evening.
- **Congestion is provider-wide; switching MODELS inside a bad window does
  not help** — the free pool is one queue. Wait, or route to a different
  FAMILY.
- **Hand the delegate a merge-base range, never `origin/main..HEAD`** — this
  leg is the most exposed of all, because the prompt tells the model which
  git command to read the diff with and you never see the output. Pin it:

  ```bash
  BASE=$(git merge-base origin/main HEAD)
  git diff --stat "$BASE" HEAD        # file list must match the change under review
  ```
- Launch in the background with a generous timeout (10m+; budget 40m under
  congestion — a measured healthy run went silent 10+ minutes mid-generation
  and then delivered a full report at ~31 minutes). Treat a missing
  `evaluated permission=` log line as "never really ran".
- **Running this leg as a subagent? You are a leaf — block, do not "wait".**
  Nothing will wake you when `opencode run` exits; ending your turn on
  "waiting for the monitor" abandons the review. Poll to exit inside a single
  tool call, and issue another immediately if it times out ([dev-lead Phase
  2](../dev-lead/SKILL.md)). This leg's long silent stretches make the urge to
  end the turn strongest here — and its documented silent-death mode means a
  leaf that leaves early cannot tell a dead run from a slow one.
- **Model: the named families are the accounting-valid reviewers.** A
  stealth model (family undisclosed by design) is an ADDITIONAL pair of
  eyes, never the leg that satisfies the cross-family rule — and never
  review a stealth model's work with itself. Between the named models,
  choose by measured hit rate and by structural properties (a huge-context
  model earns its place when the review must hold a whole subsystem at
  once); tier and parameter count did NOT predict finding yield in
  measurement.
- First run in a fresh worktree: confirm the log's `projectID=` is a hash,
  not `global` — `global` means the read-only config silently isn't loaded
  and the boundary does not exist (runtime, trap 1).

Bracket the run regardless (belt and braces — the config is the boundary,
this is the proof):

```bash
git -C "$REVIEW_TARGET_DIR" rev-parse HEAD        # before, and again after —
git -C "$REVIEW_TARGET_DIR" status --porcelain=v1 # -C so it's the TARGET, not your cwd
```

## Writing the prompt

The prompt you write is the LENS; the framing (above) already opens with the
falsify-don't-confirm stance, asks for the base revision, the per-claim
answers and the verdict line. Put into the lens what only this round knows:
the claims, the surface you worry about, what the tests do not enumerate.
Same red-team discipline as the other review skills — it matters more than
the model. The short list, with this family's specifics:

- First-party pre-merge framing; falsify, don't confirm; numbered claimed
  properties; a declared approximation gets a BOUNDED property; trigger +
  observable consequence + severity + `file:line` per finding; state fixes
  already made; forbid praise and generic summaries.
- **Ask what the tests do not enumerate** — the highest-yield sentence in
  the prompt on every family (see
  [`docs/methodology.md`](../../docs/methodology.md)).
- State the read-only intent in the prompt as well as the config, and forbid
  recursive delegation.
- Tell it NOT to run tests or builds — the config machine-blocks them, but
  saying so converts a wasted denied attempt into the useful artifact: "if
  confirming a finding requires execution, name the exact command and
  expected result; we run it."
- Tell it not to call MCP tools if the target repo wires any — the diff and
  prompt are the complete context.
- **This family's measured strength is DOCUMENT AND SPEC CONSISTENCY; it is
  the LENIENT one on attack paths.** In paired rounds it alone caught a
  design silently contradicting two accepted documents, a key reused across
  protocols with no domain separator, and a test whose name claimed more
  than its body proved — while passing attack-path defects another family
  caught. Ask this leg "does this contradict document Y", "is this claim
  supported by its cited evidence"; do not rely on it alone to decide
  whether an attack works. (Measure your own split — this is one journal's
  data.)
- **Size the evidence gate to what YOU cannot check** (documents get the
  outsider-questions gate, not the re-derivation gate — see methodology).
- **Give every claim an evidence gate with an unguessable anchor**: per
  file, line count AND verbatim last line; per claim, `file:line` plus the
  quoted code; `NOT REACHED` acceptable, HOLDS-without-quote not.

## A long review eats its own prompt — the ask lives in a FILE

Measured: a review that read nine files came back having lost the numbered
claim list to its own context compaction — the honest model stopped and said
so; a less careful one reconstructs the claims and answers a question you
never asked. Reordering the prompt does not help (compaction drops the
original user message as a unit). The defense:

- **Put the claim list in a file inside the review directory** (e.g.
  `REVIEW-CLAIMS.md`) and tell the model to re-read it whenever it needs the
  wording. A file survives compaction because it can be read again; a prompt
  cannot. Say the file plus `opencode.json` are the expected untracked
  entries, or your own tree-dirty check will fire on your scaffolding.
- **Give a reading budget for big files** ("read only lines 2150–2560 of the
  test file") — context is the resource being exhausted.
- **Authorize a partial answer explicitly**: "if you run low on context,
  stop and emit the verdicts you can support with quotes, mark the rest NOT
  REACHED."

## Reporting back

Same contract as every review leg: relay findings faithfully; verify each
against the code before acting (and record the measured hit rate in your
calibration journal — it is this family's calibration data); hold rejections
to the same evidence standard; review-only, no fixes unless asked.

Pairing rule across the suite: the reviewer must come from a different
model family than whatever implemented the change. This adapter serves
several DISCLOSED families and the accounting reads the served model's
family, not the adapter — a stealth model whose family is undisclosed can
never be the leg that satisfies the rule, however good its findings are.

The standing headline from measurement: **model tier did not predict finding
yield** — a free leg found the only HIGH on a diff where two paid legs
returned nothing usable. Do not drop this leg on the grounds that a stronger
reviewer is already running.

Files in this skill

  • SKILL.md27 KB
  • references/opencode-runtime.md69.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.