opencode-auto-approval-pluginopencode plugin that auto-approves tool permission requests based on configurable rules
0
233
233 in 7 days
34.5
Multi-signal model
1 day ago
2026-08-18
Install and configure
opencode.jsonWrites to this project's opencode.json — applies to this repository only.
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-auto-approval-plugin@0.1.1"]
}Writes to ~/.config/opencode/opencode.json — applies to every project.
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-auto-approval-plugin@0.1.1"]
}If you want to modify the plugin locally, install it into the project and reference the local path.
shell
pnpm add -D opencode-auto-approval-pluginopencode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.
An OpenCode plugin that sends tool operations to a read-only AI reviewer before automatically approving them.
The reviewer runs in its own OpenCode session. It may inspect the workspace with read, glob,
grep, and lsp, but cannot edit files, run shell commands, access the network, use MCP tools, or
start subagents.
Install
OpenCode installs npm plugins listed in opencode.json automatically. Add the package to the
project or global OpenCode configuration:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-auto-approval-plugin"],
}
For local development, build the package and add the generated dist/index.js to
.opencode/plugins/, or link the package through an npm workspace. OpenCode also loads TypeScript
files placed directly in .opencode/plugins/.
Configuration
Use a plugin tuple to pass options. The defaults are mode: "on-ask", a 30-second review timeout,
and the provider/model of the main session.
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
[
"opencode-auto-approval-plugin",
{
"mode": "on-ask",
"reviewer": {
"timeoutMs": 30000,
},
},
],
],
}
Set reviewer.model to run reviews through a separately configured OpenCode provider and model.
The plugin never reads or manages API keys; authentication remains entirely in OpenCode.
{
"plugin": [
[
"opencode-auto-approval-plugin",
{
"mode": "all-tools",
"reviewer": {
"model": {
"providerID": "openrouter",
"modelID": "openai/gpt-5.6-luna",
},
"timeoutMs": 15000,
},
},
],
],
}
Review modes
| Mode | Reviewed operations | allow |
deny |
escalate / reviewer failure |
|---|---|---|---|---|
on-ask (default) |
Only operations that OpenCode already decided should ask | Sends an SDK once approval |
Leaves the OpenCode approval pending | Leaves the OpenCode approval pending |
all-tools |
Every intercepted tool call, including OpenCode-allowed calls | Runs the tool | Blocks the tool | Blocks the tool and reports that human review is required |
OpenCode's public plugin API does not currently provide a way to create and await a new permission
dialogue from tool.execute.before. Therefore, all-tools fails closed for an escalate verdict:
the tool does not run and the user must explicitly retry after reviewing the reported reason. In
contrast, on-ask preserves OpenCode's native human permission UI.
Explicit OpenCode deny rules always remain in effect. The plugin is an additional review layer;
it never turns a built-in deny into an allow.
Toolchain
| Area | Tool | Config |
|---|---|---|
| Runtime / tooling | mise | mise.toml |
| Package manager | pnpm | pnpm-workspace.yaml, .npmrc |
| Language | TypeScript | tsconfig.json |
| Build | tsdown | tsdown.config.ts |
| Test | Vitest | vitest.config.ts |
| Format | oxfmt | .oxfmtrc.json |
| Lint | oxlint | .oxlintrc.json |
| Unused code | knip | knip.ts |
| Spelling | cspell | cspell.json |
| Secret scanning | secretlint | .secretlintrc.json |
| Git hooks | simple-git-hooks + lint-staged | package.json, .lintstagedrc.js |
| AI rules | rulesync | rulesync.jsonc, .rulesync/ |
| Workflow lint | actionlint | .github/workflows/actionlint.yml |
| Action pinning | pinact | .pinact.yaml, .github/workflows/pinact.yml |
| Dependency bumps | Dependabot | .github/dependabot.yml |
| Misconfig scan | Trivy | .trivyignore, .github/workflows/trivy-security-scan.yml |
| Dev environment | Dev Container | .devcontainer/ |
| CI / Release | GitHub Actions | .github/workflows/ci.yml, publish.yml |
Getting started
mise install # install node, pnpm, actionlint, pinact
pnpm install # install dependencies and set up the pre-commit hook
pnpm cicheck # run everything CI runs
Scripts
| Script | Description |
|---|---|
pnpm build |
Build ESM + CJS bundles and type declarations into dist |
pnpm check |
fmt:check + oxlint + typecheck |
pnpm cicheck |
cicheck:code + cicheck:content — what CI runs |
pnpm cicheck:code |
check + test |
pnpm cicheck:content |
cspell + secretlint |
pnpm fix |
Auto-fix formatting and lint problems |
pnpm generate |
Regenerate AI tool configs from .rulesync/ |
pnpm knip |
Report unused files, exports, and dependencies |
pnpm test |
Run the test suite |
pnpm test:coverage |
Run the test suite with coverage |
pnpm typecheck |
Type-check without emitting |
mise tasks
| Task | Description |
|---|---|
mise run actionlint |
Lint GitHub Actions workflows |
mise run pinact |
Pin actions in workflows to full commit SHAs |
mise run pinact:check |
Fail if any action is not pinned to a commit SHA |
mise run trivy |
Scan .devcontainer/ and workflows for misconfigurations |
Supply chain hardening
.npmrcsetssave-exact=true, so every dependency is pinned to an exact version.pnpm-workspace.yamlsetsminimumReleaseAge: 1440, so a version published less than a day ago is refused — a compromised release has time to be pulled before it reaches a lockfile.- Postinstall scripts are blocked by default via
allowBuilds; add a package there only when a build step is genuinely required. CI installs with--ignore-scripts. - Every third-party GitHub Action is pinned to a full-length commit SHA, enforced by
pinactin CI. - Workflows declare the narrowest
permissions:block they need. secretlintruns over every staged file through lint-staged, and over the whole tree in CI.trivy configscans.devcontainer/and.github/workflows/for misconfigurations on every push and pull request that touches them;CRITICALandHIGHfindings fail the build. Suppressions live in.trivyignore, each with the reason it is safe.- The dev container pins the Codex CLI installer to a version and verifies its SHA-256 checksum before running it.
Dev container
.devcontainer/ provides a sandboxed environment for running AI coding agents with relaxed
permissions. It is adapted from dyoshikawa/rulesync and
ships Node, mise-managed tooling (including actionlint and pinact), gh, Claude Code, Codex
CLI, opencode, Gemini CLI, git-gtr, and zsh/bash with completions.
Open the repository in a Dev Container-aware editor and it builds from .devcontainer/Dockerfile,
then runs .devcontainer/init.sh to configure git credentials, the pnpm store, and pnpm install.
Secrets are read from the host environment, so export the ones you need before opening the container — all of them are optional:
| Host variable | Forwarded as |
|---|---|
OPENCODE_AUTO_APPROVAL_PLUGIN_DEVCONTAINER_GITHUB_TOKEN |
GITHUB_TOKEN |
OPENCODE_AUTO_APPROVAL_PLUGIN_DEVCONTAINER_OPENAI_API_KEY |
OPENAI_API_KEY |
OPENCODE_AUTO_APPROVAL_PLUGIN_DEVCONTAINER_GEMINI_API_KEY |
GEMINI_API_KEY |
OPENCODE_AUTO_APPROVAL_PLUGIN_DEVCONTAINER_OPENROUTER_API_KEY |
OPENROUTER_API_KEY |
OPENCODE_AUTO_APPROVAL_PLUGIN_DEVCONTAINER_ZAI_API_KEY |
ZHIPU_API_KEY |
OPENCODE_AUTO_APPROVAL_PLUGIN_DEVCONTAINER_OPENCODE_API_KEY |
OPENCODE_API_KEY |
mise.toml is copied into the image at build time, so changing it requires rebuilding the
container.
AI coding agent rules
Rules live in .rulesync/ and are compiled into each tool's native format by pnpm generate:
.rulesync/rules/*.md— instructions (overview, coding, testing, GitHub Actions security).rulesync/mcp.json— MCP servers.rulesync/hooks.json— session hooks.rulesync/permissions.jsonc— per-tool permission settingsrulesync.jsonc— which tools to generate for (Claude Code, Codex CLI, GitHub Copilot, opencode)
Generated files (AGENTS.md, CLAUDE.md, .claude/, .github/instructions/, …) are gitignored —
edit .rulesync/** instead, never the generated output.
Publishing
.github/workflows/publish.yml publishes to npm when a GitHub Release is published, or when run
manually for a release tag. It checks that the tag is a semantic v*.*.* version, matches
package.json, and points to a commit in main; it then runs pnpm cicheck, builds, and publishes
through npm Trusted Publishing (OIDC — no npm token in
secrets).
Configure npm's trusted publisher for dyoshikawa/opencode-auto-approval-plugin to use GitHub
Actions and the .github/workflows/publish.yml workflow. For each later release, bump the package
version on main, create its matching v<version> tag, and publish the GitHub Release.
OpenCode publishes and distributes plugins as ordinary npm packages: users add the package name to
the plugin array in opencode.json, and OpenCode installs it with Bun at startup. See the
OpenCode plugin documentation for the loader and cache behavior.