Repository navigation
Description
Description
The migrate-v1 guide says V1 integrations must move to @opencode/client. This issue is about how they fail when they don't: silently.
Against an OpenCode 2 server, the v1 client in @opencode-ai/sdk (1.19.5, still the npm latest) doesn't fail. GET /session answers 200 with the web UI's HTML (also with Accept: application/json), so client.session.list() returns that page as data. POST /session answers 405, which the SDK hands back as {"error":{}} without throwing. An integration written for v1 keeps running and does nothing.
I measured this with coding agents. A real 2.2.7 server was running, and I asked Claude Code, Codex and Gemini (2 runs each) for a small script with "the official OpenCode JavaScript SDK or client from npm": create a session and list session titles. 3 of the 6 runs started with @opencode-ai/sdk. Claude noticed the HTML only because a live server was there to test against. It then switched to client.v2.* in the same package and passed the title through $body_title, because those types have no title field. Codex found @opencode/client via opencode.ai/docs. Without a server to test against, the v1 version would have shipped and returned [].
Related: #55705 asks for an API version in /api/info so clients can detect a v2 server. This is the other side of the same mismatch: what the server answers on the old paths.
Two changes would make this loud:
- answer the old API paths with a JSON 404 or 410 that names
@opencode/clientwhen the request asks for JSON, instead of the web UI; - a pointer to
@opencode/clienton the@opencode-ai/sdknpm page (README ornpm deprecatemessage).
OpenCode version
server: @opencode/cli 2.2.7 (opencode serve); client: @opencode-ai/sdk 1.19.5
Steps to reproduce
OPENCODE_PASSWORD=pw opencode serve --port 4096(2.2.7)-
import { createOpencodeClient } from "@opencode-ai/sdk" const client = createOpencodeClient({ baseUrl: "http://127.0.0.1:4096", headers: { Authorization: "Basic " + Buffer.from("opencode:pw").toString("base64") } }) console.log(await client.session.create({ body: { title: "x" } })) // server 405 -> { error: {}, ... }, no throw console.log((await client.session.list()).data.slice(0, 40)) // "<!doctype html>..."
- With
@opencode/client(OpenCode.make(...).session.create/list) the same server works.
Operating System
macOS 15 (Darwin 24.6), Node 24
I research how coding agents use dev tools: dev.to/yahhi · [email protected]
Activity
opencodejr commentedon Nov 12, 2026
Thanks for the measurements and the clear reproduction, @Yahhi.
I think this is a duplicate of #55704. That issue reports that a v2 server sends back the web UI's HTML with a
200for paths that have no route, including the v1 API paths, and asks for a JSON404for requests that don't want HTML. That's the server-side change you propose.In
packages/cli/src/services/web-ui.ts, only/api,/api/*,/auth/*and/openapi.jsongo to the API; every other path gets the web app, and theAcceptheader isn't checked there. That's whyGET /sessionreturns the HTML page andPOST /sessionreturns405. A contributor has posted a detailedAccept-negotiation proposal in #55704 for maintainers to review.Until then, as suggested in #55704, clients can check
GET /api/infoto detect a v2 server.Related issues, ordered from most to least likely to cover this:
200 text/html) and the same JSON404request/api/infoso clients can detect a v2 serveropencode-aito be deprecated on npm (closed); your npm-deprecation suggestion for@opencode-ai/sdkis similarI'm closing this issue now as a duplicate of #55704. Please add your details there, especially the coding-agent measurements and the suggested
npm deprecatepointer for@opencode-ai/sdk, which #55704 doesn't cover yet. If you think this isn't the same problem, reply here and the issue will reopen.