Skip to content

feat: add OpenCode engine integration#18403

Draft
Mossaka wants to merge 2 commits intomainfrom
feat/opencode-engine
Draft

feat: add OpenCode engine integration#18403
Mossaka wants to merge 2 commits intomainfrom
feat/opencode-engine

Conversation

@Mossaka
Copy link
Collaborator

@Mossaka Mossaka commented Feb 25, 2026

Summary

  • Add OpenCode as a new provider-agnostic agentic engine (BYOK — Bring Your Own Key)
  • Full API proxy support on port 10004 (default: Anthropic routing)
  • Full MCP Gateway integration with opencode.jsonc converter script
  • Dynamic domain allowlists based on model provider prefix (anthropic/, openai/, google/, etc.)
  • Headless CI mode via opencode run -q with auto-configured permissions
  • Smoke test workflow with 5 tests (GitHub MCP, web-fetch, file write, bash, make build)
  • 22 unit tests covering engine identity, secrets, installation, execution, firewall integration

New files

File Lines Purpose
pkg/workflow/opencode_engine.go 311 Engine implementation
pkg/workflow/opencode_mcp.go 71 MCP config rendering
pkg/workflow/opencode_engine_test.go 369 Unit tests
actions/setup/sh/convert_gateway_config_opencode.sh 114 MCP Gateway converter
.github/workflows/smoke-opencode.md 80 Smoke test workflow
.github/workflows/smoke-opencode.lock.yml 1386 Compiled smoke test

Modified files

  • pkg/constants/constants.go — Engine name, version (1.2.14), LLM gateway port (10004), env vars
  • pkg/workflow/domains.go — Dynamic domains with extractProviderFromModel(), provider-specific allowlists
  • pkg/workflow/agentic_engine.go — Engine registration
  • actions/setup/sh/start_mcp_gateway.shopencode) case for MCP gateway routing
  • pkg/parser/schemas/main_workflow_schema.json — Added "opencode" to engine ID enum
  • Test files updated for new engine count

Key design decisions

  • Credentials: Defaults to ANTHROPIC_API_KEY, override any provider via engine.env
  • API Proxy: Port 10004, routes to Anthropic API by default
  • Domains: Dynamic per model provider prefix (strict mode safe)
  • Config: Writes opencode.jsonc with all permissions set to allow (prevents CI hanging)
  • Marked experimental: true — can be toggled after smoke tests pass consistently

Companion PR

  • gh-aw-firewall: API proxy port 10004 support (separate PR)

Test plan

  • make build passes
  • All 22 new OpenCode unit tests pass
  • All existing tests pass (no regressions)
  • make lint clean
  • Smoke test compiles to valid lock.yml (1386 lines)
  • Lock file verified: secret validation, npm install, AWF wrapping, API proxy, NO_PROXY, safe outputs
  • Smoke test passes in CI (after firewall PR merged + secrets configured)

🤖 Generated with Claude Code

Add OpenCode as a new agentic engine supporting provider-agnostic AI
coding with BYOK (Bring Your Own Key) and full MCP Gateway + API proxy
support.

New engine features:
- Provider-agnostic: supports Anthropic, OpenAI, Google, Groq, etc.
- Dynamic domain allowlists based on model provider prefix
- API proxy on port 10004 (default: Anthropic routing)
- MCP Gateway integration with opencode.jsonc converter
- Headless CI mode via `opencode run -q`
- Auto-configured permissions to prevent CI hanging
- 22 unit tests covering all engine methods
- Smoke test workflow (5 tests)

Files: opencode_engine.go, opencode_mcp.go, opencode_engine_test.go,
convert_gateway_config_opencode.sh, smoke-opencode.md/.lock.yml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 25, 2026 20:44
Mossaka added a commit to github/gh-aw-firewall that referenced this pull request Feb 25, 2026
Add OpenCode API proxy support on port 10004, routing to Anthropic API
(OpenCode's default BYOK provider). Dynamic port range calculation in
host-iptables ensures future ports are auto-included.

- src/types.ts: Add OPENCODE port 10004 to API_PROXY_PORTS
- containers/api-proxy/server.js: Add OpenCode proxy listener (-> Anthropic)
- containers/api-proxy/Dockerfile: Expose port 10004
- src/host-iptables.ts: Use Object.values() for dynamic port range

Companion to github/gh-aw#18403 (OpenCode engine integration)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.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

This pull request adds OpenCode as a new provider-agnostic agentic engine with BYOK (Bring Your Own Key) support. It enables users to integrate OpenCode CLI with support for 75+ models across multiple providers (Anthropic, OpenAI, Google, etc.). The PR includes full API proxy support on port 10004, MCP Gateway integration, headless CI mode support, and comprehensive test coverage.

Changes:

  • Added OpenCode engine implementation with installation, execution, and MCP configuration support
  • Integrated OpenCode with AWF firewall and LLM gateway proxy on port 10004
  • Added MCP Gateway converter script for OpenCode-specific configuration format
  • Created smoke test workflow with 5 integration tests and 22 unit tests
  • Updated schema, constants, and test expectations to include the new engine

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/workflow/opencode_engine.go Core OpenCode engine implementation with installation and execution logic
pkg/workflow/opencode_mcp.go MCP configuration rendering for OpenCode JSON format
pkg/workflow/opencode_engine_test.go 22 unit tests covering engine identity, secrets, installation, execution, and firewall integration
pkg/workflow/domains.go Domain allowlist infrastructure with provider-specific domain mappings (not fully utilized)
pkg/workflow/agentic_engine.go Engine registry updated to include OpenCode
pkg/constants/constants.go OpenCode constants including version (1.2.14), LLM gateway port (10004), and environment variables
actions/setup/sh/convert_gateway_config_opencode.sh Shell script to convert MCP Gateway config to OpenCode's opencode.jsonc format
actions/setup/sh/start_mcp_gateway.sh Added OpenCode routing case to MCP gateway startup script
pkg/parser/schemas/main_workflow_schema.json Added "opencode" to engine ID enum with description
.github/workflows/smoke-opencode.md Smoke test workflow definition with 5 test requirements
.github/workflows/smoke-opencode.lock.yml Compiled smoke test workflow (1386 lines)
pkg/constants/constants_test.go Updated to expect 4 engines including "opencode"
pkg/cli/completions_test.go Updated to expect 5 engines in completions
Comments suppressed due to low confidence (1)

pkg/workflow/domains.go:155

  • The extractProviderFromModel function is exported (starts with lowercase 'e' but used outside its package context in tests), suggesting it should be used elsewhere. However, this function is never called from production code - only from GetOpenCodeDefaultDomains which itself is never called. This function should be used to implement the dynamic domain selection feature mentioned in the PR description.
// extractProviderFromModel extracts the provider name from an OpenCode model string.
// OpenCode uses "provider/model" format (e.g., "anthropic/claude-sonnet-4-20250514").
// Returns the provider prefix, or "anthropic" as default if no slash is found.
func extractProviderFromModel(model string) string {
	if model == "" {
		return "anthropic"
	}
	parts := strings.SplitN(model, "/", 2)
	if len(parts) < 2 {
		return "anthropic"
	}
	return strings.ToLower(parts[0])
}

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

Comment on lines +171 to +175
// GetOpenCodeAllowedDomainsWithToolsAndRuntimes merges OpenCode default domains with NetworkPermissions, HTTP MCP server domains, and runtime ecosystem domains
// Returns a deduplicated, sorted, comma-separated string suitable for AWF's --allow-domains flag
func GetOpenCodeAllowedDomainsWithToolsAndRuntimes(network *NetworkPermissions, tools map[string]any, runtimes map[string]any) string {
return GetAllowedDomainsForEngine(constants.OpenCodeEngine, network, tools, runtimes)
}
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

The dynamic domain selection feature described in the PR is not fully implemented. The function GetOpenCodeDefaultDomains(model string) exists at lines 157-169 to provide model-specific domains based on provider prefix (e.g., "anthropic/", "openai/"), but this function is never called. Instead, line 174 uses GetAllowedDomainsForEngine(constants.OpenCodeEngine, ...) which looks up the static OpenCodeDefaultDomains constant from the engineDefaultDomains map (line 595).

To fix this, the function should extract the model from the workflow data (if firewall is enabled) and use it to calculate provider-specific domains. However, note that GetOpenCodeAllowedDomainsWithToolsAndRuntimes doesn't have access to WorkflowData to retrieve the model, and changing the signature would affect the calling code in opencode_engine.go line 213.

This issue also appears on line 143 of the same file.

Copilot uses AI. Check for mistakes.
@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

Hi @Mossaka! 👋 Thanks for putting together this detailed OpenCode engine integration — it's clear you've put real effort into the implementation (tests, description, focused scope — all great signs!).

However, based on the project's CONTRIBUTING.md, direct PRs from community contributors aren't the expected path here. The github/gh-aw project uses an agentic contribution workflow where:

  1. Community members open a GitHub Issue describing the feature/fix they'd like to see, with as much detail as possible
  2. A core team member reviews the proposal
  3. If approved, a coding agent implements it guided by the issue

What to do next:

  • Please open a new GitHub Issue describing the OpenCode engine integration you have in mind (you can reference this PR for the design decisions and test plan)
  • Tag it with relevant labels and mention @pelikhan or another core team member to get visibility

Your work here is a great reference — the core team can use it as a starting point when implementing via the agentic workflow. Sorry for the friction, and thanks again for the contribution! 🙏

Generated by Contribution Check

@Mossaka Mossaka added the smoke-test-pr Trigger smoke tests on PR label Feb 25, 2026
@Mossaka Mossaka marked this pull request as draft February 25, 2026 21:19
Add comprehensive external-facing documentation for the OpenCode engine:
- New guide: docs/src/content/docs/guides/opencode.md (460 lines)
  - Quick start, auth/providers, network security, MCP support
  - Example workflows, engine comparison, known limitations
- Update engines.md: add OpenCode to available agents list
- Update auth.mdx: add OpenCode authentication reference
- Update network.md: add OpenCode domain config + dynamic provider docs
- Update astro.config.mjs: add sidebar link

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mossaka added a commit to github/gh-aw-firewall that referenced this pull request Feb 25, 2026
* feat: add API proxy port 10004 for OpenCode engine

Add OpenCode API proxy support on port 10004, routing to Anthropic API
(OpenCode's default BYOK provider). Dynamic port range calculation in
host-iptables ensures future ports are auto-included.

- src/types.ts: Add OPENCODE port 10004 to API_PROXY_PORTS
- containers/api-proxy/server.js: Add OpenCode proxy listener (-> Anthropic)
- containers/api-proxy/Dockerfile: Expose port 10004
- src/host-iptables.ts: Use Object.values() for dynamic port range

Companion to github/gh-aw#18403 (OpenCode engine integration)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review comments on OpenCode proxy

- Fix log injection: extract sanitized values before template literal
- Add comment explaining why OpenCode gets a separate port from Claude
  (rate limiting isolation, metrics, future multi-provider routing)
- docker-manager.ts env var not needed: gh-aw passes ANTHROPIC_BASE_URL
  via --env-all at the GitHub Actions level

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pelikhan
Copy link
Contributor

Great!

Add open code version checking to the cli version checker.

Smoke aw can go with the same label as gemini

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-work smoke-test-pr Trigger smoke tests on PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants