# Opencode Server

> |

- **Type:** Skill
- **Install:** `agentstack add skill-timmy6942025-opencode-builder-skill-opencode-server`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Timmy6942025](https://agentstack.voostack.com/s/timmy6942025)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Timmy6942025](https://github.com/Timmy6942025)
- **Source:** https://github.com/Timmy6942025/opencode-builder-skill/tree/main/skills/opencode-server

## Install

```sh
agentstack add skill-timmy6942025-opencode-builder-skill-opencode-server
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# OpenCode Server

> **📚 Official Docs:** For the latest information, always refer to the official documentation:
> [https://opencode.ai/docs/server/](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:

```bash
opencode serve [--port ] [--hostname ] [--mdns] [--mdns-domain ] [--cors ]
```

### Flags

| Flag | Description | Default |
|------|-------------|---------|
| `--port` | Port to listen on | `0 (random available port)` |
| `--hostname` | Hostname to listen on | `127.0.0.1` |
| `--mdns` | Enable mDNS discovery | `false` |
| `--mdns-domain` | Custom domain name for mDNS service | `opencode.local` |
| `--cors` | Additional browser origins to allow (repeatable) | `[]` |

The `--cors` flag can be passed multiple times:

```bash
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:

| Variable | Description | Default |
|----------|-------------|---------|
| `OPENCODE_SERVER_PASSWORD` | Password for HTTP basic auth | _(none — unauthenticated)_ |
| `OPENCODE_SERVER_USERNAME` | Username for HTTP basic auth | `opencode` |

```bash
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:

```bash
opencode --hostname 127.0.0.1 --port 4096
```

Then connect other clients to the same server:

```bash
# 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://:/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://:`.

---

### Global

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/global/health` | Get server health and version | `{ healthy: true, version: string }` |
| `GET` | `/global/event` | Get global events as SSE stream | Event stream |

#### `GET /global/health`

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

```json
{ "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

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/project` | List all projects | `Project[]` |
| `GET` | `/project/current` | Get the current project | `Project` |

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

---

### Path & VCS

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/path` | Get the current path | `Path` |
| `GET` | `/vcs` | Get VCS info for the current project | `VcsInfo` |

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

---

### Instance

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `POST` | `/instance/dispose` | Dispose the current instance | `boolean` |

Shuts down the current OpenCode instance. Use with caution — this terminates the server process.

---

### Config

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/config` | Get config info | `Config` |
| `PATCH` | `/config` | Update config | `Config` |
| `GET` | `/config/providers` | List 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

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/provider` | List all providers | `{ all: Provider[], default: {...}, connected: string[] }` |
| `GET` | `/provider/auth` | Get provider authentication methods | `{ [providerID: string]: ProviderAuthMethod[] }` |
| `POST` | `/provider/{id}/oauth/authorize` | Authorize a provider using OAuth | `ProviderAuthAuthorization` |
| `POST` | `/provider/{id}/oauth/callback` | Handle OAuth callback for a provider | `boolean` |

#### `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

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/session` | List all sessions | `Session[]` |
| `POST` | `/session` | Create a new session | `Session` |
| `GET` | `/session/status` | Get session status for all sessions | `{ [sessionID: string]: SessionStatus }` |
| `GET` | `/session/:id` | Get session details | `Session` |
| `DELETE` | `/session/:id` | Delete a session and all its data | `boolean` |
| `PATCH` | `/session/:id` | Update session properties | `Session` |
| `GET` | `/session/:id/children` | Get a session's child sessions | `Session[]` |
| `GET` | `/session/:id/todo` | Get the todo list for a session | `Todo[]` |
| `POST` | `/session/:id/init` | Analyze app and create `AGENTS.md` | `boolean` |
| `POST` | `/session/:id/fork` | Fork an existing session at a message | `Session` |
| `POST` | `/session/:id/abort` | Abort a running session | `boolean` |
| `POST` | `/session/:id/share` | Share a session | `Session` |
| `DELETE` | `/session/:id/share` | Unshare a session | `Session` |
| `GET` | `/session/:id/diff` | Get the diff for this session | `FileDiff[]` |
| `POST` | `/session/:id/summarize` | Summarize the session | `boolean` |
| `POST` | `/session/:id/revert` | Revert a message | `boolean` |
| `POST` | `/session/:id/unrevert` | Restore all reverted messages | `boolean` |
| `POST` | `/session/:id/permissions/:permissionID` | Respond to a permission request | `boolean` |

#### `POST /session`

Create a new session. Body:

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

Returns the created `Session` object.

#### `PATCH /session/:id`

Update session properties. Body:

```json
{
  "title": "New title"
}
```

#### `POST /session/:id/init`

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

```json
{
  "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:

```json
{
  "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:

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

#### `POST /session/:id/revert`

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

```json
{
  "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:

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

---

### Messages

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/session/:id/message` | List messages in a session | `{ info: Message, parts: Part[] }[]` |
| `POST` | `/session/:id/message` | Send a message and wait for response | `{ info: Message, parts: Part[] }` |
| `GET` | `/session/:id/message/:messageID` | Get message details | `{ info: Message, parts: Part[] }` |
| `POST` | `/session/:id/prompt_async` | Send a message asynchronously (no wait) | `204 No Content` |
| `POST` | `/session/:id/command` | Execute a slash command | `{ info: Message, parts: Part[] }` |
| `POST` | `/session/:id/shell` | Run a shell command | `{ info: Message, parts: Part[] }` |
| `DELETE` | `/session/:id/message/:messageID` | Delete a specific message | `boolean` |
| `DELETE` | `/session/:id/message/:messageID/part/:partID` | Delete a specific message part | `boolean` |
| `PATCH` | `/session/:id/message/:messageID/part/:partID` | Update a specific message part | `Part` |

#### `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:

```json
{
  "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:

```json
{
  "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:

```json
{
  "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:

```json
{
  "text": "Updated text content"
}
```

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

---

### Commands

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/command` | List all available commands | `Command[]` |

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

---

### Files

| Method | Path | Description | Response |
|--------|------|-------------|----------|
| `GET` | `/find?pattern=` | Search for text in files | Match objects |
| `GET` | `/find/file?query=` | Find files and directories by name | `string[]` |
| `GET` | `/find/symbol?query=` | Find workspace symbols | `Symbol[]` |
| `GET` | `/file?path=` | List files and directories | `FileNode[]` |
| `GET` | `/file/content?path=` | Read a file | `FileContent` |
| `GET` | `/file/status` | Get status for tracked files | `File[]` |

#### `GET /find?pattern=`

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

```json
[
  {
    "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=`

Find files and directories by name using fuzzy matching.

**Query Parameters:**

| Parameter | Required | Description |
|-----------|----------|-------------|
| `query` | Yes | Search string (fuzzy match) |
| `type` | No | Limit to `"file"` or `"directory"` |
| `directory` | No | Override the project root for the search |
| `limit` | No | Max results (1–200) |
| `dirs` | No | Legacy flag (`"false"` returns only files) |

Returns `string[]` — array of matching file/directory paths.

#### `GET /find/symbol?query=`

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

#### `GET /file?path=`

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

#### `GET /file/content?path=`

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)

| Method

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Timmy6942025](https://github.com/Timmy6942025)
- **Source:** [Timmy6942025/opencode-builder-skill](https://github.com/Timmy6942025/opencode-builder-skill)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-timmy6942025-opencode-builder-skill-opencode-server
- Seller: https://agentstack.voostack.com/s/timmy6942025
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
