Skip to content

Add OpenCode plugin support - #15

Merged
gpambrozio merged 14 commits into
mainfrom
luke/opencode-plugin-support
Jul 9, 2026
Merged

Add OpenCode plugin support#15
gpambrozio merged 14 commits into
mainfrom
luke/opencode-plugin-support

Conversation

@lukelabonte

@lukelabonte lukelabonte commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Overview

Adds local OpenCode support to each marketplace plugin without changing the existing Claude Code plugin format. OpenCode users can point their configuration at a plugin's opencode-plugin.js entry point, which adapts the package's existing skills, MCP servers, session context, command guardrails, and shell setup to OpenCode hooks.

The implementation also hardens the XcodeBuildTools integration around sandbox containment, stale-session cleanup, bounded process termination, non-Git project paths, and prompt-time executable trust.

Technical Details

  • Adds one canonical common/opencode-plugin.js adapter, five synchronized package-local copies, and thin per-plugin entry points.
  • Translates Claude-compatible MCP definitions while preserving endpoint precedence and exporting authoritative CLAUDE_PLUGIN_ROOT, CLAUDE_PLUGIN_DATA, and CLAUDE_PROJECT_DIR values.
  • Reuses existing session-start content and pre-tool-use rules through OpenCode's system-transform and tool hooks.
  • Gives XcodeBuildTools sessions isolated build/package directories with owner, identity, quarantine, and lifecycle checks before cleanup.
  • Tracks Xcode MCP detection and approval work per session, uses fixed system executable paths, and shares bounded SIGTERMSIGKILL cleanup across session deletion and plugin disposal.
  • Makes Node.js a required validation dependency and expands runtime/integrity coverage for the adapter and generated packages.

Register OpenCode entrypoints for each plugin, wire shared skill/MCP/context hooks, and document local OpenCode installation.
@lukelabonte
lukelabonte marked this pull request as ready for review July 2, 2026 20:03
@lukelabonte
lukelabonte requested review from Copilot and gpambrozio July 2, 2026 20:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds OpenCode local plugin support by introducing a shared OpenCode adapter (common/opencode-plugin.js), generating per-plugin adapter copies + lightweight opencode-plugin.js entrypoints, and updating docs/tests/version metadata so OpenCode users can install plugins by pointing config at each plugin directory entrypoint.

Changes:

  • Introduces createOpenCodePlugin() adapter (shared + per-plugin generated copies) and adds per-plugin opencode-plugin.js entrypoints.
  • Updates plugin documentation and repository docs to include OpenCode installation/config guidance.
  • Extends repository integrity tests and sync tooling to cover OpenCode entrypoints and generate JS helpers with // comment headers.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
common/opencode-plugin.js Adds shared OpenCode adapter for skills/MCP/session context/guardrails/shell env.
scripts/sync-plugin-common.py Generates // headers for .js/.ts common helper copies.
tests/test_repository_integrity.py Adds integrity checks for OpenCode entrypoints + JS syntax/export validation.
README.md Documents OpenCode installation flow via opencode-plugin.js entrypoints.
CLAUDE.md Documents OpenCode entrypoint presence and OpenCode test guidance.
.claude-plugin/marketplace.json Bumps plugin versions to include OpenCode support releases.
PluginBase/opencode-plugin.js Adds OpenCode entrypoint for PluginBase.
PluginBase/common/opencode-plugin.js Adds generated OpenCode adapter copy into PluginBase package.
PluginBase/info.json Records PluginBase changelog entry for OpenCode adapter/template.
PluginBase/.claude-plugin/plugin.json Bumps PluginBase version.
XcodeBuildTools/opencode-plugin.js Adds OpenCode entrypoint for XcodeBuildTools.
XcodeBuildTools/common/opencode-plugin.js Adds generated OpenCode adapter copy into XcodeBuildTools package.
XcodeBuildTools/README.md Adds OpenCode installation instructions and changelog entry.
XcodeBuildTools/info.json Records OpenCode support in version history.
XcodeBuildTools/.claude-plugin/plugin.json Bumps XcodeBuildTools version.
SwiftScaffolding/opencode-plugin.js Adds OpenCode entrypoint for SwiftScaffolding.
SwiftScaffolding/common/opencode-plugin.js Adds generated OpenCode adapter copy into SwiftScaffolding package.
SwiftScaffolding/README.md Adds OpenCode installation instructions and changelog entry.
SwiftScaffolding/info.json Records OpenCode support in version history.
SwiftScaffolding/.claude-plugin/plugin.json Bumps SwiftScaffolding version.
MarvinOutputStyle/opencode-plugin.js Adds OpenCode entrypoint for MarvinOutputStyle.
MarvinOutputStyle/common/opencode-plugin.js Adds generated OpenCode adapter copy into MarvinOutputStyle package.
MarvinOutputStyle/README.md Adds OpenCode installation instructions and changelog entry.
MarvinOutputStyle/info.json Records OpenCode support in version history.
MarvinOutputStyle/.claude-plugin/plugin.json Bumps MarvinOutputStyle version.
iOSSimulator/opencode-plugin.js Adds OpenCode entrypoint for iOSSimulator.
iOSSimulator/common/opencode-plugin.js Adds generated OpenCode adapter copy into iOSSimulator package.
iOSSimulator/README.md Adds OpenCode installation instructions and changelog entry.
iOSSimulator/info.json Records OpenCode support in version history.
iOSSimulator/.claude-plugin/plugin.json Bumps iOSSimulator version.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread common/opencode-plugin.js Outdated
Comment thread common/opencode-plugin.js
Comment thread tests/test_repository_integrity.py
@lukelabonte lukelabonte self-assigned this Jul 2, 2026
Comment thread common/opencode-plugin.js
copyOptionalFields(server, translated, ["cwd", "enabled", "timeout"], context);

const environment = isObject(server.environment) ? server.environment : server.env;
translated.environment = {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These compatibility values intentionally come after the source environment so plugin metadata cannot override host-owned paths. CLAUDE_PLUGIN_DATA stays outside the checkout, and CLAUDE_PROJECT_DIR follows the active OpenCode worktree or directory context.

self.assertTrue(entrypoint.exists())
self.assertEqual(expected, entrypoint.read_text(encoding="utf-8"))

def test_node_is_available_for_opencode_runtime_checks(self):

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This explicit availability test is intentional. The runtime and export tests still skip defensively when run in isolation, but the repository-wide suite must fail when Node is missing so CI cannot report success without exercising the OpenCode checks.

@lukelabonte lukelabonte left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional context for three non-obvious compatibility and lifecycle decisions.

Comment thread common/opencode-plugin.js
"opencode.xcodebuildtools.pending-cleanups",
);
const pendingSandboxCleanups =
globalThis[XCODE_SANDBOX_PENDING_CLEANUPS_KEY] instanceof Set

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This process-wide registry survives module reloads so a replacement plugin instance can see cleanup detached by an older one. It supplements the on-disk cleanup marker, allowing the next stale sweep to retry a failed asynchronous removal without waiting for the owner grace period.

Comment thread common/opencode-plugin.js
pluginRoot,
pluginData: () => pluginDataDirectory(pluginRoot, state),
projectDir:
input?.worktree !== "/" || input?.project?.vcs === "git"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenCode uses / as the worktree sentinel for non-Git projects, but / can also be a valid Git worktree. Prefer directory only for the non-Git sentinel so ${CLAUDE_PROJECT_DIR} and MCP cwd stay scoped to the active project.

Comment thread common/opencode-plugin.js
if (!record) return Promise.resolve();
if (!record.terminationPromise) {
record.terminating = true;
record.terminationPromise = terminateXcodeMcpApproval(record).finally(() => {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the helper record mapped until this shared promise settles. session.deleted and dispose() can race; both must await the same SIGTERMSIGKILL path, and removing the record on the child’s early exit would let disposal miss a still-live process group.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 32 changed files in this pull request and generated no new comments.

@gpambrozio
gpambrozio merged commit 0349c77 into main Jul 9, 2026
3 checks passed
@gpambrozio
gpambrozio deleted the luke/opencode-plugin-support branch July 9, 2026 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants