agentsclimarketplace

Opencode server

Skill Timmy6942025/opencode-builder-skill/skills/opencode-server

Kilo/agent skill for building OpenCode extensions, plugins, and integrations

Install
npx -y skills add Timmy6942025/opencode-builder-skill --skill opencode-server

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill when running, configuring, connecting to, or extending the OpenCode HTTP server. Covers opencode serve, opencode web, authentication, mDNS discovery, CORS, the full OpenAPI 3.1 spec, all REST endpoints (sessions, messages, config, providers, files, tools, LSP, MCP, agents, TUI control, events, docs), the SDK generated from the spec, connecting clients, attaching terminals, IDE plugin integration, and real-time SSE event streaming.

SKILL.md

32.6 KB, as published. Nobody here has run it

OpenCode Server

πŸ“š Official Docs: For the latest information, always refer to the official documentation: https://opencode.ai/docs/server/

OpenCode exposes a headless HTTP server that implements a full REST API and publishes an OpenAPI 3.1 specification. The TUI is a client that talks to this server. The server enables multiple clients (TUI, web, IDE plugins, custom integrations) to control OpenCode programmatically.


Usage

Start a standalone HTTP server:

opencode serve [--port <number>] [--hostname <string>] [--mdns] [--mdns-domain <string>] [--cors <origin>]

Flags

FlagDescriptionDefault
--portPort to listen on0 (random available port)
--hostnameHostname to listen on127.0.0.1
--mdnsEnable mDNS discoveryfalse
--mdns-domainCustom domain name for mDNS serviceopencode.local
--corsAdditional browser origins to allow (repeatable)[]

The --cors flag can be passed multiple times:

opencode serve --cors http://localhost:5173 --cors https://app.example.com

When you run opencode normally (without serve), it starts both a TUI and an internal server. The TUI is the client that talks to this server. Running opencode serve starts a standalone headless server without launching the TUI.


Authentication

Protect the server with HTTP basic auth using environment variables:

VariableDescriptionDefault
OPENCODE_SERVER_PASSWORDPassword for HTTP basic auth(none β€” unauthenticated)
OPENCODE_SERVER_USERNAMEUsername for HTTP basic authopencode
OPENCODE_SERVER_PASSWORD=your-password opencode serve

Authentication applies to both opencode serve and opencode web. If OPENCODE_SERVER_PASSWORD is not set, the server is unsecured β€” acceptable for local use, but should be set for network access.


Architecture

The architecture separates the TUI (client) from the server:

  • Server β€” Headless HTTP process that exposes the full OpenCode API.
  • TUI β€” A client that connects to the server and renders the terminal UI.
  • Web β€” A browser-based client that connects to the server.
  • SDK β€” A type-safe JavaScript/TypeScript client generated from the server's OpenAPI spec.

The server publishes an OpenAPI 3.1 specification at /doc. The SDK (@opencode-ai/sdk) is generated from this spec, providing fully typed request/response objects for every endpoint.

This separation allows multiple clients to attach simultaneously β€” a terminal TUI, a browser tab, and custom integrations can all share the same sessions and state.


Connect to an Existing Server

When you start the TUI, it randomly assigns a port and hostname. You can instead pass --hostname and --port flags to control the binding:

opencode --hostname 127.0.0.1 --port 4096

Then connect other clients to the same server:

# Connect the TUI to an existing server
opencode attach http://localhost:4096

# Or use the SDK
import { createOpencodeClient } from "@opencode-ai/sdk"
const client = createOpencodeClient({ baseUrl: "http://localhost:4096" })

TUI Endpoint for IDE Plugins

The /tui endpoint allows IDE plugins to drive the TUI through the server β€” prefill prompts, submit prompts, execute commands, open dialogs, and show notifications. This is the primary integration point for OpenCode IDE plugins.


OpenAPI Spec

The server publishes an OpenAPI 3.1 spec at:

http://<hostname>:<port>/doc

For example: http://localhost:4096/doc

Use the spec to:

  • Generate clients in any language
  • Inspect request/response types in a Swagger explorer
  • Build custom integrations with full type safety

API Reference

All endpoints are relative to http://<hostname>:<port>.


Global

MethodPathDescriptionResponse
GET/global/healthGet server health and version{ healthy: true, version: string }
GET/global/eventGet global events as SSE streamEvent stream

GET /global/health

Returns server health status and version string. Useful for health checks and monitoring.

{ "healthy": true, "version": "1.0.0" }

GET /global/event

Server-Sent Events stream of global events. First event is server.connected, then bus events stream continuously.


Project

MethodPathDescriptionResponse
GET/projectList all projectsProject[]
GET/project/currentGet the current projectProject

The Project type contains project metadata including name, path, and configuration information.


Path & VCS

MethodPathDescriptionResponse
GET/pathGet the current pathPath
GET/vcsGet VCS info for the current projectVcsInfo

/path returns the current working directory and project root. /vcs returns version control system information (branch, status, etc.).


Instance

MethodPathDescriptionResponse
POST/instance/disposeDispose the current instanceboolean

Shuts down the current OpenCode instance. Use with caution β€” this terminates the server process.


Config

MethodPathDescriptionResponse
GET/configGet config infoConfig
PATCH/configUpdate configConfig
GET/config/providersList providers and default models{ providers: Provider[], default: { [key: string]: string } }

GET /config

Returns the full configuration object for the current instance.

PATCH /config

Partially updates the configuration. Only the provided fields are modified; omitted fields remain unchanged.

GET /config/providers

Returns all configured providers and their default model mappings. The default map keys are provider IDs and values are model IDs.


Provider

MethodPathDescriptionResponse
GET/providerList all providers{ all: Provider[], default: {...}, connected: string[] }
GET/provider/authGet provider authentication methods{ [providerID: string]: ProviderAuthMethod[] }
POST/provider/{id}/oauth/authorizeAuthorize a provider using OAuthProviderAuthAuthorization
POST/provider/{id}/oauth/callbackHandle OAuth callback for a providerboolean

GET /provider

Returns:

  • all β€” All configured providers
  • default β€” Default model for each provider
  • connected β€” List of connected (authenticated) provider IDs

GET /provider/auth

Returns available authentication methods for each provider. Useful for building OAuth flows in custom clients.

POST /provider/{id}/oauth/authorize

Initiates an OAuth authorization flow for the specified provider. Returns authorization URL and state.

POST /provider/{id}/oauth/callback

Handles the OAuth callback after the user authorizes. Returns true if authentication succeeded.


Sessions

MethodPathDescriptionResponse
GET/sessionList all sessionsSession[]
POST/sessionCreate a new sessionSession
GET/session/statusGet session status for all sessions{ [sessionID: string]: SessionStatus }
GET/session/:idGet session detailsSession
DELETE/session/:idDelete a session and all its databoolean
PATCH/session/:idUpdate session propertiesSession
GET/session/:id/childrenGet a session's child sessionsSession[]
GET/session/:id/todoGet the todo list for a sessionTodo[]
POST/session/:id/initAnalyze app and create AGENTS.mdboolean
POST/session/:id/forkFork an existing session at a messageSession
POST/session/:id/abortAbort a running sessionboolean
POST/session/:id/shareShare a sessionSession
DELETE/session/:id/shareUnshare a sessionSession
GET/session/:id/diffGet the diff for this sessionFileDiff[]
POST/session/:id/summarizeSummarize the sessionboolean
POST/session/:id/revertRevert a messageboolean
POST/session/:id/unrevertRestore all reverted messagesboolean
POST/session/:id/permissions/:permissionIDRespond to a permission requestboolean

POST /session

Create a new session. Body:

{
  "parentID": "optional-parent-session-id",
  "title": "Optional session title"
}

Returns the created Session object.

PATCH /session/:id

Update session properties. Body:

{
  "title": "New title"
}

POST /session/:id/init

Analyze the application and generate an AGENTS.md file. Body:

{
  "messageID": "message-to-respond-to",
  "providerID": "anthropic",
  "modelID": "claude-3-5-sonnet-20241022"
}

POST /session/:id/fork

Fork an existing session, optionally at a specific message. Body:

{
  "messageID": "optional-message-id-to-fork-at"
}

Returns a new Session object that is a copy of the original.

POST /session/:id/share

Makes the session publicly accessible. Returns the updated session with sharing metadata.

DELETE /session/:id/share

Revokes public sharing for the session.

GET /session/:id/diff

Get file changes for the session. Optional query parameter messageID to get diff up to a specific message.

Returns FileDiff[] β€” an array of file diffs showing added, removed, and modified content.

POST /session/:id/summarize

Generate a summary of the session. Body:

{
  "providerID": "anthropic",
  "modelID": "claude-3-5-sonnet-20241022"
}

POST /session/:id/revert

Revert a specific message (and optionally a specific part within it). Body:

{
  "messageID": "message-to-revert",
  "partID": "optional-specific-part"
}

POST /session/:id/unrevert

Restores all reverted messages in the session. No body required.

POST /session/:id/permissions/:permissionID

Respond to a pending permission request. Body:

{
  "response": "allow",
  "remember": true
}

Messages

MethodPathDescriptionResponse
GET/session/:id/messageList messages in a session{ info: Message, parts: Part[] }[]
POST/session/:id/messageSend a message and wait for response{ info: Message, parts: Part[] }
GET/session/:id/message/:messageIDGet message details{ info: Message, parts: Part[] }
POST/session/:id/prompt_asyncSend a message asynchronously (no wait)204 No Content
POST/session/:id/commandExecute a slash command{ info: Message, parts: Part[] }
POST/session/:id/shellRun a shell command{ info: Message, parts: Part[] }
DELETE/session/:id/message/:messageIDDelete a specific messageboolean
DELETE/session/:id/message/:messageID/part/:partIDDelete a specific message partboolean
PATCH/session/:id/message/:messageID/part/:partIDUpdate a specific message partPart

GET /session/:id/message

List messages in a session. Optional query parameter limit to restrict the number of messages returned.

Each message contains:

  • info β€” The Message object (role, content, metadata)
  • parts β€” Array of Part objects (text chunks, tool calls, tool results)

POST /session/:id/message

Send a message and wait for the AI response. Body:

{
  "messageID": "optional-message-id",
  "model": { "providerID": "anthropic", "modelID": "claude-3-5-sonnet-20241022" },
  "agent": "optional-agent-name",
  "noReply": false,
  "system": "optional-system-prompt",
  "tools": ["optional-tool-whitelist"],
  "parts": [
    { "type": "text", "text": "Hello!" }
  ]
}
  • noReply: true β€” Injects context without triggering an AI response (returns a UserMessage)
  • model β€” Optionally override the model for this message
  • agent β€” Optionally specify an agent
  • tools β€” Optionally restrict which tools the model can use
  • parts β€” Message content parts (text, images, etc.)

POST /session/:id/prompt_async

Same body as /session/:id/message but returns immediately with 204 No Content. The response is processed asynchronously; listen to events to know when it completes.

POST /session/:id/command

Execute a slash command. Body:

{
  "messageID": "optional-message-id",
  "agent": "optional-agent",
  "model": { "providerID": "...", "modelID": "..." },
  "command": "/compact",
  "arguments": "optional arguments string"
}

POST /session/:id/shell

Run a shell command within the session context. Body:

{
  "agent": "optional-agent",
  "model": { "providerID": "...", "modelID": "..." },
  "command": "ls -la"
}

Returns the assistant message with tool call results.

DELETE /session/:id/message/:messageID

Delete a specific message from a session. This permanently removes the message and all its parts.

DELETE /session/:id/message/:messageID/part/:partID

Delete a specific part within a message. Removes only the specified part (e.g., a single tool call or text chunk).

PATCH /session/:id/message/:messageID/part/:partID

Update a specific message part. Body:

{
  "text": "Updated text content"
}

Allows modifying the content of a specific part within a message.


Commands

MethodPathDescriptionResponse
GET/commandList all available commandsCommand[]

Returns all registered slash commands (e.g., /compact, /init, /clear).


Files

MethodPathDescriptionResponse
GET/find?pattern=<pat>Search for text in filesMatch objects
GET/find/file?query=<q>Find files and directories by namestring[]
GET/find/symbol?query=<q>Find workspace symbolsSymbol[]
GET/file?path=<path>List files and directoriesFileNode[]
GET/file/content?path=<p>Read a fileFileContent
GET/file/statusGet status for tracked filesFile[]

GET /find?pattern=<pat>

Search for text in files using a regex pattern. Returns an array of match objects:

[
  {
    "path": "src/index.ts",
    "lines": ["matching line content"],
    "line_number": 42,
    "absolute_offset": 1234,
    "submatches": [{ "match": "matched text", "start": 0, "end": 12 }]
  }
]

GET /find/file?query=<q>

Find files and directories by name using fuzzy matching.

Query Parameters:

ParameterRequiredDescription
queryYesSearch string (fuzzy match)
typeNoLimit to "file" or "directory"
directoryNoOverride the project root for the search
limitNoMax results (1–200)
dirsNoLegacy flag ("false" returns only files)

Returns string[] β€” array of matching file/directory paths.

GET /find/symbol?query=<q>

Find workspace symbols (functions, classes, variables, etc.).

GET /file?path=<path>

List files and directories at the given path. Returns FileNode[] with file metadata.

GET /file/content?path=<p>

Read the content of a file. Returns FileContent with the file's raw content.

GET /file/status

Get status for all tracked (VCS-tracked) files. Returns File[] with file status information.


Tools (Experimental)

MethodPathDescriptionResponse
GET/experimental/tool/idsList all tool IDsToolIDs
GET/experimental/toolList tools with JSON schemas for a modelToolList

GET /experimental/tool

Query parameters:

  • provider β€” Provider ID
  • model β€” Model ID

Returns the full tool definitions with JSON schemas for the specified model, showing which tools are available and their argument schemas.


LSP, Formatters & MCP

MethodPathDescriptionResponse
GET/lspGet LSP server statusLSPStatus[]
GET/formatterGet formatter statusFormatterStatus[]
GET/mcpGet MCP server status{ [name: string]: MCPStatus }
POST/mcpAdd MCP server dynamicallyMCP status object

GET /lsp

Returns the status of all configured LSP (Language Server Protocol) servers β€” running, stopped, error states.

GET /formatter

Returns the status of all configured code formatters.

GET /mcp

Returns the status of all configured MCP (Model Context Protocol) servers. Each entry is keyed by server name.

POST /mcp

Dynamically add an MCP server at runtime. Body:

{
  "name": "my-mcp-server",
  "config": {
    "command": "node",
    "args": ["server.js"]
  }
}

Agents

MethodPathDescriptionResponse
GET/agentList all available agentsAgent[]

Returns all registered agents (built-in and custom) with their configurations.


Logging

MethodPathDescriptionResponse
POST/logWrite a log entryboolean

Body:

{
  "service": "my-app",
  "level": "info",
  "message": "Operation completed",
  "extra": { "key": "value" }
}

Log levels: debug, info, warn, error.


TUI Control

These endpoints control the Terminal UI through the server. Used primarily by IDE plugins.

MethodPathDescriptionResponse
POST/tui/append-promptAppend text to the promptboolean
POST/tui/submit-promptSubmit the current promptboolean
POST/tui/clear-promptClear the promptboolean
POST/tui/open-helpOpen the help dialogboolean
POST/tui/open-sessionsOpen the session selectorboolean
POST/tui/open-modelsOpen the model selectorboolean
POST/tui/open-themesOpen the theme selectorboolean
POST/tui/execute-commandExecute a commandboolean
POST/tui/show-toastShow toast notificationboolean
GET/tui/control/nextWait for the next control requestControl request object
POST/tui/control/responseRespond to a control requestboolean

POST /tui/append-prompt

Body: { "text": "text to append" }

Appends text to the current prompt input without submitting.

POST /tui/execute-command

Body: { "command": "/compact" }

Executes a slash command through the TUI.

POST /tui/show-toast

Body: { "title": "Optional title", "message": "Toast message", "variant": "success" }

Variants: info, success, warning, error.

GET /tui/control/next

Long-polling endpoint that waits for the next control request from the TUI. Returns a control request object that represents a pending user interaction (e.g., permission prompt, input request).

POST /tui/control/response

Body: { "body": "response content" }

Responds to a pending control request obtained from /tui/control/next.


PTY (Terminal Pseudoterminal)

MethodPathDescriptionResponse
GET/ptyList all PTY sessionsPTY[]
POST/ptyCreate a new PTY sessionPTY
DELETE/ptyClose all PTY sessionsboolean
GET/pty/shellsList available shellsstring[]
GET/pty/:ptyIDGet PTY session detailsPTY
PUT/pty/:ptyIDUpdate PTY session propertiesPTY
DELETE/pty/:ptyIDClose a PTY sessionboolean
GET/pty/:ptyID/connectConnect to a PTY via SSE streamEvent stream
POST/pty/:ptyID/connect-tokenGenerate a connection token for PTYConnectToken

POST /pty

Create a new PTY session. Body:

{
  "shell": "/bin/zsh",
  "cols": 80,
  "rows": 24
}

GET /pty/:ptyID/connect

Server-Sent Events stream for bidirectional terminal I/O. Use the connection token from /pty/:ptyID/connect-token to authenticate.

POST /pty/:ptyID/connect-token

Generate a short-lived token for connecting to the PTY session. Returns a token object with expiry.


Permission

MethodPathDescriptionResponse
GET/permissionList pending permission requestsPermission[]
POST/permission/:requestID/replyReply to a permission requestboolean

GET /permission

Returns all pending permission requests that require user approval (e.g., file writes, shell commands).

POST /permission/:requestID/reply

Reply to a pending permission request. Body:

{
  "response": "allow",
  "remember": true
}

Response values: allow, deny. The remember flag persists the decision for future requests of the same type.


Question

MethodPathDescriptionResponse
GET/questionList pending questionsQuestion[]
POST/question/:requestID/replyReply to a questionboolean
POST/question/:requestID/rejectReject/dismiss a questionboolean

GET /question

Returns all pending questions from the AI that require user input.

POST /question/:requestID/reply

Reply to a pending question. Body:

{
  "response": "Your answer here"
}

POST /question/:requestID/reject

Reject or dismiss a pending question without answering.


Skill

MethodPathDescriptionResponse
GET/skillList all available skillsSkill[]

Returns all registered skills with their metadata and descriptions.


Sync

MethodPathDescriptionResponse
POST/sync/historySync conversation historyboolean
POST/sync/replayReplay events to restore stateboolean
POST/sync/startStart sync sessionboolean
POST/sync/stealSteal/takeover a session from another clientboolean

POST /sync/history

Synchronize conversation history between clients. Used when a new client connects and needs to catch up.

POST /sync/replay

Replay stored events to bring a client up to date with the current server state.

POST /sync/steal

Take control of a session from another connected client. The other client receives a disconnect notification.


Workspace (Experimental)

MethodPathDescriptionResponse
GET/experimental/workspaceList workspacesWorkspace[]
POST/experimental/workspaceCreate a workspaceWorkspace
GET/experimental/workspace/adapterGet workspace adapter infoAdapter
GET/experimental/workspace/:id/statusGet workspace statusWorkspaceStatus
POST/experimental/workspace/sync-listSync workspace file listboolean
POST/experimental/workspace/warpWarp to a workspace locationboolean
DELETE/experimental/workspace/:idDelete a workspaceboolean

POST /experimental/workspace

Create a new workspace. Body:

{
  "name": "my-workspace",
  "path": "/path/to/workspace"
}

POST /experimental/workspace/warp

Navigate to a specific location within the workspace. Body:

{
  "path": "src/index.ts",
  "line": 42
}

Worktree (Experimental)

MethodPathDescriptionResponse
GET/experimental/worktreeList git worktreesWorktree[]
POST/experimental/worktreeCreate a worktreeWorktree
DELETE/experimental/worktreeDelete worktreesboolean
POST/experimental/worktree/resetReset a worktree to clean stateboolean

POST /experimental/worktree

Create a new git worktree. Body:

{
  "branch": "feature/my-branch",
  "path": "/path/to/worktree"
}

POST /experimental/worktree/reset

Reset a worktree to a clean state, discarding all uncommitted changes.


Auth

MethodPathDescriptionResponse
PUT/auth/:idSet authentication credentialsboolean
DELETE/auth/:providerIDRemove authentication credentialsboolean

Body must match the provider's auth schema. Example:

{
  "type": "api",
  "key": "your-api-key"
}

For OAuth providers, use the /provider/{id}/oauth/authorize and /provider/{id}/oauth/callback endpoints instead.


Events

MethodPathDescriptionResponse
GET/eventServer-sent events streamSSE stream

The SSE stream sends events in real-time. The first event is server.connected, followed by bus events as they occur.

Event types include:

  • server.connected β€” Server connection established
  • session.created β€” New session created
  • session.updated β€” Session properties changed
  • session.idle β€” AI finished responding
  • session.error β€” Session encountered an error
  • session.compacted β€” Context was compacted
  • session.deleted β€” Session was deleted
  • message.updated β€” Message was updated
  • message.removed β€” Message was removed
  • message.part.updated β€” Message part (text chunk, tool call) updated
  • message.part.removed β€” Message part removed
  • file.edited β€” File was edited
  • permission.asked β€” Permission request
  • permission.replied β€” Permission response
  • lsp.updated β€” LSP state change
  • todo.updated β€” Todo item changed
  • command.executed β€” Command was executed

Connect to the SSE stream:

curl -N http://localhost:4096/event

Docs

MethodPathDescriptionResponse
GET/docOpenAPI 3.1 specificationHTML page

Returns an HTML page with the full OpenAPI 3.1 specification rendered in a Swagger UI explorer. Accessible at http://localhost:4096/doc.


Web Interface

Start the browser-based web interface:

opencode web [--port <number>] [--hostname <string>] [--mdns] [--mdns-domain <string>] [--cors <origin>]

Configuration

All opencode serve flags apply to opencode web as well:

# Fixed port
opencode web --port 4096

# Accessible on network
opencode web --hostname 0.0.0.0

# With authentication
OPENCODE_SERVER_PASSWORD=secret opencode web

# With mDNS
opencode web --mdns

# With custom mDNS domain
opencode web --mdns --mdns-domain myproject.local

When using 0.0.0.0, OpenCode displays both local and network addresses:

Local access:     http://localhost:4096
Network access:   http://192.168.1.100:4096

Config File

Server settings can also be configured in opencode.json:

{
  "server": {
    "port": 4096,
    "hostname": "0.0.0.0",
    "mdns": true,
    "cors": ["https://example.com"]
  }
}

Command line flags take precedence over config file settings.

Attaching a Terminal

Attach a terminal TUI to a running web server:

# Start the web server
opencode web --port 4096

# In another terminal, attach the TUI
opencode attach http://localhost:4096

Both the web interface and terminal share the same sessions and state. You can use both simultaneously.

Web Interface Features

  • Sessions β€” View and manage sessions from the homepage. See active sessions and start new ones.
  • Server Status β€” Click "See Servers" to view connected servers and their status.

mDNS Discovery

Enable mDNS to advertise the server on the local network:

opencode serve --mdns
# or
opencode web --mdns

This automatically sets the hostname to 0.0.0.0 and advertises the server as opencode.local.

Custom Domain Names

Run multiple instances on the same network by customizing the mDNS domain:

opencode serve --mdns --mdns-domain project-a.local
opencode serve --mdns --mdns-domain project-b.local

Clients can then discover instances by browsing for _opencode._tcp services, or connect directly:

opencode attach http://project-a.local:4096

How mDNS Works

  • The server registers a DNS-SD service under _opencode._tcp
  • Default instance name: opencode (becomes opencode.local)
  • Custom domain names: --mdns-domain myapp.local becomes the service address
  • Clients on the same network can discover the server without knowing its IP address

SDK Integration

The OpenCode JS/TS SDK (@opencode-ai/sdk) is generated from the server's OpenAPI spec. It provides two modes:

Full Lifecycle (Server + Client)

import { createOpencode } from "@opencode-ai/sdk"

const { client, server } = await createOpencode({
  hostname: "127.0.0.1",
  port: 4096,
  timeout: 5000,
  config: { model: "anthropic/claude-3-5-sonnet-20241022" },
})

console.log(`Server running at ${server.url}`)

// Use the client...

server.close()

Client Only

import { createOpencodeClient } from "@opencode-ai/sdk"

const client = createOpencodeClient({
  baseUrl: "http://localhost:4096",
  throwOnError: true,
  responseStyle: "data",
})

Key SDK Methods

MethodDescription
client.global.health()Check server health
client.session.create()Create a session
client.session.list()List sessions
client.session.prompt()Send a prompt
client.session.messages()List messages
client.tui.appendPrompt()Append to prompt
client.tui.submitPrompt()Submit prompt
client.event.subscribe()Subscribe to SSE events
client.auth.set()Set provider credentials

See the SDK skill for full SDK documentation.


Complete Workflow Example

1. Start the server

opencode serve --port 4096

2. Check health

curl http://localhost:4096/global/health
# {"healthy":true,"version":"1.0.0"}

3. Create a session

curl -X POST http://localhost:4096/session \
  -H "Content-Type: application/json" \
  -d '{"title": "Code Review"}'

4. Send a prompt

curl -X POST http://localhost:4096/session/<session-id>/message \
  -H "Content-Type: application/json" \
  -d '{
    "parts": [{"type": "text", "text": "Review this codebase for issues"}],
    "model": {"providerID": "anthropic", "modelID": "claude-3-5-sonnet-20241022"}
  }'

5. Stream events

curl -N http://localhost:4096/event

6. View the spec

Open http://localhost:4096/doc in a browser.


Troubleshooting

Server won't start

  • Check if the port is already in use: lsof -i :4096
  • Try a different port: opencode serve --port 5000

Authentication fails

  • Ensure OPENCODE_SERVER_PASSWORD is set before starting the server
  • The default username is opencode; override with OPENCODE_SERVER_USERNAME
  • Both serve and web commands use the same auth environment variables

CORS errors in browser

  • Add the frontend origin to --cors: opencode serve --cors http://localhost:5173
  • Multiple --cors flags are allowed
  • The server automatically includes localhost origins for development

mDNS not discoverable

  • Ensure --mdns flag is passed
  • Check that the hostname is 0.0.0.0 (mDNS sets this automatically)
  • Verify mDNS is enabled on the client machine
  • Try connecting directly by IP instead of .local domain

TUI connection refused

  • Verify the server is running: curl http://localhost:4096/global/health
  • Check the correct port and hostname
  • Use opencode attach http://localhost:4096 to connect the TUI

SDK types not available

  • Install the SDK: npm install @opencode-ai/sdk
  • Types are auto-generated from the OpenAPI spec at /doc
  • Import types: import type { Session, Message } from "@opencode-ai/sdk"

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.