feat(config): add plugin_config for structured plugin options
What does this PR do?
Adds an optional top-level plugin_config map to the config schema so plugins can receive structured options via opencode.json(c):
{
"plugin": ["@acme/my-plugin"],
"plugin_config": {
"@acme/my-plugin": { "endpoint": "https://example.com" }
}
}
Why?
Config parsing is strict (Config.Info is .strict()), so plugins can’t add plugin-specific keys to opencode.json(c) today without an upstream schema change. The common workarounds are env vars or sidecar config files, which are harder to install/standardize.
plugin_config is a minimal, additive escape hatch: OpenCode already passes the resolved config to plugins via Hooks.config, so plugins can read/validate their own entry without any new lifecycle plumbing.
Why this shape (vs plugin: [{ name, config }])?
Keeping plugin as a plain “load list” avoids changing plugin loading/deduping/merge semantics. plugin_config adds configuration without altering how plugins are resolved or initialized.
Notes
-
plugin_configis deep-merged across config layers (same merge behavior as other config objects). - Not intended for secrets; plugins should prefer existing auth/token flows when possible.
How did you verify your code works?
-
bun test --cwd packages/opencode -
bun turbo typecheck -
bun ./script/generate.ts
Fixes #4393