feat(www): migrate docs to Blume
This commit is contained in:
parent
7d8f1bdab3
commit
203a0613b8
94 changed files with 1953 additions and 7023 deletions
38
.github/workflows/deploy-www.yml
vendored
Normal file
38
.github/workflows/deploy-www.yml
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
name: deploy-www
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- v2
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-www-${{ github.ref_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.repository == 'anomalyco/opencode' && (github.ref_name == 'dev' || github.ref_name == 'v2')
|
||||
runs-on: ubuntu-latest
|
||||
environment: ${{ github.ref_name == 'v2' && 'production' || 'dev' }}
|
||||
steps:
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- uses: ./.github/actions/setup-bun
|
||||
|
||||
- name: Build
|
||||
working-directory: packages/www
|
||||
run: bun run build
|
||||
env:
|
||||
BLUME_ENV: ${{ github.ref_name == 'v2' && 'production' || 'dev' }}
|
||||
CLOUDFLARE_ENV: ${{ github.ref_name == 'v2' && 'production' || 'dev' }}
|
||||
|
||||
- name: Deploy
|
||||
working-directory: packages/www
|
||||
run: bun run deploy
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -99,7 +99,7 @@ jobs:
|
|||
|
||||
- name: Check generated documentation
|
||||
if: runner.os == 'Linux'
|
||||
working-directory: packages/docs
|
||||
working-directory: packages/www
|
||||
run: bun run check:generated
|
||||
|
||||
e2e:
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ every field, examples, config locations, and links to dedicated feature guides.
|
|||
For any request to migrate OpenCode configuration, agents, commands, skills,
|
||||
plugins, integrations, or other behavior from V1 to V2, read the full
|
||||
[migration guide](https://v2.opencode.ai/docs/migrate-v1) before acting. In
|
||||
the repository, its source is `packages/docs/migrate-v1.mdx`.
|
||||
the repository, its source is `packages/www/content/docs/(Get started)/migrate-v1.mdx`.
|
||||
|
||||
V1 config files and `.opencode/` definitions are intended to remain compatible.
|
||||
The only intentional breaking changes are the server API and plugin API. Native
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
# V2 documentation guide
|
||||
|
||||
## Structure
|
||||
|
||||
- This directory is a standalone Mintlify site deployed from `packages/docs` on the `dev` branch.
|
||||
- Write documentation in MDX. Every page should have `title` and `description` frontmatter.
|
||||
- `docs.json` owns site configuration and navigation. Add, move, or remove its page entries whenever the corresponding MDX pages change.
|
||||
- Put static files in `assets/` and reference them with root-relative paths such as `/assets/example.svg`.
|
||||
- The API endpoint reference is generated by Mintlify from `openapi.json`; do not duplicate endpoint documentation as hand-written MDX.
|
||||
- Keep documentation aligned with the V2 packages. Do not use `packages/opencode` as the source of truth unless the task explicitly concerns V1.
|
||||
|
||||
## Local development
|
||||
|
||||
- At the start of documentation work, launch `bun dev` from `packages/docs` using the shell tool with `background: true`. Never run the dev server in a foreground shell call and do not poll the process; wait for the background completion notification.
|
||||
- Preview the site at `http://localhost:3333`. Mintlify does not expose a host option and binds the preview to all network interfaces. The server reloads changes to MDX and `docs.json` automatically.
|
||||
- Use the running preview to verify navigation, links, Mintlify components, code blocks, and desktop and mobile layout.
|
||||
|
||||
## Validation
|
||||
|
||||
- Run `bun validate` from `packages/docs` after making documentation or configuration changes.
|
||||
- Run `bun broken-links` from `packages/docs` when pages, navigation, headings, or links change.
|
||||
- Treat validation errors and broken internal links as blockers. Also verify external links relevant to the change when practical.
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
# OpenCode documentation
|
||||
|
||||
The V2 documentation is a Mintlify site deployed from `packages/docs` on the `dev` branch.
|
||||
|
||||
## Local preview
|
||||
|
||||
From this directory, run:
|
||||
|
||||
```bash
|
||||
bun dev
|
||||
```
|
||||
|
||||
The preview opens at `http://localhost:3333` and reloads when MDX or `docs.json` changes.
|
||||
|
||||
Validate changes before opening a pull request:
|
||||
|
||||
```bash
|
||||
bun validate
|
||||
bun broken-links
|
||||
```
|
||||
|
||||
The V2 theme token reference is generated from
|
||||
`packages/tui/src/theme/v2/schema.ts`. Regenerate it after schema changes:
|
||||
|
||||
```bash
|
||||
bun run generate
|
||||
```
|
||||
|
||||
`bun validate` checks that the committed snippet is current. The repository's
|
||||
generation workflow also refreshes it on pushes to `dev`, so Mintlify always
|
||||
receives the generated MDX as part of the published docs tree.
|
||||
|
||||
The hosted preview is available at [opencode.mintlify.site](https://opencode.mintlify.site).
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: "API Reference"
|
||||
description: "OpenCode HTTP API."
|
||||
---
|
||||
|
||||
The endpoint reference is generated from the current OpenCode V2 [OpenAPI specification](/openapi.json).
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 18H6V6H18V18Z" fill="#F5F5F5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 3H21V21H3V3ZM8 8V16H16V8H8Z" fill="#3B7DD8"/>
|
||||
<path d="M16 8H20V12H16V8Z" fill="#FAB283"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 297 B |
|
|
@ -1,10 +0,0 @@
|
|||
<svg width="234" height="42" viewBox="0 0 234 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 30H6V18H18V30Z" fill="#4B4646"/><path d="M18 12H6V30H18V12ZM24 36H0V6H24V36Z" fill="#B7B1B1"/>
|
||||
<path d="M48 30H36V18H48V30Z" fill="#4B4646"/><path d="M36 30H48V12H36V30ZM54 36H36V42H30V6H54V36Z" fill="#B7B1B1"/>
|
||||
<path d="M84 24V30H66V24H84Z" fill="#4B4646"/><path d="M84 24H66V30H84V36H60V6H84V24ZM66 18H78V12H66V18Z" fill="#B7B1B1"/>
|
||||
<path d="M108 36H96V18H108V36Z" fill="#4B4646"/><path d="M108 12H96V36H90V6H108V12ZM114 36H108V12H114V36Z" fill="#B7B1B1"/>
|
||||
<path d="M144 30H126V18H144V30Z" fill="#4B4646"/><path d="M144 12H126V30H144V36H120V6H144V12Z" fill="#F1ECEC"/>
|
||||
<path d="M168 30H156V18H168V30Z" fill="#4B4646"/><path d="M168 12H156V30H168V12ZM174 36H150V6H174V36Z" fill="#F1ECEC"/>
|
||||
<path d="M198 30H186V18H198V30Z" fill="#4B4646"/><path d="M198 12H186V30H198V12ZM204 36H180V6H198V0H204V36Z" fill="#F1ECEC"/>
|
||||
<path d="M234 24V30H216V24H234Z" fill="#4B4646"/><path d="M216 12V18H228V12H216ZM234 24H216V30H234V36H210V6H234V24Z" fill="#F1ECEC"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
|
@ -1,10 +0,0 @@
|
|||
<svg width="234" height="42" viewBox="0 0 234 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 30H6V18H18V30Z" fill="#CFCECD"/><path d="M18 12H6V30H18V12ZM24 36H0V6H24V36Z" fill="#656363"/>
|
||||
<path d="M48 30H36V18H48V30Z" fill="#CFCECD"/><path d="M36 30H48V12H36V30ZM54 36H36V42H30V6H54V36Z" fill="#656363"/>
|
||||
<path d="M84 24V30H66V24H84Z" fill="#CFCECD"/><path d="M84 24H66V30H84V36H60V6H84V24ZM66 18H78V12H66V18Z" fill="#656363"/>
|
||||
<path d="M108 36H96V18H108V36Z" fill="#CFCECD"/><path d="M108 12H96V36H90V6H108V12ZM114 36H108V12H114V36Z" fill="#656363"/>
|
||||
<path d="M144 30H126V18H144V30Z" fill="#CFCECD"/><path d="M144 12H126V30H144V36H120V6H144V12Z" fill="#211E1E"/>
|
||||
<path d="M168 30H156V18H168V30Z" fill="#CFCECD"/><path d="M168 12H156V30H168V12ZM174 36H150V6H174V36Z" fill="#211E1E"/>
|
||||
<path d="M198 30H186V18H198V30Z" fill="#CFCECD"/><path d="M198 12H186V30H198V12ZM204 36H180V6H198V0H204V36Z" fill="#211E1E"/>
|
||||
<path d="M234 24V30H216V24H234Z" fill="#CFCECD"/><path d="M216 12V18H228V12H216ZM234 24H216V30H234V36H210V6H234V24Z" fill="#211E1E"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
183
packages/docs/build/client.mdx
vendored
183
packages/docs/build/client.mdx
vendored
|
|
@ -1,183 +0,0 @@
|
|||
---
|
||||
title: "Client"
|
||||
description: "Connect an application to the OpenCode HTTP API."
|
||||
---
|
||||
|
||||
`@opencode-ai/client` is the generated TypeScript client for the OpenCode HTTP
|
||||
API. Use it when your application connects to an OpenCode server over the
|
||||
network. Its types and methods are generated from the same contract as the
|
||||
[API reference](/api).
|
||||
|
||||
<Warning>
|
||||
The V2 API and client are beta. Method names, inputs, and outputs may change
|
||||
before the stable release.
|
||||
</Warning>
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
bun add @opencode-ai/client@next
|
||||
```
|
||||
|
||||
## Create a client
|
||||
|
||||
Create a client with the server URL, then call methods grouped by API resource:
|
||||
|
||||
```ts
|
||||
import { OpenCode } from "@opencode-ai/client"
|
||||
|
||||
const client = OpenCode.make({
|
||||
baseUrl: "http://localhost:4096",
|
||||
})
|
||||
|
||||
const session = await client.session.create({
|
||||
location: { directory: "/workspace" },
|
||||
})
|
||||
|
||||
await client.session.prompt({
|
||||
sessionID: session.id,
|
||||
text: "Review the current changes",
|
||||
})
|
||||
```
|
||||
|
||||
## Headers and requests
|
||||
|
||||
Pass default authentication or application headers to `OpenCode.make` with
|
||||
`headers`. You can also supply a custom `fetch` implementation. Each operation
|
||||
accepts request options as its final argument for an `AbortSignal` or
|
||||
per-request headers.
|
||||
|
||||
```ts
|
||||
const client = OpenCode.make({
|
||||
baseUrl: "https://opencode.example.com",
|
||||
headers: {
|
||||
authorization: `Bearer ${process.env.OPENCODE_TOKEN}`,
|
||||
},
|
||||
})
|
||||
|
||||
await client.session.list(undefined, {
|
||||
signal: AbortSignal.timeout(10_000),
|
||||
})
|
||||
```
|
||||
|
||||
## Stream events
|
||||
|
||||
Streaming endpoints return async iterables:
|
||||
|
||||
```ts
|
||||
for await (const event of client.event.subscribe()) {
|
||||
console.log(event.type)
|
||||
}
|
||||
```
|
||||
|
||||
## Local background service
|
||||
|
||||
The main client entrypoints are browser-compatible and do not include local
|
||||
process management. In a Node application, import the native Promise service
|
||||
API from `@opencode-ai/client/service`.
|
||||
|
||||
- `Service.discover()` returns a healthy registered endpoint without starting
|
||||
a process.
|
||||
- `Service.ensure()` returns a compatible service, starting one when needed.
|
||||
- `Service.stop()` stops the exact registered service instance.
|
||||
- `Service.headers(endpoint)` creates the authentication headers for a client.
|
||||
|
||||
```ts
|
||||
import { OpenCode } from "@opencode-ai/client"
|
||||
import { Service } from "@opencode-ai/client/service"
|
||||
|
||||
const endpoint = await Service.ensure()
|
||||
const client = OpenCode.make({
|
||||
baseUrl: endpoint.url,
|
||||
headers: Service.headers(endpoint),
|
||||
})
|
||||
|
||||
const health = await client.health.get()
|
||||
```
|
||||
|
||||
`Service.ensure()` accepts an optional registration file, required version,
|
||||
service command, and `onStart` callback:
|
||||
|
||||
```ts
|
||||
const endpoint = await Service.ensure({
|
||||
file: "/var/run/opencode/service.json",
|
||||
version: "2.0.0",
|
||||
command: ["opencode", "serve", "--service"],
|
||||
onStart(reason, previousVersion) {
|
||||
console.log(reason, previousVersion)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Omit these options to use the standard registration path and
|
||||
`opencode serve --service` command.
|
||||
|
||||
## Effect
|
||||
|
||||
OpenCode provides a first-class Effect client through the
|
||||
`@opencode-ai/client/effect` entrypoint. It returns typed Effects and Streams
|
||||
and decodes responses into OpenCode schema values.
|
||||
|
||||
```sh
|
||||
bun add @opencode-ai/client@next effect
|
||||
```
|
||||
|
||||
### Create a client
|
||||
|
||||
```ts
|
||||
import { AbsolutePath, Location, OpenCode } from "@opencode-ai/client/effect"
|
||||
import { Effect } from "effect"
|
||||
import { FetchHttpClient } from "effect/unstable/http"
|
||||
|
||||
const program = Effect.gen(function* () {
|
||||
const client = yield* OpenCode.make({ baseUrl: "http://localhost:4096" })
|
||||
const session = yield* client.session.create({
|
||||
location: Location.Ref.make({
|
||||
directory: AbsolutePath.make("/workspace"),
|
||||
}),
|
||||
})
|
||||
|
||||
return yield* client.session.get({ sessionID: session.id })
|
||||
})
|
||||
|
||||
const session = await Effect.runPromise(
|
||||
program.pipe(Effect.provide(FetchHttpClient.layer)),
|
||||
)
|
||||
```
|
||||
|
||||
Streaming operations, including `client.event.subscribe()` and
|
||||
`client.session.log(...)`, return Effect `Stream` values.
|
||||
|
||||
### Local background service
|
||||
|
||||
The Node-only `@opencode-ai/client/effect/service` entrypoint exposes the same
|
||||
operations as Effect values. Add `@effect/platform-node` and provide its
|
||||
filesystem layer when running them.
|
||||
|
||||
```sh
|
||||
bun add @effect/platform-node
|
||||
```
|
||||
|
||||
```ts
|
||||
import { NodeFileSystem } from "@effect/platform-node"
|
||||
import { OpenCode } from "@opencode-ai/client/effect"
|
||||
import { Service } from "@opencode-ai/client/effect/service"
|
||||
import { Effect } from "effect"
|
||||
import { FetchHttpClient } from "effect/unstable/http"
|
||||
|
||||
const program = Effect.gen(function* () {
|
||||
const endpoint = yield* Service.ensure()
|
||||
const client = yield* OpenCode.make({
|
||||
baseUrl: endpoint.url,
|
||||
headers: Service.headers(endpoint),
|
||||
})
|
||||
return yield* client.health.get()
|
||||
})
|
||||
|
||||
const health = await Effect.runPromise(
|
||||
program.pipe(
|
||||
Effect.provide(FetchHttpClient.layer),
|
||||
Effect.provide(NodeFileSystem.layer),
|
||||
),
|
||||
)
|
||||
```
|
||||
24
packages/docs/build/index.mdx
vendored
24
packages/docs/build/index.mdx
vendored
|
|
@ -1,24 +0,0 @@
|
|||
---
|
||||
title: "Build"
|
||||
description: "Build on the engine used by millions daily."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Extend OpenCode" href="/build/plugins">
|
||||
Build plugins that add tools, integrations, commands, agents, and custom behavior while keeping the rest of OpenCode
|
||||
intact.
|
||||
</Card>
|
||||
<Card title="Run it as a server" href="/build/client">
|
||||
Connect to OpenCode with the same client used by the TUI and desktop app, then build any interface, workflow, or agent
|
||||
experience around it.
|
||||
</Card>
|
||||
<Card title="Embed it" href="/build/sdk">
|
||||
Embed OpenCode directly into your application and build a completely custom agent, interface, or developer product
|
||||
around it.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Warning>
|
||||
The plugin API, client, and SDK are still being finalized during beta and may change before OpenCode 2.0 is stable.
|
||||
</Warning>
|
||||
446
packages/docs/build/plugins.mdx
vendored
446
packages/docs/build/plugins.mdx
vendored
|
|
@ -1,446 +0,0 @@
|
|||
---
|
||||
title: "Plugins"
|
||||
description: "Extend OpenCode with plugins."
|
||||
---
|
||||
|
||||
Plugins extend OpenCode in-process. They can transform agents, models, commands,
|
||||
integrations, references, skills, and tools; intercept model requests and tool
|
||||
execution; and call a subset of the V2 client.
|
||||
|
||||
<Warning>
|
||||
The V2 plugin API is beta. Entrypoints, hooks, draft shapes, and configuration may change before the stable release.
|
||||
Use the `/v2` exports described on this page.
|
||||
</Warning>
|
||||
|
||||
## Load plugins
|
||||
|
||||
Plugins can be loaded from npm packages, explicit local paths, or config
|
||||
directories. Each module must have one default export containing a unique
|
||||
plugin `id` and a `setup` function.
|
||||
|
||||
### Configuration
|
||||
|
||||
Add ordered entries to the `plugins` field in `opencode.json(c)`:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"plugins": [
|
||||
"opencode-acme-plugin@1.2.0",
|
||||
"@acme/opencode-plugin",
|
||||
"./plugins/local.ts",
|
||||
{
|
||||
"package": "./plugins/reviewer.ts",
|
||||
"options": {
|
||||
"agent": "reviewer",
|
||||
"strict": true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
A string is either a package specifier or a local path. Local paths must start
|
||||
with `./` or `../` and resolve relative to the configuration file containing
|
||||
the entry. Absolute paths and `file://` URLs are also supported. Both scoped
|
||||
packages and versioned package specifiers are supported.
|
||||
|
||||
Use the object form to pass JSON configuration to the plugin. OpenCode passes
|
||||
`options` unchanged as `ctx.options`; omitted options become an empty object.
|
||||
The plugin owns validation and defaults for its options.
|
||||
|
||||
See [Config](/config#locations) for configuration locations and precedence.
|
||||
Entries from all applicable files are processed from lowest to highest
|
||||
precedence rather than replacing the entire array.
|
||||
|
||||
### Local discovery
|
||||
|
||||
OpenCode automatically scans this directory in every discovered OpenCode config
|
||||
directory:
|
||||
|
||||
```text
|
||||
.opencode/plugins/
|
||||
```
|
||||
|
||||
The equivalent global directory is `~/.config/opencode/plugins/`. Direct `.ts`
|
||||
and `.js` children are loaded. An immediate child directory is also loaded as a
|
||||
package when OpenCode can resolve a string `exports`, `module`, or `main`
|
||||
entrypoint, or an `index.ts` or `index.js` file.
|
||||
|
||||
A `plugins/` directory beside a project-root `opencode.json` is not discovered
|
||||
automatically. Put it under `.opencode/`, or add its file explicitly with a
|
||||
relative config entry.
|
||||
|
||||
### Enable and disable
|
||||
|
||||
A string beginning with `-` disables plugins by their exported `id`. `*`
|
||||
matches every ID, and a suffix of `.*` matches an ID prefix. Directives are
|
||||
applied in order:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"plugins": ["./plugins/reviewer.ts", "-acme.reviewer", "-opencode.provider.*", "opencode.provider.openai"],
|
||||
}
|
||||
```
|
||||
|
||||
Package specifiers and local paths locate plugin modules; they are not disable
|
||||
selectors. Use the `id` from the plugin's default export to disable it. A later
|
||||
ID entry re-enables a loaded or built-in plugin. Explicit config directives run
|
||||
after local auto-discovery, so they can disable discovered plugins by ID.
|
||||
|
||||
User plugins are activated in configured order between OpenCode's internal
|
||||
plugin phases. Hooks run sequentially in registration order, and later hooks
|
||||
observe earlier mutations. Do not depend on the internal phase ordering while
|
||||
the API is beta.
|
||||
|
||||
### Installation and dependencies
|
||||
|
||||
OpenCode installs bare package entries and their production dependencies into
|
||||
an isolated cache. Package installation does not run lifecycle scripts.
|
||||
Published packages should expose their plugin entrypoint and include every
|
||||
runtime import in `dependencies`.
|
||||
|
||||
Local files and local package directories are imported directly. OpenCode does
|
||||
**not** install their dependencies. Install dependencies in a `package.json`
|
||||
visible from the plugin file, for example:
|
||||
|
||||
```sh
|
||||
cd .opencode
|
||||
bun add @opencode-ai/plugin@next
|
||||
```
|
||||
|
||||
Match the plugin package version to the OpenCode release you target.
|
||||
|
||||
Configuration and discovered plugin files under watched config directories are
|
||||
reloaded when they change. Reloading replaces the active plugin generation and
|
||||
releases its scoped registrations. Restart OpenCode after changing an npm
|
||||
package version or a local dependency when no watched file changed.
|
||||
|
||||
## Create a plugin
|
||||
|
||||
Export the result of `Plugin.define` as the module default:
|
||||
|
||||
```ts title=".opencode/plugins/reviewer.ts"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme.reviewer",
|
||||
setup: async (ctx) => {
|
||||
const description =
|
||||
typeof ctx.options.description === "string" ? ctx.options.description : "Reviews code for regressions"
|
||||
|
||||
await ctx.agent.transform((agents) => {
|
||||
agents.update("reviewer", (agent) => {
|
||||
agent.description = description
|
||||
agent.mode = "subagent"
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
`setup` runs each time the plugin is activated. Register long-lived behavior
|
||||
during setup; do not wait there on an infinite event stream. It may return a
|
||||
synchronous or asynchronous cleanup function. OpenCode awaits that cleanup
|
||||
when the plugin is disabled, reloaded, or shut down:
|
||||
|
||||
```ts
|
||||
setup: async (ctx) => {
|
||||
const controller = new AbortController()
|
||||
const task = synchronize(ctx, controller.signal)
|
||||
|
||||
return async () => {
|
||||
controller.abort()
|
||||
await task
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Hook registrations are released automatically with the same plugin scope. Use
|
||||
the returned cleanup for resources the plugin owns, such as timers, watchers,
|
||||
connections, and background tasks.
|
||||
|
||||
### Context
|
||||
|
||||
The plugin context is essentially an [OpenCode server client](/build/client).
|
||||
Its read and action methods use the same inputs and responses as the client. It
|
||||
adds plugin-only methods for transforms, runtime hooks, reloads, registrations,
|
||||
and plugin options.
|
||||
|
||||
| Capability | Available operations |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| `ctx.agent` | `list`, `get`, `transform`, `reload` |
|
||||
| `ctx.catalog.provider` | `list`, `get` |
|
||||
| `ctx.catalog.model` | `list`, `get`, `default` |
|
||||
| `ctx.catalog` | `transform`, `reload` |
|
||||
| `ctx.command` | `list`, `transform`, `reload` |
|
||||
| `ctx.integration` | `list`, `get`, `connect`, `attempt`, `transform`, `reload`, and connection lookup/resolution |
|
||||
| `ctx.plugin` | `list` currently active plugin IDs |
|
||||
| `ctx.reference` | `list`, `transform`, `reload` |
|
||||
| `ctx.session` | `create`, `get`, `prompt`, `command`, `synthetic`, `interrupt`, and `hook` |
|
||||
| `ctx.skill` | `list`, `transform`, `reload` |
|
||||
| `ctx.tool` | `transform` and `hook` |
|
||||
| `ctx.aisdk` | `hook` |
|
||||
| `ctx.event` | `subscribe` to the current public server event stream |
|
||||
| `ctx.options` | Readonly options from the matching config object |
|
||||
|
||||
### Transform hooks
|
||||
|
||||
Transform hooks let a plugin modify how OpenCode is configured. Use them to add
|
||||
or remove definitions, override settings, choose defaults, and provide tools or
|
||||
other sources.
|
||||
|
||||
| Transform | Draft operations |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `agent.transform` | `list`, `get`, `default`, `update`, `remove` |
|
||||
| `catalog.transform` | Provider `list`, `get`, `update`, `remove`; model `get`, `update`, `remove`; default model `get`, `set` |
|
||||
| `command.transform` | `list`, `get`, `update`, `remove` |
|
||||
| `integration.transform` | Integration `list`, `get`, `update`, `remove`; method `list`, `update`, `remove` |
|
||||
| `reference.transform` | `add`, `remove`, `list` |
|
||||
| `skill.transform` | `source`, `list` |
|
||||
| `tool.transform` | `add` |
|
||||
|
||||
Here's an example that keeps models synced from a remote source:
|
||||
|
||||
```js title=".opencode/plugins/remote-models.js"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme.remote-models",
|
||||
setup: async (ctx) => {
|
||||
let models = []
|
||||
|
||||
await ctx.catalog.transform((catalog) => {
|
||||
for (const model of models) {
|
||||
catalog.model.update(model.providerID, model.id, (draft) => Object.assign(draft, model))
|
||||
}
|
||||
})
|
||||
|
||||
const refresh = async () => {
|
||||
const response = await fetch("https://example.com/opencode/models.json", {
|
||||
signal: AbortSignal.timeout(10_000),
|
||||
})
|
||||
if (!response.ok) return
|
||||
models = await response.json()
|
||||
await ctx.catalog.reload()
|
||||
}
|
||||
|
||||
await refresh()
|
||||
const timer = setInterval(() => void refresh().catch(console.error), 60_000)
|
||||
return () => clearInterval(timer)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
`ctx.catalog.reload()` replays every catalog transform to derive the new
|
||||
catalog. Each plugin's logic remains composed with the others, so a later
|
||||
plugin can still modify models added by an earlier one. The catalog updates
|
||||
without restarting OpenCode.
|
||||
|
||||
### Runtime hooks
|
||||
|
||||
Runtime hooks intercept live operations. Their event objects expose specific
|
||||
mutable fields:
|
||||
|
||||
| Hook | Mutable fields |
|
||||
| ------------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| `ctx.aisdk.hook("sdk", callback)` | `sdk`, after inspecting `model`, `package`, and `options` |
|
||||
| `ctx.aisdk.hook("language", callback)` | `language`, after inspecting `model`, `sdk`, and `options` |
|
||||
| `ctx.session.hook("request", callback)` | `system`, `messages`, and the `tools` record immediately before model dispatch |
|
||||
| `ctx.tool.hook("execute.before", callback)` | `input`, before the selected tool executes |
|
||||
| `ctx.tool.hook("execute.after", callback)` | Terminal `content`, `metadata`, and `outputPaths`; `error` on failure |
|
||||
|
||||
For example, remove a tool from selected model requests and normalize another
|
||||
tool's input:
|
||||
|
||||
```ts title=".opencode/plugins/guards.ts"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme.guards",
|
||||
setup: async (ctx) => {
|
||||
await ctx.session.hook("request", (event) => {
|
||||
delete event.tools.write
|
||||
})
|
||||
|
||||
await ctx.tool.hook("execute.before", (event) => {
|
||||
if (event.tool !== "lookup" || typeof event.input !== "object" || event.input === null) return
|
||||
event.input = { ...event.input, source: "plugin" }
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
A hook failure fails the operation it intercepts. Keep runtime hooks fast and
|
||||
handle expected errors inside the callback.
|
||||
|
||||
## Examples
|
||||
|
||||
### Add a tool
|
||||
|
||||
Create an executable tool with `Tool.make`, then register it with a name
|
||||
and registration options. Define its input with JSON Schema and use an async
|
||||
executor:
|
||||
|
||||
```js title=".opencode/plugins/greeting.js"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
import { Tool } from "@opencode-ai/plugin/v2/tool"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme.greeting",
|
||||
setup: async (ctx) => {
|
||||
await ctx.tool.transform((tools) => {
|
||||
tools.add(
|
||||
"greeting",
|
||||
Tool.make({
|
||||
description: "Create a greeting",
|
||||
input: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
},
|
||||
required: ["name"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
output: {
|
||||
type: "object",
|
||||
properties: { greeting: { type: "string" } },
|
||||
required: ["greeting"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
execute: async ({ name }) => {
|
||||
const text = `Hello, ${name}!`
|
||||
return {
|
||||
output: { greeting: text },
|
||||
content: text,
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Unsupported characters in tool names are normalized to underscores. Namespace
|
||||
segments must begin with a letter, contain at most 64 letters, digits,
|
||||
underscores, or hyphens, and are joined with dots. Pass the optional third
|
||||
argument to `tools.add` to configure the registration with
|
||||
`{ namespace, codemode }`:
|
||||
|
||||
- `namespace` prefixes and groups the exposed tool name.
|
||||
- `codemode` defaults to `true` and makes the tool available through the
|
||||
`execute` CodeMode tool. Set `codemode: false` to expose it directly to the
|
||||
provider.
|
||||
|
||||
The executor receives a second context argument containing `sessionID`,
|
||||
`agent`, `messageID`, `callID`, and `progress`. A tool with `output`
|
||||
must return `output`; Effect and Standard Schema codecs validate it, while raw
|
||||
JSON Schema definitions enforce JSON compatibility only. A tool
|
||||
without `output` returns model-visible `content` instead.
|
||||
|
||||
### Add a command
|
||||
|
||||
```js title=".opencode/plugins/review-command.js"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme.review-command",
|
||||
setup: async (ctx) => {
|
||||
await ctx.command.transform((commands) => {
|
||||
commands.update("review", (command) => {
|
||||
command.description = "Review the current changes"
|
||||
command.template = "Review the current changes for correctness and missing tests."
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Set the default model
|
||||
|
||||
```js title=".opencode/plugins/default-model.js"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme.default-model",
|
||||
setup: async (ctx) => {
|
||||
await ctx.catalog.transform((catalog) => {
|
||||
catalog.model.default.set("anthropic", "claude-sonnet-4-5")
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Publish a package
|
||||
|
||||
A package plugin uses the same default export as a local plugin. A minimal
|
||||
manifest is:
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
"name": "opencode-acme-plugin",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"exports": "./src/index.ts",
|
||||
"dependencies": {
|
||||
"@opencode-ai/plugin": "next"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use versions compatible with the OpenCode release you target and test the
|
||||
installed package, not only a workspace-linked copy. Because the plugin API is
|
||||
beta, publish compatible plugin updates when V2 entrypoints or contracts
|
||||
change.
|
||||
|
||||
## Verify loading
|
||||
|
||||
List active plugin IDs through the V2 API:
|
||||
|
||||
```sh
|
||||
opencode2 api get /api/plugin
|
||||
```
|
||||
|
||||
If a plugin is absent, check the server log described in
|
||||
[Troubleshooting](/troubleshooting#read-logs). Invalid modules and setup failures are
|
||||
logged; one failing package does not prevent unrelated valid packages from
|
||||
being resolved.
|
||||
|
||||
## Effect
|
||||
|
||||
OpenCode provides a first-class Effect API for plugins through the
|
||||
`@opencode-ai/plugin/v2/effect` entrypoint. Install `effect` alongside the
|
||||
plugin package and export an `effect` function instead of `setup`:
|
||||
|
||||
```sh
|
||||
bun add @opencode-ai/plugin@next effect
|
||||
```
|
||||
|
||||
```ts title=".opencode/plugins/reviewer-effect.ts"
|
||||
import { Plugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import { Effect } from "effect"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme.reviewer-effect",
|
||||
effect: (ctx) =>
|
||||
Effect.gen(function* () {
|
||||
yield* ctx.agent.transform((agents) => {
|
||||
agents.update("reviewer", (agent) => {
|
||||
agent.description = "Reviews code for regressions"
|
||||
agent.mode = "subagent"
|
||||
})
|
||||
})
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
Context operations return Effects. The plugin effect is scoped, so finalizers,
|
||||
fibers, and registrations are released when the plugin reloads or unloads.
|
||||
OpenCode does not expose its private Core services to the plugin; use the
|
||||
capabilities on `ctx`.
|
||||
|
||||
Typed tools can use `Schema` from `effect` and `Tool.make` from
|
||||
`@opencode-ai/plugin/v2/effect/tool`. Effect and Promise plugins use the same
|
||||
`tools.add(name, tool, options?)` registration shape. Effect executors
|
||||
return an Effect and may fail with the typed tool failure channel.
|
||||
84
packages/docs/build/sdk.mdx
vendored
84
packages/docs/build/sdk.mdx
vendored
|
|
@ -1,84 +0,0 @@
|
|||
---
|
||||
title: "SDK"
|
||||
description: "Embed OpenCode directly in your application."
|
||||
---
|
||||
|
||||
We're working on a general-purpose SDK for embedding OpenCode directly inside
|
||||
your application. The regular SDK is coming soon.
|
||||
|
||||
An Effect-native version is available now for applications built with Effect.
|
||||
Its current documentation is below. For other applications, run OpenCode as a
|
||||
server and use the [TypeScript client](/build/client) in the meantime.
|
||||
|
||||
## Effect
|
||||
|
||||
`@opencode-ai/sdk-next` hosts OpenCode in-process. Unlike the
|
||||
[network client](/build/client), it assembles the OpenCode server and routes API
|
||||
calls through its HTTP router in memory. It opens no HTTP listener and adds no
|
||||
network hop between the client and server.
|
||||
|
||||
<Warning>
|
||||
The V2 SDK is beta and currently private to the OpenCode workspace. It is not
|
||||
published for external installation yet, and its package name and API may
|
||||
change before release.
|
||||
</Warning>
|
||||
|
||||
## Create a host
|
||||
|
||||
`OpenCode.create()` creates a scoped host. Closing its Effect Scope releases
|
||||
the router, location services, fibers, and scoped plugin registrations.
|
||||
|
||||
```ts
|
||||
import {
|
||||
AbsolutePath,
|
||||
Location,
|
||||
OpenCode,
|
||||
} from "@opencode-ai/sdk-next"
|
||||
import { Effect } from "effect"
|
||||
|
||||
const program = Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const opencode = yield* OpenCode.create()
|
||||
const session = yield* opencode.sessions.create({
|
||||
location: Location.Ref.make({
|
||||
directory: AbsolutePath.make("/workspace"),
|
||||
}),
|
||||
})
|
||||
|
||||
return yield* opencode.sessions.get({ sessionID: session.id })
|
||||
}),
|
||||
)
|
||||
|
||||
const session = await Effect.runPromise(program)
|
||||
```
|
||||
|
||||
The embedded host uses the same routes, middleware, codecs, errors, and schema
|
||||
values as `@opencode-ai/client/effect`. It exposes the full generated client and
|
||||
adds the convenience aliases `sessions` and `events` for the session and event
|
||||
groups.
|
||||
|
||||
## Use as a service
|
||||
|
||||
Use `OpenCode.layer` when the host should be provided through Effect dependency
|
||||
injection:
|
||||
|
||||
```ts
|
||||
import { OpenCode } from "@opencode-ai/sdk-next"
|
||||
import { Effect } from "effect"
|
||||
|
||||
const program = Effect.gen(function* () {
|
||||
const opencode = yield* OpenCode.Service
|
||||
return yield* opencode.sessions.active()
|
||||
})
|
||||
|
||||
const active = await Effect.runPromise(
|
||||
program.pipe(Effect.provide(OpenCode.layer)),
|
||||
)
|
||||
```
|
||||
|
||||
## Register plugins
|
||||
|
||||
Call `opencode.plugin(...)` to register an embedded V2 plugin. Embedded plugins
|
||||
use the same discovery and location-scoped activation path as configured
|
||||
plugins. The SDK also exports `Tool` for plugin-defined tools. See the
|
||||
[Plugins guide](/build/plugins) for the plugin shape and available hooks.
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
{
|
||||
"$schema": "https://mintlify.com/docs.json",
|
||||
"theme": "mint",
|
||||
"name": "OpenCode",
|
||||
"description": "OpenCode documentation.",
|
||||
"colors": {
|
||||
"primary": "#3B7DD8",
|
||||
"light": "#3B7DD8",
|
||||
"dark": "#FAB283"
|
||||
},
|
||||
"favicon": "/assets/favicon.svg",
|
||||
"logo": {
|
||||
"light": "/assets/logo-light.svg",
|
||||
"dark": "/assets/logo-dark.svg"
|
||||
},
|
||||
"navigation": {
|
||||
"tabs": [
|
||||
{
|
||||
"tab": "Docs",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Get started",
|
||||
"pages": ["index", "migrate-v1", "config", "troubleshooting"]
|
||||
},
|
||||
{
|
||||
"group": "Configure",
|
||||
"pages": [
|
||||
"providers",
|
||||
"models",
|
||||
"agents",
|
||||
"permissions",
|
||||
"sharing",
|
||||
"snapshots",
|
||||
"commands",
|
||||
"skills",
|
||||
"instructions",
|
||||
"mcp-servers",
|
||||
"attachments",
|
||||
"compaction",
|
||||
"warming",
|
||||
"themes",
|
||||
"formatters",
|
||||
"lsp",
|
||||
"references"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "Build",
|
||||
"pages": ["build/index", "build/plugins", "build/client", "build/sdk"]
|
||||
},
|
||||
{
|
||||
"tab": "API",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Overview",
|
||||
"pages": ["api/index"]
|
||||
},
|
||||
{
|
||||
"group": "Endpoints",
|
||||
"openapi": "openapi.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"global": {}
|
||||
},
|
||||
"contextual": {
|
||||
"options": ["copy", "view", "chatgpt", "claude", "mcp", "cursor", "vscode"]
|
||||
},
|
||||
"footer": {
|
||||
"socials": {
|
||||
"github": "https://github.com/anomalyco/opencode",
|
||||
"x": "https://x.com/opencode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
---
|
||||
title: "LSP"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Language Server Protocol (LSP) integrations can provide code diagnostics,
|
||||
symbols, definitions, references, and other language-aware context.
|
||||
|
||||
<Warning>
|
||||
OpenCode V2 does not yet have an LSP runtime or built-in language servers.
|
||||
The `lsp` configuration is accepted and preserved, but it does not currently
|
||||
start or download servers, expose an LSP tool, or add diagnostics to file tool
|
||||
results.
|
||||
</Warning>
|
||||
|
||||
## Built-in servers
|
||||
|
||||
There are no built-in LSP servers in the current V2 implementation. Setting
|
||||
`lsp` to `true` declares that built-ins should be enabled, but has no runtime
|
||||
effect until V2 provides a server registry and LSP runtime.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"lsp": true
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The `lsp` field accepts a boolean or an object keyed by server name:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"lsp": {
|
||||
"custom-typescript": {
|
||||
"command": ["typescript-language-server", "--stdio"],
|
||||
"extensions": [".ts", ".tsx"],
|
||||
"env": {
|
||||
"TSS_LOG": "-level verbose"
|
||||
},
|
||||
"initialization": {
|
||||
"preferences": {
|
||||
"importModuleSpecifierPreference": "relative"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each enabled server entry has this shape:
|
||||
|
||||
| Property | Type | Required | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `command` | `string[]` | Yes | Executable followed by any arguments. |
|
||||
| `extensions` | `string[]` | No | File extensions associated with the server, including the leading dot. |
|
||||
| `disabled` | `boolean` | No | Disables the entry when `true`. |
|
||||
| `env` | `Record<string, string>` | No | Environment variables for the server process. The property is named `env`, not `environment`. |
|
||||
| `initialization` | `Record<string, unknown>` | No | Server-specific options for the LSP `initialize` request. |
|
||||
|
||||
The only entry that may omit `command` is the disable-only form:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"lsp": {
|
||||
"typescript": {
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Server names are arbitrary. The V2 schema permits `extensions` to be omitted,
|
||||
including for a custom server, although a future runtime will need a way to
|
||||
associate that server with files.
|
||||
|
||||
## Disable LSP
|
||||
|
||||
Omit `lsp` when no configuration is needed. Set it to `false` to explicitly
|
||||
disable the whole integration, including when a lower-priority configuration
|
||||
set it to `true` or supplied an object:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"lsp": false
|
||||
}
|
||||
```
|
||||
|
||||
Use `{ "disabled": true }` under a server name to disable one server while
|
||||
retaining the object form. `OPENCODE_DISABLE_LSP_DOWNLOAD` is not used by V2;
|
||||
V2 currently performs no automatic LSP downloads.
|
||||
|
||||
## Current usage
|
||||
|
||||
V2 loads and validates the configuration shape for compatibility and future
|
||||
integration. It does not currently use LSP when reading, writing, editing, or
|
||||
patching files, and those tools do not notify a language server or return LSP
|
||||
diagnostics.
|
||||
|
||||
For reliable feedback today, have the agent run the project's lint, typecheck,
|
||||
test, or compiler commands. Record those commands in an `AGENTS.md` file or a
|
||||
skill so the agent knows when and where to run them.
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/docs",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "bun run generate && bun --bun mint dev --no-open --port 3333",
|
||||
"generate": "bun script/generate-theme-tokens.ts",
|
||||
"check:generated": "bun script/generate-theme-tokens.ts --check",
|
||||
"validate": "bun run check:generated && bun --bun mint validate",
|
||||
"broken-links": "bun --bun mint broken-links"
|
||||
},
|
||||
"devDependencies": {
|
||||
"effect": "catalog:",
|
||||
"mint": "4.2.666",
|
||||
"prettier": "3.6.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
---
|
||||
title: "Permissions"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Permissions control whether an agent may perform an action on a resource. V2
|
||||
configuration uses the `permissions` field and an ordered array of rules.
|
||||
|
||||
<Warning>
|
||||
The V1 object syntax uses different field and action names. Do not use
|
||||
`permission`, `bash`, or `task` in V2 configuration; use `permissions`,
|
||||
`shell`, and `subagent`.
|
||||
</Warning>
|
||||
|
||||
## Rule schema
|
||||
|
||||
Each rule has three required string fields:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permissions": [
|
||||
{ "action": "*", "resource": "*", "effect": "ask" },
|
||||
{ "action": "read", "resource": "*", "effect": "allow" },
|
||||
{ "action": "read", "resource": "*.env", "effect": "deny" },
|
||||
{ "action": "shell", "resource": "git status *", "effect": "allow" },
|
||||
{ "action": "shell", "resource": "git push *", "effect": "deny" },
|
||||
{ "action": "edit", "resource": "packages/docs/*.mdx", "effect": "allow" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `action` matches a tool permission action.
|
||||
- `resource` matches the value the tool is trying to use, such as a path,
|
||||
command, URL, query, or agent ID.
|
||||
- `effect` is `"allow"`, `"deny"`, or `"ask"`.
|
||||
|
||||
`allow` proceeds without prompting, `deny` blocks the operation, and `ask`
|
||||
waits for a user decision. If no rule matches, the result is `ask`.
|
||||
|
||||
## Matching and order
|
||||
|
||||
Both `action` and `resource` support simple wildcards:
|
||||
|
||||
- `*` matches zero or more characters, including `/`.
|
||||
- `?` matches exactly one character.
|
||||
- All other characters are literal.
|
||||
|
||||
Matches cover the entire value. Slashes are normalized, and matching is
|
||||
case-insensitive on Windows. For shell convenience, a pattern ending in
|
||||
`" *"` also matches the command without arguments: `"git status *"` matches
|
||||
both `git status` and `git status --short`.
|
||||
|
||||
The **last matching rule wins**. Put broad rules first and exceptions later.
|
||||
Rules from lower-priority configuration files are loaded first. OpenCode then
|
||||
appends all global rules before agent-specific rules, so a matching agent rule
|
||||
overrides a global rule.
|
||||
|
||||
Some operations check several resources at once, such as a patch touching
|
||||
multiple files. OpenCode denies the operation if any resource resolves to
|
||||
`deny`; otherwise it asks if any resolves to `ask`; otherwise it allows it.
|
||||
|
||||
## Actions and resources
|
||||
|
||||
V2 action names are strings, so plugins may introduce additional actions. The
|
||||
current built-in actions use these resources:
|
||||
|
||||
| Action | Resource matched |
|
||||
| --- | --- |
|
||||
| `read` | Location-relative path for an internal file or directory; canonical absolute path for an external target |
|
||||
| `edit` | Target path for `edit`, `write`, and `patch`; all three tools share this action |
|
||||
| `glob` | The requested glob pattern |
|
||||
| `grep` | The requested regular expression, not the search path |
|
||||
| `shell` | The complete raw shell command string |
|
||||
| `subagent` | The target agent ID |
|
||||
| `skill` | The skill ID |
|
||||
| `question` | `*` |
|
||||
| `webfetch` | The requested URL |
|
||||
| `websearch` | The search query |
|
||||
| `external_directory` | A canonical external directory boundary, normally ending in `/*` |
|
||||
| `<server>_<tool>` | `*` for an MCP tool; unsupported characters in both names become `_` |
|
||||
| `execute` | `*`; controls availability of the Code Mode dispatcher, while each nested tool still enforces its own permission |
|
||||
|
||||
Built-in agent policy also reserves `plan_enter` and `plan_exit` for plan-mode
|
||||
transitions. `doom_loop` and `lsp` are not current V2 Core permission actions.
|
||||
|
||||
## External directories
|
||||
|
||||
An external path requires a separate `external_directory` decision before the
|
||||
tool's own `read` or `edit` decision. This applies to external paths used by
|
||||
`read`, `edit`, `write`, and `patch`, and to an external `shell` working
|
||||
directory.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permissions": [
|
||||
{
|
||||
"action": "external_directory",
|
||||
"resource": "~/projects/reference/*",
|
||||
"effect": "allow"
|
||||
},
|
||||
{
|
||||
"action": "read",
|
||||
"resource": "~/projects/reference/*",
|
||||
"effect": "allow"
|
||||
},
|
||||
{
|
||||
"action": "edit",
|
||||
"resource": "~/projects/reference/*",
|
||||
"effect": "deny"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
For `external_directory`, `read`, and `edit` resources, a leading `~`, `~/`,
|
||||
`$HOME`, or `$HOME/` is expanded when configuration loads. Shell resources are
|
||||
raw command text and are **not** home-expanded.
|
||||
|
||||
<Warning>
|
||||
`shell` runs with the host user's filesystem, process, and network authority.
|
||||
Its resource is raw text, not a parsed command. External command arguments
|
||||
produce only best-effort warnings; `external_directory` is enforced for the
|
||||
working directory, not every path embedded in a command. Prefer a narrow
|
||||
shell allowlist over patterns intended to identify every dangerous command.
|
||||
</Warning>
|
||||
|
||||
Relative mutation paths cannot escape the active Location, and symlink escapes
|
||||
from inside it are rejected. Explicit external paths are canonicalized before
|
||||
matching, so authorize only trusted directory boundaries.
|
||||
|
||||
## Defaults
|
||||
|
||||
The evaluator's fallback is `ask`, but shipped agents include ordered defaults:
|
||||
|
||||
| Agent | Effective default policy |
|
||||
| --- | --- |
|
||||
| `build` | Allows most actions; asks for external directories and `.env` reads; allows questions and entering plan mode; denies exiting plan mode |
|
||||
| `plan` | Uses the same base, allows questions and exiting plan mode, and denies edits except OpenCode plan files |
|
||||
| `general` | Uses the base policy but cannot launch another subagent; questions and plan transitions remain denied |
|
||||
| `explore` | Denies everything except `read`, `glob`, `grep`, `webfetch`, and `websearch`; cannot launch subagents and asks for external directories |
|
||||
| Hidden maintenance agents | Deny all actions |
|
||||
|
||||
The base read rules are ordered as follows:
|
||||
|
||||
```jsonc
|
||||
[
|
||||
{ "action": "read", "resource": "*", "effect": "allow" },
|
||||
{ "action": "read", "resource": "*.env", "effect": "ask" },
|
||||
{ "action": "read", "resource": "*.env.*", "effect": "ask" },
|
||||
{ "action": "read", "resource": "*.env.example", "effect": "allow" }
|
||||
]
|
||||
```
|
||||
|
||||
OpenCode also permits its managed tool-output and temporary directories where
|
||||
needed. These exceptions do not grant general external-directory access.
|
||||
|
||||
## Agent overrides
|
||||
|
||||
Configure shared policy at the top level and append narrower rules to a named
|
||||
agent under `agents.<id>.permissions`:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permissions": [
|
||||
{ "action": "shell", "resource": "*", "effect": "ask" },
|
||||
{ "action": "shell", "resource": "git diff *", "effect": "allow" },
|
||||
{ "action": "shell", "resource": "git status *", "effect": "allow" }
|
||||
],
|
||||
"agents": {
|
||||
"reviewer": {
|
||||
"description": "Review code without changing it",
|
||||
"mode": "subagent",
|
||||
"permissions": [
|
||||
{ "action": "edit", "resource": "*", "effect": "deny" },
|
||||
{ "action": "shell", "resource": "git diff *", "effect": "allow" },
|
||||
{ "action": "shell", "resource": "git status *", "effect": "allow" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Agent rules do not replace the global array; they are appended after it. A
|
||||
custom subagent executes with its own permissions, not a permission subset
|
||||
derived from the parent agent.
|
||||
|
||||
## Approval choices
|
||||
|
||||
When an `ask` rule matches, clients can reply with:
|
||||
|
||||
- **Allow once** (`once`): approve only the pending request.
|
||||
- **Allow always** (`always`): approve this request and save the patterns
|
||||
proposed by the tool for the current project.
|
||||
- **Reject** (`reject`): reject the request. Rejecting also rejects other
|
||||
pending permission requests in the same session; clients may attach feedback.
|
||||
|
||||
Saved approvals are durable and project-scoped. They are additional `allow`
|
||||
rules, but they can never override a configured `deny`. The proposed saved
|
||||
pattern may be broader than the displayed resource: several tools propose `*`,
|
||||
shell proposes the exact command text, and skills and subagents propose their
|
||||
IDs. Review the confirmation carefully and remove saved approvals that are no
|
||||
longer needed.
|
||||
|
||||
For non-interactive runs, `opencode2 run --auto` replies `once` to permission
|
||||
requests. It does not save approvals, and explicit `deny` rules remain enforced.
|
||||
Without `--auto`, a non-interactive run rejects permission requests.
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
---
|
||||
title: "References"
|
||||
description: ""
|
||||
---
|
||||
|
||||
References give OpenCode named access to directories outside the current
|
||||
project. Use them for documentation, shared libraries, examples, or source from
|
||||
another repository.
|
||||
|
||||
Configure references by alias in `opencode.json` or `opencode.jsonc`:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"references": {
|
||||
"docs": {
|
||||
"path": "../product-docs",
|
||||
"description": "Use for product behavior and terminology"
|
||||
},
|
||||
"effect": {
|
||||
"repository": "Effect-TS/effect",
|
||||
"branch": "main",
|
||||
"description": "Use for Effect implementation details"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Local directories
|
||||
|
||||
Use `path` for a local directory:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"references": {
|
||||
"design-system": {
|
||||
"path": "../design-system",
|
||||
"description": "Use when working with components or design tokens"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Relative paths resolve from the directory containing the config file that
|
||||
defines them. Absolute paths and home-relative paths such as `~/docs` are also
|
||||
supported.
|
||||
|
||||
The string shorthand is useful when no other fields are needed:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"references": {
|
||||
"docs": "../docs",
|
||||
"shared": "~/work/shared"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
A shorthand string is treated as a local path only when it starts with `.`,
|
||||
`/`, or `~`. Use `./docs`, not `docs`; a bare `docs` value is interpreted as
|
||||
a Git repository.
|
||||
</Note>
|
||||
|
||||
## Git repositories
|
||||
|
||||
Use `repository` for a remote Git repository. GitHub `owner/repo` shorthand,
|
||||
Git URLs, host/path forms, and SCP-style remotes are supported.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"references": {
|
||||
"effect": {
|
||||
"repository": "Effect-TS/effect",
|
||||
"branch": "main"
|
||||
},
|
||||
"internal-sdk": {
|
||||
"repository": "git@gitlab.example.com:platform/sdk.git",
|
||||
"branch": "release/v2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Without `branch`, OpenCode checks out and refreshes the remote's default
|
||||
branch. Branch names may contain letters, numbers, `/`, `_`, `.`, and `-`, but
|
||||
cannot start with `-` or contain `..`. Local `file:` repositories are not
|
||||
supported.
|
||||
|
||||
Git references also support shorthand:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"references": {
|
||||
"effect": "Effect-TS/effect",
|
||||
"sdk": "gitlab.com/platform/sdk"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Cloning and storage
|
||||
|
||||
OpenCode normalizes a remote and stores one checkout under its global data
|
||||
directory at `opencode/repos/<host>/<repository-path>`. On a typical Linux
|
||||
installation, for example, `Effect-TS/effect` is stored at:
|
||||
|
||||
```text
|
||||
~/.local/share/opencode/repos/github.com/Effect-TS/effect
|
||||
```
|
||||
|
||||
Missing repositories are cloned. Existing checkouts are fetched and reset to
|
||||
the requested branch, or to the remote default branch when `branch` is omitted.
|
||||
Materialization runs asynchronously when references load or reload, so a new
|
||||
reference can appear before its checkout is ready. Clone and refresh failures
|
||||
are logged and do not stop other references from loading.
|
||||
|
||||
<Warning>
|
||||
The cache has one checkout per normalized remote, not one per branch. Do not
|
||||
configure the same repository at multiple branches; only one branch can be
|
||||
exposed. Avoid editing cached checkouts because a refresh resets them.
|
||||
</Warning>
|
||||
|
||||
## Description and visibility
|
||||
|
||||
`description` tells agents when a reference is relevant. References with a
|
||||
description are included in agent instructions with their alias and resolved
|
||||
path. References without one remain available in `@` autocomplete but are not
|
||||
advertised automatically.
|
||||
|
||||
Set `hidden` to `true` to remove a reference from TUI `@` autocomplete:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"references": {
|
||||
"internal": {
|
||||
"path": "../internal",
|
||||
"description": "Use for internal service behavior",
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`hidden` controls only autocomplete visibility. It does not remove the
|
||||
reference from the reference API or agent instructions when a description is
|
||||
present.
|
||||
|
||||
## Use references
|
||||
|
||||
Type `@` in the TUI and select a reference alias to attach its root directory:
|
||||
|
||||
```text
|
||||
Compare the current implementation with @effect
|
||||
```
|
||||
|
||||
The attachment provides a non-recursive listing of the root's immediate files
|
||||
and directories. V2 currently attaches references by root alias;
|
||||
`@alias/path` is not a reference-specific file browser. Ask the agent to
|
||||
inspect a particular path when more detail is needed.
|
||||
|
||||
References do not grant extra tool permissions. Access outside the active
|
||||
Location remains subject to the agent's normal tool rules and the
|
||||
`external_directory` permission. Editing a reference additionally requires the
|
||||
applicable edit permission.
|
||||
|
||||
## Fields
|
||||
|
||||
| Field | Local | Git | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `path` | Required | No | Local directory path |
|
||||
| `repository` | No | Required | Remote Git repository |
|
||||
| `branch` | No | Optional | Branch to fetch and check out |
|
||||
| `description` | Optional | Optional | Guidance describing when agents should use it |
|
||||
| `hidden` | Optional | Optional | Hide it from TUI `@` autocomplete |
|
||||
|
||||
An alias cannot be empty or contain `/`, `\`, whitespace, a backtick, or a
|
||||
comma.
|
||||
10
packages/www/.gitignore
vendored
10
packages/www/.gitignore
vendored
|
|
@ -1,6 +1,4 @@
|
|||
.source
|
||||
.tanstack
|
||||
.wrangler
|
||||
dist
|
||||
node_modules
|
||||
worker-configuration.d.ts
|
||||
.blume/
|
||||
dist/
|
||||
node_modules/
|
||||
.blume-verify/
|
||||
|
|
|
|||
22
packages/www/AGENTS.md
Normal file
22
packages/www/AGENTS.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Website and documentation guide
|
||||
|
||||
## Structure
|
||||
|
||||
- This package owns the `opencode.ai` website.
|
||||
- Add custom marketing routes as Astro files under `pages/`.
|
||||
- The whole project is mounted at `/v2/` by `deployment.base`, and documentation lives under `content/docs/` at `/v2/docs` through `basePath` in `blume.config.ts`.
|
||||
- Write documentation in MDX. Every page should have `title` and `description` frontmatter.
|
||||
- Use parenthesized content folders for sidebar groups that must not add a URL segment. Keep ungrouped top-level pages directly under `content/docs/`.
|
||||
- Put static files in `public/` and reference them with root-relative paths.
|
||||
- The API reference is generated from `openapi.json`; do not duplicate endpoint documentation as hand-written MDX.
|
||||
- Keep documentation aligned with the V2 packages. Do not use `packages/opencode` as the source of truth unless the task explicitly concerns V1.
|
||||
|
||||
## Local development
|
||||
|
||||
- Run `bun dev` from this package and preview the site at `http://localhost:3000/v2/`.
|
||||
- Verify both custom marketing routes and documentation routes after changing shared navigation or layout code.
|
||||
|
||||
## Validation
|
||||
|
||||
- Run `bun typecheck`, `bun validate`, and `bun run build` from this package after documentation or configuration changes.
|
||||
- Treat validation and build errors as blockers.
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
# OpenCode website
|
||||
|
||||
The server-rendered `opencode.ai` website. It uses TanStack Start on Cloudflare Workers and serves the V2 documentation with Fumadocs.
|
||||
The OpenCode V2 website, powered by Blume and deployed with Wrangler at `https://opencode.ai/v2/`. Blume mounts the documentation at `/v2/docs`, and `https://v2.opencode.ai` redirects to the same deployment.
|
||||
|
||||
Wrangler deploys the site through Blume's Cloudflare server adapter. Documentation pages are prerendered, while custom dynamic routes and endpoints can run in the Worker. Production uses `opencode-www` at `opencode.ai/v2/`; dev uses `opencode-www-dev` at `dev.opencode.ai/v2/`. The `v2.opencode.ai` alias is handled by a Cloudflare Redirect Rule outside this project.
|
||||
|
||||
The `deploy-www` GitHub workflow deploys the `dev` branch to the dev Worker and the `v2` branch to the production Worker.
|
||||
|
||||
## Development
|
||||
|
||||
|
|
@ -10,13 +14,12 @@ From this directory, run:
|
|||
bun dev
|
||||
```
|
||||
|
||||
The site opens at `http://localhost:3000`; documentation is available at `http://localhost:3000/docs`.
|
||||
The site opens at `http://localhost:3000/v2/`; documentation is available at `http://localhost:3000/v2/docs`.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
bun typecheck
|
||||
bun validate
|
||||
bun run build
|
||||
```
|
||||
|
||||
The existing `packages/web`, `packages/docs`, and `packages/stats/app` deployments remain in place until their routes have been migrated and verified.
|
||||
|
|
|
|||
43
packages/www/blume.config.ts
Normal file
43
packages/www/blume.config.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { defineConfig } from "blume"
|
||||
|
||||
export default defineConfig({
|
||||
title: "OpenCode",
|
||||
description: "The open source AI coding agent.",
|
||||
basePath: "/docs",
|
||||
logo: {
|
||||
image: {
|
||||
light: "/assets/logo-light.svg",
|
||||
dark: "/assets/logo-dark.svg",
|
||||
alt: "OpenCode",
|
||||
},
|
||||
text: "",
|
||||
href: "/",
|
||||
},
|
||||
content: {
|
||||
root: "content/docs",
|
||||
},
|
||||
github: {
|
||||
owner: "anomalyco",
|
||||
repo: "opencode",
|
||||
branch: "dev",
|
||||
dir: "packages/www",
|
||||
},
|
||||
navigation: {
|
||||
tabs: [
|
||||
{ label: "Docs", path: "/" },
|
||||
{ label: "Build", path: "/build" },
|
||||
{ label: "API", path: "/api" },
|
||||
],
|
||||
},
|
||||
openapi: {
|
||||
enabled: true,
|
||||
route: "/api",
|
||||
spec: "./openapi.json",
|
||||
},
|
||||
deployment: {
|
||||
adapter: "cloudflare",
|
||||
base: "/v2/",
|
||||
output: "server",
|
||||
site: process.env.BLUME_ENV === "dev" ? "https://dev.opencode.ai" : "https://opencode.ai",
|
||||
},
|
||||
})
|
||||
8
packages/www/components.ts
Normal file
8
packages/www/components.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { defineComponents } from "blume"
|
||||
import ThemeTokens from "./snippets/generated/theme-tokens.mdx"
|
||||
|
||||
export default defineComponents({
|
||||
mdx: {
|
||||
ThemeTokens,
|
||||
},
|
||||
})
|
||||
|
|
@ -227,10 +227,10 @@ shell commands, `edit` for all edit/write/patch tools, and `subagent` for child
|
|||
agents. Other tools generally use their tool name, such as `read`, `glob`,
|
||||
`grep`, `webfetch`, `websearch`, and `skill`.
|
||||
|
||||
<Tip>
|
||||
<Callout type="tip">
|
||||
Put broad wildcard rules first and exceptions afterward. For example, deny
|
||||
all subagents first, then allow `explore`.
|
||||
</Tip>
|
||||
</Callout>
|
||||
|
||||
`~` and `$HOME` are expanded in filesystem resources for `read`, `edit`, and
|
||||
`external_directory`. Shell resources are raw command text and are not
|
||||
|
|
@ -274,10 +274,10 @@ The V2 schema accepts per-agent request `headers` and JSON `body` overlays:
|
|||
}
|
||||
```
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
The current V2 session runner preserves these overlays on the agent
|
||||
definition but does not yet apply them to model requests. Configure effective
|
||||
request settings on the provider, model, or model variant instead. Do not use
|
||||
legacy top-level agent fields such as `temperature`, `top_p`, `prompt`,
|
||||
`permission`, `tools`, `disable`, or `maxSteps` in new V2 configuration.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
|
@ -17,12 +17,12 @@ and other binary prompt attachments are not currently included in the model
|
|||
request. Some clients may let you select a PDF, but V2 does not yet make that
|
||||
PDF visible to the model.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
Use a model that supports image input before attaching an image. OpenCode
|
||||
passes supported image media to the selected provider, but the provider and
|
||||
model still enforce their own formats, dimensions, file counts, and size
|
||||
limits. A text-only model may reject the request.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Add attachments
|
||||
|
||||
|
|
@ -131,12 +131,12 @@ All fields are optional:
|
|||
| `max_height` | `2000` | Maximum height in pixels. Must be a positive integer. |
|
||||
| `max_base64_bytes` | `5242880` | Maximum byte length of the Base64-encoded image string. Must be a positive integer. |
|
||||
|
||||
<Note>
|
||||
<Callout type="note">
|
||||
In the current V2 runtime, these settings apply to image media produced by
|
||||
the built-in `read` tool. Images attached directly through the TUI, desktop,
|
||||
web, CLI, or API bypass this normalization. Resize direct attachments before
|
||||
adding them if the provider requires smaller media.
|
||||
</Note>
|
||||
</Callout>
|
||||
|
||||
The `read` tool recognizes PNG, JPEG, GIF, and WebP by their contents and will
|
||||
ingest at most 20 MiB of source image bytes. It decodes the image and compares
|
||||
|
|
@ -137,10 +137,10 @@ project location and inserts its combined output into the template. Argument
|
|||
interpolation happens first, so avoid placing untrusted arguments inside shell
|
||||
interpolations.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
Shell interpolations run when the command is evaluated, outside the agent's
|
||||
tool permission flow. Only use commands from sources you trust.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
No other template interpolation is performed. In particular, an `@path`
|
||||
written into a stored template remains ordinary prompt text; V2 does not
|
||||
|
|
@ -6,10 +6,10 @@ description: ""
|
|||
OpenCode V2 accepts formatter configuration, but it does not yet include a
|
||||
formatter runtime. File writes and edits are not automatically formatted.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
V2 currently has no built-in formatters. The built-in formatter list and
|
||||
automatic post-edit formatting documented for V1 do not apply to V2.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Configuration
|
||||
|
||||
|
|
@ -43,10 +43,10 @@ If the Location is outside the project root, only the global file is loaded.
|
|||
Setting `OPENCODE_DISABLE_PROJECT_CONFIG=1` also skips project `AGENTS.md`
|
||||
discovery but does not disable the global file.
|
||||
|
||||
<Note>
|
||||
<Callout type="note">
|
||||
Current V2 discovery only recognizes `AGENTS.md`. The `CLAUDE.md` fallback
|
||||
and related precedence described by older OpenCode documentation do not apply.
|
||||
</Note>
|
||||
</Callout>
|
||||
|
||||
### Nested instructions
|
||||
|
||||
|
|
@ -80,13 +80,13 @@ Configuration is loaded from global through project-local files. If more than
|
|||
one config defines `instructions`, the highest-precedence, closest config's
|
||||
entire array is selected; arrays are not merged.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
V2 currently parses and retains this field but does not resolve its entries
|
||||
into instruction sources. Local files, glob patterns, and HTTP or HTTPS URLs
|
||||
in `instructions` therefore do not reach the model yet. Use `AGENTS.md` for
|
||||
active V2 instructions. URL fetching and timeout behavior documented for V1
|
||||
are not supported by the current V2 implementation.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
See [Config](/config) for config locations and general precedence.
|
||||
|
||||
|
|
@ -6,12 +6,12 @@ description: ""
|
|||
Language Server Protocol (LSP) integrations can provide code diagnostics,
|
||||
symbols, definitions, references, and other language-aware context.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
OpenCode V2 does not yet have an LSP runtime or built-in language servers.
|
||||
The `lsp` configuration is accepted and preserved, but it does not currently
|
||||
start or download servers, expose an LSP tool, or add diagnostics to file tool
|
||||
results.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Built-in servers
|
||||
|
||||
24
packages/www/content/docs/(Configure)/meta.ts
Normal file
24
packages/www/content/docs/(Configure)/meta.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { defineMeta } from "blume"
|
||||
|
||||
export default defineMeta({
|
||||
title: "Configure",
|
||||
pages: [
|
||||
"providers",
|
||||
"models",
|
||||
"agents",
|
||||
"permissions",
|
||||
"sharing",
|
||||
"snapshots",
|
||||
"commands",
|
||||
"skills",
|
||||
"instructions",
|
||||
"mcp-servers",
|
||||
"attachments",
|
||||
"compaction",
|
||||
"warming",
|
||||
"themes",
|
||||
"formatters",
|
||||
"lsp",
|
||||
"references",
|
||||
],
|
||||
})
|
||||
|
|
@ -6,11 +6,11 @@ description: ""
|
|||
Permissions control whether an agent may perform an action on a resource. V2
|
||||
configuration uses the `permissions` field and an ordered array of rules.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
The V1 object syntax uses different field and action names. Do not use
|
||||
`permission`, `bash`, or `task` in V2 configuration; use `permissions`,
|
||||
`shell`, and `subagent`.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Rule schema
|
||||
|
||||
|
|
@ -118,13 +118,13 @@ For `external_directory`, `read`, and `edit` resources, a leading `~`, `~/`,
|
|||
`$HOME`, or `$HOME/` is expanded when configuration loads. Shell resources are
|
||||
raw command text and are **not** home-expanded.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
`shell` runs with the host user's filesystem, process, and network authority.
|
||||
Its resource is raw text, not a parsed command. External command arguments
|
||||
produce only best-effort warnings; `external_directory` is enforced for the
|
||||
working directory, not every path embedded in a command. Prefer a narrow
|
||||
shell allowlist over patterns intended to identify every dangerous command.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
Relative mutation paths cannot escape the active Location, and symlink escapes
|
||||
from inside it are rejected. Explicit external paths are canonicalized before
|
||||
|
|
@ -55,7 +55,7 @@ When several credential sources exist, OpenCode uses the stored credential first
|
|||
}
|
||||
```
|
||||
|
||||
<Warning>Do not commit API keys or authorization headers to your repository.</Warning>
|
||||
<Callout type="warning">Do not commit API keys or authorization headers to your repository.</Callout>
|
||||
|
||||
## Configure
|
||||
|
||||
|
|
@ -56,11 +56,11 @@ The string shorthand is useful when no other fields are needed:
|
|||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
<Callout type="note">
|
||||
A shorthand string is treated as a local path only when it starts with `.`,
|
||||
`/`, or `~`. Use `./docs`, not `docs`; a bare `docs` value is interpreted as
|
||||
a Git repository.
|
||||
</Note>
|
||||
</Callout>
|
||||
|
||||
## Git repositories
|
||||
|
||||
|
|
@ -114,11 +114,11 @@ Materialization runs asynchronously when references load or reload, so a new
|
|||
reference can appear before its checkout is ready. Clone and refresh failures
|
||||
are logged and do not stop other references from loading.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
The cache has one checkout per normalized remote, not one per branch. Do not
|
||||
configure the same repository at multiple branches; only one branch can be
|
||||
exposed. Avoid editing cached checkouts because a refresh resets them.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Description and visibility
|
||||
|
||||
|
|
@ -7,10 +7,10 @@ Session sharing is not yet available in OpenCode V2. V2 does not currently
|
|||
publish sessions, upload conversation history to a sharing service, or create
|
||||
public links.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
The V2 TUI registers `/share`, but it currently only reports that sharing is unavailable. There is no functional
|
||||
share/unshare command or server API endpoint.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Configuration
|
||||
|
||||
|
|
@ -58,10 +58,10 @@ Running `/undo` again moves the staged boundary to an earlier user message. Open
|
|||
immediately before the first undo as the redo baseline, so repeated undos form one wider staged revert rather than a redo
|
||||
stack.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
Sending a new prompt while an undo is staged commits the revert. The hidden message range is removed from the active
|
||||
session history, the currently reverted files are kept, and redo is no longer available.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Redo
|
||||
|
||||
|
|
@ -103,6 +103,6 @@ are not included.
|
|||
Review the staged file summary and your Git diff before continuing. Commit or back up important work independently before
|
||||
using undo on a dirty worktree.
|
||||
|
||||
<Note>
|
||||
<Callout type="note">
|
||||
`/undo` and `/redo` are interactive TUI commands. The non-interactive `run` command does not provide them.
|
||||
</Note>
|
||||
</Callout>
|
||||
|
|
@ -3,8 +3,6 @@ title: "Themes"
|
|||
description: "Choose a built-in TUI theme or create a custom color scheme."
|
||||
---
|
||||
|
||||
import ThemeTokens from "/snippets/generated/theme-tokens.mdx"
|
||||
|
||||
OpenCode includes built-in light and dark themes and can load custom themes
|
||||
from your global configuration or a project directory. The default theme is
|
||||
`opencode`.
|
||||
|
|
@ -41,10 +39,10 @@ path under `$XDG_CONFIG_HOME`:
|
|||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
<Callout type="note">
|
||||
Theme selection applies to the full-screen TUI. Direct interactive runs use colors derived from the terminal palette
|
||||
and honor only the color mode.
|
||||
</Note>
|
||||
</Callout>
|
||||
|
||||
## Built-in themes
|
||||
|
||||
|
|
@ -90,11 +88,11 @@ supported.
|
|||
V2 themes organize colors into hue scales and semantic tokens. Set `version`
|
||||
to `2` and define at least one of `light` or `dark`:
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
Native V2 custom theme files are not loaded directly by the current beta. Existing custom files use the V1 format and
|
||||
are migrated to these tokens at runtime. This reference tracks the native V2 schema while direct file loading is
|
||||
completed.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
By default, a theme inherits OpenCode's complete theme, so you only need to
|
||||
define overrides. Set `mergeMode` to `true` to inherit one mode from the other
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
---
|
||||
title: "Agents"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Agents combine a system prompt, model preference, tool permissions, and display
|
||||
metadata into a reusable assistant profile. OpenCode includes agents for common
|
||||
workflows, and you can override them or add your own in configuration or
|
||||
Markdown files.
|
||||
|
||||
## Built-in agents
|
||||
|
||||
| Agent | Mode | Purpose |
|
||||
| --- | --- | --- |
|
||||
| **Build** (`build`) | `primary` | Default coding agent. Tools are allowed by default, sensitive environment-file reads ask for approval, and access outside the workspace asks for approval. |
|
||||
| **Plan** (`plan`) | `primary` | Planning agent. File edits are denied except for OpenCode plan files. Shell commands are not generally denied. |
|
||||
| **General** (`general`) | `subagent` | General-purpose research and multi-step work. It has broad tool access but cannot launch more subagents. |
|
||||
| **Explore** (`explore`) | `subagent` | Read-only code and web exploration using `read`, `glob`, `grep`, `webfetch`, and `websearch`. |
|
||||
|
||||
OpenCode also has hidden `compaction`, `title`, and `summary` system agents.
|
||||
They run internal maintenance tasks and are not selectable. There is no built-in
|
||||
`scout` agent in V2.
|
||||
|
||||
You can override a built-in agent with an entry of the same ID. Set
|
||||
`disabled: true` to remove one.
|
||||
|
||||
## Default agent
|
||||
|
||||
Set the primary agent used when a session has not selected one:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"default_agent": "reviewer"
|
||||
}
|
||||
```
|
||||
|
||||
The configured agent must exist, must not have `mode: "subagent"`, and must not
|
||||
be hidden. If it is unavailable, OpenCode falls back to `build`, then to the
|
||||
first visible agent that can run as a primary agent. This selection does not
|
||||
rewrite the agent already stored on an existing session.
|
||||
|
||||
## Modes
|
||||
|
||||
An agent's `mode` controls where it can run:
|
||||
|
||||
| Mode | Behavior |
|
||||
| --- | --- |
|
||||
| `primary` | Can be selected as the main agent for a session. It cannot be launched as a subagent. |
|
||||
| `subagent` | Can run in a child session through the `subagent` tool, but cannot be selected as the main agent. |
|
||||
| `all` | Can be used either way. This is the default for a custom agent when `mode` is omitted. |
|
||||
|
||||
In the TUI, press <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> to cycle
|
||||
through visible primary and `all` agents, or use `/agents` to choose one.
|
||||
|
||||
Subagents run in child sessions with fresh context. A primary agent can invoke
|
||||
one with the `subagent` tool, either in the foreground or in the background.
|
||||
You can also `@` mention a visible subagent to ask the current agent to delegate
|
||||
work to it:
|
||||
|
||||
```text
|
||||
@explore find where authentication errors are handled
|
||||
```
|
||||
|
||||
The parent agent's `subagent` permission controls which agents it may launch.
|
||||
The child currently uses its own configured permissions, not a restricted copy
|
||||
of the parent's permissions.
|
||||
|
||||
## Configure agents
|
||||
|
||||
### Markdown files
|
||||
|
||||
The recommended file locations are:
|
||||
|
||||
```text
|
||||
~/.config/opencode/agents/<name>.md
|
||||
.opencode/agents/<name>.md
|
||||
```
|
||||
|
||||
OpenCode discovers project `.opencode` directories from the current directory
|
||||
up to the project root. The path below `agents/` becomes the agent ID, so
|
||||
`.opencode/agents/team/reviewer.md` defines `team/reviewer`.
|
||||
|
||||
Frontmatter uses the same fields as an entry under `agents`. The Markdown body
|
||||
becomes `system`:
|
||||
|
||||
```md title=".opencode/agents/reviewer.md"
|
||||
---
|
||||
description: Reviews changes without modifying files
|
||||
mode: subagent
|
||||
model: anthropic/claude-sonnet-4-5#high
|
||||
color: "#ff6b6b"
|
||||
steps: 8
|
||||
permissions:
|
||||
- action: edit
|
||||
resource: "*"
|
||||
effect: deny
|
||||
- action: shell
|
||||
resource: "*"
|
||||
effect: deny
|
||||
---
|
||||
|
||||
Review for correctness, security, regressions, and missing tests.
|
||||
List findings in severity order with file and line references.
|
||||
```
|
||||
|
||||
### JSON or JSONC
|
||||
|
||||
Use the `agents` field in any [OpenCode configuration file](/docs/config):
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"default_agent": "reviewer",
|
||||
"agents": {
|
||||
"reviewer": {
|
||||
"description": "Reviews changes for correctness, security, and missing tests",
|
||||
"mode": "all",
|
||||
"model": "anthropic/claude-sonnet-4-5#high",
|
||||
"system": "Review the current changes. Report findings before any summary.",
|
||||
"color": "#ff6b6b",
|
||||
"steps": 8,
|
||||
"permissions": [
|
||||
{ "action": "edit", "resource": "*", "effect": "deny" },
|
||||
{ "action": "shell", "resource": "*", "effect": "deny" }
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
"permissions": [
|
||||
{ "action": "shell", "resource": "git push *", "effect": "ask" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Agent definitions merge in configuration order. Later scalar fields replace
|
||||
earlier values, request maps merge by key, and permission rules are appended.
|
||||
Global `permissions` are applied to every agent before its agent-specific rules,
|
||||
so a later agent rule can refine a global rule.
|
||||
|
||||
## Options
|
||||
|
||||
### `description`
|
||||
|
||||
Explains the agent's purpose. It is optional, but strongly recommended for
|
||||
subagents because OpenCode includes it in the subagent catalog shown to the
|
||||
model.
|
||||
|
||||
### `mode`
|
||||
|
||||
Accepts `primary`, `subagent`, or `all`. The default is `all`.
|
||||
|
||||
### `model`
|
||||
|
||||
Selects a model using `provider/model` with an optional `#variant`:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agents": {
|
||||
"reviewer": {
|
||||
"model": "anthropic/claude-sonnet-4-5#high"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The equivalent expanded form is:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agents": {
|
||||
"reviewer": {
|
||||
"model": {
|
||||
"providerID": "anthropic",
|
||||
"model": "claude-sonnet-4-5",
|
||||
"variant": "high"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The TUI uses this as the preferred model when the agent is selected. A child
|
||||
session uses its subagent's configured model, or inherits the parent session's
|
||||
model when none is configured. In the API, the session's selected model is
|
||||
stored separately; creating or switching a primary session with only an agent
|
||||
ID does not itself change that session model.
|
||||
|
||||
### `system`
|
||||
|
||||
Sets the agent's system prompt. A non-empty value replaces OpenCode's
|
||||
provider-specific base prompt for that agent. Project instructions, skills,
|
||||
references, and other instruction sources are still added separately.
|
||||
|
||||
For a Markdown agent, use the document body instead of a `system` frontmatter
|
||||
field.
|
||||
|
||||
### `permissions`
|
||||
|
||||
Permissions are an ordered array of rules:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agents": {
|
||||
"orchestrator": {
|
||||
"permissions": [
|
||||
{ "action": "subagent", "resource": "*", "effect": "deny" },
|
||||
{ "action": "subagent", "resource": "explore", "effect": "allow" },
|
||||
{ "action": "shell", "resource": "git *", "effect": "ask" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each rule has:
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `action` | Tool or permission action, with `*` wildcards supported. |
|
||||
| `resource` | The path, command, agent ID, or other resource matched by the action. Wildcards are supported. |
|
||||
| `effect` | `allow`, `ask`, or `deny`. |
|
||||
|
||||
The last matching rule wins. Important V2 action names include `shell` for
|
||||
shell commands, `edit` for all edit/write/patch tools, and `subagent` for child
|
||||
agents. Other tools generally use their tool name, such as `read`, `glob`,
|
||||
`grep`, `webfetch`, `websearch`, and `skill`.
|
||||
|
||||
<Tip>
|
||||
Put broad wildcard rules first and exceptions afterward. For example, deny
|
||||
all subagents first, then allow `explore`.
|
||||
</Tip>
|
||||
|
||||
`~` and `$HOME` are expanded in filesystem resources for `read`, `edit`, and
|
||||
`external_directory`. Shell resources are raw command text and are not
|
||||
expanded.
|
||||
|
||||
### `steps`
|
||||
|
||||
Sets a positive maximum number of model steps. On the final allowed step,
|
||||
OpenCode removes tools and asks the model to summarize its work in text. New
|
||||
user input resets the allowance.
|
||||
|
||||
### `hidden`
|
||||
|
||||
When `true`, removes the agent from normal selectors, `@` autocomplete, and the
|
||||
subagent catalog advertised to models. It is a visibility setting, not a
|
||||
security boundary.
|
||||
|
||||
### `color`
|
||||
|
||||
Sets the agent's UI color. Use a six-digit hex color such as `#ff6b6b`.
|
||||
|
||||
### `disabled`
|
||||
|
||||
When `true`, removes the agent definition at that point in configuration
|
||||
loading. This works for built-in and custom agents.
|
||||
|
||||
### `request`
|
||||
|
||||
The V2 schema accepts per-agent request `headers` and JSON `body` overlays:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agents": {
|
||||
"reviewer": {
|
||||
"request": {
|
||||
"headers": { "x-agent": "reviewer" },
|
||||
"body": { "temperature": 0.1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Warning>
|
||||
The current V2 session runner preserves these overlays on the agent
|
||||
definition but does not yet apply them to model requests. Configure effective
|
||||
request settings on the provider, model, or model variant instead. Do not use
|
||||
legacy top-level agent fields such as `temperature`, `top_p`, `prompt`,
|
||||
`permission`, `tools`, `disable`, or `maxSteps` in new V2 configuration.
|
||||
</Warning>
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
---
|
||||
title: "Attachments"
|
||||
description: ""
|
||||
---
|
||||
|
||||
OpenCode can add local context to a prompt as text or image media. Current V2
|
||||
sessions make these attachment types visible to the model:
|
||||
|
||||
| Input | Model receives |
|
||||
| --- | --- |
|
||||
| UTF-8 text file | The filename and decoded text |
|
||||
| Directory | A non-recursive listing of its immediate files and directories |
|
||||
| PNG, JPEG, GIF, or WebP | Image media |
|
||||
|
||||
SVG files are treated as text, not image media. PDF, AVIF, BMP, audio, video,
|
||||
and other binary prompt attachments are not currently included in the model
|
||||
request. Some clients may let you select a PDF, but V2 does not yet make that
|
||||
PDF visible to the model.
|
||||
|
||||
<Warning>
|
||||
Use a model that supports image input before attaching an image. OpenCode
|
||||
passes supported image media to the selected provider, but the provider and
|
||||
model still enforce their own formats, dimensions, file counts, and size
|
||||
limits. A text-only model may reject the request.
|
||||
</Warning>
|
||||
|
||||
## Add attachments
|
||||
|
||||
### TUI
|
||||
|
||||
Type `@` followed by a filename and select the result to attach a project file.
|
||||
This is the preferred way to add source code and other text files:
|
||||
|
||||
```text
|
||||
Explain the error handling in @src/server.ts
|
||||
```
|
||||
|
||||
Paste an image from the clipboard with the configured paste key, `Ctrl+V` by
|
||||
default. You can also drag a supported image into a terminal that exposes the
|
||||
dropped file path to the TUI. The TUI reads PNG, JPEG, GIF, and WebP as image
|
||||
attachments; a dropped SVG is inserted as text.
|
||||
|
||||
### Desktop and web
|
||||
|
||||
Use **Attach file**, paste, or drag and drop. Attach UTF-8 text or a PNG, JPEG,
|
||||
GIF, or WebP image. The desktop file picker limits one selection to 20 MiB in
|
||||
total; the server also applies the per-attachment limit described below.
|
||||
|
||||
### CLI
|
||||
|
||||
Pass `--file` or `-f` to `opencode2 run`. Repeat the flag for multiple files:
|
||||
|
||||
```bash
|
||||
opencode2 run -f src/server.ts -f screenshot.png "Explain the failure"
|
||||
```
|
||||
|
||||
The run command accepts at most 100 file flags and reads at most 10 MiB per
|
||||
file. Use it for text files and the four supported image formats; other binary
|
||||
files do not become model context.
|
||||
|
||||
### API
|
||||
|
||||
The V2 prompt and command payloads accept a `files` array. Each item requires a
|
||||
`uri` and can include `name` and `description`:
|
||||
|
||||
```bash
|
||||
opencode2 api post /api/session/ses_example/prompt --data '{
|
||||
"text": "Review this file",
|
||||
"files": [
|
||||
{
|
||||
"uri": "file:///home/me/project/src/server.ts",
|
||||
"name": "server.ts",
|
||||
"description": "Request handler"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
Use an absolute `file:` URL for a file available to the server, or an inline
|
||||
data URL:
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "What is wrong with this layout?",
|
||||
"files": [
|
||||
{
|
||||
"uri": "data:image/png;base64,<base64-data>",
|
||||
"name": "layout.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
HTTP and HTTPS attachment URLs are not supported. OpenCode materializes each
|
||||
attachment before admitting the prompt and rejects invalid URLs, unreadable
|
||||
paths, non-files other than directories, and attachments over 20 MiB decoded.
|
||||
For a text `file:` URL, optional positive `start` and `end` query parameters
|
||||
select one-based lines:
|
||||
|
||||
```text
|
||||
file:///home/me/project/src/server.ts?start=20&end=60
|
||||
```
|
||||
|
||||
The server infers the media type from the bytes. A supplied filename or data
|
||||
URL media type does not make an unsupported binary format model-visible.
|
||||
|
||||
## Configure image processing
|
||||
|
||||
Configure image normalization in `opencode.json` or `opencode.jsonc`:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"attachments": {
|
||||
"image": {
|
||||
"auto_resize": true,
|
||||
"max_width": 2000,
|
||||
"max_height": 2000,
|
||||
"max_base64_bytes": 5242880
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All fields are optional:
|
||||
|
||||
| Field | Default | Behavior |
|
||||
| --- | ---: | --- |
|
||||
| `auto_resize` | `true` | Resize an image that exceeds any configured limit. If `false`, reject it. |
|
||||
| `max_width` | `2000` | Maximum width in pixels. Must be a positive integer. |
|
||||
| `max_height` | `2000` | Maximum height in pixels. Must be a positive integer. |
|
||||
| `max_base64_bytes` | `5242880` | Maximum byte length of the Base64-encoded image string. Must be a positive integer. |
|
||||
|
||||
<Note>
|
||||
In the current V2 runtime, these settings apply to image media produced by
|
||||
the built-in `read` tool. Images attached directly through the TUI, desktop,
|
||||
web, CLI, or API bypass this normalization. Resize direct attachments before
|
||||
adding them if the provider requires smaller media.
|
||||
</Note>
|
||||
|
||||
The `read` tool recognizes PNG, JPEG, GIF, and WebP by their contents and will
|
||||
ingest at most 20 MiB of source image bytes. It decodes the image and compares
|
||||
its width, height, and encoded Base64 length with all three configured limits.
|
||||
|
||||
When `auto_resize` is `true`, OpenCode preserves the aspect ratio, scales the
|
||||
image down to the dimension limits, and tries progressively smaller PNG and
|
||||
JPEG encodings until the Base64 limit is met. The resulting media type can
|
||||
therefore change to PNG or JPEG. If no encoding fits, the tool call fails.
|
||||
|
||||
When `auto_resize` is `false`, exceeding any limit fails the tool call without
|
||||
modifying the image. An image that cannot be decoded also fails. If the image
|
||||
resizer cannot be loaded, the `read` tool returns the
|
||||
original image instead, so these settings are processing limits rather than an
|
||||
upload or security boundary.
|
||||
|
||||
## Limits and provider behavior
|
||||
|
||||
- Direct prompt attachments are limited to 20 MiB decoded per item by the V2
|
||||
server. Client-specific limits can be lower.
|
||||
- `max_base64_bytes` counts the encoded Base64 characters in bytes, not the
|
||||
decoded file size and not the complete `data:` URL.
|
||||
- Text attachments are inserted into the prompt as text and do not require a
|
||||
multimodal model. Large text read through the `read` tool has separate
|
||||
paging and truncation limits.
|
||||
- Image attachments use provider-native image input. Provider errors can still
|
||||
occur when OpenCode's limits pass but the selected model's limits do not.
|
||||
- PDFs and other unsupported binary prompt attachments should be converted to
|
||||
text or supported images before attaching them.
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
---
|
||||
title: "Commands"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Custom commands turn a named prompt template into a slash command. Type the
|
||||
command in the TUI, followed by any arguments:
|
||||
|
||||
```text
|
||||
/review src/auth
|
||||
```
|
||||
|
||||
## Configure with Markdown
|
||||
|
||||
OpenCode discovers `.md` command files in `commands/` directories:
|
||||
|
||||
```text
|
||||
~/.config/opencode/commands/ # Global
|
||||
.opencode/commands/ # Project
|
||||
```
|
||||
|
||||
Files may be nested; for example, `.opencode/commands/team/review.md` defines
|
||||
`/team/review`. Files with other extensions, including `.mdx`, are not
|
||||
discovered.
|
||||
|
||||
```md title=".opencode/commands/review.md"
|
||||
---
|
||||
description: Review code for correctness and missing tests
|
||||
agent: plan
|
||||
model: anthropic/claude-sonnet-4-5#high
|
||||
---
|
||||
|
||||
Review $ARGUMENTS. Report bugs first, then missing tests.
|
||||
```
|
||||
|
||||
The file body, with surrounding whitespace removed, is the command template.
|
||||
JSON and Markdown commands share one registry. Project definitions take
|
||||
precedence over global definitions, and a later definition can override a
|
||||
built-in or earlier command with the same name. Changes are reloaded
|
||||
automatically.
|
||||
|
||||
Run it with:
|
||||
|
||||
```text
|
||||
/review src/auth
|
||||
```
|
||||
|
||||
## Configure with JSON
|
||||
|
||||
Add commands under the `commands` key in any OpenCode JSON or JSONC
|
||||
[configuration file](/docs/config). Each entry's key is the command name and
|
||||
`template` is required.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"commands": {
|
||||
"review": {
|
||||
"description": "Review code for correctness and missing tests",
|
||||
"template": "Review $ARGUMENTS. Report bugs first, then missing tests.",
|
||||
"agent": "plan",
|
||||
"model": "anthropic/claude-sonnet-4-5#high"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Fields
|
||||
|
||||
| Field | Required | Behavior |
|
||||
| --- | --- | --- |
|
||||
| `template` | JSON only | Prompt template. In a Markdown command, the file body supplies it. |
|
||||
| `description` | No | Text shown with the command in autocomplete. |
|
||||
| `agent` | No | Agent selected before the prompt runs. |
|
||||
| `model` | No | Model override in `provider/model` or `provider/model#variant` format. |
|
||||
| `subtask` | No | Accepted as a boolean, but currently has no execution effect in V2. |
|
||||
|
||||
The four optional fields can be used in JSON or YAML frontmatter. Do not put
|
||||
`template` in frontmatter because the Markdown body always supplies it.
|
||||
|
||||
## Arguments
|
||||
|
||||
Use `$ARGUMENTS` for the complete argument string:
|
||||
|
||||
```md title=".opencode/commands/component.md"
|
||||
---
|
||||
description: Create a component
|
||||
---
|
||||
|
||||
Create a typed React component named $ARGUMENTS.
|
||||
```
|
||||
|
||||
```text
|
||||
/component Button
|
||||
```
|
||||
|
||||
Use `$1`, `$2`, and higher numbers for parsed positional arguments. Single and
|
||||
double quotes group text containing spaces and are removed during parsing.
|
||||
|
||||
```md title=".opencode/commands/check.md"
|
||||
---
|
||||
description: Check one area with a specific focus
|
||||
---
|
||||
|
||||
Check $1. Focus on $2.
|
||||
```
|
||||
|
||||
```text
|
||||
/check src/auth "error handling and missing tests"
|
||||
```
|
||||
|
||||
The highest-numbered positional placeholder present in the template consumes
|
||||
that argument and all remaining arguments. For example, if a template contains
|
||||
only `$1`, then `$1` receives the full parsed argument list. Missing positions
|
||||
become empty strings.
|
||||
|
||||
If a template contains neither positional placeholders nor `$ARGUMENTS`,
|
||||
OpenCode appends non-empty arguments to the template after a blank line.
|
||||
|
||||
## Shell interpolation
|
||||
|
||||
Wrap a shell command in `!` followed by backticks to insert its output before
|
||||
the prompt is submitted:
|
||||
|
||||
```md title=".opencode/commands/review-diff.md"
|
||||
---
|
||||
description: Review the current diff
|
||||
---
|
||||
|
||||
Review this diff:
|
||||
|
||||
!`git diff --stat && git diff`
|
||||
```
|
||||
|
||||
OpenCode runs each interpolation with the configured shell in the active
|
||||
project location and inserts its combined output into the template. Argument
|
||||
interpolation happens first, so avoid placing untrusted arguments inside shell
|
||||
interpolations.
|
||||
|
||||
<Warning>
|
||||
Shell interpolations run when the command is evaluated, outside the agent's
|
||||
tool permission flow. Only use commands from sources you trust.
|
||||
</Warning>
|
||||
|
||||
No other template interpolation is performed. In particular, an `@path`
|
||||
written into a stored template remains ordinary prompt text; V2 does not
|
||||
automatically attach that file.
|
||||
|
||||
## Agent, model, and execution
|
||||
|
||||
Running a command evaluates its arguments and shell blocks, submits the result
|
||||
as a durable user prompt in the current session, and schedules normal model
|
||||
execution.
|
||||
|
||||
If `agent` is set, it overrides the agent selected when the command was
|
||||
invoked and becomes the session's active agent. If `model` is set, it overrides
|
||||
the model. Otherwise, a model configured on the command's agent takes
|
||||
precedence over the model selected at invocation.
|
||||
|
||||
Although `subtask` is accepted in JSON and frontmatter, V2 currently ignores
|
||||
it: commands run in the current session and do not create a child session.
|
||||
Selecting an agent whose mode is `subagent` also does not turn the command into
|
||||
a subtask.
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
---
|
||||
title: "Compaction"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Compaction replaces the active model context from an older part of a session
|
||||
with a generated checkpoint. The checkpoint contains a structured summary and
|
||||
a serialized tail of recent context, so the agent can continue with more room
|
||||
in the model's context window.
|
||||
|
||||
Compaction is lossy, but it does not delete the earlier durable session
|
||||
messages. After a successful compaction, V2 builds model requests from the
|
||||
latest completed checkpoint and the messages that follow it.
|
||||
|
||||
## Automatic compaction
|
||||
|
||||
Automatic compaction is enabled by default. Before a model call, V2 estimates
|
||||
the size of the final system prompt, messages, and advertised tools. It starts
|
||||
compaction when:
|
||||
|
||||
```text
|
||||
estimated tokens > context limit - max(requested output tokens, buffer)
|
||||
```
|
||||
|
||||
The estimate is approximate: V2 JSON-serializes the request and assumes four
|
||||
characters per token. When compaction succeeds, V2 rebuilds the request from
|
||||
the new checkpoint and retries the step without promoting the input again.
|
||||
|
||||
V2 also recognizes provider errors classified as context overflow. If an
|
||||
overflow occurs before the provider produces assistant output or other retry
|
||||
evidence, V2 can compact and retry that step once. This recovery is attempted
|
||||
even when `auto` is `false`; `auto` controls only the preflight size check. A
|
||||
second overflow after recovery is returned as an error.
|
||||
|
||||
## Manual compaction
|
||||
|
||||
In the TUI, run:
|
||||
|
||||
```text
|
||||
/compact
|
||||
```
|
||||
|
||||
`/summarize` is an alias. The default keybind is `<leader>c`, configured as
|
||||
`session_compact`.
|
||||
|
||||
A manual request is durably admitted and wakes the session runner. It can
|
||||
compact short histories that would not trigger automatic compaction. If the
|
||||
session is busy, compaction runs at the next safe drain boundary before later
|
||||
steered or queued prompts are promoted. Repeated requests while one is pending
|
||||
coalesce into that pending request. Whether compaction completes or fails, the
|
||||
barrier is then settled so later prompts can proceed.
|
||||
|
||||
The CLI has no separate `compact` subcommand. Use the TUI command or the server
|
||||
API. For example:
|
||||
|
||||
```bash
|
||||
opencode2 api v2.session.compact \
|
||||
--param sessionID=ses_example \
|
||||
--data '{}'
|
||||
```
|
||||
|
||||
The equivalent raw request is:
|
||||
|
||||
```bash
|
||||
opencode2 api post /api/session/ses_example/compact --data '{}'
|
||||
```
|
||||
|
||||
`POST /api/session/:sessionID/compact` returns the admitted compaction input;
|
||||
it does not wait for summary generation. Clients can call
|
||||
`client.session.compact({ sessionID })` and then wait for the session or follow
|
||||
the `session.compaction.*` events. Supplying an optional message `id` makes an
|
||||
exact retry idempotent, but reusing an ID owned by another record returns a
|
||||
conflict.
|
||||
|
||||
## Configuration
|
||||
|
||||
Add `compaction` to any [OpenCode configuration file](/docs/config):
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"compaction": {
|
||||
"auto": true,
|
||||
"prune": false,
|
||||
"keep": {
|
||||
"tokens": 8000
|
||||
},
|
||||
"buffer": 20000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Default | V2 behavior |
|
||||
| --- | ---: | --- |
|
||||
| `auto` | `true` | Runs the preflight context-size check. It does not disable manual compaction or one-shot provider-overflow recovery. |
|
||||
| `prune` | None | Accepted by the V2 schema, but currently has no runtime effect. V2 does not prune old tool outputs in place. |
|
||||
| `keep.tokens` | `8000` | Approximate number of tokens from the newest serialized conversation context to retain beside the summary. |
|
||||
| `buffer` | `20000` | Token reserve used by the automatic threshold. The requested model output allowance wins when it is larger. |
|
||||
|
||||
`keep.tokens` and `buffer` accept non-negative integers. Larger `keep.tokens`
|
||||
preserves more recent detail but leaves less room for future work. Larger
|
||||
`buffer` triggers preflight compaction earlier.
|
||||
|
||||
## Checkpoint contents
|
||||
|
||||
V2 uses the session's selected or default model to generate the summary, with
|
||||
tools disabled and at most 4096 output tokens. The summary records the
|
||||
objective, important details, completed and active work, blockers, next moves,
|
||||
and relevant files.
|
||||
|
||||
The newest serialized context up to `keep.tokens` is retained separately. This
|
||||
is not a byte-for-byte transcript: tool output is limited to 2000 characters,
|
||||
and file or media attachments become textual descriptors rather than embedded
|
||||
data. On later compactions, V2 updates the previous summary and carries forward
|
||||
its retained recent context before selecting a new tail.
|
||||
|
||||
The completed compaction is presented to the model as historical conversation
|
||||
context, explicitly not as new instructions. Running and failed compactions are
|
||||
not included in model context.
|
||||
|
||||
## Compaction advances the instruction epoch
|
||||
|
||||
Conversation compaction and instruction synchronization are separate. Before
|
||||
promoting pending input, V2 compares live instruction sources with the latest
|
||||
admitted values. Ordinary changes become durable value deltas; their
|
||||
model-facing System messages are derived during request assembly rather than
|
||||
persisted.
|
||||
|
||||
Completed compaction advances the instruction epoch at the exact ended-event
|
||||
sequence and makes the currently admitted values initial. It does not reread
|
||||
sources or publish an instruction event. Session movement and committed revert
|
||||
clear the instruction fold so the next safe boundary requires one complete
|
||||
source read. See [Instructions](/docs/instructions) for source ordering and update
|
||||
behavior.
|
||||
|
||||
## Current limitations
|
||||
|
||||
- `prune` is reserved configuration; V1-style in-place tool-output pruning is
|
||||
not implemented in V2.
|
||||
- Compaction requires a resolvable model with a positive catalog context limit.
|
||||
There is no separate compaction-model setting or fallback model.
|
||||
- Summary generation can fail if the summary prompt itself cannot fit beside
|
||||
its output allowance, the model returns no summary, or the provider fails.
|
||||
- Automatic and overflow compaction need older conversation context that can be
|
||||
replaced. A provider overflow can still surface when there is no compressible
|
||||
head or fixed instructions and tool schemas dominate the request.
|
||||
- Overflow recovery retries only once per step. Token estimation is heuristic,
|
||||
so it cannot prevent every provider-specific overflow.
|
||||
- Earlier durable messages remain stored even though they are no longer in the
|
||||
active model context.
|
||||
|
||||
V1 used additional tail-turn and pruning behavior. Those V1 details are only
|
||||
migration context; the settings and behavior on this page describe V2.
|
||||
|
|
@ -1,450 +0,0 @@
|
|||
---
|
||||
title: "Config"
|
||||
description: ""
|
||||
---
|
||||
|
||||
<Tip>
|
||||
You shouldn't have to configure OpenCode manually. Ask OpenCode to update its configuration for you.
|
||||
</Tip>
|
||||
|
||||
## Format
|
||||
|
||||
OpenCode supports both **JSON** and **JSONC** (JSON with Comments) configuration files.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "openai/gpt-5.2-custom",
|
||||
"providers": {
|
||||
"openai": {
|
||||
"models": {
|
||||
"gpt-5.2-custom": {
|
||||
"modelID": "gpt-5.2",
|
||||
"name": "GPT-5.2 Custom"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Locations
|
||||
|
||||
OpenCode loads global configuration from:
|
||||
|
||||
```text
|
||||
~/.config/opencode/opencode.json(c)
|
||||
```
|
||||
|
||||
Project-specific configuration can use either form:
|
||||
|
||||
```text
|
||||
/home/user/projects/my-app/opencode.json(c)
|
||||
/home/user/projects/my-app/.opencode/opencode.json(c)
|
||||
```
|
||||
|
||||
When OpenCode starts, it searches for configuration files from the current
|
||||
directory upward to the project root. It merges direct `opencode.json(c)` files
|
||||
from the project root toward the current directory, then does the same for
|
||||
files inside `.opencode` directories. A `.opencode` config therefore overrides
|
||||
every direct config, even when the direct config is closer to the current
|
||||
directory. Avoid mixing the two forms across one project hierarchy unless this
|
||||
precedence is intentional.
|
||||
|
||||
For example, consider a monorepo with OpenCode started from
|
||||
`/home/user/projects/acme/packages/web`:
|
||||
|
||||
```text
|
||||
~/.config/opencode/opencode.json
|
||||
|
||||
/home/user/projects/acme/
|
||||
├── opencode.json
|
||||
└── packages/
|
||||
└── web/
|
||||
├── opencode.json
|
||||
└── src/
|
||||
```
|
||||
|
||||
OpenCode applies these files from lowest to highest precedence:
|
||||
|
||||
1. `~/.config/opencode/opencode.json`
|
||||
2. `/home/user/projects/acme/opencode.json`
|
||||
3. `/home/user/projects/acme/packages/web/opencode.json`
|
||||
|
||||
In this direct-config example, the package config overrides matching settings
|
||||
from the repository config, which overrides matching settings from the global
|
||||
config. Settings that do not conflict are preserved from every file.
|
||||
|
||||
## Schema
|
||||
|
||||
The complete OpenCode configuration schema is available at
|
||||
[opencode.ai/config.json](https://opencode.ai/config.json).
|
||||
|
||||
Add the `$schema` field to your configuration file to enable validation and
|
||||
autocomplete in editors that support JSON Schema:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json"
|
||||
}
|
||||
```
|
||||
|
||||
Use the schema as the source of truth for available fields, accepted values,
|
||||
and nested configuration shapes.
|
||||
|
||||
### Shell
|
||||
|
||||
Set the shell used by the terminal and shell tools.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"shell": "/bin/zsh"
|
||||
}
|
||||
```
|
||||
|
||||
### Model
|
||||
|
||||
Set the default model in `provider/model` format. The root default currently
|
||||
does not retain a `#variant`; select variants in the TUI or on an agent or command.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"model": "anthropic/claude-sonnet-4-5"
|
||||
}
|
||||
```
|
||||
|
||||
See the [models guide](/docs/models) for model selection
|
||||
and local models.
|
||||
|
||||
### Default agent
|
||||
|
||||
Choose the primary agent used when a session does not select one explicitly.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"default_agent": "build"
|
||||
}
|
||||
```
|
||||
|
||||
See the [agents guide](/docs/agents) for built-in and custom
|
||||
agents.
|
||||
|
||||
### Autoupdate
|
||||
|
||||
Control automatic updates from the global config. Set this to `false` to
|
||||
disable updates. The current beta treats `true` and `"notify"` identically and
|
||||
automatically installs compatible non-major updates; project-level values are
|
||||
ignored.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"autoupdate": false
|
||||
}
|
||||
```
|
||||
|
||||
### Sharing
|
||||
|
||||
Set the intended session sharing policy. V2 accepts this field, but session
|
||||
sharing is not implemented yet.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"share": "manual"
|
||||
}
|
||||
```
|
||||
|
||||
See the [sharing guide](/docs/sharing) for more details.
|
||||
|
||||
### Username
|
||||
|
||||
Set a username for future display behavior. V2 accepts this field but does not
|
||||
currently display it in conversations.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"username": "alice"
|
||||
}
|
||||
```
|
||||
|
||||
### Permissions
|
||||
|
||||
Define ordered rules that allow, deny, or ask before an agent uses a tool on a
|
||||
matching resource.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"permissions": [
|
||||
{
|
||||
"action": "shell",
|
||||
"resource": "git push *",
|
||||
"effect": "ask"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See the [permissions guide](/docs/permissions) for rule matching and available actions.
|
||||
|
||||
### Agents
|
||||
|
||||
Override built-in agents or define specialized agents with their own model,
|
||||
instructions, mode, and permissions.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"agents": {
|
||||
"reviewer": {
|
||||
"description": "Review changes without editing files",
|
||||
"mode": "subagent",
|
||||
"system": "Focus on correctness, security, and missing tests.",
|
||||
"permissions": [
|
||||
{ "action": "edit", "resource": "*", "effect": "deny" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [agents guide](/docs/agents) for all agent options and file-based agents.
|
||||
|
||||
### Snapshots
|
||||
|
||||
Enable or disable filesystem snapshots used by undo and revert behavior.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"snapshots": false
|
||||
}
|
||||
```
|
||||
|
||||
See the [snapshots guide](/docs/snapshots) for undo and redo behavior.
|
||||
|
||||
### Watcher
|
||||
|
||||
Ignore files and directories that should not trigger filesystem updates.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"watcher": {
|
||||
"ignore": ["dist/**", "coverage/**"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Formatter
|
||||
|
||||
Define formatter settings for compatibility and future use. V2 accepts this
|
||||
field, but it does not run formatters yet.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"formatter": {
|
||||
"prettier": {
|
||||
"command": ["bunx", "prettier", "--write", "$FILE"],
|
||||
"extensions": [".js", ".ts", ".tsx"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [formatters guide](/docs/formatters) for accepted fields and current limitations.
|
||||
|
||||
### LSP
|
||||
|
||||
Define language server settings for compatibility and future use. V2 accepts
|
||||
this field, but it does not start language servers yet.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"lsp": {
|
||||
"typescript": {
|
||||
"command": ["typescript-language-server", "--stdio"],
|
||||
"extensions": [".ts", ".tsx"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [LSP guide](/docs/lsp) for accepted fields and current limitations.
|
||||
|
||||
### Attachments
|
||||
|
||||
Control how oversized images loaded by the `read` tool are resized or rejected
|
||||
before they are sent to a model.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"attachments": {
|
||||
"image": {
|
||||
"auto_resize": true,
|
||||
"max_width": 2000,
|
||||
"max_height": 2000,
|
||||
"max_base64_bytes": 5242880
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [attachments guide](/docs/attachments) for image processing and limits.
|
||||
|
||||
### Tool output
|
||||
|
||||
Set the maximum number of lines and bytes retained from a tool result.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"tool_output": {
|
||||
"max_lines": 2000,
|
||||
"max_bytes": 51200
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### MCP
|
||||
|
||||
Configure local and remote Model Context Protocol servers. Global timeouts can
|
||||
be overridden by an individual server.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"playwright": {
|
||||
"type": "local",
|
||||
"command": ["bunx", "@playwright/mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [MCP guide](/docs/mcp-servers) for remote servers, OAuth, environment variables, and timeouts.
|
||||
|
||||
### Compaction
|
||||
|
||||
Control automatic context compaction and how much recent context it preserves.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"compaction": {
|
||||
"auto": true,
|
||||
"keep": {
|
||||
"tokens": 8000
|
||||
},
|
||||
"buffer": 20000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [compaction guide](/docs/compaction) for automatic context management.
|
||||
|
||||
### Skills
|
||||
|
||||
Add directories or URLs that OpenCode should search for agent skills.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"skills": ["./team-skills", "https://example.com/.well-known/skills/"]
|
||||
}
|
||||
```
|
||||
|
||||
See the [skills guide](/docs/skills) for skill structure and automatic discovery under `.opencode/skills/`.
|
||||
|
||||
### Commands
|
||||
|
||||
Define reusable slash commands as named prompt templates.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"commands": {
|
||||
"review": {
|
||||
"description": "Review the current changes",
|
||||
"template": "Review the current diff for correctness and missing tests."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [commands guide](/docs/commands) for arguments, models, agents, and file-based commands.
|
||||
|
||||
### Instructions
|
||||
|
||||
Declare additional instruction files, globs, or URLs. V2 accepts this field,
|
||||
but does not load these entries yet; use `AGENTS.md` for active instructions.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"instructions": ["CONTRIBUTING.md", "docs/guidelines/*.md"]
|
||||
}
|
||||
```
|
||||
|
||||
See the [instructions guide](/docs/instructions) for project instructions and `AGENTS.md`.
|
||||
|
||||
### References
|
||||
|
||||
Make local directories or Git repositories available as named supporting
|
||||
context.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"references": {
|
||||
"docs": {
|
||||
"path": "../product-docs",
|
||||
"description": "Product behavior and terminology"
|
||||
},
|
||||
"effect": {
|
||||
"repository": "Effect-TS/effect",
|
||||
"branch": "main"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [references guide](/docs/references) for shorthand, visibility, and path resolution.
|
||||
|
||||
### Plugins
|
||||
|
||||
Load plugins from packages or local files. Use the object form when a plugin
|
||||
accepts options.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"plugins": [
|
||||
"opencode-example-plugin",
|
||||
{
|
||||
"package": "./plugins/local.ts",
|
||||
"options": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See the [plugins guide](/docs/build/plugins) for plugin development and configuration.
|
||||
|
||||
### Providers
|
||||
|
||||
Configure providers and add or override their models, request settings,
|
||||
headers, and model variants.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"providers": {
|
||||
"openai": {
|
||||
"models": {
|
||||
"gpt-5.2-custom": {
|
||||
"modelID": "gpt-5.2",
|
||||
"name": "GPT-5.2 Custom",
|
||||
"limit": {
|
||||
"context": 200000,
|
||||
"output": 32000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the [providers guide](/docs/providers) for credentials, custom endpoints, provider packages, and model configuration.
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
---
|
||||
title: "Formatters"
|
||||
description: ""
|
||||
---
|
||||
|
||||
OpenCode V2 accepts formatter configuration, but it does not yet include a
|
||||
formatter runtime. File writes and edits are not automatically formatted.
|
||||
|
||||
<Warning>
|
||||
V2 currently has no built-in formatters. The built-in formatter list and
|
||||
automatic post-edit formatting documented for V1 do not apply to V2.
|
||||
</Warning>
|
||||
|
||||
## Configuration
|
||||
|
||||
The `formatter` field accepts a boolean or an object keyed by formatter name:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"formatter": {
|
||||
"prettier": {
|
||||
"disabled": false,
|
||||
"command": ["prettier", "--write", "$FILE"],
|
||||
"environment": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"extensions": [".js", ".jsx", ".ts", ".tsx"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example is valid V2 configuration, but V2 does not currently execute the
|
||||
command.
|
||||
|
||||
Each named formatter entry supports these optional fields:
|
||||
|
||||
| Field | Type | Current V2 behavior |
|
||||
| --- | --- | --- |
|
||||
| `disabled` | `boolean` | Accepted, but there is no runtime formatter to enable or disable. |
|
||||
| `command` | `string[]` | Accepted as an argument array, but not executed. |
|
||||
| `environment` | `Record<string, string>` | Accepts string environment variable names and values, but they are not applied. |
|
||||
| `extensions` | `string[]` | Accepted without extension-specific validation, but files are not matched against it. |
|
||||
|
||||
All entry fields are optional. The schema therefore also accepts an empty entry
|
||||
such as `"prettier": {}`.
|
||||
|
||||
## Enable and disable
|
||||
|
||||
The schema accepts all of the following forms:
|
||||
|
||||
```jsonc
|
||||
// Omit `formatter`, or use false, when formatting is not requested.
|
||||
{
|
||||
"formatter": false
|
||||
}
|
||||
```
|
||||
|
||||
```jsonc
|
||||
// Reserved for enabling all built-ins once a V2 runtime provides them.
|
||||
{
|
||||
"formatter": true
|
||||
}
|
||||
```
|
||||
|
||||
```jsonc
|
||||
// Configure named entries or mark one as disabled.
|
||||
{
|
||||
"formatter": {
|
||||
"prettier": { "disabled": true },
|
||||
"custom": {
|
||||
"command": ["custom-fmt", "$FILE"],
|
||||
"extensions": [".foo"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
At present, omitted, `false`, `true`, and object forms have the same runtime
|
||||
result: V2 runs no formatter. `disabled` is retained as configuration data but
|
||||
does not control an executable formatter.
|
||||
|
||||
## Commands and placeholders
|
||||
|
||||
`command` is an array of strings, not a shell command string. `$FILE` is the V1
|
||||
file-path placeholder and is often retained in migrated configuration. V2 does
|
||||
not currently substitute `$FILE` or define another formatter placeholder.
|
||||
|
||||
Likewise, V2 does not currently use `extensions` to select commands, merge
|
||||
`environment` into a child process, discover formatter executables or project
|
||||
configuration, or run multiple matching formatters. These behaviors will only
|
||||
be available after a V2 formatter runtime is implemented.
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
---
|
||||
title: "Intro"
|
||||
description: "Get started with OpenCode."
|
||||
---
|
||||
|
||||
<Warning>
|
||||
These docs are for the beta version of OpenCode, which will become OpenCode 2.0. The beta is still changing: we may
|
||||
wipe your data, things may break, and APIs, configuration, and plugin APIs may change.
|
||||
</Warning>
|
||||
|
||||
## Install
|
||||
|
||||
<Note>The curl install script is not available in beta.</Note>
|
||||
|
||||
You can also install it with the following package managers.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
```bash
|
||||
npm install -g @opencode-ai/cli@next
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="bun">
|
||||
```bash
|
||||
bun install -g @opencode-ai/cli@next
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
```bash
|
||||
pnpm install -g @opencode-ai/cli@next
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Yarn">
|
||||
```bash
|
||||
yarn global add @opencode-ai/cli@next
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>During beta, the binary is called `opencode2`.</Note>
|
||||
|
||||
### Homebrew
|
||||
|
||||
Homebrew installation is not available in beta.
|
||||
|
||||
### Arch Linux
|
||||
|
||||
Arch Linux installation is not available in beta.
|
||||
|
||||
### Windows
|
||||
|
||||
<Tip>
|
||||
For the best experience on Windows, install [Windows Subsystem for Linux
|
||||
(WSL)](https://learn.microsoft.com/windows/wsl/install), open your Linux distribution, and use one of the beta package
|
||||
manager commands above.
|
||||
</Tip>
|
||||
|
||||
<Tabs>
|
||||
<Tab title="chocolatey">
|
||||
Chocolatey installation is not available in beta.
|
||||
</Tab>
|
||||
<Tab title="scoop">
|
||||
Scoop installation is not available in beta.
|
||||
</Tab>
|
||||
<Tab title="mise">
|
||||
Mise installation is not available in beta.
|
||||
</Tab>
|
||||
<Tab title="docker">
|
||||
Docker installation is not available in beta.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Standalone binaries are not available in beta.
|
||||
|
||||
---
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
To use OpenCode in your terminal, you'll need:
|
||||
|
||||
1. A modern terminal emulator like:
|
||||
- [Ghostty](https://ghostty.org), Linux and macOS
|
||||
- [WezTerm](https://wezterm.org), cross-platform
|
||||
- [Alacritty](https://alacritty.org), cross-platform
|
||||
- [Kitty](https://sw.kovidgoyal.net/kitty/), Linux and macOS
|
||||
2. API keys for the LLM providers you want to use.
|
||||
|
||||
---
|
||||
|
||||
## Connect
|
||||
|
||||
With OpenCode you can use any LLM provider by configuring its API key.
|
||||
|
||||
Run `/connect` in the TUI and select your provider.
|
||||
|
||||
```text
|
||||
/connect
|
||||
```
|
||||
|
||||
If you'd like easy access to all the best coding models you can try out
|
||||
[OpenCode Console](https://console.opencode.ai).
|
||||
|
||||
You can also try [OpenCode Go](https://opencode.ai/go) a $10/month subscription
|
||||
plan that grants you access to the best open source models.
|
||||
|
||||
Use `/models` to browse the providers and models available to your project. See [Providers](/docs/providers) for connection and
|
||||
configuration details.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
You are now ready to use OpenCode in your project. Here are a few common workflows.
|
||||
|
||||
### Ask questions
|
||||
|
||||
Ask OpenCode to explain your codebase.
|
||||
|
||||
<Tip>Use `@` to fuzzy search for files in the project.</Tip>
|
||||
|
||||
```text
|
||||
How is authentication handled in @packages/functions/src/api/index.ts
|
||||
```
|
||||
|
||||
### Add features
|
||||
|
||||
Ask OpenCode to add a feature by describing the desired behavior and providing relevant context.
|
||||
|
||||
```text
|
||||
When a user deletes a note, flag it as deleted in the database.
|
||||
Create a screen that shows recently deleted notes.
|
||||
From this screen, the user can restore a note or permanently delete it.
|
||||
```
|
||||
|
||||
<Tip>Give OpenCode plenty of context and examples.</Tip>
|
||||
|
||||
### Undo changes
|
||||
|
||||
Use `/undo` when a change isn't what you wanted.
|
||||
|
||||
```text
|
||||
/undo
|
||||
```
|
||||
|
||||
OpenCode stages a conversation revert and restores your original message so you can revise it. In a Git repository, it
|
||||
also restores file changes when snapshots were captured successfully. Run `/undo` multiple times to move the conversation
|
||||
boundary back, or use `/redo` to restore the staged conversation and files. See [Undo](/docs/snapshots) for
|
||||
limitations and safety details.
|
||||
|
||||
```text
|
||||
/redo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Customize
|
||||
|
||||
Make OpenCode your own by [picking a theme](https://opencode.ai/docs/themes), [customizing
|
||||
keybinds](https://opencode.ai/docs/keybinds), [configuring formatters](/docs/formatters), [creating commands](/docs/commands), or
|
||||
editing the [OpenCode config](/docs/config).
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
---
|
||||
title: "Instructions"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Instructions are privileged context that guide an agent throughout a session.
|
||||
V2 combines built-in context, discovered `AGENTS.md` files, and dynamic sources
|
||||
such as skill, reference, MCP, and session context. It stores source values as
|
||||
durable deltas, then renders initial instructions and chronological updates when
|
||||
assembling each model request.
|
||||
|
||||
## AGENTS.md
|
||||
|
||||
Use `AGENTS.md` for persistent guidance such as build commands, architecture,
|
||||
code conventions, and verification requirements. Commit project files so the
|
||||
whole team receives the same instructions.
|
||||
|
||||
V2 loads:
|
||||
|
||||
1. The global file at `$XDG_CONFIG_HOME/opencode/AGENTS.md`, normally
|
||||
`~/.config/opencode/AGENTS.md`.
|
||||
2. Every `AGENTS.md` from the current Location up to and including the project
|
||||
root.
|
||||
|
||||
For example, when the Location is `packages/web`, OpenCode can load all three
|
||||
project files below:
|
||||
|
||||
```text
|
||||
my-project/
|
||||
├── AGENTS.md
|
||||
└── packages/
|
||||
├── AGENTS.md
|
||||
└── web/
|
||||
└── AGENTS.md
|
||||
```
|
||||
|
||||
The files are combined rather than selecting a single winner. They are rendered
|
||||
in this order: global, then project files from the Location toward the project
|
||||
root. OpenCode does not resolve conflicts between their contents, so keep broad
|
||||
guidance global and put scoped guidance in the relevant project directory.
|
||||
|
||||
If the Location is outside the project root, only the global file is loaded.
|
||||
Setting `OPENCODE_DISABLE_PROJECT_CONFIG=1` also skips project `AGENTS.md`
|
||||
discovery but does not disable the global file.
|
||||
|
||||
<Note>
|
||||
Current V2 discovery only recognizes `AGENTS.md`. The `CLAUDE.md` fallback
|
||||
and related precedence described by older OpenCode documentation do not apply.
|
||||
</Note>
|
||||
|
||||
### Nested instructions
|
||||
|
||||
An `AGENTS.md` below the Location is not part of the initial upward scan. When
|
||||
the read tool successfully reads a file or lists a directory, OpenCode discovers
|
||||
`AGENTS.md` files from that target upward to, but not including, the Location.
|
||||
It adds newly discovered files to the session in nearest-first order.
|
||||
|
||||
Each nested file is injected once per session and recorded in durable session
|
||||
history. Reading the same area again does not inject it again. Consequently,
|
||||
editing an already injected nested `AGENTS.md` does not replace its earlier
|
||||
session entry automatically; start a new session if the updated text must apply
|
||||
immediately.
|
||||
|
||||
## Config entries
|
||||
|
||||
The V2 config schema accepts an `instructions` array of strings:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"instructions": [
|
||||
"CONTRIBUTING.md",
|
||||
"docs/guidelines/*.md",
|
||||
"https://example.com/shared-instructions.md"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Configuration is loaded from global through project-local files. If more than
|
||||
one config defines `instructions`, the highest-precedence, closest config's
|
||||
entire array is selected; arrays are not merged.
|
||||
|
||||
<Warning>
|
||||
V2 currently parses and retains this field but does not resolve its entries
|
||||
into instruction sources. Local files, glob patterns, and HTTP or HTTPS URLs
|
||||
in `instructions` therefore do not reach the model yet. Use `AGENTS.md` for
|
||||
active V2 instructions. URL fetching and timeout behavior documented for V1
|
||||
are not supported by the current V2 implementation.
|
||||
</Warning>
|
||||
|
||||
See [Config](/docs/config) for config locations and general precedence.
|
||||
|
||||
## Ordering
|
||||
|
||||
The selected agent or provider system prompt is sent first. OpenCode then sends
|
||||
the session's initial instructions, composed in this order:
|
||||
|
||||
1. Built-in environment and date context.
|
||||
2. Ambient `AGENTS.md` discovery.
|
||||
3. Available skill, reference, and MCP guidance.
|
||||
4. Session-specific instruction entries supplied through the API.
|
||||
|
||||
These sources are combined; ordering is not an override mechanism. Nested
|
||||
`AGENTS.md` files discovered by reads are chronological session entries rather
|
||||
than part of the initial instructions.
|
||||
|
||||
## Changes
|
||||
|
||||
Before promoting pending input, V2 compares live instruction sources with the
|
||||
latest admitted source values:
|
||||
|
||||
- A new or changed ambient `AGENTS.md` aggregate is announced as a system update
|
||||
that replaces the previous ambient aggregate.
|
||||
- Removing all ambient files announces that the previous ambient instructions
|
||||
no longer apply.
|
||||
- A temporary read or discovery failure preserves the session's last known
|
||||
instructions instead of treating them as deleted. If no instruction epoch
|
||||
exists yet, pending input waits until every source is available.
|
||||
- Completed conversation compaction advances the instruction epoch, making the
|
||||
currently admitted values initial without rereading sources or authoring an
|
||||
instruction event.
|
||||
- Moving a session or committing a revert clears the instruction fold. The next
|
||||
safe boundary requires one complete source read before promoting input.
|
||||
|
||||
The durable event stores changed source keys and value hashes, not rendered
|
||||
prose. During request assembly, OpenCode renders the epoch's initial values and
|
||||
interleaves later changes as chronological System messages. Clients see changed
|
||||
keys but never the privileged value bodies.
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
---
|
||||
title: "MCP servers"
|
||||
description: ""
|
||||
---
|
||||
|
||||
OpenCode can connect to [Model Context Protocol](https://modelcontextprotocol.io/) servers and make their tools, prompts, and instructions available to agents. MCP tools consume model context, so enable only the servers you need.
|
||||
|
||||
## Configure servers
|
||||
|
||||
Define each server by a unique name under `mcp.servers` in your [OpenCode configuration](/docs/config). V2 does not place server names directly under `mcp`.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"my-server": {
|
||||
"type": "local",
|
||||
"command": ["npx", "-y", "example-mcp-server"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Servers connect automatically unless `disabled` is `true`. There is no V2 `enabled` field.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"my-server": {
|
||||
"type": "local",
|
||||
"command": ["npx", "-y", "example-mcp-server"],
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As with other configuration, a server in a higher-precedence project config replaces a server with the same name from a lower-precedence config. Use different names when you need separate connections or accounts.
|
||||
|
||||
## Local servers
|
||||
|
||||
A local server is a command that OpenCode starts using the MCP stdio transport.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"everything": {
|
||||
"type": "local",
|
||||
"command": [
|
||||
"npx",
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-everything"
|
||||
],
|
||||
"cwd": ".",
|
||||
"environment": {
|
||||
"LOG_LEVEL": "info",
|
||||
"MCP_API_KEY": "{env:MCP_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `type` | Yes | Must be `"local"`. |
|
||||
| `command` | Yes | Executable followed by its arguments. |
|
||||
| `cwd` | No | Process working directory. Relative paths resolve from the workspace directory; the workspace is the default. |
|
||||
| `environment` | No | String environment variables added to the inherited OpenCode process environment. |
|
||||
| `disabled` | No | Set to `true` to prevent the server from connecting. Defaults to `false`. |
|
||||
| `timeout` | No | Per-server timeout overrides. |
|
||||
|
||||
Use `{env:NAME}` to substitute an environment variable while loading config. Shell expressions such as `$NAME` are not expanded in JSON strings.
|
||||
|
||||
## Remote servers
|
||||
|
||||
A remote server uses the MCP Streamable HTTP transport. Its `url` must be a valid absolute URL.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"context7": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.context7.com/mcp",
|
||||
"oauth": false,
|
||||
"headers": {
|
||||
"CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `type` | Yes | Must be `"remote"`. |
|
||||
| `url` | Yes | Streamable HTTP endpoint. |
|
||||
| `headers` | No | String HTTP headers sent to the MCP endpoint. |
|
||||
| `oauth` | No | OAuth client settings, or `false` to disable OAuth support. |
|
||||
| `disabled` | No | Set to `true` to prevent the server from connecting. Defaults to `false`. |
|
||||
| `timeout` | No | Per-server timeout overrides. |
|
||||
|
||||
Use `oauth: false` for a server that exclusively uses an API key or another header-based credential.
|
||||
|
||||
## OAuth
|
||||
|
||||
OAuth support is enabled for remote servers unless `oauth` is `false`. OpenCode discovers the authorization server, uses PKCE, refreshes tokens, and attempts dynamic client registration when the server supports it. OAuth credentials are stored outside project configuration.
|
||||
|
||||
For a server that supports dynamic client registration, only the remote server is required:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"sentry": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.sentry.dev/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When the server reports that it needs authentication, run `/connect` in the TUI:
|
||||
|
||||
```text
|
||||
/connect
|
||||
```
|
||||
|
||||
Select the MCP server under **Services**, then complete the browser authorization flow.
|
||||
|
||||
You can also authenticate from the command line:
|
||||
|
||||
```bash
|
||||
opencode2 mcp auth sentry
|
||||
```
|
||||
|
||||
The CLI command prints the authorization URL and waits for the redirect to OpenCode's loopback callback server.
|
||||
|
||||
If the provider issued client credentials, configure them using V2's snake_case field names:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"company-tools": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.example.com/mcp",
|
||||
"oauth": {
|
||||
"client_id": "{env:MCP_CLIENT_ID}",
|
||||
"client_secret": "{env:MCP_CLIENT_SECRET}",
|
||||
"scope": "tools:read tools:execute",
|
||||
"callback_port": 19876,
|
||||
"redirect_uri": "http://127.0.0.1:19876/callback"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| OAuth field | Description |
|
||||
| --- | --- |
|
||||
| `client_id` | Pre-registered OAuth client ID. If omitted, OpenCode attempts dynamic client registration. |
|
||||
| `client_secret` | Client secret for a pre-registered client. |
|
||||
| `scope` | Space-delimited scopes to request. |
|
||||
| `callback_port` | Local callback port, from `1` through `65535`. An available ephemeral port is used by default. |
|
||||
| `redirect_uri` | Pre-registered loopback redirect URI. Its path and port must reach the local callback listener. |
|
||||
|
||||
Remove stored credentials with:
|
||||
|
||||
```bash
|
||||
opencode2 mcp logout sentry
|
||||
```
|
||||
|
||||
## Timeouts
|
||||
|
||||
Timeouts are positive integer milliseconds. Configure defaults under `mcp.timeout`; a server's `timeout` fields override matching defaults.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"timeout": {
|
||||
"startup": 45000,
|
||||
"catalog": 30000,
|
||||
"execution": 600000
|
||||
},
|
||||
"servers": {
|
||||
"slow-tools": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.example.com/mcp",
|
||||
"timeout": {
|
||||
"catalog": 60000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Timeout | Default | Applies to |
|
||||
| --- | --- | --- |
|
||||
| `startup` | 30 seconds | Establishing the transport and initializing the server. |
|
||||
| `catalog` | 30 seconds | Listing tools, prompts, resources, and resource templates. |
|
||||
| `execution` | 12 hours | Calling tools, getting prompts, and reading resources. |
|
||||
|
||||
## Names and permissions
|
||||
|
||||
OpenCode combines the server name and MCP tool name as `<server>_<tool>`. Characters other than letters, numbers, `_`, and `-` are replaced with `_`; for example, server `context 7` and tool `resolve.library/id` become `context_7_resolve_library_id`. MCP prompts appear as slash commands named `<server>:<prompt>` using the same normalization.
|
||||
|
||||
Choose short server names that remain unique after normalization. Under the default Code Mode, MCP tools are grouped by the normalized server name.
|
||||
|
||||
Use permission actions to hide or deny a server's tools without stopping its connection:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"permissions": [
|
||||
{
|
||||
"action": "context7_*",
|
||||
"resource": "*",
|
||||
"effect": "deny"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## CLI commands
|
||||
|
||||
V2 provides these MCP management commands:
|
||||
|
||||
```bash
|
||||
# Add a local server to the project config
|
||||
opencode2 mcp add everything --env LOG_LEVEL=info -- npx -y @modelcontextprotocol/server-everything
|
||||
|
||||
# Add a remote server to the project config
|
||||
opencode2 mcp add context7 --url https://mcp.context7.com/mcp --header 'CONTEXT7_API_KEY={env:CONTEXT7_API_KEY}'
|
||||
|
||||
# Add to the global config instead
|
||||
opencode2 mcp add context7 --global --url https://mcp.context7.com/mcp
|
||||
|
||||
# List configured servers and connection status
|
||||
opencode2 mcp list
|
||||
|
||||
# Authenticate or remove OAuth credentials
|
||||
opencode2 mcp auth context7
|
||||
opencode2 mcp logout context7
|
||||
```
|
||||
|
||||
`mcp add` accepts either `--url` for a remote server or a command after `--` for a local server, not both. Use `--header NAME=VALUE` only with remote servers and `--env NAME=VALUE` only with local servers. Edit the config directly for OAuth, timeout, working-directory, or enablement settings.
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"title": "Docs",
|
||||
"description": "Use and configure OpenCode.",
|
||||
"root": true,
|
||||
"pages": [
|
||||
"---Get started---",
|
||||
"index",
|
||||
"migrate-v1",
|
||||
"config",
|
||||
"troubleshooting",
|
||||
"---Configure---",
|
||||
"providers",
|
||||
"models",
|
||||
"agents",
|
||||
"permissions",
|
||||
"sharing",
|
||||
"snapshots",
|
||||
"commands",
|
||||
"skills",
|
||||
"instructions",
|
||||
"mcp-servers",
|
||||
"attachments",
|
||||
"compaction",
|
||||
"formatters",
|
||||
"lsp",
|
||||
"references"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,576 +0,0 @@
|
|||
---
|
||||
title: "Migrate from V1"
|
||||
description: "Move from OpenCode V1 to the OpenCode 2.0 beta."
|
||||
---
|
||||
|
||||
## Breaking changes
|
||||
|
||||
V2 has three intentional breaking changes:
|
||||
|
||||
- [Plugins](#plugins) use a new plugin API.
|
||||
- The [server API and clients](#server-api-and-clients) have new contracts.
|
||||
- [TUI configuration](#tui-configuration) moves from layered `tui.json(c)` files to one global `cli.json` file (auto migrated).
|
||||
|
||||
All other functionality is intended to remain compatible with V1.
|
||||
|
||||
Existing server config files, agent definitions, command definitions, skills, and other files in `.opencode/` should
|
||||
continue to work without changes. If one of these stops working in V2, treat it as a beta compatibility bug rather than
|
||||
an expected migration requirement.
|
||||
|
||||
<Tip>
|
||||
Run `/report` if existing V1 functionality does not work in V2. The report skill collects diagnostics and helps you file
|
||||
a compatibility issue.
|
||||
</Tip>
|
||||
|
||||
<Warning>
|
||||
OpenCode 2.0 is in beta. Beta data may be wiped, features may break unintentionally, and the server and plugin APIs may
|
||||
continue to change.
|
||||
</Warning>
|
||||
|
||||
During the beta, OpenCode V1 and V2 use different executable names. You can keep using `opencode` for V1 while trying V2
|
||||
with `opencode2`.
|
||||
|
||||
## Install the beta
|
||||
|
||||
Install the beta from the `next` distribution tag:
|
||||
|
||||
```bash
|
||||
npm install -g @opencode-ai/cli@next
|
||||
```
|
||||
|
||||
Start it in your project with:
|
||||
|
||||
```bash
|
||||
opencode2
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
This section covers both JSON/JSONC configuration and file-based definitions under `.opencode/`.
|
||||
|
||||
### Use your existing configuration
|
||||
|
||||
V2 reads existing global and project configuration from the same locations as V1:
|
||||
|
||||
```text
|
||||
~/.config/opencode/opencode.json(c)
|
||||
<project>/opencode.json(c)
|
||||
<project>/.opencode/opencode.json(c)
|
||||
```
|
||||
|
||||
V2 reads these same locations. It detects V1-shaped configuration and translates it in memory without rewriting the
|
||||
source file. Existing V1 configuration is intended to keep working, so you do not need to convert it to try or adopt V2.
|
||||
|
||||
### Ask OpenCode to migrate
|
||||
|
||||
The V1 config format remains supported. The native V2 format is optional and makes several settings more explicit and
|
||||
ergonomic.
|
||||
|
||||
The recommended migration path is to ask OpenCode to update the configuration for you:
|
||||
|
||||
```text
|
||||
Migrate my OpenCode configuration, including file-based definitions, from the V1 format to the native V2 format.
|
||||
Preserve its behavior and all unrelated settings.
|
||||
```
|
||||
|
||||
OpenCode can inspect the complete file, apply the relevant changes below, and avoid rewriting settings that do not need to
|
||||
change. Do not mix V1 and V2 field names manually in one file.
|
||||
|
||||
### Sharing
|
||||
|
||||
The deprecated V1 `autoshare` boolean becomes the explicit `share` policy:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{ "autoshare": true }
|
||||
|
||||
// V2
|
||||
{ "share": "auto" }
|
||||
```
|
||||
|
||||
Use `"manual"`, `"auto"`, or `"disabled"`. If the V1 file already uses `share`, no change is needed.
|
||||
|
||||
### Permissions and tools
|
||||
|
||||
V1 groups permission effects by tool. V2 uses one ordered `permissions` array, making precedence and exceptions explicit:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"permission": {
|
||||
"bash": {
|
||||
"git push *": "ask"
|
||||
},
|
||||
"edit": "allow"
|
||||
},
|
||||
"tools": {
|
||||
"websearch": false
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"permissions": [
|
||||
{ "action": "shell", "resource": "git push *", "effect": "ask" },
|
||||
{ "action": "edit", "resource": "*", "effect": "allow" },
|
||||
{ "action": "websearch", "resource": "*", "effect": "deny" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Permission actions also changed: `bash` is now `shell`, `task` is now `subagent`, and `write` and `patch` are now `edit`.
|
||||
See [Permissions](/docs/permissions) for the ordered V2 rule format.
|
||||
|
||||
### Agents and modes
|
||||
|
||||
The singular `agent` and deprecated `mode` maps become `agents`. Agent fields become more consistent with the rest of the
|
||||
V2 config:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"agent": {
|
||||
"reviewer": {
|
||||
"prompt": "Review for correctness and missing tests.",
|
||||
"model": "anthropic/claude-sonnet-4-5",
|
||||
"variant": "high",
|
||||
"disable": false,
|
||||
"permission": {
|
||||
"edit": "deny"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"agents": {
|
||||
"reviewer": {
|
||||
"system": "Review for correctness and missing tests.",
|
||||
"model": "anthropic/claude-sonnet-4-5#high",
|
||||
"disabled": false,
|
||||
"permissions": [
|
||||
{ "action": "edit", "resource": "*", "effect": "deny" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`prompt` becomes `system`, `disable` becomes `disabled`, and a separate `variant` joins the model reference after `#`.
|
||||
`temperature`, `top_p`, and provider-specific `options` move under `request.body`. `maxSteps` becomes `steps`. Entries from
|
||||
the old `mode` map become primary agents.
|
||||
|
||||
### Snapshots
|
||||
|
||||
Rename the singular `snapshot` field to `snapshots`. Its boolean value does not change:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{ "snapshot": false }
|
||||
|
||||
// V2
|
||||
{ "snapshots": false }
|
||||
```
|
||||
|
||||
### Attachments
|
||||
|
||||
Rename the singular `attachment` object to `attachments`. Nested image settings keep the same names:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{ "attachment": { "image": { "auto_resize": true } } }
|
||||
|
||||
// V2
|
||||
{ "attachments": { "image": { "auto_resize": true } } }
|
||||
```
|
||||
|
||||
### MCP servers
|
||||
|
||||
V2 groups servers under `mcp.servers`, replaces `enabled` with the inverse `disabled`, and separates timeout purposes:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"mcp": {
|
||||
"playwright": {
|
||||
"type": "local",
|
||||
"command": ["npx", "@playwright/mcp"],
|
||||
"enabled": true,
|
||||
"timeout": 30000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"playwright": {
|
||||
"type": "local",
|
||||
"command": ["npx", "@playwright/mcp"],
|
||||
"disabled": false,
|
||||
"timeout": {
|
||||
"catalog": 30000,
|
||||
"execution": 30000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Remote OAuth fields use snake case: `clientId` becomes `client_id`, `clientSecret` becomes `client_secret`,
|
||||
`callbackPort` becomes `callback_port`, and `redirectUri` becomes `redirect_uri`. The V1 `experimental.mcp_timeout` value
|
||||
also becomes the default `mcp.timeout.catalog` and `mcp.timeout.execution` values. See [MCP servers](/docs/mcp-servers).
|
||||
|
||||
### Compaction
|
||||
|
||||
V2 groups the retained-context token budget under `keep` and gives the reserve a clearer name:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"compaction": {
|
||||
"preserve_recent_tokens": 8000,
|
||||
"reserved": 20000
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"compaction": {
|
||||
"keep": {
|
||||
"tokens": 8000
|
||||
},
|
||||
"buffer": 20000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`auto` and `prune` keep their names. V2 has no native `tail_turns` field; recent context is retained by token budget instead.
|
||||
See [Compaction](/docs/compaction).
|
||||
|
||||
### Skills
|
||||
|
||||
V1 separates extra skill paths and URLs. V2 combines both into one ordered array:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"skills": {
|
||||
"paths": ["./team-skills"],
|
||||
"urls": ["https://example.com/skills/"]
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"skills": ["./team-skills", "https://example.com/skills/"]
|
||||
}
|
||||
```
|
||||
|
||||
Existing skill files and automatic `.opencode/skills/` discovery do not change. See [Skills](/docs/skills).
|
||||
|
||||
### Commands
|
||||
|
||||
Rename the singular `command` map to `commands`. Join a separate model `variant` to the model reference:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"command": {
|
||||
"review": {
|
||||
"template": "Review the current changes.",
|
||||
"model": "anthropic/claude-sonnet-4-5",
|
||||
"variant": "high"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"commands": {
|
||||
"review": {
|
||||
"template": "Review the current changes.",
|
||||
"model": "anthropic/claude-sonnet-4-5#high"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`template`, `description`, `agent`, and `subtask` keep their names. Existing Markdown command definitions remain supported.
|
||||
See [Commands](/docs/commands).
|
||||
|
||||
### References
|
||||
|
||||
Rename the deprecated singular `reference` map to `references`:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{ "reference": { "docs": "../docs" } }
|
||||
|
||||
// V2
|
||||
{ "references": { "docs": "../docs" } }
|
||||
```
|
||||
|
||||
V1 already accepts `references`, so no change is needed when the file uses it. Reference entries keep the
|
||||
same shapes. See [References](/docs/references).
|
||||
|
||||
### Providers
|
||||
|
||||
Rename the singular `provider` map to `providers`. V2 separates the runtime package, endpoint, and request settings:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"provider": {
|
||||
"acme": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"api": "https://llm.example.com/v1",
|
||||
"options": {
|
||||
"apiKey": "{env:ACME_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"providers": {
|
||||
"acme": {
|
||||
"package": "aisdk:@ai-sdk/openai-compatible",
|
||||
"settings": {
|
||||
"baseURL": "https://llm.example.com/v1",
|
||||
"apiKey": "{env:ACME_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
V1 `npm` becomes `package`, and AI SDK packages receive the `aisdk:` prefix. `api` becomes `settings.baseURL`. Provider
|
||||
`options` are separated into `settings`, `headers`, and `body` according to their request role. See [Providers](/docs/providers).
|
||||
|
||||
### Models and variants
|
||||
|
||||
Models remain nested under their provider, but several model fields become more explicit:
|
||||
|
||||
- `id` becomes `modelID`.
|
||||
- `tool_call` and `modalities` become `capabilities.tools`, `capabilities.input`, and `capabilities.output`.
|
||||
- A `status` of `"deprecated"` becomes `disabled: true`.
|
||||
- Cache costs move from `cache_read` and `cache_write` to `cache.read` and `cache.write`.
|
||||
- Provider-specific `options` become `settings`.
|
||||
- A V1 variants object becomes a V2 array with an `id` on each entry.
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"variants": {
|
||||
"high": {
|
||||
"reasoningEffort": "high"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"variants": [
|
||||
{
|
||||
"id": "high",
|
||||
"settings": {
|
||||
"reasoningEffort": "high"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See [Models](/docs/models) for the complete native model shape.
|
||||
|
||||
### Fields without native equivalents
|
||||
|
||||
Most fields that keep the same shape, including `shell`, `model`, `default_agent`, `autoupdate`, `watcher`, `formatter`,
|
||||
`lsp`, `instructions`, `enterprise`, and `tool_output`, require no migration.
|
||||
|
||||
These V1 fields do not have one-to-one native V2 config fields:
|
||||
|
||||
- `logLevel`: use `OPENCODE_LOG_LEVEL` when starting OpenCode.
|
||||
- `server`: use the V2 service and explicit server options; the server API is an intentional breaking change.
|
||||
- `layout`: remove it; V1 already treated it as deprecated and always used stretch layout.
|
||||
- `enabled_providers` and `disabled_providers`: there is no native provider allowlist or denylist field yet.
|
||||
- `small_model`: V2 selects models for internal maintenance agents without a separate top-level field.
|
||||
- `compaction.tail_turns`: V2 uses `compaction.keep.tokens` instead.
|
||||
|
||||
If your V1 configuration relies on a field without a native equivalent, keep using the supported V1 format rather than
|
||||
forcing a manual conversion. Run `/report` if V2 does not preserve the behavior you rely on.
|
||||
|
||||
### Agent files
|
||||
|
||||
V1 agent files may use `agent/`, `agents/`, `mode/`, or `modes/`. V2 still discovers all four directories. The preferred
|
||||
V2 location is:
|
||||
|
||||
```text
|
||||
.opencode/agents/<name>.md
|
||||
```
|
||||
|
||||
Files under a V1 `mode/` or `modes/` directory represent primary agents. When moving one into `agents/`, add
|
||||
`mode: primary` to its frontmatter. Files under `agent/` can move to `agents/` without changing their path-derived ID.
|
||||
|
||||
When converting the frontmatter to native V2 fields:
|
||||
|
||||
- Keep the Markdown body as the agent's system instructions.
|
||||
- Rename `prompt` to `system` when it appears in JSON configuration; file bodies do not need a `system` field.
|
||||
- Rename `disable` to `disabled` and `permission` to `permissions`.
|
||||
- Join `model` and `variant` as `provider/model#variant`.
|
||||
- Move `temperature`, `top_p`, and provider-specific options under `request.body`.
|
||||
|
||||
V2 translates legacy agent frontmatter automatically, so these edits are optional. See [Agents](/docs/agents).
|
||||
|
||||
### Command files
|
||||
|
||||
V1 command files may use `command/` or `commands/`. V2 discovers both. The preferred location is:
|
||||
|
||||
```text
|
||||
.opencode/commands/<name>.md
|
||||
```
|
||||
|
||||
Move files from `command/` to the same relative path under `commands/` to preserve command names. The Markdown body remains
|
||||
the command template, and `description`, `agent`, and `subtask` frontmatter keep the same names. If frontmatter has separate
|
||||
`model` and `variant` fields, append the variant to the model and remove `variant`:
|
||||
|
||||
```yaml
|
||||
# V1
|
||||
model: anthropic/claude-sonnet-4-5
|
||||
variant: high
|
||||
|
||||
# V2
|
||||
model: anthropic/claude-sonnet-4-5#high
|
||||
```
|
||||
|
||||
See [Commands](/docs/commands).
|
||||
|
||||
### Skill files
|
||||
|
||||
V2 discovers skills from both `.opencode/skill/` and `.opencode/skills/`. The preferred layout is:
|
||||
|
||||
```text
|
||||
.opencode/skills/<skill-id>/SKILL.md
|
||||
```
|
||||
|
||||
Move the complete skill directory, not only `SKILL.md`, so relative scripts, references, and other supporting files remain
|
||||
available. Keep the directory name stable to preserve the skill ID. Existing skill frontmatter and Markdown bodies do not
|
||||
require a V2 rewrite. See [Skills](/docs/skills).
|
||||
|
||||
### Instruction files
|
||||
|
||||
Existing `AGENTS.md` files stay in place. V2 discovers the global `~/.config/opencode/AGENTS.md` and project `AGENTS.md`
|
||||
files from the current directory up to the project root.
|
||||
|
||||
If a V1 setup relied on a `CLAUDE.md` fallback, move that guidance into the applicable `AGENTS.md`. V2 currently only
|
||||
discovers `AGENTS.md`; because non-API V1 behavior is intended to remain compatible, also run `/report` with the affected
|
||||
project details. See [Instructions](/docs/instructions).
|
||||
|
||||
## TUI configuration
|
||||
|
||||
V1 loaded `tui.json(c)` from the global config directory and from project directories discovered while walking up from
|
||||
the current directory. V2 instead stores CLI and TUI settings in one global file:
|
||||
|
||||
```text
|
||||
~/.config/opencode/cli.json
|
||||
```
|
||||
|
||||
The CLI owns this file. The background service does not load it, and V2 does not discover or merge project-local
|
||||
`tui.json(c)` or `cli.json` files.
|
||||
|
||||
The native V2 format groups related settings. For example:
|
||||
|
||||
```jsonc
|
||||
// V1: ~/.config/opencode/tui.json
|
||||
{
|
||||
"theme": "tokyonight",
|
||||
"scroll_speed": 2,
|
||||
"scroll_acceleration": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
|
||||
// V2: ~/.config/opencode/cli.json
|
||||
{
|
||||
"theme": {
|
||||
"name": "tokyonight"
|
||||
},
|
||||
"scroll": {
|
||||
"speed": 2,
|
||||
"acceleration": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
V2 migrates the global TUI configuration automatically. On the first CLI or TUI startup, when `cli.json` does not already
|
||||
exist, it:
|
||||
|
||||
- Reads `~/.config/opencode/tui.json`.
|
||||
- Reads persisted TUI preferences from the legacy `kv.json` state file.
|
||||
- Converts supported settings to the native grouped format and writes `~/.config/opencode/cli.json`.
|
||||
- Leaves the V1 files unchanged so V1 can continue using them.
|
||||
|
||||
Migration runs only while `cli.json` is absent. Once that file exists, V2 treats it as the source of truth and does not
|
||||
continually synchronize later changes from `tui.json` or `kv.json`. If you created `cli.json` before starting V2, merge any
|
||||
V1 settings you still need into it manually.
|
||||
|
||||
Project-local V1 TUI configuration is not migrated because V2 has no project-local CLI configuration. Move settings you
|
||||
still want into the global `cli.json`; when multiple projects used different values for the same setting, choose the
|
||||
global behavior you want V2 to use.
|
||||
|
||||
## Plugins
|
||||
|
||||
Rename `plugin` to `plugins`. Replace a package-and-options tuple with an object:
|
||||
|
||||
```jsonc
|
||||
// V1
|
||||
{
|
||||
"plugin": [
|
||||
"opencode-example-plugin",
|
||||
["./plugin/local.ts", { "enabled": true }]
|
||||
]
|
||||
}
|
||||
|
||||
// V2
|
||||
{
|
||||
"plugins": [
|
||||
"opencode-example-plugin",
|
||||
{
|
||||
"package": "./plugin/local.ts",
|
||||
"options": { "enabled": true }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
V2 discovers local plugins from both `.opencode/plugin/` and `.opencode/plugins/`; use `.opencode/plugins/` for V2 files.
|
||||
Moving a file between these directories does not migrate its implementation.
|
||||
|
||||
<Warning>V1 plugins will not work in V2.</Warning>
|
||||
|
||||
The config entry can be translated automatically, but plugin implementation code must be ported to the new API. The V2
|
||||
plugin API is still being finalized during beta, and detailed plugin migration guidance will be published when it is
|
||||
ready.
|
||||
|
||||
Once the V2 plugin API is finalized, OpenCode should be able to migrate the majority of V1 plugins while keeping related
|
||||
local modules and dependencies together. See the current beta [Plugins guide](/docs/build/plugins).
|
||||
|
||||
## Server API and clients
|
||||
|
||||
OpenCode 2 has a revised, more ergonomic server API and a new set of clients. Integrations that call the V1 server API
|
||||
must migrate to the V2 API.
|
||||
|
||||
Use the `@opencode-ai/client` package to access the new clients. The server API and clients are still being finalized
|
||||
during beta, so their contracts may continue to change. See the generated [API reference](/docs/api) for the current endpoints,
|
||||
request types, and responses.
|
||||
|
||||
## Verify your setup
|
||||
|
||||
Start `opencode2` in a project and verify your model, provider credentials, agents, permissions, MCP servers, and plugins
|
||||
before relying on the beta for regular work. Keep your V1 setup until you have confirmed the V2 behavior you need, and do
|
||||
not point V1 at configuration that you have converted to the native V2 shape.
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
---
|
||||
title: "Models"
|
||||
description: ""
|
||||
---
|
||||
|
||||
OpenCode builds its model catalog from [Models.dev](https://models.dev), provider integrations, and your configuration.
|
||||
Only enabled models whose provider is available for the current project appear in the model picker.
|
||||
|
||||
Connect a provider with `/connect` in the TUI, or configure it in [Providers](/docs/providers).
|
||||
|
||||
## Choose a model
|
||||
|
||||
Open the model picker with `/models` or the default `<leader>m` keybind. The picker shows the models available from
|
||||
providers connected to the current project.
|
||||
|
||||
Select a model to use it in the current session. Switching models updates that session without changing your config. Use
|
||||
the catalog entries shown in the picker rather than guessing a provider or model name.
|
||||
|
||||
## Per-run model
|
||||
|
||||
Select a model for one non-interactive run with `--model` or `-m`:
|
||||
|
||||
```bash
|
||||
opencode2 run --model openai/gpt-5.2 "Explain this repository"
|
||||
opencode2 run -m openai/gpt-5.2#high "Review the current changes"
|
||||
```
|
||||
|
||||
Agents and commands can also select their own model. See [Agents](/docs/agents) and [Commands](/docs/commands).
|
||||
|
||||
## Variants
|
||||
|
||||
Variants are named request overlays for one model, commonly used for reasoning effort or token budgets. Available names
|
||||
are model-specific and are derived from current catalog metadata. Do not assume that names such as `low`, `high`, or
|
||||
`max` exist for every model; `/variants` shows the valid choices.
|
||||
|
||||
Use `/variants` to choose one for the current model, or press `ctrl+t` to cycle through available variants.
|
||||
|
||||
## Configure
|
||||
|
||||
### Default model
|
||||
|
||||
Set `model` in `opencode.json` or `opencode.jsonc`:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "anthropic/claude-sonnet-4-5"
|
||||
}
|
||||
```
|
||||
|
||||
The configured model becomes the catalog default when its provider is available and the model is enabled. Otherwise,
|
||||
session execution falls back to the newest available supported model. An explicit model already selected on a session
|
||||
takes precedence over the default; switching models changes that session and does not rewrite your config.
|
||||
|
||||
See [Config](/docs/config) for configuration locations and precedence.
|
||||
|
||||
### Model settings
|
||||
|
||||
Provider and model entries can supply three kinds of request configuration:
|
||||
|
||||
- `settings` contains provider-package options such as `baseURL`, `reasoningEffort`, or `thinkingConfig`.
|
||||
- `headers` adds HTTP request headers.
|
||||
- `body` adds provider-specific fields to the request body.
|
||||
|
||||
These values are provider-specific JSON. OpenCode applies provider values first, then model values, then the selected
|
||||
variant. Nested `settings` and `body` objects are merged; later array and scalar values replace earlier values. Header
|
||||
names are matched case-insensitively.
|
||||
|
||||
You can also map a friendly catalog ID to a different API model ID with `modelID`:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "openai/coding-default",
|
||||
"providers": {
|
||||
"openai": {
|
||||
"models": {
|
||||
"coding-default": {
|
||||
"modelID": "gpt-5.2",
|
||||
"name": "Coding default",
|
||||
"capabilities": {
|
||||
"tools": true,
|
||||
"input": ["text", "image"],
|
||||
"output": ["text"]
|
||||
},
|
||||
"limit": {
|
||||
"context": 200000,
|
||||
"output": 32000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here `openai/coding-default` is the selectable catalog reference, while `gpt-5.2` is sent to the provider. When adding a
|
||||
model that is not already in the catalog, set accurate `capabilities` and `limit` values so OpenCode can expose tools and
|
||||
enforce the correct context limits. Set `disabled: true` on a model entry to hide it from the available catalog.
|
||||
|
||||
### Custom variants
|
||||
|
||||
Add a variant, or override a catalog variant with the same ID, under the model's `variants` array:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"openai": {
|
||||
"models": {
|
||||
"gpt-5.2": {
|
||||
"settings": {
|
||||
"reasoningEffort": "medium"
|
||||
},
|
||||
"variants": [
|
||||
{
|
||||
"id": "fast",
|
||||
"settings": {
|
||||
"reasoningEffort": "low"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deep",
|
||||
"settings": {
|
||||
"reasoningEffort": "high",
|
||||
"reasoningSummary": "auto"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Variant entries support `settings`, `headers`, and `body`. Selecting one deeply overlays its values on the effective
|
||||
provider and model configuration. An unknown variant fails model resolution instead of silently using the base model.
|
||||
|
||||
### Local models
|
||||
|
||||
For an OpenAI-compatible server, define a provider package, endpoint, and at least one model:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "local/coder",
|
||||
"providers": {
|
||||
"local": {
|
||||
"name": "Local server",
|
||||
"package": "aisdk:@ai-sdk/openai-compatible",
|
||||
"settings": {
|
||||
"baseURL": "http://127.0.0.1:1234/v1"
|
||||
},
|
||||
"models": {
|
||||
"coder": {
|
||||
"modelID": "model-name-on-server",
|
||||
"capabilities": {
|
||||
"tools": true,
|
||||
"input": ["text"],
|
||||
"output": ["text"]
|
||||
},
|
||||
"limit": {
|
||||
"context": 32768,
|
||||
"output": 8192
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use the server's real model name, limits, modalities, and tool support. OpenCode cannot infer these for a model you add
|
||||
manually. If the endpoint requires a key, add `apiKey` to provider `settings` using an environment substitution such as
|
||||
`"apiKey": "{env:LOCAL_API_KEY}"`; do not commit secrets.
|
||||
|
||||
### Model references
|
||||
|
||||
Configuration and CLI options identify a model as `provider/model`, with an optional `#variant`:
|
||||
|
||||
```text
|
||||
openai/gpt-5.2
|
||||
openai/gpt-5.2#high
|
||||
openrouter/anthropic/claude-sonnet-4.5#high
|
||||
```
|
||||
|
||||
OpenCode splits the reference at the first `/`, so model IDs may contain additional slashes. Provider and model IDs are
|
||||
case-sensitive. Provider IDs cannot contain `/` or `#`, and model IDs cannot contain `#`.
|
||||
|
||||
The expanded config form is equivalent when generated or programmatic configuration is more convenient:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"model": {
|
||||
"providerID": "openrouter",
|
||||
"model": "anthropic/claude-sonnet-4.5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Root, agent, and command `model` fields accept both forms. Use the IDs shown by `/models`, not provider display names.
|
||||
|
||||
### Caveats
|
||||
|
||||
- The selector object uses `model`, while a provider catalog entry uses `modelID` for the upstream API identifier.
|
||||
- The root `model` currently sets the default provider and model only. Although its selection shape accepts a variant,
|
||||
the V2 catalog default does not retain it; select a variant in the TUI, with `opencode2 run`, or on an agent or command.
|
||||
- Model options are provider-specific. A setting accepted by one provider package may be ignored or rejected by another.
|
||||
- Catalog data, credentials, and config are location-scoped. A model available in one project may be unavailable in
|
||||
another.
|
||||
- Configuration files are watched and normally reload automatically, but an in-flight model request keeps the settings
|
||||
with which it started.
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
---
|
||||
title: "Providers"
|
||||
description: ""
|
||||
---
|
||||
|
||||
OpenCode builds its provider and model catalog from [Models.dev](https://models.dev), then applies the `providers`
|
||||
overlays from your [configuration](/docs/config). A provider needs both a usable runtime package and, when required, an
|
||||
active connection.
|
||||
|
||||
## Connect a provider
|
||||
|
||||
Run `/connect` in the TUI, choose an integration, and complete one of the methods it offers:
|
||||
|
||||
```text
|
||||
/connect
|
||||
```
|
||||
|
||||
An integration may support an API key, OAuth, environment variables, or a combination of them. API keys and OAuth
|
||||
tokens entered through `/connect` are stored by the OpenCode service in its database. Run `/connect` again to replace
|
||||
or remove a stored credential.
|
||||
|
||||
Providers from Models.dev also declare their standard environment variables. A non-empty declared variable is exposed
|
||||
as an environment connection automatically, so common providers usually need no config:
|
||||
|
||||
```bash
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
```
|
||||
|
||||
For a custom provider, `env` declares the variables that can supply its key:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"acme": {
|
||||
"env": ["ACME_API_KEY"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When several credential sources exist, OpenCode uses the stored credential first, then the first non-empty variable in
|
||||
`env`, then `settings.apiKey`. Use config substitution instead of committing a literal key:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"acme": {
|
||||
"settings": {
|
||||
"apiKey": "{env:ACME_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Warning>Do not commit API keys or authorization headers to your repository.</Warning>
|
||||
|
||||
## Configure
|
||||
|
||||
The `providers` object is keyed by provider ID. Each provider accepts these fields:
|
||||
|
||||
| Field | Purpose |
|
||||
| --- | --- |
|
||||
| `name` | Display name. |
|
||||
| `env` | Ordered environment variable names that provide a connection. |
|
||||
| `package` | Runtime provider package. |
|
||||
| `settings` | JSON settings passed to the runtime package, such as `baseURL`. |
|
||||
| `headers` | String-valued HTTP headers added to requests. |
|
||||
| `body` | JSON fields merged into request bodies. |
|
||||
| `models` | Models to add or override, keyed by catalog model ID. |
|
||||
|
||||
Configuration files are applied from lowest to highest precedence. `settings` and `body` are deep-merged. Headers are
|
||||
merged case-insensitively. At request time, provider values are inherited by the model, model values override them, and
|
||||
the selected variant is applied last.
|
||||
|
||||
### Endpoint
|
||||
|
||||
Override `settings.baseURL` to send an existing provider through a proxy or compatible endpoint. Its existing package,
|
||||
models, and connection continue to apply:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"anthropic": {
|
||||
"settings": {
|
||||
"baseURL": "https://llm-proxy.example.com/anthropic"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`settings` is package-specific. A field only has an effect when the selected package supports it.
|
||||
|
||||
### Headers and body
|
||||
|
||||
Headers and body fields can be set at provider, model, or variant scope:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"openai": {
|
||||
"headers": {
|
||||
"X-Gateway-Tenant": "engineering"
|
||||
},
|
||||
"body": {
|
||||
"metadata": {
|
||||
"application": "opencode"
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"gpt-5.2": {
|
||||
"headers": {
|
||||
"X-Model-Policy": "coding"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These are request overlays, not a generic authentication scheme. Prefer `/connect`, `env`, or `settings.apiKey` for
|
||||
provider credentials unless the endpoint explicitly requires a custom header.
|
||||
|
||||
### Provider packages
|
||||
|
||||
For an OpenAI-compatible service, use the V2 native compatible package. The model map is explicit because a custom
|
||||
provider has no Models.dev catalog entries:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "acme/qwen3-coder",
|
||||
"providers": {
|
||||
"acme": {
|
||||
"name": "Acme Gateway",
|
||||
"env": ["ACME_API_KEY"],
|
||||
"package": "@opencode-ai/ai/providers/openai-compatible",
|
||||
"settings": {
|
||||
"baseURL": "https://llm.acme.example/v1"
|
||||
},
|
||||
"models": {
|
||||
"qwen3-coder": {
|
||||
"name": "Qwen 3 Coder",
|
||||
"capabilities": {
|
||||
"tools": true,
|
||||
"input": ["text"],
|
||||
"output": ["text"]
|
||||
},
|
||||
"limit": {
|
||||
"context": 131072,
|
||||
"output": 32768
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Omit `env` for an endpoint that does not require authentication. The native compatible package requires
|
||||
`settings.baseURL` and uses bearer authentication when a key is available.
|
||||
|
||||
The `package` field supports two runtime contracts:
|
||||
|
||||
| Form | Contract |
|
||||
| --- | --- |
|
||||
| `"@opencode-ai/ai/providers/openai-compatible"` | A V2 native package exporting `model(modelID, settings)`. An npm specifier or absolute `file://` URL may use the same contract. |
|
||||
| `"aisdk:@ai-sdk/openai-compatible"` | An AI SDK provider package. The `aisdk:` prefix is required. |
|
||||
|
||||
Native packages receive the merged `settings` plus the resolved `apiKey`, `headers`, `body`, and `limits`. AI SDK
|
||||
packages receive their merged provider options. Use a package's own documentation for accepted settings; OpenCode does
|
||||
not validate package-specific keys.
|
||||
|
||||
`package` may also be set on one model to override the provider package for that model.
|
||||
|
||||
### Models
|
||||
|
||||
Add a model under a provider's `models` map. The object key is the model ID used in OpenCode; `modelID` is the ID sent to
|
||||
the provider:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "openai/coding",
|
||||
"providers": {
|
||||
"openai": {
|
||||
"models": {
|
||||
"coding": {
|
||||
"modelID": "gpt-5.2",
|
||||
"name": "GPT-5.2 Coding"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [Models](/docs/models) for model selection, defaults, capabilities, limits, costs, and variants.
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
---
|
||||
title: "Session sharing"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Session sharing is not yet available in OpenCode V2. V2 does not currently
|
||||
publish sessions, upload conversation history to a sharing service, or create
|
||||
public links.
|
||||
|
||||
<Warning>
|
||||
The V2 TUI registers `/share`, but it currently only reports that sharing is unavailable. There is no functional
|
||||
share/unshare command or server API endpoint.
|
||||
</Warning>
|
||||
|
||||
## Configuration
|
||||
|
||||
The V2 configuration schema accepts a `share` field with three values:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"share": "manual"
|
||||
}
|
||||
```
|
||||
|
||||
- `"manual"` represents sharing only when explicitly requested.
|
||||
- `"auto"` represents automatically sharing new sessions.
|
||||
- `"disabled"` represents preventing session sharing.
|
||||
|
||||
These values are parsed but are not acted on by the current V2 runtime. In
|
||||
particular, setting `"auto"` does not publish sessions. If `share` is omitted,
|
||||
V2 leaves the sharing policy unspecified.
|
||||
|
||||
## Beta limitations
|
||||
|
||||
V2 currently provides no public session viewer, share URL, history sync,
|
||||
retention controls, or unshare/delete operation. Until those surfaces are
|
||||
implemented in the V2 server and protocol, keep using sessions locally and do
|
||||
not treat the `share` configuration field as a privacy or publishing control.
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
---
|
||||
title: "Skills"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Skills are Markdown instructions that OpenCode can advertise to an agent and
|
||||
load when they are relevant. A skill can include supporting scripts,
|
||||
references, and other files in the same directory.
|
||||
|
||||
## Create a skill
|
||||
|
||||
Create one directory per skill with a `SKILL.md` file:
|
||||
|
||||
```text
|
||||
.opencode/skills/
|
||||
└── git-release/
|
||||
├── SKILL.md
|
||||
├── scripts/
|
||||
│ └── changelog.ts
|
||||
└── references/
|
||||
└── release-policy.md
|
||||
```
|
||||
|
||||
```markdown title=".opencode/skills/git-release/SKILL.md"
|
||||
---
|
||||
name: Git Release
|
||||
description: Prepare release notes, version bumps, and GitHub releases
|
||||
metadata:
|
||||
opencode/slash: "true"
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Read `references/release-policy.md`.
|
||||
2. Summarize merged changes since the previous tag.
|
||||
3. Propose the version bump before changing files.
|
||||
4. Run `scripts/changelog.ts` only after the user approves the version.
|
||||
```
|
||||
|
||||
Paths in a skill are relative to the directory containing `SKILL.md`.
|
||||
|
||||
## Discovery
|
||||
|
||||
OpenCode automatically adds the following source directories:
|
||||
|
||||
| Scope | Sources |
|
||||
| --- | --- |
|
||||
| Global | `~/.config/opencode/skills` |
|
||||
| Global compatibility | `~/.claude/skills`, `~/.agents/skills` |
|
||||
| Project | `.opencode/skills` |
|
||||
| Project compatibility | `.claude/skills`, `.agents/skills` |
|
||||
|
||||
For project sources, OpenCode searches from the current directory upward to
|
||||
the project root and includes matching directories at every level.
|
||||
|
||||
Within each source directory, OpenCode discovers:
|
||||
|
||||
- Markdown files at the source root, such as `skills/git-release.md`
|
||||
- `SKILL.md` files at any depth, such as `skills/git-release/SKILL.md`
|
||||
|
||||
The directory form is recommended because it gives the skill a private base
|
||||
directory for supporting files.
|
||||
|
||||
## Configure sources
|
||||
|
||||
Use the `skills` array in any `opencode.json` or `opencode.jsonc` to add local
|
||||
directories or HTTP catalogs:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"skills": [
|
||||
"./team-skills",
|
||||
"~/shared/opencode-skills",
|
||||
"/opt/company-skills",
|
||||
"https://example.com/opencode/skills/"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Relative paths are resolved from the active OpenCode working directory, not
|
||||
from the directory containing the config file. Paths beginning with `~/` use
|
||||
the current user's home directory. Only `http://` and `https://` values are
|
||||
treated as URL sources.
|
||||
|
||||
Every discovered config document contributes its `skills` entries; the arrays
|
||||
are additive rather than replacing one another.
|
||||
|
||||
### HTTP catalogs
|
||||
|
||||
An HTTP source is a base URL containing an `index.json`:
|
||||
|
||||
```json title="index.json"
|
||||
{
|
||||
"skills": [
|
||||
{
|
||||
"name": "git-release",
|
||||
"version": "3",
|
||||
"files": [
|
||||
"git-release.md",
|
||||
"references/release-policy.md"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
OpenCode downloads those files from
|
||||
`<base-url>/git-release/<file>`. File paths must be safe, relative,
|
||||
same-origin paths. Each entry must include either `SKILL.md` or a Markdown file
|
||||
named after the index entry, such as `git-release.md`.
|
||||
|
||||
Use the named Markdown form for HTTP catalogs. Each downloaded skill directory
|
||||
is itself a source root, so `git-release.md` produces the ID `git-release`; a
|
||||
root-level `SKILL.md` produces the literal ID `SKILL` in the current V2
|
||||
implementation. Increment `version` when files change so OpenCode refreshes
|
||||
the cached copy.
|
||||
|
||||
## Frontmatter
|
||||
|
||||
V2 reads these fields:
|
||||
|
||||
| Field | Purpose |
|
||||
| --- | --- |
|
||||
| `name` | Display name; defaults to the path-derived ID |
|
||||
| `description` | Summary shown to the model and command catalog |
|
||||
| `slash` | Set to `false` to hide the skill from the V2 slash-command catalog |
|
||||
| `metadata.opencode/slash` | Boolean or `"true"`/`"false"`; overrides `slash` |
|
||||
| `metadata.opencode/autoinvoke` | Set to `false` to omit the skill from model-facing discovery |
|
||||
|
||||
Frontmatter, `name`, and `description` are optional at runtime. However, a
|
||||
clear `description` is strongly recommended: skills without one are not
|
||||
advertised to the model. `license`, `compatibility`, and other metadata may be
|
||||
included for portability, but V2 does not interpret them.
|
||||
|
||||
`opencode/autoinvoke: false` only removes the skill from the model's available
|
||||
skills list. The skill remains registered and can still be activated explicitly
|
||||
by its ID.
|
||||
|
||||
## IDs and validation
|
||||
|
||||
The skill ID comes from its path, not its frontmatter:
|
||||
|
||||
| File | ID |
|
||||
| --- | --- |
|
||||
| `<source>/git-release.md` | `git-release` |
|
||||
| `<source>/git-release/SKILL.md` | `git-release` |
|
||||
| `<source>/teams/release/SKILL.md` | `release` |
|
||||
|
||||
IDs are exact and case-sensitive. V2 currently does not enforce the Agent
|
||||
Skills name regex, length limits, a match between `name` and the directory, or
|
||||
a maximum description length. The frontmatter `name` is only a display label.
|
||||
|
||||
For portable, predictable skills, use a unique lowercase kebab-case ID of 1-64
|
||||
characters and keep it aligned with the directory name:
|
||||
|
||||
```text
|
||||
^[a-z0-9]+(-[a-z0-9]+)*$
|
||||
```
|
||||
|
||||
## Precedence
|
||||
|
||||
Skills are keyed by ID. If several sources define the same ID, the later source
|
||||
wins. Sources are registered in this order, from lower to higher precedence:
|
||||
|
||||
1. Built-in skills
|
||||
2. `.claude/skills` sources, global first and then from the current directory upward
|
||||
3. `.agents/skills` sources, global first and then from the current directory upward
|
||||
4. `~/.config/opencode/skills`
|
||||
5. Project `.opencode/skills`, from the project root toward the current directory
|
||||
6. Explicit `skills` config entries, in config priority and array order
|
||||
|
||||
Avoid duplicate IDs unless an override is intentional.
|
||||
|
||||
## Runtime loading
|
||||
|
||||
At each model step, OpenCode advertises permitted skills that have a
|
||||
description and do not set `opencode/autoinvoke` to `false`. The advertisement
|
||||
contains only each skill's ID, name, and description; it does not add every
|
||||
skill body to the prompt.
|
||||
|
||||
When the model calls the `skill` tool with an exact ID, OpenCode:
|
||||
|
||||
1. Resolves the current winning definition for that ID
|
||||
2. Checks the `skill` permission for the selected agent
|
||||
3. Adds the Markdown body, without frontmatter, to the conversation
|
||||
4. Provides the skill's base directory and a sample of up to ten supporting file paths
|
||||
|
||||
Supporting file contents are not loaded automatically. The agent can read a
|
||||
referenced file when the skill instructs it to do so. The supporting-file
|
||||
sample is available for directory-based `SKILL.md` skills; flat Markdown skills
|
||||
receive no neighboring file list.
|
||||
|
||||
In the V2 CLI, skills appear as `/id` commands unless `slash` resolves to
|
||||
`false`. Selecting one appends the skill body as a skill message and resumes
|
||||
the session.
|
||||
|
||||
## Permissions
|
||||
|
||||
Permission rules use the `skill` action and the skill ID as the resource. Rules
|
||||
are evaluated in order, with the last matching rule winning:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"permissions": [
|
||||
{ "action": "skill", "resource": "*", "effect": "allow" },
|
||||
{ "action": "skill", "resource": "internal-*", "effect": "deny" },
|
||||
{ "action": "skill", "resource": "experimental-*", "effect": "ask" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`deny` removes matching skills from model-facing discovery and rejects skill
|
||||
tool loading. `ask` advertises the skill but requests approval when the model
|
||||
loads it. The same rules can be placed under an individual
|
||||
`agents.<id>.permissions` array.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If a skill is missing or loads the wrong content:
|
||||
|
||||
1. Confirm the file is either a root-level `*.md` or a nested file named exactly `SKILL.md`.
|
||||
2. Check the path-derived ID rather than the frontmatter `name`.
|
||||
3. Add a `description` if the skill should be advertised to the model.
|
||||
4. Check `opencode/autoinvoke` and the selected agent's `skill` permissions.
|
||||
5. Look for a later source defining the same ID.
|
||||
6. For HTTP catalogs, verify `index.json`, same-origin file paths, and a changed `version`.
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
---
|
||||
title: "Undo"
|
||||
description: ""
|
||||
---
|
||||
|
||||
OpenCode snapshots let the default interactive TUI roll back conversation history and related file changes. They are a
|
||||
convenience for revising recent work, not a replacement for Git commits or backups.
|
||||
|
||||
## Configuration
|
||||
|
||||
Snapshots are enabled by default. Set `snapshots` to `false` in your [configuration](/docs/config#snapshots) to stop capturing
|
||||
filesystem state:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"snapshots": false
|
||||
}
|
||||
```
|
||||
|
||||
Filesystem snapshots require a Git repository. With snapshots disabled, unavailable, or missing, undo can still stage a
|
||||
conversation rollback, but it has no captured file state to restore. Disabling snapshots does not delete snapshots that
|
||||
were already stored.
|
||||
|
||||
## What is captured
|
||||
|
||||
For each model step, OpenCode attempts to capture the worktree immediately before the model call and after a cleanly
|
||||
completed step. It records the paths changed between those two points on the assistant message.
|
||||
|
||||
Snapshots use a separate internal Git object database in the OpenCode data directory. They do not create commits, move
|
||||
branches, or intentionally modify your repository's Git index. Capture is limited to the session's active directory, which
|
||||
may be a subdirectory of the repository.
|
||||
|
||||
Within that directory, snapshots include tracked files and untracked files that are not ignored by Git. An individual
|
||||
untracked file larger than 2 MiB is excluded. Ignored files, files outside the active directory, and changes to Git
|
||||
metadata are not captured.
|
||||
|
||||
During undo, OpenCode does not check out an entire tree. It restores only paths attributed to cleanly completed assistant
|
||||
steps after the selected conversation boundary. Each path is restored to its state before the first affected step.
|
||||
|
||||
## Undo
|
||||
|
||||
Wait for the session to become idle, then run:
|
||||
|
||||
```text
|
||||
/undo
|
||||
```
|
||||
|
||||
The TUI finds the latest non-empty user message and stages a revert at that message:
|
||||
|
||||
- The selected user message and every later message are hidden, but not deleted yet.
|
||||
- The selected message's text, attachments, and agent mentions are placed in the composer for revision.
|
||||
- Captured files changed by the affected assistant steps are restored to their earlier contents. Files created by those
|
||||
steps are removed when they did not exist in the earlier snapshot.
|
||||
- A summary shows the staged message count and restored paths.
|
||||
|
||||
Running `/undo` again moves the staged boundary to an earlier user message. OpenCode keeps the filesystem state from
|
||||
immediately before the first undo as the redo baseline, so repeated undos form one wider staged revert rather than a redo
|
||||
stack.
|
||||
|
||||
<Warning>
|
||||
Sending a new prompt while an undo is staged commits the revert. The hidden message range is removed from the active
|
||||
session history, the currently reverted files are kept, and redo is no longer available.
|
||||
</Warning>
|
||||
|
||||
## Redo
|
||||
|
||||
While a revert is staged, run:
|
||||
|
||||
```text
|
||||
/redo
|
||||
```
|
||||
|
||||
Redo clears the staged boundary, makes the hidden messages visible again, and restores affected files to their exact state
|
||||
immediately before the first undo. It does not rerun the model. After multiple undos, one redo restores the whole staged
|
||||
range; there is no step-by-step redo stack.
|
||||
|
||||
## Revert a message
|
||||
|
||||
The TUI's **Message Actions** menu also provides **Revert**. It stages the selected message as the conversation boundary
|
||||
and uses the same file restoration and redo behavior, but it does not copy that message into the composer.
|
||||
|
||||
For a conversation-and-files rollback, select a user message. If an assistant message is selected, that message is hidden,
|
||||
but only file changes attributed to later assistant steps are restored; the selected assistant message's own file changes
|
||||
are not included.
|
||||
|
||||
## Limitations and safety
|
||||
|
||||
- Capture is best effort. A failed capture is logged and the model step continues, so conversation rollback may have no
|
||||
matching file rollback.
|
||||
- Interrupted or failed steps do not receive a completed end snapshot. File changes made before the failure may remain.
|
||||
- Shell commands can change databases, services, processes, network resources, Git state, ignored build output, or files
|
||||
outside the active directory. Undo and redo do not reverse those side effects.
|
||||
- Undo overwrites the current contents of affected paths with older contents. Redo likewise overwrites those paths with
|
||||
the pre-undo state, including edits made after running undo.
|
||||
- Other processes can edit the worktree between capture and restore. The server rejects revert operations while the
|
||||
session is actively running, but it cannot protect against external editors or commands.
|
||||
- Snapshot objects can contain complete contents of tracked and non-ignored untracked files. They are stored locally in
|
||||
the OpenCode data directory; do not treat snapshots as secret-free metadata.
|
||||
- Undo is not secure erasure. Committing a revert removes messages from the active projection, not from durable session
|
||||
history or existing snapshot storage.
|
||||
|
||||
Review the staged file summary and your Git diff before continuing. Commit or back up important work independently before
|
||||
using undo on a dirty worktree.
|
||||
|
||||
<Note>
|
||||
`/undo` and `/redo` are interactive TUI commands. The non-interactive `run` command does not provide them.
|
||||
</Note>
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
---
|
||||
title: "Troubleshooting"
|
||||
description: "Diagnose OpenCode startup, server, and session issues."
|
||||
---
|
||||
|
||||
<Tip>
|
||||
You can ask OpenCode to debug itself. Describe the problem and ask it to use this troubleshooting page; it can read
|
||||
the steps below, inspect its service and logs, and help identify the issue.
|
||||
</Tip>
|
||||
|
||||
OpenCode runs as two processes: the TUI is a client, while a background server owns sessions, plugins, permissions, and
|
||||
other application state. Start by determining whether an issue is in the client, the shared server, or a specific project.
|
||||
|
||||
## Check the background service
|
||||
|
||||
Show the current server status:
|
||||
|
||||
```bash
|
||||
opencode2 service status
|
||||
```
|
||||
|
||||
Verify that its API is healthy:
|
||||
|
||||
```bash
|
||||
opencode2 api get /api/health
|
||||
```
|
||||
|
||||
If the service is stuck or unhealthy, restart it:
|
||||
|
||||
```bash
|
||||
opencode2 service restart
|
||||
```
|
||||
|
||||
From inside the TUI, run `/restart` to restart the managed service and reconnect:
|
||||
|
||||
```text
|
||||
/restart
|
||||
```
|
||||
|
||||
You can also stop and start it explicitly:
|
||||
|
||||
```bash
|
||||
opencode2 service stop
|
||||
opencode2 service start
|
||||
```
|
||||
|
||||
<Note>
|
||||
OpenCode normally discovers or starts the shared background service automatically. The service commands are only
|
||||
needed when diagnosing its lifecycle.
|
||||
</Note>
|
||||
|
||||
## Run an isolated session
|
||||
|
||||
Use standalone mode to run the TUI with a private server that exits with it:
|
||||
|
||||
```bash
|
||||
opencode2 --standalone
|
||||
```
|
||||
|
||||
If an issue disappears in standalone mode, it is likely related to the shared background service rather than the TUI or
|
||||
project itself.
|
||||
|
||||
## Inspect the API
|
||||
|
||||
The `api` command uses the same discovery and authentication flow as the TUI. It accepts either an HTTP method and path or
|
||||
an OpenAPI operation ID.
|
||||
|
||||
See the [API reference](/docs/api) for all endpoints and operation IDs.
|
||||
|
||||
Pass a JSON request body with `--data` or `-d`, and add headers with `--header` or `-H`.
|
||||
|
||||
<Warning>
|
||||
Running `opencode2 api` may start the background service when no compatible healthy service is available.
|
||||
</Warning>
|
||||
|
||||
## Read logs
|
||||
|
||||
Installed builds write logs to:
|
||||
|
||||
```text
|
||||
~/.local/share/opencode/log/opencode.log
|
||||
```
|
||||
|
||||
Follow the log while reproducing the problem:
|
||||
|
||||
```bash
|
||||
tail -f ~/.local/share/opencode/log/opencode.log
|
||||
```
|
||||
|
||||
Each line includes a process `run` ID and a `role` field. Use `role=cli` for TUI and command startup, and `role=server` for
|
||||
session, provider, plugin, permission, and tool activity.
|
||||
|
||||
```bash
|
||||
grep 'role=cli' ~/.local/share/opencode/log/opencode.log
|
||||
grep 'role=server' ~/.local/share/opencode/log/opencode.log
|
||||
grep 'run=8fc3b1d5' ~/.local/share/opencode/log/opencode.log
|
||||
```
|
||||
|
||||
Increase verbosity for one reproduction:
|
||||
|
||||
```bash
|
||||
OPENCODE_LOG_LEVEL=DEBUG opencode2
|
||||
```
|
||||
|
||||
## Service files
|
||||
|
||||
The shared server registers itself at:
|
||||
|
||||
```text
|
||||
~/.local/state/opencode/service.json
|
||||
```
|
||||
|
||||
Its private service configuration is stored separately at:
|
||||
|
||||
```text
|
||||
~/.config/opencode/service.json
|
||||
```
|
||||
|
||||
The database normally lives at:
|
||||
|
||||
```text
|
||||
~/.local/share/opencode/opencode-next.db
|
||||
```
|
||||
|
||||
`OPENCODE_DB` can override the database location.
|
||||
|
||||
<Warning>
|
||||
Do not delete or edit service files or the database while troubleshooting. Use the service commands to manage the
|
||||
daemon, and make a backup before inspecting persistent data with external tools.
|
||||
</Warning>
|
||||
|
||||
## Explicit servers
|
||||
|
||||
When connecting with `--server`, set `OPENCODE_PASSWORD` if the server requires authentication:
|
||||
|
||||
```bash
|
||||
OPENCODE_PASSWORD=secret opencode2 --server http://127.0.0.1:4096
|
||||
```
|
||||
|
||||
The CLI checks the server before opening the TUI and reports whether it is unreachable, requires a password, or rejected
|
||||
the supplied password.
|
||||
|
||||
## Report an issue
|
||||
|
||||
Include the following when reporting a reproducible problem:
|
||||
|
||||
- Output from `opencode2 --version`
|
||||
- Output from `opencode2 service status`
|
||||
- The smallest sequence of steps that reproduces the issue
|
||||
- Whether the issue also occurs with `opencode2 --standalone`
|
||||
- Relevant log lines, including their `run` and `role` fields
|
||||
|
||||
Remove API keys, authorization headers, prompts, file contents, and other sensitive data before sharing logs.
|
||||
|
||||
## Local development
|
||||
|
||||
When working from the OpenCode repository, run V2 commands from the repository root:
|
||||
|
||||
```bash
|
||||
bun dev
|
||||
```
|
||||
|
||||
The local development channel keeps its logs, SQLite database, and service registration separate from installed builds:
|
||||
|
||||
```text
|
||||
~/.local/share/opencode/log/opencode-local.log
|
||||
~/.local/share/opencode/opencode-local.db
|
||||
~/.local/state/opencode/service-local.json
|
||||
```
|
||||
|
||||
Use the same diagnostics through the package development command:
|
||||
|
||||
```bash
|
||||
bun dev service status
|
||||
bun dev service restart
|
||||
bun dev api get /api/health
|
||||
```
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: "API Reference"
|
||||
description: "OpenCode HTTP API."
|
||||
---
|
||||
|
||||
The endpoint reference is generated from the current OpenCode V2 [OpenAPI specification](/openapi.json).
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"title": "API",
|
||||
"description": "Use the OpenCode HTTP API.",
|
||||
"root": true,
|
||||
"pages": ["index"]
|
||||
}
|
||||
61
packages/www/content/docs/build/client.mdx
vendored
61
packages/www/content/docs/build/client.mdx
vendored
|
|
@ -6,12 +6,12 @@ description: "Connect an application to the OpenCode HTTP API."
|
|||
`@opencode-ai/client` is the generated TypeScript client for the OpenCode HTTP
|
||||
API. Use it when your application connects to an OpenCode server over the
|
||||
network. Its types and methods are generated from the same contract as the
|
||||
[API reference](/docs/api).
|
||||
[API reference](/api).
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
The V2 API and client are beta. Method names, inputs, and outputs may change
|
||||
before the stable release.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Install
|
||||
|
||||
|
|
@ -70,6 +70,48 @@ for await (const event of client.event.subscribe()) {
|
|||
}
|
||||
```
|
||||
|
||||
## Local background service
|
||||
|
||||
The main client entrypoints are browser-compatible and do not include local
|
||||
process management. In a Node application, import the native Promise service
|
||||
API from `@opencode-ai/client/service`.
|
||||
|
||||
- `Service.discover()` returns a healthy registered endpoint without starting
|
||||
a process.
|
||||
- `Service.ensure()` returns a compatible service, starting one when needed.
|
||||
- `Service.stop()` stops the exact registered service instance.
|
||||
- `Service.headers(endpoint)` creates the authentication headers for a client.
|
||||
|
||||
```ts
|
||||
import { OpenCode } from "@opencode-ai/client"
|
||||
import { Service } from "@opencode-ai/client/service"
|
||||
|
||||
const endpoint = await Service.ensure()
|
||||
const client = OpenCode.make({
|
||||
baseUrl: endpoint.url,
|
||||
headers: Service.headers(endpoint),
|
||||
})
|
||||
|
||||
const health = await client.health.get()
|
||||
```
|
||||
|
||||
`Service.ensure()` accepts an optional registration file, required version,
|
||||
service command, and `onStart` callback:
|
||||
|
||||
```ts
|
||||
const endpoint = await Service.ensure({
|
||||
file: "/var/run/opencode/service.json",
|
||||
version: "2.0.0",
|
||||
command: ["opencode", "serve", "--service"],
|
||||
onStart(reason, previousVersion) {
|
||||
console.log(reason, previousVersion)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Omit these options to use the standard registration path and
|
||||
`opencode serve --service` command.
|
||||
|
||||
## Effect
|
||||
|
||||
OpenCode provides a first-class Effect client through the
|
||||
|
|
@ -106,16 +148,11 @@ const session = await Effect.runPromise(
|
|||
Streaming operations, including `client.event.subscribe()` and
|
||||
`client.session.log(...)`, return Effect `Stream` values.
|
||||
|
||||
### Service
|
||||
### Local background service
|
||||
|
||||
`Service` discovers and manages the local OpenCode background service from a
|
||||
Node application:
|
||||
|
||||
- `Service.discover()` returns a healthy registered endpoint without starting
|
||||
a process.
|
||||
- `Service.ensure()` returns a compatible service, starting one when needed.
|
||||
- `Service.stop()` stops the registered service.
|
||||
- `Service.headers(endpoint)` creates the authentication headers for a client.
|
||||
The Node-only `@opencode-ai/client/effect/service` entrypoint exposes the same
|
||||
operations as Effect values. Add `@effect/platform-node` and provide its
|
||||
filesystem layer when running them.
|
||||
|
||||
```sh
|
||||
bun add @effect/platform-node
|
||||
|
|
|
|||
11
packages/www/content/docs/build/index.mdx
vendored
11
packages/www/content/docs/build/index.mdx
vendored
|
|
@ -1,24 +1,23 @@
|
|||
---
|
||||
title: "Build"
|
||||
description: "Build on the engine used by millions daily."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Extend OpenCode" href="/docs/build/plugins">
|
||||
<Card title="Extend OpenCode" href="/build/plugins">
|
||||
Build plugins that add tools, integrations, commands, agents, and custom behavior while keeping the rest of OpenCode
|
||||
intact.
|
||||
</Card>
|
||||
<Card title="Run it as a server" href="/docs/build/client">
|
||||
<Card title="Run it as a server" href="/build/client">
|
||||
Connect to OpenCode with the same client used by the TUI and desktop app, then build any interface, workflow, or agent
|
||||
experience around it.
|
||||
</Card>
|
||||
<Card title="Embed it" href="/docs/build/sdk">
|
||||
<Card title="Embed it" href="/build/sdk">
|
||||
Embed OpenCode directly into your application and build a completely custom agent, interface, or developer product
|
||||
around it.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
The plugin API, client, and SDK are still being finalized during beta and may change before OpenCode 2.0 is stable.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
|
|
|||
7
packages/www/content/docs/build/meta.json
vendored
7
packages/www/content/docs/build/meta.json
vendored
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"title": "Build",
|
||||
"description": "Extend and embed OpenCode.",
|
||||
"root": true,
|
||||
"defaultOpen": true,
|
||||
"pages": ["index", "plugins", "client", "sdk"]
|
||||
}
|
||||
6
packages/www/content/docs/build/meta.ts
vendored
Normal file
6
packages/www/content/docs/build/meta.ts
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { defineMeta } from "blume"
|
||||
|
||||
export default defineMeta({
|
||||
title: "Build",
|
||||
pages: ["index", "plugins", "client", "sdk"],
|
||||
})
|
||||
23
packages/www/content/docs/build/plugins.mdx
vendored
23
packages/www/content/docs/build/plugins.mdx
vendored
|
|
@ -7,10 +7,10 @@ Plugins extend OpenCode in-process. They can transform agents, models, commands,
|
|||
integrations, references, skills, and tools; intercept model requests and tool
|
||||
execution; and call a subset of the V2 client.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
The V2 plugin API is beta. Entrypoints, hooks, draft shapes, and configuration may change before the stable release.
|
||||
Use the `/v2` exports described on this page.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Load plugins
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ Use the object form to pass JSON configuration to the plugin. OpenCode passes
|
|||
`options` unchanged as `ctx.options`; omitted options become an empty object.
|
||||
The plugin owns validation and defaults for its options.
|
||||
|
||||
See [Config](/docs/config#locations) for configuration locations and precedence.
|
||||
See [Config](/config#locations) for configuration locations and precedence.
|
||||
Entries from all applicable files are processed from lowest to highest
|
||||
precedence rather than replacing the entire array.
|
||||
|
||||
|
|
@ -162,22 +162,22 @@ connections, and background tasks.
|
|||
|
||||
### Context
|
||||
|
||||
The plugin context is essentially an [OpenCode server client](/docs/build/client).
|
||||
The plugin context is essentially an [OpenCode server client](/build/client).
|
||||
Its read and action methods use the same inputs and responses as the client. It
|
||||
adds plugin-only methods for transforms, runtime hooks, reloads, registrations,
|
||||
and plugin options.
|
||||
|
||||
| Capability | Available operations |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| `ctx.agent` | `list`, `transform`, `reload` |
|
||||
| `ctx.agent` | `list`, `get`, `transform`, `reload` |
|
||||
| `ctx.catalog.provider` | `list`, `get` |
|
||||
| `ctx.catalog.model` | `list`, `default` |
|
||||
| `ctx.catalog.model` | `list`, `get`, `default` |
|
||||
| `ctx.catalog` | `transform`, `reload` |
|
||||
| `ctx.command` | `list`, `transform`, `reload` |
|
||||
| `ctx.integration` | `list`, `get`, `connect`, `attempt`, `transform`, `reload`, and connection lookup/resolution |
|
||||
| `ctx.plugin` | `list` currently active plugin IDs |
|
||||
| `ctx.reference` | `list`, `transform`, `reload` |
|
||||
| `ctx.session` | `create`, `get`, `prompt`, `command`, `interrupt`, and `hook` |
|
||||
| `ctx.session` | `create`, `get`, `prompt`, `command`, `synthetic`, `interrupt`, and `hook` |
|
||||
| `ctx.skill` | `list`, `transform`, `reload` |
|
||||
| `ctx.tool` | `transform` and `hook` |
|
||||
| `ctx.aisdk` | `hook` |
|
||||
|
|
@ -403,7 +403,7 @@ opencode2 api get /api/plugin
|
|||
```
|
||||
|
||||
If a plugin is absent, check the server log described in
|
||||
[Troubleshooting](/docs/troubleshooting#read-logs). Invalid modules and setup failures are
|
||||
[Troubleshooting](/troubleshooting#read-logs). Invalid modules and setup failures are
|
||||
logged; one failing package does not prevent unrelated valid packages from
|
||||
being resolved.
|
||||
|
||||
|
|
@ -440,6 +440,7 @@ fibers, and registrations are released when the plugin reloads or unloads.
|
|||
OpenCode does not expose its private Core services to the plugin; use the
|
||||
capabilities on `ctx`.
|
||||
|
||||
Typed tools can use `Schema` from `effect` and the contracts exported from
|
||||
`@opencode-ai/plugin/v2/effect/tool`. Their executors return an Effect and may
|
||||
fail with the typed tool failure channel.
|
||||
Typed tools can use `Schema` from `effect` and `Tool.make` from
|
||||
`@opencode-ai/plugin/v2/effect/tool`. Effect and Promise plugins use the same
|
||||
`tools.add(name, tool, options?)` registration shape. Effect executors
|
||||
return an Effect and may fail with the typed tool failure channel.
|
||||
|
|
|
|||
25
packages/www/content/docs/build/sdk.mdx
vendored
25
packages/www/content/docs/build/sdk.mdx
vendored
|
|
@ -1,18 +1,27 @@
|
|||
---
|
||||
title: "SDK"
|
||||
description: "Embed an OpenCode host in an Effect application."
|
||||
description: "Embed OpenCode directly in your application."
|
||||
---
|
||||
|
||||
`@opencode-ai/sdk-next` is the Effect-native SDK for applications that need to
|
||||
host OpenCode in-process. Unlike the [network client](/docs/build/client), it assembles the
|
||||
OpenCode server and routes API calls through its HTTP router in memory. It opens
|
||||
no HTTP listener and adds no network hop between the client and server.
|
||||
We're working on a general-purpose SDK for embedding OpenCode directly inside
|
||||
your application. The regular SDK is coming soon.
|
||||
|
||||
<Warning>
|
||||
An Effect-native version is available now for applications built with Effect.
|
||||
Its current documentation is below. For other applications, run OpenCode as a
|
||||
server and use the [TypeScript client](/build/client) in the meantime.
|
||||
|
||||
## Effect
|
||||
|
||||
`@opencode-ai/sdk-next` hosts OpenCode in-process. Unlike the
|
||||
[network client](/build/client), it assembles the OpenCode server and routes API
|
||||
calls through its HTTP router in memory. It opens no HTTP listener and adds no
|
||||
network hop between the client and server.
|
||||
|
||||
<Callout type="warning">
|
||||
The V2 SDK is beta and currently private to the OpenCode workspace. It is not
|
||||
published for external installation yet, and its package name and API may
|
||||
change before release.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Create a host
|
||||
|
||||
|
|
@ -72,4 +81,4 @@ const active = await Effect.runPromise(
|
|||
Call `opencode.plugin(...)` to register an embedded V2 plugin. Embedded plugins
|
||||
use the same discovery and location-scoped activation path as configured
|
||||
plugins. The SDK also exports `Tool` for plugin-defined tools. See the
|
||||
[Plugins guide](/docs/build/plugins) for the plugin shape and available hooks.
|
||||
[Plugins guide](/build/plugins) for the plugin shape and available hooks.
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ title: "Config"
|
|||
description: ""
|
||||
---
|
||||
|
||||
<Tip>
|
||||
<Callout type="tip">
|
||||
You shouldn't have to configure OpenCode manually. Ask OpenCode to update its configuration for you.
|
||||
</Tip>
|
||||
</Callout>
|
||||
|
||||
## Format
|
||||
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
---
|
||||
title: "Intro"
|
||||
title: "Get started"
|
||||
description: "Get started with OpenCode."
|
||||
---
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
These docs are for the beta version of OpenCode, which will become OpenCode 2.0. The beta is still changing: we may
|
||||
wipe your data, things may break, and APIs, configuration, and plugin APIs may change.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Install
|
||||
|
||||
<Note>The curl install script is not available in beta.</Note>
|
||||
<Callout type="note">The curl install script is not available in beta.</Callout>
|
||||
|
||||
You can also install it with the following package managers.
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ You can also install it with the following package managers.
|
|||
The package uses a trusted postinstall script to select the native binary for your platform. The Bun and pnpm commands
|
||||
above explicitly allow that script to run.
|
||||
|
||||
<Note>During beta, the binary is called `opencode2`.</Note>
|
||||
<Callout type="note">During beta, the binary is called `opencode2`.</Callout>
|
||||
|
||||
### Homebrew
|
||||
|
||||
|
|
@ -52,11 +52,11 @@ Arch Linux installation is not available in beta.
|
|||
|
||||
### Windows
|
||||
|
||||
<Tip>
|
||||
<Callout type="tip">
|
||||
For the best experience on Windows, install [Windows Subsystem for Linux
|
||||
(WSL)](https://learn.microsoft.com/windows/wsl/install), open your Linux distribution, and use one of the beta package
|
||||
manager commands above.
|
||||
</Tip>
|
||||
</Callout>
|
||||
|
||||
<Tabs>
|
||||
<Tab title="chocolatey">
|
||||
|
|
@ -119,7 +119,7 @@ You are now ready to use OpenCode in your project. Here are a few common workflo
|
|||
|
||||
Ask OpenCode to explain your codebase.
|
||||
|
||||
<Tip>Use `@` to fuzzy search for files in the project.</Tip>
|
||||
<Callout type="tip">Use `@` to fuzzy search for files in the project.</Callout>
|
||||
|
||||
```text
|
||||
How is authentication handled in @packages/functions/src/api/index.ts
|
||||
|
|
@ -135,7 +135,7 @@ Create a screen that shows recently deleted notes.
|
|||
From this screen, the user can restore a note or permanently delete it.
|
||||
```
|
||||
|
||||
<Tip>Give OpenCode plenty of context and examples.</Tip>
|
||||
<Callout type="tip">Give OpenCode plenty of context and examples.</Callout>
|
||||
|
||||
### Undo changes
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"title": "Documentation",
|
||||
"pages": ["(docs)", "build", "api"]
|
||||
}
|
||||
5
packages/www/content/docs/meta.ts
Normal file
5
packages/www/content/docs/meta.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { defineMeta } from "blume"
|
||||
|
||||
export default defineMeta({
|
||||
pages: ["index", "migrate-v1", "config", "troubleshooting", "configure", "build"],
|
||||
})
|
||||
|
|
@ -17,15 +17,15 @@ Existing server config files, agent definitions, command definitions, skills, an
|
|||
continue to work without changes. If one of these stops working in V2, treat it as a beta compatibility bug rather than
|
||||
an expected migration requirement.
|
||||
|
||||
<Tip>
|
||||
<Callout type="tip">
|
||||
Run `/report` if existing V1 functionality does not work in V2. The report skill collects diagnostics and helps you file
|
||||
a compatibility issue.
|
||||
</Tip>
|
||||
</Callout>
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
OpenCode 2.0 is in beta. Beta data may be wiped, features may break unintentionally, and the server and plugin APIs may
|
||||
continue to change.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
During the beta, OpenCode V1 and V2 use different executable names. You can keep using `opencode` for V1 while trying V2
|
||||
with `opencode2`.
|
||||
|
|
@ -551,7 +551,7 @@ Rename `plugin` to `plugins`. Replace a package-and-options tuple with an object
|
|||
V2 discovers local plugins from both `.opencode/plugin/` and `.opencode/plugins/`; use `.opencode/plugins/` for V2 files.
|
||||
Moving a file between these directories does not migrate its implementation.
|
||||
|
||||
<Warning>V1 plugins will not work in V2.</Warning>
|
||||
<Callout type="warning">V1 plugins will not work in V2.</Callout>
|
||||
|
||||
The config entry can be translated automatically, but plugin implementation code must be ported to the new API. The V2
|
||||
plugin API is still being finalized during beta, and detailed plugin migration guidance will be published when it is
|
||||
|
|
@ -3,10 +3,10 @@ title: "Troubleshooting"
|
|||
description: "Diagnose OpenCode startup, server, and session issues."
|
||||
---
|
||||
|
||||
<Tip>
|
||||
<Callout type="tip">
|
||||
You can ask OpenCode to debug itself. Describe the problem and ask it to use this troubleshooting page; it can read
|
||||
the steps below, inspect its service and logs, and help identify the issue.
|
||||
</Tip>
|
||||
</Callout>
|
||||
|
||||
OpenCode runs as two processes: the TUI is a client, while a background server owns sessions, plugins, permissions, and
|
||||
other application state. Start by determining whether an issue is in the client, the shared server, or a specific project.
|
||||
|
|
@ -44,10 +44,10 @@ opencode2 service stop
|
|||
opencode2 service start
|
||||
```
|
||||
|
||||
<Note>
|
||||
<Callout type="note">
|
||||
OpenCode normally discovers or starts the shared background service automatically. The service commands are only
|
||||
needed when diagnosing its lifecycle.
|
||||
</Note>
|
||||
</Callout>
|
||||
|
||||
## Run an isolated session
|
||||
|
||||
|
|
@ -69,9 +69,9 @@ See the [API reference](/api) for all endpoints and operation IDs.
|
|||
|
||||
Pass a JSON request body with `--data` or `-d`, and add headers with `--header` or `-H`.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
Running `opencode2 api` may start the background service when no compatible healthy service is available.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Read logs
|
||||
|
||||
|
|
@ -124,10 +124,10 @@ The database normally lives at:
|
|||
|
||||
`OPENCODE_DB` can override the database location.
|
||||
|
||||
<Warning>
|
||||
<Callout type="warning">
|
||||
Do not delete or edit service files or the database while troubleshooting. Use the service commands to manage the
|
||||
daemon, and make a backup before inspecting persistent data with external tools.
|
||||
</Warning>
|
||||
</Callout>
|
||||
|
||||
## Explicit servers
|
||||
|
||||
|
|
@ -1,41 +1,30 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/www",
|
||||
"version": "1.17.18",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev --host 0.0.0.0 --port 3000",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview --host 0.0.0.0",
|
||||
"pretypecheck": "fumadocs-mdx",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"dev": "bun run generate && blume dev --host --port 3000",
|
||||
"build": "bun run generate && blume build && bun script/prepare-cloudflare.ts",
|
||||
"deploy": "wrangler deploy --config dist/server/wrangler.json",
|
||||
"generate": "bun script/generate-theme-tokens.ts",
|
||||
"check:generated": "bun script/generate-theme-tokens.ts --check",
|
||||
"typecheck": "blume check",
|
||||
"validate": "blume validate",
|
||||
"doctor": "blume doctor"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.44.0",
|
||||
"@tailwindcss/vite": "4.3.2",
|
||||
"@tanstack/react-router": "1.170.17",
|
||||
"@tanstack/react-start": "1.168.27",
|
||||
"@tanstack/router-plugin": "1.168.19",
|
||||
"fumadocs-core": "16.11.1",
|
||||
"fumadocs-mdx": "15.1.0",
|
||||
"fumadocs-ui": "16.11.1",
|
||||
"react": "19.2.7",
|
||||
"react-dom": "19.2.7",
|
||||
"tailwindcss": "4.3.2",
|
||||
"vite": "8.1.4"
|
||||
"blume": "1.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mdx": "2.0.14",
|
||||
"@types/node": "catalog:",
|
||||
"@types/react": "19.2.17",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"@vitejs/plugin-react": "6.0.3",
|
||||
"typescript": "catalog:",
|
||||
"@astrojs/cloudflare": "14.1.4",
|
||||
"@types/bun": "catalog:",
|
||||
"astro": "7.1.3",
|
||||
"effect": "catalog:",
|
||||
"prettier": "3.6.2",
|
||||
"wrangler": "4.110.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
"node": ">=22.12"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
packages/www/pages/index.astro
Normal file
5
packages/www/pages/index.astro
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
export const prerender = false
|
||||
|
||||
return Astro.redirect(`${import.meta.env.BASE_URL}docs`, 308)
|
||||
---
|
||||
|
|
@ -55,7 +55,7 @@ const example = {
|
|||
} satisfies ThemeDocument
|
||||
Schema.decodeUnknownSync(ThemeDocument)(example)
|
||||
const output = await format(
|
||||
`{/* Generated by packages/docs/script/generate-theme-tokens.ts. Do not edit. */}
|
||||
`{/* Generated by packages/www/script/generate-theme-tokens.ts. Do not edit. */}
|
||||
|
||||
\`\`\`json title="my-theme.json"
|
||||
${JSON.stringify(example, null, 2)}
|
||||
|
|
@ -102,7 +102,7 @@ surfaces that need different contrast without changing the base theme.
|
|||
if (process.argv.includes("--check")) {
|
||||
const current = await Bun.file(target).text()
|
||||
if (current === output) process.exit(0)
|
||||
console.error("Generated theme token documentation is stale. Run `bun run generate` from packages/docs.")
|
||||
console.error("Generated theme token documentation is stale. Run `bun run generate` from packages/www.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
8
packages/www/script/prepare-cloudflare.ts
Normal file
8
packages/www/script/prepare-cloudflare.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
const path = "dist/server/wrangler.json"
|
||||
const config = await Bun.file(path).json()
|
||||
|
||||
delete config.kv_namespaces
|
||||
delete config.images
|
||||
delete config.previews
|
||||
|
||||
await Bun.write(path, JSON.stringify(config))
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{/* Generated by packages/docs/script/generate-theme-tokens.ts. Do not edit. */}
|
||||
{/* Generated by packages/www/script/generate-theme-tokens.ts. Do not edit. */}
|
||||
|
||||
```json title="my-theme.json"
|
||||
{
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import { defineDocs } from "fumadocs-mdx/config"
|
||||
|
||||
export const docs = defineDocs({
|
||||
dir: "content/docs",
|
||||
})
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
import { Children, isValidElement, type ComponentProps, type ReactNode } from "react"
|
||||
import { Callout } from "fumadocs-ui/components/callout"
|
||||
import { Card, Cards } from "fumadocs-ui/components/card"
|
||||
import { Tab as FumadocsTab, Tabs as FumadocsTabs } from "fumadocs-ui/components/tabs"
|
||||
import defaultMdxComponents from "fumadocs-ui/mdx"
|
||||
import type { MDXComponents } from "mdx/types"
|
||||
|
||||
function Tip(props: { children: ReactNode }) {
|
||||
return <Callout type="idea">{props.children}</Callout>
|
||||
}
|
||||
|
||||
function Note(props: { children: ReactNode }) {
|
||||
return <Callout>{props.children}</Callout>
|
||||
}
|
||||
|
||||
function Warning(props: { children: ReactNode }) {
|
||||
return <Callout type="warn">{props.children}</Callout>
|
||||
}
|
||||
|
||||
function Tab(props: { title?: string; value?: string; children: ReactNode }) {
|
||||
return <FumadocsTab value={props.value ?? props.title}>{props.children}</FumadocsTab>
|
||||
}
|
||||
|
||||
function Tabs(props: { children: ReactNode }) {
|
||||
const items = Children.toArray(props.children).flatMap((child) => {
|
||||
if (!isValidElement<ComponentProps<typeof Tab>>(child)) return []
|
||||
const value = child.props.value ?? child.props.title
|
||||
return value ? [value] : []
|
||||
})
|
||||
return <FumadocsTabs items={items}>{props.children}</FumadocsTabs>
|
||||
}
|
||||
|
||||
function CardGroup(props: { children: ReactNode; cols?: number }) {
|
||||
return <Cards>{props.children}</Cards>
|
||||
}
|
||||
|
||||
export function getMdxComponents(components?: MDXComponents) {
|
||||
return {
|
||||
...defaultMdxComponents,
|
||||
Tip,
|
||||
Note,
|
||||
Warning,
|
||||
Tabs,
|
||||
Tab,
|
||||
CardGroup,
|
||||
Card,
|
||||
...components,
|
||||
} satisfies MDXComponents
|
||||
}
|
||||
|
||||
export const useMDXComponents = getMdxComponents
|
||||
|
||||
declare global {
|
||||
type MDXProvidedComponents = ReturnType<typeof getMdxComponents>
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"
|
||||
|
||||
export function baseOptions(): BaseLayoutProps {
|
||||
return {
|
||||
nav: {
|
||||
title: "OpenCode",
|
||||
url: "/",
|
||||
},
|
||||
links: [
|
||||
{
|
||||
text: "GitHub",
|
||||
url: "https://github.com/anomalyco/opencode",
|
||||
external: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import { docs } from "collections/server"
|
||||
import { loader } from "fumadocs-core/source"
|
||||
|
||||
export const source = loader({
|
||||
baseUrl: "/docs",
|
||||
source: docs.toFumadocsSource(),
|
||||
})
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/* eslint-disable */
|
||||
|
||||
// @ts-nocheck
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
// This file was automatically generated by TanStack Router.
|
||||
// You should NOT make any changes in this file as it will be overwritten.
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as IndexRouteImport } from './routes/index'
|
||||
import { Route as DocsSplatRouteImport } from './routes/docs/$'
|
||||
import { Route as ApiSearchRouteImport } from './routes/api/search'
|
||||
|
||||
const IndexRoute = IndexRouteImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const DocsSplatRoute = DocsSplatRouteImport.update({
|
||||
id: '/docs/$',
|
||||
path: '/docs/$',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const ApiSearchRoute = ApiSearchRouteImport.update({
|
||||
id: '/api/search',
|
||||
path: '/api/search',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/api/search': typeof ApiSearchRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
}
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/api/search': typeof ApiSearchRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
}
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
'/': typeof IndexRoute
|
||||
'/api/search': typeof ApiSearchRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
}
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
fullPaths: '/' | '/api/search' | '/docs/$'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to: '/' | '/api/search' | '/docs/$'
|
||||
id: '__root__' | '/' | '/api/search' | '/docs/$'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
ApiSearchRoute: typeof ApiSearchRoute
|
||||
DocsSplatRoute: typeof DocsSplatRoute
|
||||
}
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/': {
|
||||
id: '/'
|
||||
path: '/'
|
||||
fullPath: '/'
|
||||
preLoaderRoute: typeof IndexRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/docs/$': {
|
||||
id: '/docs/$'
|
||||
path: '/docs/$'
|
||||
fullPath: '/docs/$'
|
||||
preLoaderRoute: typeof DocsSplatRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/api/search': {
|
||||
id: '/api/search'
|
||||
path: '/api/search'
|
||||
fullPath: '/api/search'
|
||||
preLoaderRoute: typeof ApiSearchRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
ApiSearchRoute: ApiSearchRoute,
|
||||
DocsSplatRoute: DocsSplatRoute,
|
||||
}
|
||||
export const routeTree = rootRouteImport
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
||||
import type { getRouter } from './router.tsx'
|
||||
import type { createStart } from '@tanstack/react-start'
|
||||
declare module '@tanstack/react-start' {
|
||||
interface Register {
|
||||
ssr: true
|
||||
router: Awaited<ReturnType<typeof getRouter>>
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import { createRouter } from "@tanstack/react-router"
|
||||
import { routeTree } from "./routeTree.gen"
|
||||
|
||||
export function getRouter() {
|
||||
return createRouter({
|
||||
routeTree,
|
||||
scrollRestoration: true,
|
||||
defaultPreload: "intent",
|
||||
})
|
||||
}
|
||||
|
||||
declare module "@tanstack/react-router" {
|
||||
interface Register {
|
||||
router: ReturnType<typeof getRouter>
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
import { HeadContent, Scripts, createRootRoute } from "@tanstack/react-router"
|
||||
import { RootProvider } from "fumadocs-ui/provider/tanstack"
|
||||
import type { ReactNode } from "react"
|
||||
import styles from "../styles.css?url"
|
||||
|
||||
export const Route = createRootRoute({
|
||||
head: () => ({
|
||||
meta: [
|
||||
{ charSet: "utf-8" },
|
||||
{ name: "viewport", content: "width=device-width, initial-scale=1" },
|
||||
{ title: "OpenCode" },
|
||||
{
|
||||
name: "description",
|
||||
content: "The open source AI coding agent.",
|
||||
},
|
||||
],
|
||||
links: [{ rel: "stylesheet", href: styles }],
|
||||
}),
|
||||
shellComponent: RootDocument,
|
||||
})
|
||||
|
||||
function RootDocument(props: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<HeadContent />
|
||||
</head>
|
||||
<body>
|
||||
<RootProvider>{props.children}</RootProvider>
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { createFromSource } from "fumadocs-core/search/server"
|
||||
import { source } from "@/lib/source"
|
||||
|
||||
const search = createFromSource(source, {
|
||||
language: "english",
|
||||
})
|
||||
|
||||
export const Route = createFileRoute("/api/search")({
|
||||
server: {
|
||||
handlers: {
|
||||
GET: ({ request }) => search.GET(request),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import { createFileRoute, notFound } from "@tanstack/react-router"
|
||||
import { createServerFn } from "@tanstack/react-start"
|
||||
import browserCollections from "collections/browser"
|
||||
import { useFumadocsLoader } from "fumadocs-core/source/client"
|
||||
import { DocsLayout } from "fumadocs-ui/layouts/docs"
|
||||
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from "fumadocs-ui/layouts/docs/page"
|
||||
import { Suspense } from "react"
|
||||
import { getMdxComponents } from "@/components/mdx"
|
||||
import { baseOptions } from "@/lib/layout"
|
||||
import { source } from "@/lib/source"
|
||||
|
||||
export const Route = createFileRoute("/docs/$")({
|
||||
loader: async ({ params }) => {
|
||||
const slugs = params._splat?.split("/").filter(Boolean) ?? []
|
||||
const data = await loadPage({ data: slugs })
|
||||
await clientLoader.preload(data.path)
|
||||
return data
|
||||
},
|
||||
head: ({ loaderData }) => ({
|
||||
meta: [
|
||||
{ title: `${loaderData?.title ?? "Docs"} | OpenCode` },
|
||||
{ name: "description", content: loaderData?.description ?? "OpenCode documentation." },
|
||||
],
|
||||
}),
|
||||
component: Documentation,
|
||||
})
|
||||
|
||||
const loadPage = createServerFn({ method: "GET" })
|
||||
.validator((slugs: string[]) => slugs)
|
||||
.handler(async ({ data: slugs }) => {
|
||||
const page = source.getPage(slugs)
|
||||
if (!page) throw notFound()
|
||||
return {
|
||||
path: page.path,
|
||||
title: page.data.title,
|
||||
description: page.data.description,
|
||||
tree: await source.serializePageTree(source.getPageTree()),
|
||||
}
|
||||
})
|
||||
|
||||
const clientLoader = browserCollections.docs.createClientLoader({
|
||||
component({ toc, frontmatter, default: Content }) {
|
||||
return (
|
||||
<DocsPage toc={toc}>
|
||||
<DocsTitle>{frontmatter.title}</DocsTitle>
|
||||
<DocsDescription>{frontmatter.description}</DocsDescription>
|
||||
<DocsBody>
|
||||
<Content components={getMdxComponents()} />
|
||||
</DocsBody>
|
||||
</DocsPage>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
function Documentation() {
|
||||
const data = useFumadocsLoader(Route.useLoaderData())
|
||||
return (
|
||||
<DocsLayout {...baseOptions()} tree={data.tree} tabMode="top">
|
||||
<Suspense>{clientLoader.useContent(data.path)}</Suspense>
|
||||
</DocsLayout>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { createFileRoute } from "@tanstack/react-router"
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: Home,
|
||||
})
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<main className="home">
|
||||
<p className="home-kicker">OpenCode</p>
|
||||
<h1>The open source AI coding agent</h1>
|
||||
<p className="home-copy">The new opencode.ai SSR site is running. The V2 documentation is available now.</p>
|
||||
<a className="home-link" href="/docs">
|
||||
Read the docs
|
||||
</a>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
@import "tailwindcss";
|
||||
@import "fumadocs-ui/css/neutral.css";
|
||||
@import "fumadocs-ui/css/preset.css";
|
||||
|
||||
:root {
|
||||
--site-background: #f7f7f5;
|
||||
--site-foreground: #171717;
|
||||
--site-border: #d8d8d2;
|
||||
--site-accent: #3b7dd8;
|
||||
--fd-layout-width: 90rem;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Fumadocs 16.11 stretches top layout tabs across the main grid row. */
|
||||
#nd-docs-layout > div:has(> a[href="/docs/build"], > a[href="/docs/api"]) {
|
||||
align-self: start;
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.home {
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
align-content: center;
|
||||
justify-items: start;
|
||||
gap: 1.5rem;
|
||||
padding: clamp(1.5rem, 7vw, 7rem);
|
||||
color: var(--site-foreground);
|
||||
background: var(--site-background);
|
||||
}
|
||||
|
||||
.home-kicker,
|
||||
.home-copy,
|
||||
.home h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.home-kicker {
|
||||
font:
|
||||
600 0.75rem/1.2 ui-monospace,
|
||||
monospace;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.home h1 {
|
||||
max-width: 13ch;
|
||||
font:
|
||||
500 clamp(3rem, 9vw, 8rem) / 0.92 ui-monospace,
|
||||
monospace;
|
||||
letter-spacing: -0.07em;
|
||||
}
|
||||
|
||||
.home-copy {
|
||||
max-width: 42rem;
|
||||
font:
|
||||
400 clamp(1rem, 2vw, 1.25rem) / 1.5 ui-monospace,
|
||||
monospace;
|
||||
}
|
||||
|
||||
.home-link {
|
||||
display: inline-block;
|
||||
padding: 0.8rem 1rem;
|
||||
color: var(--site-background);
|
||||
background: var(--site-foreground);
|
||||
font:
|
||||
500 0.875rem/1 ui-monospace,
|
||||
monospace;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.home-link:hover {
|
||||
background: var(--site-accent);
|
||||
}
|
||||
|
|
@ -1,24 +1,7 @@
|
|||
{
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "source.config.ts", "vite.config.ts", ".source/**/*.ts"],
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"include": [".blume/.astro/types.d.ts", ".blume/src/env.d.ts", "**/*"],
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"jsx": "react-jsx",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"types": ["vite/client"],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"collections/*": ["./.source/*"]
|
||||
}
|
||||
"types": ["bun"]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import { cloudflare } from "@cloudflare/vite-plugin"
|
||||
import tailwindcss from "@tailwindcss/vite"
|
||||
import { tanstackStart } from "@tanstack/react-start/plugin/vite"
|
||||
import viteReact from "@vitejs/plugin-react"
|
||||
import mdx from "fumadocs-mdx/vite"
|
||||
import { defineConfig } from "vite"
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
tsconfigPaths: true,
|
||||
},
|
||||
plugins: [
|
||||
cloudflare({
|
||||
viteEnvironment: { name: "ssr" },
|
||||
configPath: process.env.SST_WRANGLER_PATH,
|
||||
}),
|
||||
tailwindcss(),
|
||||
mdx(),
|
||||
tanstackStart(),
|
||||
viteReact(),
|
||||
],
|
||||
})
|
||||
|
|
@ -1,7 +1,41 @@
|
|||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "opencode-www",
|
||||
"compatibility_date": "2026-07-12",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
"main": "@tanstack/react-start/server-entry",
|
||||
"compatibility_date": "2026-07-25",
|
||||
"workers_dev": false,
|
||||
"preview_urls": false,
|
||||
"assets": {
|
||||
"binding": "ASSETS",
|
||||
"directory": "./dist/client",
|
||||
"html_handling": "auto-trailing-slash",
|
||||
"not_found_handling": "404-page"
|
||||
},
|
||||
"env": {
|
||||
"dev": {
|
||||
"name": "opencode-www-dev",
|
||||
"routes": [
|
||||
{
|
||||
"pattern": "dev.opencode.ai/v2",
|
||||
"zone_name": "opencode.ai"
|
||||
},
|
||||
{
|
||||
"pattern": "dev.opencode.ai/v2/*",
|
||||
"zone_name": "opencode.ai"
|
||||
}
|
||||
]
|
||||
},
|
||||
"production": {
|
||||
"name": "opencode-www",
|
||||
"routes": [
|
||||
{
|
||||
"pattern": "opencode.ai/v2",
|
||||
"zone_name": "opencode.ai"
|
||||
},
|
||||
{
|
||||
"pattern": "opencode.ai/v2/*",
|
||||
"zone_name": "opencode.ai"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ await $`bun ./packages/sdk/js/script/build.ts`
|
|||
|
||||
await $`bun dev generate > ../sdk/openapi.json`.cwd("packages/opencode")
|
||||
|
||||
await $`bun run generate`.cwd("packages/docs")
|
||||
await $`bun run generate`.cwd("packages/www")
|
||||
|
||||
await $`./script/format.ts`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue