Layer 1: Hard-block execution guard

June 6, 2026 · View on GitHub

Converts advisory read-only caps into real hard-blocks for subagent sessions. Opt-in; orchestrator sessions and mode:"off" are byte-identical to pre-enforcement routing (GA-1).

Mechanism

A tool.execute.before hook. In enforced mode, when the guard denies a call it throws; opencode aborts the tool call and the thrown message reaches the model as that tool's error text (empirically confirmed).

Applies only to subagent sessions — sessions whose agent matches a tier name, or plugin-created delegate producer sessions. Orchestrator sessions and mode:"off" are early-return no-ops.

Modes (enforcement.mode)

modeeffect
offHook is a no-op. Zero added tokens. Byte-identical to pre-enforcement (GA-1).
advisoryGuard is evaluated; a [⚠ GUARD:<name>] <forcing message> banner is appended to the tool result via the after-hook. Never throws.
enforcedDeny ⇒ throw <observation>\n<forcing message>.

Guard evaluation (evaluateGuards)

Pure / non-mutating. First match wins.

#conditionverdictguard name
1call is a finish / return / task_complete signalALLOW
2call matches self-script patternDENYanti_self_script
3toolCallCount >= budgetDENYiteration_cap
4read whose fingerprint was seen >= sameOpRetryCap timesDENYredundant_read
5read while consecutiveNonProducing >= readDraftCapDENYread_budget
6deliverableFirst enabled AND deliverable signal exists AND not yet executed AND call is read/otherDENYdeliverable_first
7ALLOW

Self-script detection (isSelfScript)

Writing source files (.ts, .js, .py, .mjs, etc.) is the normal coding deliverable and is not blocked by default. Extension-based write blocking is opt-in via blockScriptWrites (default false).

Note the two settings are independent: blockSelfScript (default true) keeps the self-script guard active, but with blockScriptWrites left at false that guard's default scope is bash ad-hoc execution only — it does not touch write/edit of source files. Setting blockScriptWrites: true additionally blocks writes to script extensions; setting blockSelfScript: false disables the guard entirely.

The always-on self-script signal catches bash ad-hoc execution only:

heredocs  ·  node|python|deno|bun -e/-c  ·  cat > file  ·  bash -c  ·  redirect-to-script

Intent exemptions: if the DoD's declared deliverable is a script (deliverableIsScript), or the write target equals the declared deliverable path, the call is allowed.

Policy defaults (buildGuardPolicy)

fielddefault
budget25 (DEFAULT_GUARD_BUDGET)
readDraftCap3
sameOpRetryCap1
blockSelfScripttrue
deliverableFirsttrue
blockScriptWritesfalse
deliverableSignalnull (deliverable-first effectively disabled until wired)

Forcing message format

[budget N/B | deliverable=n/a|ran|NOT RUN | reads_since_produce=K] NEXT: <instruction>

Proportional enforcement (GA-6)

trivial is classified at dispatch, not from realized tool counts. classifyTrivial is tier-gated to the fast tier and requires a fast taskPattern keyword match with no medium/heavy signal — conservative, biased toward non-trivial so real work is never mis-classified.

A trivial fast dispatch downgrades enforcedadvisory when enforcement.proportional.trivialBypass !== false (default true). medium / heavy work is always fully enforced.

Security

Thrown messages and banners pass through scrubText (redacts API keys / bearer tokens / key=value secrets). No secrets leak into observations.

Enabling enforcement

// tiers.json
"enforcement": { "mode": "enforced" }
# environment variable
MODEL_ROUTER_ENFORCE=1
# slash command
/router enforce <off|advisory|enforced>

See CONFIG_REFERENCE.md for the full schema and ENFORCEMENT_PRESETS.md for per-mode example blocks.