Connectors

OpenCode

The OpenCode connector wires DefenseClaw into opencode via a dependency-free JavaScript bridge plugin auto-loaded from ~/.config/opencode/plugins/, whose tool.execute.before hook blocks risky tool calls by throwing.

The OpenCode connector wires DefenseClaw into opencode. Unlike the shell-hook connectors, opencode has no command-hook config surface — it auto-loads JavaScript/TypeScript plugins from ~/.config/opencode/plugins/ at startup. DefenseClaw installs a single, dependency-free bridge plugin (defenseclaw.js) there. The plugin's tool.execute.before hook forwards every tool call to the local DefenseClaw gateway and throws — aborting the tool, exactly like opencode's own .env-protection example — whenever the gateway returns a block decision. opencode continues to talk directly to its configured upstream model provider; DefenseClaw never inserts an LLM proxy.

Three commands against one opencode session (v1.17.3) with the DefenseClaw bridge plugin loaded: (1) `echo hello` runs through as action=allow / severity=NONE and prints `hello`; (2) `chmod 777 /tmp/dc_test` trips a CRITICAL finding → the bridge's tool.execute.before hook throws new Error(reason), so opencode aborts the tool and strikes the command out without ever running it; (3) `cat /etc/shadow` raises another sensitive-file finding. Each tool.execute.before / tool.execute.after event streams into the Splunk Connector Activity dashboard filtered to connector=opencode on the right.

No opencode.json edit, no shell shim. Local plugins under ~/.config/opencode/plugins/ are loaded automatically, so installing the connector is just writing one file. The bridge uses the runtime's global fetch, so it needs no npm dependencies (and never triggers a bun install). Because the mechanism is a JavaScript plugin rather than a shell script, OpenCode is cross-platform — including Windows — without the native defenseclaw-gateway hook entrypoint used by the other hook connectors on Windows.

Setup

defenseclaw setup opencode                # observe (default) - record only
defenseclaw setup opencode --mode action  # block on policy hits by throwing

This connector is global/user-scoped only. DefenseClaw writes the bridge plugin to ~/.config/opencode/plugins/defenseclaw.js (owner-only, 0o600, because it carries the gateway token) with the gateway address, token, and fail mode substituted in at setup time. There is no proxy-enforcement path for OpenCode — blocking happens plugin-side by throwing inside tool.execute.before.

Version contract

The current contract is opencode-hooks-v1 (the plugin API is documented as a stable contract rather than a versioned floor, so the contract is unbounded — min 0.0.0). tool.execute.before is the only blockable event; tool.execute.after is observe-only telemetry.

Lifecycle events

EventWhen it firesDefenseClaw roleAction verdict → behavior
tool.execute.beforeRight before a tool (bash, read, edit, …) executesInspect tool args; intercept risky commandsblock → gateway returns {decision: "deny", reason}; the bridge throws new Error(reason), aborting the tool
tool.execute.afterImmediately after a tool returnsCapture diagnostics / flag secrets in output. Cannot block — tool already ran.Observe-only (fire-and-forget; never adds latency)

opencode has no hook-driven ask or context-injection surface, so confirm verdicts fall back to allow and findings on tool.execute.after are telemetry only.

The bridge plugin

DefenseClaw writes a single managed plugin file. Its tool.execute.before resolves the gateway verdict before throwing, so a fail-open transport error never turns into an accidental block:

"tool.execute.before": async (input, output) => {
  const verdict = await defenseclawPost("tool.execute.before", input.tool, output.args, cwd);
  if (verdict) throw new Error(verdict.reason); // block: aborts the tool
}

When the gateway is unreachable, the bridge honors the configured fail mode: FAIL_MODE=closed throws (fail closed); FAIL_MODE=open allows. Because the thrown Error is authoritative, OpenCode genuinely supports fail-closed — unlike the shell-hook connectors that can only fail open when their host process has already cached the hook path.

Local surfaces

defenseclaw.js

DefenseClaw v1 governs opencode tool execution via the bridge plugin. opencode's MCP servers live in opencode.json; defenseclaw mcp list --connector opencode, defenseclaw mcp set <name> --connector opencode, and defenseclaw mcp unset <name> --connector opencode read or update the top-level mcp map. For local MCP servers, mcp set refuses commands outside trusted install prefixes unless you add the directory to DEFENSECLAW_TRUSTED_BIN_PREFIXES or pass --force-untrusted-command for that one write, because OpenCode will execute the stored command. Skills / rules / plugins / agents surfaces remain unsupported and their panels are hidden while claw.mode=opencode.

Hook capabilities

Block events

  • tool.execute.before

Native ask events

None — confirm verdicts are downgraded with the raw action preserved.

Disable

defenseclaw setup guardrail --disable

Teardown removes the managed ~/.config/opencode/plugins/defenseclaw.js when it is unchanged since setup. If the operator hand-edited the file, teardown leaves it in place and defenseclaw doctor surfaces the lingering managed plugin. No tombstone is needed: opencode re-reads the plugins directory on each startup, so removing the file stops it loading.