| name | opencode-conflict-prevention |
| description | OpenCode plugin conflict prevention - loading order, deduplication rules, naming conventions, and troubleshooting. Use when publishing plugins or diagnosing plugin conflicts. |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"ai-agents","workflow":"plugin-development"} |
OpenCode Conflict Prevention
Guidelines for avoiding plugin conflicts when developing and publishing OpenCode plugins.
Plugin Loading Priority
Load Order (Lowest to Highest Priority)
OpenCode loads plugins in this order. Later sources override earlier ones:
| Priority | Source | Location |
|---|
| 1 (lowest) | Internal plugins | Built-in to OpenCode |
| 2 | Built-in npm plugins | opencode-anthropic-auth, @gitlab/opencode-gitlab-auth |
| 3 | Global config | ~/.config/opencode/opencode.json |
| 4 | Project config | <project>/opencode.json |
| 5 | Global plugin directory | ~/.config/opencode/plugins/ |
| 6 (highest) | Project plugin directory | <project>/.opencode/plugins/ |
Key Implications
Priority Rule: Local > Project > Global > npm > Internal
Deduplication Mechanism
How Deduplication Works
OpenCode implements a deduplication system where plugins with the same name from different sources are deduplicated. Higher priority sources win.
export function deduplicatePlugins(plugins: string[]): string[] {
const seenNames = new Set<string>()
const uniqueSpecifiers = new Set<string>()
for (const plugin of plugins.toReversed()) {
const name = extractPluginName(plugin)
if (!seenNames.has(name)) {
seenNames.add(name)
uniqueSpecifiers.add(plugin)
}
}
return Array.from(uniqueSpecifiers).toReversed()
}
What Gets Deduplicated
Plugins are considered the same if they have the same package name:
"my-plugin"
"@scope/my-plugin"
"file:///path/to/my-plugin"
Priority Hierarchy
.opencode/plugins/ (highest - overrides everything)
↓
opencode.json (project) (overrides global)
↓
~/.config/opencode/opencode.json (global)
↓
~/.config/opencode/plugins/ (global directory)
↓
npm packages (lowest - gets overridden)
Naming Conventions
Avoiding Name Conflicts
When publishing a plugin to npm, use a scoped package name to minimize conflicts:
@yourcompany/opencode-plugin-name
@yourusername/opencode-feature
opencode-utils
opencode-helper
opencode-enhancer
opencode-typecheck-integration
opencode-docker-command-runner
Plugin Naming Best Practices
- Use a scope -
@username/plugin-name or @company/plugin-name
- Be descriptive -
opencode-my-feature not my-plugin
- Avoid common prefixes - Don't use
utils, helpers, core
- Include "opencode" - Helps users identify the plugin
Tool Naming
Custom tools within plugins should also follow naming conventions:
myplugin: tool({
myplugin_analyze: tool({ }),
myplugin_transform: tool({ }),
})
analyze: tool({ }),
helper: tool({ }),
Common Conflict Scenarios
Scenario 1: Local vs npm Plugin
Problem: User installs your npm plugin, but also has a local version.
Solution: Document this behavior and advise users to uninstall the local version.
Scenario 2: Duplicate Plugin Names
Problem: Two plugins have the same name.
{
"plugin": ["opencode-enhancer", "my-plugin"]
}
{
"plugin": ["opencode-enhancer-v2", "my-plugin"]
}
Result: The project config's opencode-enhancer-v2 loads, but if there's a naming conflict, only one wins.
Solution: Use unique, descriptive names with scopes.
Scenario 3: Hook Conflicts
Problem: Multiple plugins implement the same hook with conflicting behavior.
"tool.execute.before": async (input, output) => {
}
"tool.execute.before": async (input, output) => {
}
Result: Both hooks run. Order is undefined. If one throws, execution stops.
Solution: Document hook behavior and use graceful degradation.
Troubleshooting Conflicts
Checklist for Diagnosing Issues
opencode status
/status_view
ls -la ~/.config/opencode/plugins/
ls -la .opencode/plugins/
cat ~/.config/opencode/opencode.json
cat opencode.json
Disable Plugins Temporarily
To isolate conflicts, disable plugins in your config:
{
"plugin": []
}
Then add plugins back one by one to identify the culprit.
Clear Cache
If plugins cause crashes or strange behavior:
rm -rf ~/.cache/opencode
opencode
Check Plugin Load Order
export const MyPlugin: Plugin = async (ctx) => {
await ctx.client.app.log({
service: "my-plugin",
level: "info",
message: "Plugin loaded",
extra: { priority: "should be high" },
})
}
Publishing Guidelines
Before Publishing
-
Check for name conflicts
npm search opencode-your-name
-
Test in clean environment
opencode --plugin ./your-plugin.ts
-
Document compatibility
## Compatibility
- Conflicts with: (list known conflicts)
- Tested with: (list tested plugins)
Package.json Recommendations
{
"name": "@yourcompany/opencode-your-feature",
"version": "1.0.0",
"description": "OpenCode plugin for...",
"keywords": ["opencode", "opencode-plugin", "your-feature"],
"peerDependencies": {
"opencode": ">=1.0.0"
},
"opencode": {
"type": "plugin",
"hooks": ["event", "tool.execute.after"],
"tools": ["yourtool_*"]
}
}
Best Practices
✅ Do
@company/opencode-feature
myfeature_analyze
myfeature_transform
"tool.execute.before": async (input, output) => {
try {
} catch (error) {
}
}
if (input.tool === "read" && alreadyProcessed(input)) {
return
}
❌ Don't
utils
helpers
core
"tool.execute.before": async (input, output) => {
throw new Error("I don't like this tool")
}
Resources
See opencode-plugin-compliance for hook system details.
See opencode-tui-safety for TUI-related guidelines.
See opencode-tool-compliance for tool development patterns.