From 32a973f1cdfc49c9fffee6a7f880e2d335e1cf13 Mon Sep 17 00:00:00 2001 From: gavrielc Date: Fri, 17 Apr 2026 14:14:10 +0300 Subject: [PATCH] docs(add-opencode): rewrite skill for copy-from-providers-branch pattern v2 no longer ships opencode on trunk. The skill now: - Fetches origin/providers - Copies opencode source files to their target paths - Appends self-registration imports to both provider barrels - Adds @opencode-ai/sdk@1.4.3 as a pinned agent-runner dep - Adds OPENCODE_VERSION ARG + opencode-ai pnpm global install to Dockerfile - Rebuilds host + container All steps idempotent. Credential/env/Zen docs unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- .claude/skills/add-opencode/SKILL.md | 117 ++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 20 deletions(-) diff --git a/.claude/skills/add-opencode/SKILL.md b/.claude/skills/add-opencode/SKILL.md index 89ea3c063..1edaaad6d 100644 --- a/.claude/skills/add-opencode/SKILL.md +++ b/.claude/skills/add-opencode/SKILL.md @@ -5,16 +5,94 @@ description: Use OpenCode as an agent provider on NanoClaw v2 (AGENT_PROVIDER=op # OpenCode agent provider (v2) -NanoClaw **v2** runs agents in a long-lived **poll loop** inside the container. The backend is selected with **`AGENT_PROVIDER`** (`claude` | `opencode` | `mock`), not the v1 `AGENT_RUNNER` env var. +NanoClaw **v2** runs agents in a long-lived **poll loop** inside the container. The backend is selected with **`AGENT_PROVIDER`** (`claude` | `opencode` | `mock`). -## What it does (upstream v2) +v2 trunk ships with only the `claude` provider baked in. This skill copies the OpenCode provider files in from the `providers` branch, wires them into the host and container barrels, installs dependencies, and rebuilds the image. -- **`container/agent-runner/src/providers/opencode.ts`** — `OpenCodeProvider` implementing `AgentProvider` (SSE via OpenCode server, session resume, MCP from merged `ProviderOptions.mcpServers` only — no `settings.json` MCP bridge). -- **`container/agent-runner/src/providers/mcp-to-opencode.ts`** — maps v2 `McpServerConfig` to OpenCode `mcp` entries. -- **`container/agent-runner/src/providers/factory.ts`** — registers `opencode`. -- **`container/agent-runner/package.json`** — dependency `@opencode-ai/sdk`. -- **`container/Dockerfile`** — global **`opencode-ai`** CLI for `opencode serve`. -- **`src/container-runner.ts`** — when effective provider is `opencode`: `XDG_DATA_HOME=/opencode-xdg`, session-scoped host mount, `NO_PROXY`/`no_proxy` merge for `127.0.0.1,localhost`, passes through `OPENCODE_PROVIDER`, `OPENCODE_MODEL`, `OPENCODE_SMALL_MODEL` from the host environment. +## Install + +### Pre-flight + +If all of the following are already present, skip to **Configuration**: + +- `src/providers/opencode.ts` +- `container/agent-runner/src/providers/opencode.ts` +- `import './opencode.js';` line in `src/providers/index.ts` +- `import './opencode.js';` line in `container/agent-runner/src/providers/index.ts` +- `@opencode-ai/sdk` in `container/agent-runner/package.json` +- `opencode-ai@${OPENCODE_VERSION}` in the pnpm global-install block in `container/Dockerfile` + +Missing pieces — continue below. All steps are idempotent; re-running is safe. + +### 1. Fetch the providers branch + +```bash +git fetch origin providers +``` + +### 2. Copy the OpenCode source files + +Wholesale copies (owned entirely by this skill — user edits to these files won't survive a re-run, as designed): + +```bash +git show origin/providers:src/providers/opencode.ts > src/providers/opencode.ts +git show origin/providers:container/agent-runner/src/providers/opencode.ts > container/agent-runner/src/providers/opencode.ts +git show origin/providers:container/agent-runner/src/providers/mcp-to-opencode.ts > container/agent-runner/src/providers/mcp-to-opencode.ts +git show origin/providers:container/agent-runner/src/providers/mcp-to-opencode.test.ts > container/agent-runner/src/providers/mcp-to-opencode.test.ts +git show origin/providers:container/agent-runner/src/providers/opencode.factory.test.ts > container/agent-runner/src/providers/opencode.factory.test.ts +``` + +### 3. Append the self-registration imports + +Each barrel gets one line appended at the end — skip if the line is already present. + +`src/providers/index.ts`: + +```typescript +import './opencode.js'; +``` + +`container/agent-runner/src/providers/index.ts`: + +```typescript +import './opencode.js'; +``` + +### 4. Add the agent-runner dependency + +Pinned. Bump deliberately, not with `bun update`. + +```bash +cd container/agent-runner && bun add @opencode-ai/sdk@1.4.3 && cd - +``` + +### 5. Add `opencode-ai` to the container Dockerfile + +Two edits to `container/Dockerfile`, both idempotent (skip if already present): + +**(a)** In the "Pin CLI versions" ARG block (around line 18), add after `ARG VERCEL_VERSION=latest`: + +```dockerfile +ARG OPENCODE_VERSION=latest +``` + +**(b)** In the `pnpm install -g` block (around line 80), append `"opencode-ai@${OPENCODE_VERSION}"` to the list: + +```dockerfile + pnpm install -g \ + "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}" \ + "agent-browser@${AGENT_BROWSER_VERSION}" \ + "vercel@${VERCEL_VERSION}" \ + "opencode-ai@${OPENCODE_VERSION}" +``` + +### 6. Build + +```bash +pnpm run build # host +pnpm exec tsc -p container/agent-runner/tsconfig.json --noEmit # container typecheck +./container/build.sh # agent image +``` ## Configuration @@ -22,18 +100,16 @@ NanoClaw **v2** runs agents in a long-lived **poll loop** inside the container. Set model/provider strings in the form OpenCode expects (often `provider/model-id`). **Put comments on their own lines** — a `#` inside a value is kept verbatim and breaks model IDs. -These variables are read **on the host** and passed into the container only when the effective provider is `opencode` (see `src/container-runner.ts`). They do not switch the provider by themselves; the DB still needs `agent_provider` set (below). +These variables are read **on the host** and passed into the container only when the effective provider is `opencode`. They do not switch the provider by themselves; the DB still needs `agent_provider` set (below). - `OPENCODE_PROVIDER` — OpenCode provider id, e.g. `openrouter`, `anthropic` (if unset, the runner defaults to `anthropic`). - `OPENCODE_MODEL` — full model id, e.g. `openrouter/anthropic/claude-sonnet-4`. -- `OPENCODE_SMALL_MODEL` — optional second model for “small” tasks. +- `OPENCODE_SMALL_MODEL` — optional second model for "small" tasks. Credentials: OneCLI / credential proxy patterns are unchanged. For non-`anthropic` OpenCode providers, the runner registers a placeholder API key and **`ANTHROPIC_BASE_URL`** (the credential proxy) as `baseURL` so the real key never lives in the container. #### Example: OpenRouter -Use ids that match OpenCode’s registry / your custom registrations. Adjust names to what you actually run. - ```env # OpenCode — host passes these into the container when agent_provider is opencode OPENCODE_PROVIDER=openrouter @@ -59,9 +135,9 @@ OPENCODE_MODEL=openrouter/google/gemini-2.5-pro-preview #### OpenCode Zen (`x-api-key`, not Bearer) -Zen’s HTTP API (e.g. `POST …/zen/v1/messages`) expects the key in the **`x-api-key`** header. If OneCLI injects **`Authorization: Bearer …`** only, Zen often returns **401 / “Missing API key”** even though the gateway is working. +Zen's HTTP API (e.g. `POST …/zen/v1/messages`) expects the key in the **`x-api-key`** header. If OneCLI injects **`Authorization: Bearer …`** only, Zen often returns **401 / "Missing API key"** even though the gateway is working. -**Naming:** NanoClaw **`AGENT_PROVIDER=opencode`** (v2 DB `agent_provider`) means “run the **OpenCode agent provider**.” Separately, **`OPENCODE_PROVIDER=opencode`** in `.env` is OpenCode’s **Zen provider id** inside the OpenCode config (see [Zen docs](https://opencode.ai/docs/zen/)). +**Naming:** NanoClaw **`AGENT_PROVIDER=opencode`** (v2 DB `agent_provider`) means "run the **OpenCode agent provider**." Separately, **`OPENCODE_PROVIDER=opencode`** in `.env` is OpenCode's **Zen provider id** inside the OpenCode config (see [Zen docs](https://opencode.ai/docs/zen/)). **Host `.env` (typical Zen shape):** @@ -72,7 +148,7 @@ OPENCODE_PROVIDER=opencode OPENCODE_MODEL=opencode/big-pickle OPENCODE_SMALL_MODEL=opencode/big-pickle -# Point the credential proxy at Zen’s Anthropic-compatible base URL (host + OneCLI must forward this host). +# Point the credential proxy at Zen's Anthropic-compatible base URL (host + OneCLI must forward this host). ANTHROPIC_BASE_URL=https://opencode.ai/zen/v1 ``` @@ -97,18 +173,19 @@ Extra MCP servers still come from **`NANOCLAW_MCP_SERVERS`** / `container_config ## Operational notes - OpenCode keeps a local **`opencode serve`** process and SSE subscription; the provider tears down with **`stream.return`** and **SIGKILL** on the server process on **`abort()`** / shared runtime reset to avoid MCP/zombie hangs. -- Session continuation is opaque (`ses_*` ids); stale sessions are cleared using **`isSessionInvalid`** on OpenCode-specific errors (timeouts, connection resets, not-found patterns) in addition to the poll-loop’s existing recovery. +- Session continuation is opaque (`ses_*` ids); stale sessions are cleared using **`isSessionInvalid`** on OpenCode-specific errors (timeouts, connection resets, not-found patterns) in addition to the poll-loop's existing recovery. - **`NO_PROXY`** for localhost matters when the OpenCode client talks to `127.0.0.1` inside the container while HTTP(S)_PROXY is set (e.g. OneCLI). ## Verify ```bash -grep -q opencode container/agent-runner/src/providers/factory.ts && echo "OpenCode registered" || echo "Missing" -npm run build --prefix container/agent-runner +grep -q "./opencode.js" container/agent-runner/src/providers/index.ts && echo "container barrel: OK" +grep -q "./opencode.js" src/providers/index.ts && echo "host barrel: OK" +grep -q "@opencode-ai/sdk" container/agent-runner/package.json && echo "agent-runner dep: OK" +grep -q "opencode-ai@" container/Dockerfile && echo "Dockerfile install: OK" +cd container/agent-runner && bun test src/providers/ && cd - ``` -Rebuild the agent image after Dockerfile changes: `./container/build.sh` (or your usual image build). - ## Migrate from v1 wording If documentation or habits still say **`AGENT_RUNNER=opencode`**, update to **`AGENT_PROVIDER=opencode`** and store **`agent_provider`** in v2 tables, not v1 runner columns.