Fork of 13rac1/openclaw-plugin-claude-code
This is a community fork that replaces Claude Code with OpenCode — an open-source, provider-agnostic coding agent. While the upstream plugin is locked to Anthropic's Claude Code CLI, this fork works with any of the 75+ LLM providers that OpenCode supports.
See Differences from Upstream for a full comparison.
Run OpenCode in secure, isolated containers with any LLM provider.
An OpenClaw plugin that executes OpenCode agent sessions in rootless Podman containers. Let your AI agents delegate complex coding tasks to OpenCode without risking your host system — and without being locked to a single provider.
- Differences from Upstream
- Why Use This Plugin?
- FAQ
- Features
- Requirements
- Installation
- Configuration
- Authentication
- Job Completion Notifications
- Registered Tools
- Security
- Development
- Container Image
- Releasing
- Troubleshooting
This fork is a full architectural rewrite. The tool interface (6 tools, same parameters) is preserved for compatibility, but everything behind it has changed.
| Aspect | Upstream (Claude Code) | This Fork (OpenCode) |
|---|---|---|
| Agent | Claude Code CLI (claude) |
OpenCode (opencode serve) |
| Provider support | Anthropic only | 75+ providers (Anthropic, OpenAI, Google, local models, etc.) |
| Communication | Parse CLI stdout (stream-json) | HTTP API via OpenCode SDK |
| Container lifecycle | One-shot per job (start, run, exit) | Long-lived server per session (reused across jobs) |
| Auth mechanism | ~/.claude/.credentials.json or ANTHROPIC_API_KEY |
~/.local/share/opencode/auth.json (multi-provider) |
| Permission bypass | --dangerously-skip-permissions CLI flag |
"permission": "allow" in config (container is the boundary) |
| Session resume | --resume <id> CLI flag |
SDK session API (create once, send multiple prompts) |
| Port mapping | None (stdout-based) | Dynamic host port -> container port 4096 |
| Rate limit handling | Regex parsing of stdout errors | Handled internally by OpenCode per-provider |
| Server health | N/A (process-based) | GET /global/health with exponential backoff |
| Output capture | Stream-json parsing with regex extraction | Structured SDK responses written to local log files |
| Orphan recovery | Kill orphaned containers | Reconnect to healthy orphaned servers via port readback |
| Container user | claude (UID 1000) |
opencode (UID 1000) |
| Tool names | claude_code_* |
opencode_* |
The upstream plugin is tightly coupled to Claude Code's proprietary CLI, its stream-json output format, and Anthropic's authentication. OpenCode is open-source, supports many providers, and has a proper headless server mode with an HTTP API — making it a better fit for a containerized agent architecture.
The long-lived server model also eliminates cold-start overhead for multi-turn sessions: the first job starts the server, and subsequent jobs reuse it instantly.
Use any LLM provider OpenCode supports — Anthropic, OpenAI, Google, Groq, local models via Ollama, and many more. Configure your provider once with opencode auth login and the plugin handles the rest.
OpenCode with "permission": "allow" can modify any file and run any command. This plugin contains each session in a rootless container with:
- All Linux capabilities dropped
- Configurable network isolation
- Memory and CPU limits
- Optional AppArmor profiles
Bad code, infinite loops, or accidental rm -rf stays inside the container. Your host system remains untouched.
Run multiple OpenCode sessions simultaneously, each in its own isolated workspace. Sessions maintain state across interactions, enabling complex multi-step workflows without interference.
Unlike the upstream's one-shot model, each session runs a persistent OpenCode server. The first job pays the startup cost; subsequent jobs in the same session get instant responses with no cold start.
Any OpenClaw agent can use the opencode_start tool to offload coding tasks. The orchestrating agent stays lightweight while OpenCode handles the heavy lifting in its own container.
Security. This plugin runs AI-generated code with all permissions allowed — the container is your only safety net. Podman is rootless by default: no daemon, no root process, no privilege escalation path. If an AI agent escapes the container, it lands in an unprivileged user namespace with no capabilities.
Docker's default mode runs a root daemon. A container escape from a root-daemon Docker setup gives the attacker full root access to the host. Docker can run rootless, but it requires additional setup and isn't the default.
The plugin supports runtime: "docker" for users who have configured rootless Docker, but Podman is strongly recommended.
The built-in coding-agent skill runs agents directly on your host. This plugin provides containment: each session runs in a rootless Podman container with dropped capabilities, resource limits, and tmpfs isolation.
Use the coding-agent skill when:
- Quick setup matters more than isolation
- You're already comfortable with OpenClaw's sandbox mode
- Tasks are short-lived and don't need session persistence
Use this plugin when:
- You want real containment for code execution
- You need persistent sessions that survive across interactions
- You want structured job management (status, output pagination, activity detection, crash recovery)
- You're running untrusted or experimental code and need hard resource limits
- Isolated Execution: Each OpenCode session runs in its own container with dropped capabilities
- SDK-based Communication: Structured HTTP API instead of fragile stdout parsing
- Long-lived Servers: One server per session, reused across multiple jobs
- Provider Agnostic: Works with any provider OpenCode supports (75+)
- Session Persistence: Sessions maintain state across multiple interactions
- Resource Limits: Configurable memory, CPU, and PID limits
- AppArmor Support: Optional AppArmor profile for additional security hardening
- Automatic Cleanup: Idle sessions are automatically cleaned up
- Orphan Recovery: Reconnects to healthy orphaned servers on startup instead of killing them
- OpenClaw >= 2025.1.0
- Podman (recommended) or Docker
- OpenCode installed locally (for
opencode auth login) - Node.js >= 22
openclaw plugins install @13rac1/openclaw-plugin-opencodeDownload the latest release zip from GitHub Releases and extract to your plugins directory:
unzip openclaw-plugin-opencode-*.zip -d ~/.openclaw/plugins/openclaw-plugin-opencodeThe plugin requires a container image with OpenCode installed. Pull the pre-built image:
podman pull ghcr.io/13rac1/openclaw-opencode:latestOr build it yourself:
podman build -t ghcr.io/13rac1/openclaw-opencode:latest .Before using the plugin, configure OpenCode with your preferred provider:
# Install OpenCode if not already installed
npm install -g opencode-ai
# Login to your provider (interactive)
opencode auth loginThis creates credentials at ~/.local/share/opencode/auth.json which the plugin mounts into each container.
Add to your openclaw.json:
{
"plugins": {
"enabled": true,
"load": {
"paths": ["path/to/dist/opencode.js"]
},
"entries": {
"opencode": {
"enabled": true,
"config": {
"image": "ghcr.io/13rac1/openclaw-opencode:latest",
"runtime": "podman",
"serverReadyTimeout": 30,
"idleTimeout": 120,
"memory": "512m",
"cpus": "1.0",
"network": "bridge",
"sessionsDir": "~/.openclaw/opencode-sessions",
"workspacesDir": "~/.openclaw/workspaces",
"sessionIdleTimeout": 3600
}
}
}
}
}| Option | Type | Default | Description |
|---|---|---|---|
image |
string | ghcr.io/13rac1/openclaw-opencode:latest |
Container image for OpenCode |
runtime |
string | podman |
Container runtime (podman or docker) |
serverReadyTimeout |
number | 30 |
Seconds to wait for OpenCode server to become healthy |
idleTimeout |
number | 120 |
Kill container after this many seconds of no activity |
memory |
string | 512m |
Memory limit for containers |
cpus |
string | 1.0 |
CPU limit for containers |
network |
string | bridge |
Network mode (none, bridge, host). Must be bridge or host for LLM API access. |
sessionsDir |
string | ~/.openclaw/opencode-sessions |
Directory for session metadata |
workspacesDir |
string | ~/.openclaw/workspaces |
Directory for session workspaces |
sessionIdleTimeout |
number | 3600 |
Cleanup idle sessions after this many seconds |
apparmorProfile |
string | "" |
AppArmor profile name (empty = disabled) |
maxOutputSize |
number | 10485760 |
Maximum output size in bytes (10MB default, 0 = unlimited) |
notifyWebhookUrl |
string | http://localhost:18789/hooks/agent |
OpenClaw webhook URL for notifications |
hooksToken |
string | "" |
Webhook auth token (must match OpenClaw hooks.token to enable notifications) |
OpenCode manages its own multi-provider authentication. The plugin mounts your local OpenCode configuration into each container:
~/.config/opencode/— provider configuration, model settings~/.local/share/opencode/— authentication credentials
Run opencode auth login once on the host to configure your provider. The plugin will fail with a clear error if ~/.local/share/opencode/auth.json does not exist.
opencode auth loginThis supports any provider OpenCode offers: Anthropic, OpenAI, Google, Groq, Mistral, local models, and many more.
The plugin sends webhook notifications when jobs complete. No polling required.
Enable webhooks in OpenClaw config (~/.openclaw/openclaw.json):
{
"hooks": {
"enabled": true,
"token": "your-secret-token"
}
}The plugin automatically reads the token from the OpenClaw config file. When a job completes, fails, or is cancelled, the agent receives a message with the job status, duration, and output size.
If you use OpenClaw's sandbox mode, add the plugin's tools to your sandbox tool allowlist:
{
"tools": {
"sandbox": {
"tools": {
"allow": [
"exec",
"process",
"read",
"write",
"edit",
"apply_patch",
"image",
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
"opencode_start",
"opencode_status",
"opencode_output",
"opencode_cancel",
"opencode_cleanup",
"opencode_sessions"
]
}
}
}
}Start an OpenCode task in the background. Returns immediately with a job ID.
Parameters:
prompt(required): The task or prompt to send to OpenCodesession_id(optional): Session ID to continue a previous session
Returns: { jobId, sessionKey, status: "running" }
Check the status of a running or completed job.
Parameters:
job_id(required): Job ID returned fromopencode_startsession_id(optional): Session ID
Returns:
status: Job status (pending, running, completed, failed, cancelled)elapsedSeconds: Time since job startedoutputSize: Total output size in bytestailOutput: Last ~500 chars of output (for quick preview)lastOutputSecondsAgo: Seconds since last output was producedactivityState: "active" (producing output), "processing" (CPU busy), or "idle"metrics: CPU and memory usageexitCode: Process exit code (when completed)error: Error message (if failed)
Read output from a job. Supports reading partial output while job is running.
Parameters:
job_id(required): Job IDsession_id(optional): Session IDoffset(optional): Byte offset to start reading from (for pagination)limit(optional): Maximum bytes to read (default 64KB)
Returns: Output content with hasMore flag for pagination
Cancel a running job. Attempts to abort via the OpenCode API first, then kills the container.
Parameters:
job_id(required): Job IDsession_id(optional): Session ID
Clean up idle sessions and their containers.
Parameters:
delete_workspaces(optional, boolean): Also delete workspace data (code, files, git history). Default false — only session metadata is removed.
List all active sessions with age, last activity, message count, server health, and active job info.
The plugin implements multiple layers of security:
- Rootless Containers: Uses Podman rootless mode by default
- Capability Dropping: All Linux capabilities are dropped (
--cap-drop ALL) - Resource Limits: Memory, CPU, and PID limits prevent resource exhaustion
- tmpfs:
/tmpis mounted as tmpfs withnosuid(512MB, exec allowed for compilers) - Network Isolation: Configurable network mode (can be set to
nonefor fully offline tasks, but LLM API calls requirebridge) - AppArmor: Optional AppArmor profile support for MAC enforcement
- User Namespace Mapping:
--userns=keep-id:uid=1000,gid=1000maps the host user to the container'sopencodeuser
git clone https://github.com/atharen/openclaw-plugin-opencode.git
cd openclaw-plugin-opencode
npm installnpm run build# Unit tests (mocked)
npm test
# Integration tests (requires Podman + container image)
npm run test:integration
# All tests
npm run test:all
# Watch mode
npm run test:watchLink the plugin for development:
openclaw plugins install -l ./path/to/openclaw-plugin-opencodeRun the test harness against a real container (requires OpenCode auth configured):
npx tsx src/test-harness.tsThe included Dockerfile creates a Debian Bookworm-based image with:
- Node.js 22
- OpenCode CLI (
opencode-ainpm package) - Go 1.22.5 + TinyGo 0.32.0
- Python 3 with venv
- Common dev tools: git, ripgrep, fd-find, jq, curl, sqlite3
The image runs opencode serve --port 4096 --hostname 0.0.0.0 by default, with a baked-in config that sets "permission": "allow" (the container is the security boundary).
# Single architecture (current platform)
podman build -t ghcr.io/13rac1/openclaw-opencode:latest .
# Multi-architecture (arm64 + amd64)
GITHUB_USERNAME=13rac1 ./scripts/build-and-push.sh --multi-archReleases are automated via GitHub Actions when a version tag is pushed.
- Configure
NPM_TOKENsecret in GitHub repository settings - Ensure you have push access to the repository
- Update version in
package.json - Update
CHANGELOG.mdwith release notes - Commit the changes:
git add package.json CHANGELOG.md git commit -m "chore: release v2.x.x" - Create and push a version tag:
git tag v2.x.x git push origin main --tags
The release workflow will automatically:
- Run tests
- Publish to npm with provenance
- Build and push multi-arch container images to ghcr.io
Error: Container image not found: ghcr.io/13rac1/openclaw-opencode:latest
Pull or build the container image:
podman pull ghcr.io/13rac1/openclaw-opencode:latestError: OpenCode not configured. Run 'opencode auth login' first to set up provider credentials.
Install OpenCode and authenticate with your provider:
npm install -g opencode-ai
opencode auth loginError: OpenCode server did not become healthy within 30 seconds on port 12345
The OpenCode server inside the container failed to start. Check:
- Container image is valid and built correctly
- Sufficient system resources (memory, CPU)
- Network connectivity (if
network: bridge) - Container logs:
podman logs opencode-<session-key>
Increase serverReadyTimeout if needed.
Error: idle_timeout - No activity for 120 seconds
OpenCode stopped producing output or consuming CPU. This may indicate:
- Task completed but output wasn't captured
- The agent is stuck
- Task requires more time (increase
idleTimeout)
Error: Git identity not configured. Set it before using OpenCode:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
The plugin injects your host git identity into containers. Configure it before starting jobs.
This project is a fork of 13rac1/openclaw-plugin-claude-code (Apache-2.0). The upstream plugin runs Anthropic's Claude Code CLI; this fork replaces it with OpenCode for provider-agnostic operation and SDK-based communication.
Apache-2.0 — see LICENSE