Skip to content

feat: add native OpenCode integration#306

Merged
danielmeppiel merged 11 commits intomainfrom
feat/opencode-integration
Mar 14, 2026
Merged

feat: add native OpenCode integration#306
danielmeppiel merged 11 commits intomainfrom
feat/opencode-integration

Conversation

@danielmeppiel
Copy link
Collaborator

Summary

Add native OpenCode as an opt-in integration target. When .opencode/ directory exists, apm install deploys agents, commands, skills, and MCP configuration.

Closes #305
Supersedes #257 — credits @timvw via Co-authored-by trailer

What's Included

Core Integration (31 files, 894 additions)

Primitive Source Deployment Target
Agents .apm/agents/*.agent.md .opencode/agents/<name>.md
Commands .apm/prompts/*.prompt.md .opencode/commands/<name>.md
Skills .apm/skills/*/SKILL.md .opencode/skills/<name>/SKILL.md
MCP apm.yml scripts opencode.jsonmcp key
Instructions apm compile AGENTS.md (OpenCode reads natively)

Files Changed

New files:

  • src/apm_cli/adapters/client/opencode.pyOpenCodeClientAdapter for opencode.json MCP format (translates command/args/envcommand array/environment)

Modified (integration layer):

  • targets.pyopencode TargetProfile with agents, commands, skills primitives
  • target_detection.py.opencode/ auto-detection, should_integrate_opencode()
  • base_integrator.pyagents_opencode, commands_opencode partition buckets
  • agent_integrator.pyintegrate_package_agents_opencode() + sync_integration_opencode()
  • command_integrator.pyintegrate_package_commands_opencode() + sync_integration_opencode()
  • skill_integrator.py.opencode in opt-in target loops
  • mcp_integrator.py — OpenCode runtime detection, opencode.json stale cleanup
  • factory.py — Register OpenCodeClientAdapter

Modified (CLI wiring):

  • install.pyintegrate_opencode flag, OpenCode agent/command integration in all 3 code paths
  • uninstall.py.opencode/ cleanup for agents, commands, skills
  • compile.py--target opencode option
  • pack.py / packer.pyopencode target support

Tests (20 new, 1778 total passing):

  • Target detection: 6 tests (auto-detect, should_integrate, compile routing)
  • Agent integration: 5 tests (opt-in guard, deploy, multiple, sync cleanup)
  • Command integration: 5 tests (opt-in guard, deploy, multiple, sync cleanup)

Docs (13 Starlight pages updated):

  • Added OpenCode to IDE support tables, getting-started guides, integration docs, CLI reference

Design Decisions

  1. Opt-in via directory presence — Same pattern as Cursor: only integrates when .opencode/ exists
  2. Commands = prompts — OpenCode's .opencode/commands/ maps directly to APM's .prompt.md files (same concept as Claude's .claude/commands/)
  3. MCP format translation — OpenCode uses opencode.json with different schema (command array, environment key, mcp wrapper) — the adapter translates from Copilot format
  4. AGENTS.md native — OpenCode reads AGENTS.md at project root, so apm compile --target opencode just generates that file

Contributor Credit

@timvw researched OpenCode integration in #257. That PR conflicts with the architecture refactoring from PR #301 (TargetProfile + KNOWN_TARGETS pattern), so we reimplemented using the current architecture. Tim is credited via Co-authored-by trailer on all commits.

Copilot AI review requested due to automatic review settings March 14, 2026 22:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds opt-in native OpenCode support across APM’s target detection, integration, MCP configuration, CLI flags, docs, and tests. Integration is enabled when a .opencode/ directory exists and deploys agents/commands/skills plus MCP config updates to opencode.json.

Changes:

  • Introduces OpenCode as a first-class target (opencode) with auto-detection and CLI support.
  • Adds OpenCode agent/command integration paths and MCP config adapter (opencode.json schema).
  • Expands docs + tests to cover OpenCode behavior and target detection.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
tests/unit/integration/test_command_integrator.py Adds OpenCode command integration tests (opt-in + sync removal).
tests/unit/integration/test_agent_integrator.py Adds OpenCode agent integration tests (opt-in + sync removal).
tests/unit/core/test_target_detection.py Adds OpenCode detection/integration tests + adjusts reason assertions.
src/apm_cli/integration/targets.py Registers opencode TargetProfile primitives.
src/apm_cli/integration/skill_integrator.py Adds .opencode to opt-in skill copy & sub-skill promotion paths.
src/apm_cli/integration/mcp_integrator.py Adds OpenCode runtime handling + stale cleanup in opencode.json.
src/apm_cli/integration/command_integrator.py Adds .opencode/commands deployment + sync cleanup.
src/apm_cli/integration/base_integrator.py Adds managed-file bucketing for .opencode agents/commands/skills.
src/apm_cli/integration/agent_integrator.py Adds .opencode/agents deployment + sync cleanup.
src/apm_cli/factory.py Registers OpenCodeClientAdapter.
src/apm_cli/core/target_detection.py Adds opencode to target types + auto-detect rules + descriptions.
src/apm_cli/commands/uninstall.py Adds .opencode cleanup paths for agents/commands/skills.
src/apm_cli/commands/pack.py Adds cursor + opencode pack targets.
src/apm_cli/commands/install.py Wires integrate_opencode into install paths + deploy OpenCode primitives.
src/apm_cli/commands/compile.py Adds --target opencode option and help text.
src/apm_cli/bundle/packer.py Adds .cursor/ + .opencode/ to bundle target filters.
src/apm_cli/adapters/client/opencode.py Implements OpenCode MCP adapter writing opencode.json with mcp schema.
docs/src/content/docs/reference/cli-commands.md Documents OpenCode integration + updated pack targets.
docs/src/content/docs/introduction/why-apm.md Updates product positioning to include OpenCode.
docs/src/content/docs/introduction/what-is-apm.md Adds OpenCode to supported tools and capability table.
docs/src/content/docs/introduction/how-it-works.md Notes OpenCode native integration and MCP output.
docs/src/content/docs/integrations/ide-tool-integration.md Adds OpenCode integration section and file destinations.
docs/src/content/docs/integrations/github-rulesets.md Updates compile guidance text.
docs/src/content/docs/integrations/ci-cd.md Expands drift check paths and guidance to cursor/opencode.
docs/src/content/docs/guides/skills.md Documents .opencode/skills compatibility destination.
docs/src/content/docs/guides/pack-distribute.md Documents cursor/opencode in pack filtering.
docs/src/content/docs/guides/compilation.md Adds OpenCode to “no compile needed” set + capability table.
docs/src/content/docs/getting-started/quick-start.md Shows .cursor/.opencode outputs and guidance.
docs/src/content/docs/getting-started/first-package.md Updates compile guidance for “other tools”.
docs/src/content/docs/enterprise/teams.md Updates enterprise narrative to include OpenCode.
docs/src/content/docs/enterprise/security.md Updates allowed prefixes / deploy locations to include .opencode/.
CHANGELOG.md Adds OpenCode integration and adapter entries.
Comments suppressed due to low confidence (1)

src/apm_cli/integration/mcp_integrator.py:1

  • In the ImportError fallback path, runtimes are filtered via shutil.which(rt). OpenCode is directory-presence based (like Cursor), so it likely won’t have an opencode binary and will be incorrectly filtered out, preventing MCP setup for OpenCode in environments missing RuntimeManager. Recommendation: special-case opencode (and ideally cursor) in this fallback by checking for the corresponding directory (e.g., .opencode/) rather than relying on which().
"""Standalone MCP lifecycle orchestrator.

Comment on lines +56 to +58
opencode_dir = Path(os.getcwd()) / ".opencode"
if not opencode_dir.exists():
return
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

✅ Fixed in earlier commit — update_config() now uses .is_dir() (not .exists()) at line 57, and configure_mcp_server() returns False when .opencode/ is absent (line 101-102). The enabled param is also threaded through to _to_opencode_format().

Comment on lines +82 to +90
def configure_mcp_server(
self,
server_url,
server_name=None,
enabled=True,
env_overrides=None,
server_info_cache=None,
runtime_vars=None,
):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

✅ Fixed — configure_mcp_server() at line 101 now uses .is_dir() and returns False when .opencode/ is absent. See the guard at lines 100-102.

danielmeppiel and others added 9 commits March 14, 2026 23:46
Add .cursor/ to directory tree example, file deployment description,
editor pickup list, commit guidance, and sync tip. Remove Cursor from
the compile-only note since it now has full native install support.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update 8 doc pages that still described Cursor as compile-only or
omitted .cursor/ from path lists:
- first-package.md: Cursor no longer needs apm compile
- why-apm.md: Cursor moved from 'bridges other tools' to native
- ci-cd.md: drift checks include .cursor/, compile comments updated
- github-rulesets.md: Cursor removed from compile-only category
- security.md: .cursor/ added to deploy path allowlists and FAQ
- compilation.md: .cursor/ in folder tree, Cursor in native list
- pack-distribute.md: cursor target option, .cursor/ in bundle tree
- cli-commands.md: Cursor integration detection, uninstall table

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add OpenCode as a new opt-in integration target. When .opencode/
directory exists, apm install deploys:
- Agents → .opencode/agents/<name>.md
- Commands → .opencode/commands/<name>.md (from .prompt.md)
- Skills → .opencode/skills/<name>/SKILL.md
- MCP → opencode.json (new OpenCodeClientAdapter)

OpenCode reads AGENTS.md natively, so apm compile already works.

Implementation:
- Add opencode TargetProfile to KNOWN_TARGETS (targets.py)
- Wire agent, command, skill integrators for .opencode/ (opt-in)
- Create OpenCodeClientAdapter for opencode.json MCP format
- Add opencode to pack/compile target options
- Wire install/uninstall for all OpenCode primitives
- Add 20 unit tests (1778 total passing)
- Update 13 Starlight doc pages
- Credit @timvw in CHANGELOG (PR #257 research)

Closes #257

Co-authored-by: Tim Van Wassenhove <timvw@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add .opencode/skills/ prefix to manifest-based skill removal
- Add .opencode/skills/ to legacy orphan cleanup loop
- Remove '# only if .cursor/ already exists' comments from quick-start.md

Co-authored-by: Tim Van Wassenhove <timvw@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use .is_dir() instead of .exists() for target marker checks
- Return False (not True) from configure_mcp_server when .opencode/ absent
- Thread 'enabled' param through to _to_opencode_format
- Add commands_opencode to partition_managed_files docstring
- Fix OpenCode MCP format description in ide-tool-integration docs

Co-authored-by: Tim Van Wassenhove <timvw@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OpenCode reads AGENTS.md (not per-file instructions), so apm compile
is required for instructions — unlike Copilot/Claude/Cursor which read
.github/instructions/ and .cursor/rules/ natively.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

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 as a first-class, opt-in integration target so apm install can deploy agents/commands/skills (and MCP config via opencode.json) when a .opencode/ directory exists, aligning OpenCode support with the existing multi-target integration architecture.

Changes:

  • Add opencode target detection + CLI target options (compile/pack) and wiring throughout install/uninstall.
  • Implement OpenCode agents/commands integration and OpenCode MCP adapter (opencode.json format).
  • Add unit tests and update Starlight docs + changelog for OpenCode support.

Reviewed changes

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

Show a summary per file
File Description
src/apm_cli/commands/install.py Adds integrate_opencode plumbing and invokes OpenCode agent/command integrators during install.
src/apm_cli/commands/uninstall.py Adds sync cleanup for .opencode/agents and .opencode/commands (and skills via SkillIntegrator).
src/apm_cli/commands/compile.py Adds --target opencode option and help text.
src/apm_cli/commands/pack.py Extends --target choice list to include opencode.
src/apm_cli/bundle/packer.py Adds .opencode/ as a supported pack filter prefix.
src/apm_cli/core/target_detection.py Adds .opencode/ auto-detection, should_integrate_opencode, and target descriptions.
src/apm_cli/integration/targets.py Registers opencode TargetProfile with agents/commands/skills primitives.
src/apm_cli/integration/base_integrator.py Adds managed-files partition buckets for .opencode/agents and .opencode/commands and recognizes .opencode/skills.
src/apm_cli/integration/agent_integrator.py Adds OpenCode agent deployment + sync removal for .opencode/agents/.
src/apm_cli/integration/command_integrator.py Adds OpenCode command deployment from .prompt.md into .opencode/commands/ + sync removal.
src/apm_cli/integration/skill_integrator.py Extends opt-in skill copy/promotion and orphan cleanup to include .opencode/skills/.
src/apm_cli/integration/mcp_integrator.py Adds opencode runtime handling and stale cleanup for opencode.json’s mcp section.
src/apm_cli/factory.py Registers OpenCodeClientAdapter in ClientFactory.
src/apm_cli/adapters/client/opencode.py Implements MCP config translation/writes to repo-root opencode.json under mcp.
tests/unit/core/test_target_detection.py Adds tests for opencode detection, should_integrate_opencode, and descriptions.
tests/unit/integration/test_agent_integrator.py Adds OpenCode agent integration + sync cleanup tests.
tests/unit/integration/test_command_integrator.py Adds OpenCode command integration + sync cleanup tests.
docs/src/content/docs/reference/cli-commands.md Documents .opencode/ detection and CLI pack target options.
docs/src/content/docs/introduction/why-apm.md Updates “integrates primitives” narrative to include OpenCode.
docs/src/content/docs/introduction/what-is-apm.md Adds OpenCode to supported tools table and narrative.
docs/src/content/docs/introduction/how-it-works.md Adds OpenCode to native integration overview and list.
docs/src/content/docs/integrations/ide-tool-integration.md Adds OpenCode integration section + notes on AGENTS.md/instructions.
docs/src/content/docs/integrations/ci-cd.md Extends drift-check paths and commit guidance to include .opencode/.
docs/src/content/docs/guides/skills.md Documents .opencode/skills/ compatibility deployment.
docs/src/content/docs/guides/pack-distribute.md Documents opencode pack target and .opencode/ inclusion in bundles.
docs/src/content/docs/guides/compilation.md Clarifies OpenCode instructions flow via AGENTS.md and tool support matrix.
docs/src/content/docs/getting-started/quick-start.md Updates example tree and explanation to mention .opencode/.
docs/src/content/docs/getting-started/first-package.md Updates compile guidance text to mention OpenCode.
docs/src/content/docs/enterprise/teams.md Updates enterprise narrative to mention OpenCode.
docs/src/content/docs/enterprise/security.md Updates security posture page to include .opencode/ in allowed prefixes.
CHANGELOG.md Adds Unreleased “Native OpenCode integration” entry and adapter mention.
.gitignore Adds scout-pipeline-result.png ignore entry.
Comments suppressed due to low confidence (2)

src/apm_cli/commands/install.py:688

  • Same as the OpenCode agents block: OpenCode command integration is called unconditionally, so .opencode/commands can be populated even when should_integrate_opencode(detected_target) is false. Guard this block with if integrate_opencode: to ensure --target / apm.yml target is actually respected.
    # --- OpenCode commands (.opencode) ---
    opencode_command_result = command_integrator.integrate_package_commands_opencode(
        package_info, project_root,
        force=force, managed_files=managed_files,
        diagnostics=diagnostics,
    )
    if opencode_command_result.files_integrated > 0:
        result["commands"] += opencode_command_result.files_integrated
        _rich_info(f"  └─ {opencode_command_result.files_integrated} commands integrated → .opencode/commands/")
    result["links_resolved"] += opencode_command_result.links_resolved
    for tp in opencode_command_result.target_paths:
        deployed.append(tp.relative_to(project_root).as_posix())

src/apm_cli/core/target_detection.py:177

  • get_target_description()’s minimal description still says “create .github/ or .claude/ for full integration”, but OpenCode is now also a full integration path (via .opencode/). Update the description to include .opencode/ (and likely .cursor/ as well) to avoid misleading CLI help output.
    descriptions = {
        "vscode": "AGENTS.md + .github/prompts/ + .github/agents/",
        "claude": "CLAUDE.md + .claude/commands/ + .claude/agents/ + .claude/skills/",
        "opencode": "AGENTS.md + .opencode/agents/ + .opencode/commands/ + .opencode/skills/",
        "all": "AGENTS.md + CLAUDE.md + .github/ + .claude/ (+ .cursor/ .opencode/ if present)",
        "minimal": "AGENTS.md only (create .github/ or .claude/ for full integration)",
    }

## The problem at scale

Consider a mid-to-large engineering organization: 50 repositories, 200 developers, three AI coding tools (Copilot, Claude, Cursor).
Consider a mid-to-large engineering organization: 50 repositories, 200 developers, three AI coding tools (Copilot, Claude, Cursor, OpenCode).
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

✅ Fixed — changed "three" to "four" to match the list (Copilot, Claude, Cursor, OpenCode).

Comment on lines 13 to +17
- Native Cursor IDE integration — `apm install` deploys primitives to `.cursor/` when the directory exists: instructions→rules (`.mdc`), agents, skills, hooks (`hooks.json`), and MCP (`mcp.json`)
- Native OpenCode integration — `apm install` deploys primitives to `.opencode/` when the directory exists: agents, commands (from prompts), skills, and MCP (`opencode.json`) — inspired by @timvw (#257)
- `TargetProfile` data layer (`src/apm_cli/integration/targets.py`) — data-driven target definitions for scalable multi-target architecture
- `CursorClientAdapter` for MCP server management in `.cursor/mcp.json`
- `OpenCodeClientAdapter` for MCP server management in `opencode.json`
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

✅ Fixed — added #306 to the PR reference and kept the @timvw credit: — inspired by @timvw (#257, #306).

- Add .opencode/hooks/ to partition_managed_files filter (defensive)
- Add comment explaining OpenCode has no hooks support
- Fix quick-start.md and making-the-case.md missing OpenCode in tool lists

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix 'three' → 'four' AI coding tools count in teams.md
- Clarify OpenCode needs apm compile for instructions in first-package.md
- Fix should_integrate_opencode docstring: include 'commands'
- Add PR #306 reference to CHANGELOG entry

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel danielmeppiel merged commit a450236 into main Mar 14, 2026
8 checks passed
@danielmeppiel danielmeppiel deleted the feat/opencode-integration branch March 14, 2026 23:30
This was referenced Mar 14, 2026
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.

feat: Native OpenCode integration Support OpenCode.ai skills directory during install [FEATURE] Opencode support

2 participants