feat: add native OpenCode integration#306
Conversation
There was a problem hiding this comment.
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.jsonschema). - 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
ImportErrorfallback path, runtimes are filtered viashutil.which(rt). OpenCode is directory-presence based (like Cursor), so it likely won’t have anopencodebinary and will be incorrectly filtered out, preventing MCP setup for OpenCode in environments missingRuntimeManager. Recommendation: special-caseopencode(and ideallycursor) in this fallback by checking for the corresponding directory (e.g.,.opencode/) rather than relying onwhich().
"""Standalone MCP lifecycle orchestrator.
| opencode_dir = Path(os.getcwd()) / ".opencode" | ||
| if not opencode_dir.exists(): | ||
| return |
There was a problem hiding this comment.
✅ 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().
| def configure_mcp_server( | ||
| self, | ||
| server_url, | ||
| server_name=None, | ||
| enabled=True, | ||
| env_overrides=None, | ||
| server_info_cache=None, | ||
| runtime_vars=None, | ||
| ): |
There was a problem hiding this comment.
✅ 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.
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>
f251e1c to
aa3c1fd
Compare
There was a problem hiding this comment.
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
opencodetarget detection + CLI target options (compile/pack) and wiring throughout install/uninstall. - Implement OpenCode agents/commands integration and OpenCode MCP adapter (
opencode.jsonformat). - 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/commandscan be populated even whenshould_integrate_opencode(detected_target)is false. Guard this block withif integrate_opencode:to ensure--target/apm.yml targetis 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()’sminimaldescription 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). |
There was a problem hiding this comment.
✅ Fixed — changed "three" to "four" to match the list (Copilot, Claude, Cursor, OpenCode).
| - 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` |
There was a problem hiding this comment.
✅ 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>
Summary
Add native OpenCode as an opt-in integration target. When
.opencode/directory exists,apm installdeploys agents, commands, skills, and MCP configuration.Closes #305
Supersedes #257 — credits @timvw via
Co-authored-bytrailerWhat's Included
Core Integration (31 files, 894 additions)
.apm/agents/*.agent.md.opencode/agents/<name>.md.apm/prompts/*.prompt.md.opencode/commands/<name>.md.apm/skills/*/SKILL.md.opencode/skills/<name>/SKILL.mdapm.ymlscriptsopencode.json→mcpkeyapm compileAGENTS.md(OpenCode reads natively)Files Changed
New files:
src/apm_cli/adapters/client/opencode.py—OpenCodeClientAdapterforopencode.jsonMCP format (translatescommand/args/env→commandarray/environment)Modified (integration layer):
targets.py—opencodeTargetProfile with agents, commands, skills primitivestarget_detection.py—.opencode/auto-detection,should_integrate_opencode()base_integrator.py—agents_opencode,commands_opencodepartition bucketsagent_integrator.py—integrate_package_agents_opencode()+sync_integration_opencode()command_integrator.py—integrate_package_commands_opencode()+sync_integration_opencode()skill_integrator.py—.opencodein opt-in target loopsmcp_integrator.py— OpenCode runtime detection,opencode.jsonstale cleanupfactory.py— RegisterOpenCodeClientAdapterModified (CLI wiring):
install.py—integrate_opencodeflag, OpenCode agent/command integration in all 3 code pathsuninstall.py—.opencode/cleanup for agents, commands, skillscompile.py—--target opencodeoptionpack.py/packer.py—opencodetarget supportTests (20 new, 1778 total passing):
Docs (13 Starlight pages updated):
Design Decisions
.opencode/exists.opencode/commands/maps directly to APM's.prompt.mdfiles (same concept as Claude's.claude/commands/)opencode.jsonwith different schema (commandarray,environmentkey,mcpwrapper) — the adapter translates from Copilot formatAGENTS.mdat project root, soapm compile --target opencodejust generates that fileContributor 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-bytrailer on all commits.