diff --git a/packages/docs/agents.mdx b/packages/docs/agents.mdx new file mode 100644 index 0000000000..54503dfb0a --- /dev/null +++ b/packages/docs/agents.mdx @@ -0,0 +1,288 @@ +--- +title: "Agents" +description: "Configure and use primary agents and subagents in OpenCode." +--- + +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. + +## 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 Tab and Shift+Tab 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. + +## 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. + +## Configure agents + +### JSON or JSONC + +Use the plural `agents` field in any [OpenCode configuration file](/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": "warning", + "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. + +### Markdown files + +The recommended file locations are: + +```text +~/.config/opencode/agents/.md +.opencode/agents/.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: warning +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. +``` + +For compatibility with older layouts, V2 also discovers Markdown under +`agent/`, and treats files under `mode/` or `modes/` as primary agents. Prefer +`agents/` for new files. + +## 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`. + + + Put broad wildcard rules first and exceptions afterward. For example, deny + all subagents first, then allow `explore`. + + +`~` 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`, or one +of `primary`, `secondary`, `accent`, `success`, `warning`, `error`, or `info`. + +### `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 } + } + } + } +} +``` + + + 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. + diff --git a/packages/docs/attachments.mdx b/packages/docs/attachments.mdx new file mode 100644 index 0000000000..16e009fa18 --- /dev/null +++ b/packages/docs/attachments.mdx @@ -0,0 +1,168 @@ +--- +title: "Attachments" +description: "Attach supported files and images to V2 prompts and configure image processing." +--- + +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. + + + 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. + + +## 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,", + "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. | + + + 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. + + +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. diff --git a/packages/docs/commands.mdx b/packages/docs/commands.mdx new file mode 100644 index 0000000000..9c889bd48e --- /dev/null +++ b/packages/docs/commands.mdx @@ -0,0 +1,164 @@ +--- +title: "Commands" +description: "Create reusable slash commands from configuration or Markdown files." +--- + +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 JSON + +Add commands under the plural `commands` key in any OpenCode JSON or JSONC +[configuration file](/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" + } + } +} +``` + +Run it with: + +```text +/review src/auth +``` + +## Configure with Markdown + +OpenCode discovers `.md` command files in both the singular `command/` and +plural `commands/` directories: + +```text +~/.config/opencode/commands/ # Global +.opencode/commands/ # Project +``` + +The equivalent `command/` paths also work. 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. + +## 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. + + + Shell interpolations run when the command is evaluated, outside the agent's + tool permission flow. Only use commands from sources you trust. + + +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. diff --git a/packages/docs/compaction.mdx b/packages/docs/compaction.mdx new file mode 100644 index 0000000000..79316019e9 --- /dev/null +++ b/packages/docs/compaction.mdx @@ -0,0 +1,151 @@ +--- +title: "Context compaction" +description: "Configure and run context compaction in OpenCode V2." +--- + +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 `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](/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 checkpoint is presented to the model as historical conversation +context, explicitly not as new instructions. Running and failed compactions are +not included in model context. + +## Instructions and checkpoints + +Conversation compaction and the durable instruction checkpoint are separate. +Before each model step, V2 compares live instruction sources with what that +session's model was last told. Ordinary changes are durable chronological +system updates and do not rewrite the established instruction baseline. + +After a completed compaction, the next model step creates a fresh instruction +baseline from current sources. If a source is temporarily unavailable, V2 +restates the last-applied value instead of treating it as removed. Session +movement and a committed revert reset the instruction checkpoint as well. See +[Instructions](/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. diff --git a/packages/docs/config.mdx b/packages/docs/config.mdx index 09294d094a..096620a6b0 100644 --- a/packages/docs/config.mdx +++ b/packages/docs/config.mdx @@ -44,8 +44,12 @@ Project-specific configuration can use either form: ``` When OpenCode starts, it searches for configuration files from the current -directory upward to the project root. The files are merged, and configuration -closer to the current directory takes precedence. +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`: @@ -67,9 +71,9 @@ OpenCode applies these files from lowest to highest precedence: 2. `/home/user/projects/acme/opencode.json` 3. `/home/user/projects/acme/packages/web/opencode.json` -Settings in the package config override matching settings from the repository -config, which override matching settings from the global config. Settings that -do not conflict are preserved from every file. +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 @@ -100,16 +104,16 @@ Set the shell used by the terminal and shell tools. ### Model -Set the default model in `provider/model` format. Add `#variant` to select a -specific model variant. +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#high" + "model": "anthropic/claude-sonnet-4-5" } ``` -See the [models guide](https://opencode.ai/docs/models/) for model selection +See the [models guide](/models) for model selection and local models. ### Default agent @@ -122,13 +126,15 @@ Choose the primary agent used when a session does not select one explicitly. } ``` -See the [agents guide](https://opencode.ai/docs/agents/) for built-in and custom +See the [agents guide](/agents) for built-in and custom agents. ### Autoupdate -Control automatic updates. Set this to `false` to disable updates or `"notify"` -to receive update notifications. +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 { @@ -138,8 +144,8 @@ to receive update notifications. ### Sharing -Control whether sessions can be shared manually, shared automatically, or not -shared at all. +Set the intended session sharing policy. V2 accepts this field, but session +sharing is not implemented yet. ```jsonc { @@ -147,11 +153,12 @@ shared at all. } ``` -See the [sharing guide](https://opencode.ai/docs/share/) for more details. +See the [sharing guide](/sharing) for more details. ### Username -Set the username displayed in conversations. +Set a username for future display behavior. V2 accepts this field but does not +currently display it in conversations. ```jsonc { @@ -168,7 +175,7 @@ matching resource. { "permissions": [ { - "action": "bash", + "action": "shell", "resource": "git push *", "effect": "ask" } @@ -176,8 +183,7 @@ matching resource. } ``` -See the [permissions guide](https://opencode.ai/docs/permissions/) for rule -matching and available actions. +See the [permissions guide](/permissions) for rule matching and available actions. ### Agents @@ -199,12 +205,11 @@ instructions, mode, and permissions. } ``` -See the [agents guide](https://opencode.ai/docs/agents/) for all agent options -and file-based agents. +See the [agents guide](/agents) for all agent options and file-based agents. ### Snapshots -Enable or disable the snapshots used by undo and revert behavior. +Enable or disable filesystem snapshots used by undo and revert behavior. ```jsonc { @@ -212,6 +217,8 @@ Enable or disable the snapshots used by undo and revert behavior. } ``` +See the [snapshots guide](/snapshots) for undo and redo behavior. + ### Watcher Ignore files and directories that should not trigger filesystem updates. @@ -226,8 +233,8 @@ Ignore files and directories that should not trigger filesystem updates. ### Formatter -Enable built-in formatters, disable formatting entirely, or configure formatter -commands by name. +Define formatter settings for compatibility and future use. V2 accepts this +field, but it does not run formatters yet. ```jsonc { @@ -240,12 +247,12 @@ commands by name. } ``` -See the [formatters guide](https://opencode.ai/docs/formatters/) for built-in -formatters and custom commands. +See the [formatters guide](/formatters) for accepted fields and current limitations. ### LSP -Enable built-in language servers, disable them, or configure servers by name. +Define language server settings for compatibility and future use. V2 accepts +this field, but it does not start language servers yet. ```jsonc { @@ -258,12 +265,12 @@ Enable built-in language servers, disable them, or configure servers by name. } ``` -See the [LSP guide](https://opencode.ai/docs/lsp/) for language server setup. +See the [LSP guide](/lsp) for accepted fields and current limitations. ### Attachments -Control how oversized image attachments are resized or rejected before they are -sent to a model. +Control how oversized images loaded by the `read` tool are resized or rejected +before they are sent to a model. ```jsonc { @@ -278,6 +285,8 @@ sent to a model. } ``` +See the [attachments guide](/attachments) for image processing and limits. + ### Tool output Set the maximum number of lines and bytes retained from a tool result. @@ -309,8 +318,7 @@ be overridden by an individual server. } ``` -See the [MCP guide](https://opencode.ai/docs/mcp-servers/) for remote servers, -OAuth, environment variables, and timeouts. +See the [MCP guide](/mcp) for remote servers, OAuth, environment variables, and timeouts. ### Compaction @@ -328,6 +336,8 @@ Control automatic context compaction and how much recent context it preserves. } ``` +See the [compaction guide](/compaction) for automatic context management. + ### Skills Add directories or URLs that OpenCode should search for agent skills. @@ -338,8 +348,7 @@ Add directories or URLs that OpenCode should search for agent skills. } ``` -See the [skills guide](https://opencode.ai/docs/skills/) for skill structure and -automatic discovery under `.opencode/skills/`. +See the [skills guide](/skills) for skill structure and automatic discovery under `.opencode/skills/`. ### Commands @@ -356,12 +365,12 @@ Define reusable slash commands as named prompt templates. } ``` -See the [commands guide](https://opencode.ai/docs/commands/) for arguments, -models, agents, and file-based commands. +See the [commands guide](/commands) for arguments, models, agents, and file-based commands. ### Instructions -Load additional instruction files, globs, or URLs into the agent's context. +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 { @@ -369,8 +378,7 @@ Load additional instruction files, globs, or URLs into the agent's context. } ``` -See the [rules guide](https://opencode.ai/docs/rules/) for project instructions -and `AGENTS.md`. +See the [instructions guide](/instructions) for project instructions and `AGENTS.md`. ### References @@ -392,8 +400,7 @@ context. } ``` -See the [references guide](https://opencode.ai/docs/references/) for shorthand, -visibility, and path resolution. +See the [references guide](/references) for shorthand, visibility, and path resolution. ### Plugins @@ -440,5 +447,4 @@ headers, and model variants. } ``` -See the [providers guide](https://opencode.ai/docs/providers/) for credentials, -custom endpoints, provider packages, and model configuration. +See the [providers guide](/providers) for credentials, custom endpoints, provider packages, and model configuration. diff --git a/packages/docs/docs.json b/packages/docs/docs.json index e8559d72f6..35d81ac0d9 100644 --- a/packages/docs/docs.json +++ b/packages/docs/docs.json @@ -20,7 +20,32 @@ "groups": [ { "group": "Get started", - "pages": ["index", "config", "plugins", "troubleshooting"] + "pages": ["index", "config", "troubleshooting"] + }, + { + "group": "Migrate from V1", + "pages": ["migrate-v1"] + }, + { + "group": "Configure", + "pages": [ + "models", + "providers", + "agents", + "permissions", + "sharing", + "snapshots", + "commands", + "skills", + "instructions", + "mcp", + "attachments", + "compaction", + "formatters", + "lsp", + "references", + "plugins" + ] } ] }, diff --git a/packages/docs/formatters.mdx b/packages/docs/formatters.mdx new file mode 100644 index 0000000000..a8e8702e85 --- /dev/null +++ b/packages/docs/formatters.mdx @@ -0,0 +1,93 @@ +--- +title: "Formatters" +description: "Configure formatter settings and understand formatter support in OpenCode V2." +--- + +OpenCode V2 accepts formatter configuration, but it does not yet include a +formatter runtime. File writes and edits are not automatically formatted. + + + 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. + + +## 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` | 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. diff --git a/packages/docs/index.mdx b/packages/docs/index.mdx index 8e61f92a6b..d0e967b0fd 100644 --- a/packages/docs/index.mdx +++ b/packages/docs/index.mdx @@ -3,6 +3,11 @@ title: "Intro" description: "Get started with OpenCode." --- + + 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. + + [**OpenCode**](https://opencode.ai) is an open source AI coding agent. It's available as a terminal-based interface or desktop app. @@ -70,9 +75,9 @@ Arch Linux installation is not available in beta. ### Windows - For the best experience on Windows, use [Windows Subsystem for Linux - (WSL)](https://opencode.ai/docs/windows-wsl). It provides better performance and full compatibility with OpenCode's - features. + 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. @@ -110,7 +115,8 @@ If you'd like easy access to all the best coding models you can try out 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. -See the current [provider directory](https://opencode.ai/docs/providers#directory). +Use `/models` to browse the providers and models available to your project. See [Providers](/providers) for connection and +configuration details. --- @@ -148,8 +154,10 @@ Use `/undo` when a change isn't what you wanted. /undo ``` -OpenCode reverts the changes and restores your original message so you can revise it. Run `/undo` multiple times to undo -multiple changes, or use `/redo` to reapply them. +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 [Snapshots and undo](/snapshots) for +limitations and safety details. ```text /redo @@ -160,5 +168,5 @@ multiple changes, or use `/redo` to reapply them. ## Customize Make OpenCode your own by [picking a theme](https://opencode.ai/docs/themes), [customizing -keybinds](https://opencode.ai/docs/keybinds), [configuring formatters](https://opencode.ai/docs/formatters), [creating -commands](https://opencode.ai/docs/commands), or editing the [OpenCode config](https://opencode.ai/docs/config). +keybinds](https://opencode.ai/docs/keybinds), [configuring formatters](/formatters), [creating commands](/commands), or +editing the [OpenCode config](/config). diff --git a/packages/docs/instructions.mdx b/packages/docs/instructions.mdx new file mode 100644 index 0000000000..7c45ddb968 --- /dev/null +++ b/packages/docs/instructions.mdx @@ -0,0 +1,124 @@ +--- +title: "Instructions" +description: "Give OpenCode global, project, and directory-specific guidance." +--- + +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 into a durable instruction +baseline. + +## 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. + + + Current V2 discovery only recognizes `AGENTS.md`. The `CLAUDE.md` fallback + and related precedence described by older OpenCode documentation do not apply. + + +### 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. + + + 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. + + +See [Config](/config) for config locations and general precedence. + +## Ordering + +The selected agent or provider system prompt is sent first. OpenCode then sends +the session's instruction baseline, 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 baseline. + +## Changes + +Before each model step, V2 compares live instruction sources with what that +session's model was last told: + +- 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 baseline exists yet, + the first model step waits until required sources are available. +- Completed conversation compaction creates a fresh baseline from the current + sources. Moving a session or committing a revert also resets its instruction + checkpoint so the next step establishes a new baseline. + +Updates are durable session history. OpenCode does not rewrite the original +baseline on every change; it records the change so subsequent model steps see +both the established baseline and the chronological update. diff --git a/packages/docs/lsp.mdx b/packages/docs/lsp.mdx new file mode 100644 index 0000000000..baf09b278a --- /dev/null +++ b/packages/docs/lsp.mdx @@ -0,0 +1,105 @@ +--- +title: "LSP" +description: "Configure language servers and understand LSP support in OpenCode V2." +--- + +Language Server Protocol (LSP) integrations can provide code diagnostics, +symbols, definitions, references, and other language-aware context. + + + 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. + + +## 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` | No | Environment variables for the server process. The property is named `env`, not `environment`. | +| `initialization` | `Record` | 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. diff --git a/packages/docs/mcp.mdx b/packages/docs/mcp.mdx new file mode 100644 index 0000000000..c19b76ce8d --- /dev/null +++ b/packages/docs/mcp.mdx @@ -0,0 +1,254 @@ +--- +title: "MCP servers" +description: "Connect local and remote Model Context Protocol servers to OpenCode." +--- + +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](/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 `needs authentication`, start the browser authorization flow: + +```bash +opencode2 mcp auth sentry +``` + +The 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 `_`. 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 `:` 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. diff --git a/packages/docs/migrate-v1.mdx b/packages/docs/migrate-v1.mdx new file mode 100644 index 0000000000..c9be38907d --- /dev/null +++ b/packages/docs/migrate-v1.mdx @@ -0,0 +1,89 @@ +--- +title: "Overview" +description: "Move from OpenCode V1 to the OpenCode 2.0 beta." +--- + + + OpenCode 2.0 is in beta. Back up important configuration and data before migrating. Beta data may be wiped, features may + break, and configuration and plugin APIs may change. + + +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 +``` + +## Back up your configuration + +Before making changes, back up your global and project configuration files: + +```text +~/.config/opencode/opencode.json(c) +/opencode.json(c) +/.opencode/opencode.json(c) +``` + +V2 reads these same locations. It detects V1-shaped configuration and translates supported fields in memory without +rewriting the source file. Keep shared files in their V1 shape while evaluating both versions; V1 does not understand the +native plural V2 fields and may silently ignore them. + +## Update configuration + +Automatic translation is a compatibility aid, not a guarantee that every V1 setting behaves identically. Convert your +configuration to the native V2 shape only when you no longer need V1 to read those same files. + + + Do not mix V1 and V2 field names in one file. Back up the V1 file, update the complete working file to the V2 shape, and + validate it against the current schema. Restore the V1 copy before using V1 again. + + +The main field changes are: + +| V1 | V2 | +| --- | --- | +| `permission` | `permissions` | +| `agent` and `mode` | `agents` | +| `snapshot` | `snapshots` | +| `attachment` | `attachments` | +| `command` | `commands` | +| `reference` | `references` | +| `plugin` | `plugins` | +| `provider` | `providers` | +| Servers directly under `mcp` | Servers under `mcp.servers` | +| `skills.paths` and `skills.urls` | A single `skills` array | + +Permission actions also changed: `bash` is now `shell`, `task` is now `subagent`, and `write` and `patch` are now `edit`. +See [Permissions](/permissions) for the ordered V2 rule format. + +V1-only fields including `logLevel`, `server`, `layout`, `disabled_providers`, `enabled_providers`, and `small_model` are +not carried into the native V2 configuration. Remove them and use the current [Config](/config) and +[Providers](/providers) guides to configure their replacements where applicable. + +## Review extensions + +V2 continues to discover file-based agents, commands, and skills from OpenCode configuration directories. Their schemas +have changed, so review each extension against the current [Agents](/agents), [Commands](/commands), and +[Skills](/skills) guides. + + + V1 plugins are not guaranteed to work with V2. The plugin API is changing during beta; review and port each plugin using + the [V2 plugin guide](/plugins). + + +## 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 and backups 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. diff --git a/packages/docs/models.mdx b/packages/docs/models.mdx new file mode 100644 index 0000000000..937fbb80e3 --- /dev/null +++ b/packages/docs/models.mdx @@ -0,0 +1,223 @@ +--- +title: "Models" +description: "Select, configure, and customize models in OpenCode 2.0." +--- + +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 a provider and its credentials in `opencode.json`. + +## Select a model + +Open the model picker with `/models` or the default `m` keybind. Use `/variants` to choose a variant for the +current model, or press `ctrl+t` to cycle through its variants. + +A model reference has this form: + +```text +provider/model#variant +``` + +The variant is optional. OpenCode splits at the first `/`, so model IDs may contain additional slashes: + +```text +openai/gpt-5.2 +openai/gpt-5.2#high +openrouter/anthropic/claude-sonnet-4.5#high +``` + +Use the catalog IDs shown by `/models`, not a provider's display name. Omit `#variant` to use the model's base settings. + +### Command line + +Select a model for a 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" +``` + + + `opencode2 run` accepts `provider/model#variant`. The current `opencode2 mini --model` option accepts only + `provider/model`; choose its variant from the interactive interface. + + +## Set the default + +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 explicit object form is equivalent: + +```jsonc title="opencode.jsonc" +{ + "$schema": "https://opencode.ai/config.json", + "model": { + "providerID": "openrouter", + "model": "anthropic/claude-sonnet-4.5" + } +} +``` + +Root, agent, and command `model` fields accept these same selection forms. See [Config](/config) for configuration +locations and precedence. + +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. + +## 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. + +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" + } + } + ] + } + } + } + }, + "commands": { + "deep-review": { + "description": "Review with high reasoning effort", + "template": "Review the current changes for correctness and missing tests.", + "model": "openai/gpt-5.2#deep" + } + } +} +``` + +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. + + + V2 uses `providers` (plural) and an array of `{ "id": "..." }` variant entries. The V1 `provider` key and + object-shaped `variants` configuration are not the V2 format. + + +## Configure a model + +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. + +## Local and compatible 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. + +## Caveats + +- Provider and model IDs are case-sensitive. Provider IDs cannot contain `/` or `#`; model IDs cannot contain `#`. +- 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. diff --git a/packages/docs/permissions.mdx b/packages/docs/permissions.mdx new file mode 100644 index 0000000000..7da958df0c --- /dev/null +++ b/packages/docs/permissions.mdx @@ -0,0 +1,209 @@ +--- +title: "Permissions" +description: "Configure ordered V2 rules for tool access, approvals, and agent overrides." +--- + +Permissions control whether an agent may perform an action on a resource. V2 +configuration uses the plural `permissions` field and an ordered array of rules. + + + 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`. + + +## 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 `/*` | +| `_` | `*` 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. + + + `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. + + +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..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. diff --git a/packages/docs/plugins.mdx b/packages/docs/plugins.mdx index cdc38a8808..878473c5e4 100644 --- a/packages/docs/plugins.mdx +++ b/packages/docs/plugins.mdx @@ -2,3 +2,368 @@ 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 location-scoped subset of the V2 client. + + + The V2 plugin API is beta. Entrypoints, hooks, draft shapes, and configuration + may change before the stable release. Use only the `/v2` exports described on + this page; the root `@opencode-ai/plugin` API is the legacy API. + + +## 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 either a Promise `setup` function or an Effect `effect` +function. + +### Configuration + +Add ordered entries to the plural `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 both of these directories in every discovered +OpenCode config directory: + +```text +.opencode/plugin/ +.opencode/plugins/ +``` + +The equivalent global directories are +`~/.config/opencode/plugin/` and `~/.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 `plugin/` 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 `-` removes a previously selected target. `*` matches +everything, and a suffix of `.*` matches an ID or target prefix. Directives are +applied in order: + +```jsonc title="opencode.jsonc" +{ + "plugins": [ + "-opencode.provider.*", + "opencode.provider.openai", + "-./plugin/old.ts", + "-*", + "./plugins/only-this-one.ts" + ] +} +``` + +Use the same package specifier or resolved local target to remove an external +plugin. Built-in and embedded plugins can be selected by their plugin ID. +Explicit config directives run after local auto-discovery, so they can disable +discovered plugins. + +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@1.17.15 effect@4.0.0-beta.83 +``` + +`effect` is required for Effect plugins and for the `Schema` values used by +typed tools. A Promise plugin that does not define tools may only need +`@opencode-ai/plugin`. Match these versions 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 + +The Promise API is the simplest option. 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 for a Location. Register +long-lived behavior during setup; do not wait there on an infinite event +stream. + +### Effect plugins + +Use the Effect entrypoint when the implementation benefits from Effect +composition, fibers, or scoped resources: + +```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" + }) + }) + }), +}) +``` + +The plugin effect is scoped. Finalizers, scoped fibers, and registrations are +released when the plugin reloads or unloads. OpenCode deliberately isolates the +effect from its private Core services; use only the public `ctx` capabilities. + +## Context + +Promise methods return Promises; the equivalent Effect methods return +`Effect`. Read and action methods use the same inputs and location-aware +responses as the V2 client APIs. + +| Capability | Available operations | +| --- | --- | +| `ctx.agent` | `list`, `transform`, `reload` | +| `ctx.catalog.provider` | `list`, `get` | +| `ctx.catalog.model` | `list`, `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.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 | + +Unlike the legacy API, V2 does not provide `$`, `directory`, `worktree`, or a +general SDK client on the context. A plugin is Location-scoped, and the exposed +domain clients apply that Location by default. + +### Transform hooks + +Transforms synchronously edit a draft whenever a stateful domain is built. +Registering or disposing a transform rebuilds the domain from fresh state and +runs all active transforms in order. Call the domain's `reload()` method when +external data captured by a transform changes. + +| 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` | + +Hook registrations are owned by the plugin scope. Transform and runtime hook +calls also return a `Registration` with `dispose` for explicit cleanup. Tool +contributions currently remain until the owning plugin scope closes, so prefer +scope cleanup for plugin-wide teardown while this API is beta. + +### 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)` | `result`, `output`, and `outputPaths`, after execution settles | + +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. + +## Add a tool + +Use `Tool.make` with Effect schemas. Promise tools use async executors: + +```ts title=".opencode/plugins/greeting.ts" +import { Plugin } from "@opencode-ai/plugin/v2" +import { Tool } from "@opencode-ai/plugin/v2/tool" +import { Schema } from "effect" + +const greeting = Tool.make({ + description: "Create a greeting", + input: Schema.Struct({ name: Schema.String }), + output: Schema.String, + execute: async ({ name }) => `Hello, ${name}!`, +}) + +export default Plugin.define({ + id: "acme.greeting", + setup: async (ctx) => { + await ctx.tool.transform((tools) => { + tools.add("greeting", greeting) + }) + }, +}) +``` + +Unsupported characters in tool and group names are normalized to underscores. +The resulting exposed key must begin with a letter and contain at most 64 +letters, digits, underscores, or hyphens. `tools.add` also accepts +`{ group, deferred }`: + +- `group` prefixes and groups the exposed tool name. +- `deferred: true` makes the tool available through the deferred `execute` + tool instead of exposing it directly. + +The executor receives a second context argument containing `sessionID`, +`agent`, `assistantMessageID`, and `toolCallID`. Use +`Tool.withPermission(tool, "permission-name")` to assign a permission key. +Effect plugins import the helper from `@opencode-ai/plugin/v2/effect/tool` and +return an `Effect` from `execute`. + +## Types + +`Plugin.define` infers the context and callbacks. The Promise root also +re-exports the canonical `Agent`, `Command`, `Connection`, `Credential`, +`Integration`, `Model`, `Provider`, `Reference`, and `Skill` schema namespaces. +Import narrower API types from their public subpaths when needed: + +```ts +import { Plugin, Model } from "@opencode-ai/plugin/v2" +import type { Context } from "@opencode-ai/plugin/v2/plugin" +import type { AgentDraft } from "@opencode-ai/plugin/v2/agent" +import type { ToolExecuteBeforeEvent } from "@opencode-ai/plugin/v2/tool" +``` + +Effect equivalents live below `@opencode-ai/plugin/v2/effect`, such as +`@opencode-ai/plugin/v2/effect/plugin` and +`@opencode-ai/plugin/v2/effect/tool`. Avoid importing types or runtime values +from `@opencode-ai/core` or `@opencode-ai/server`; those are private host +implementation details. + +## 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": "1.17.15", + "effect": "4.0.0-beta.83" + } +} +``` + +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 for the current Location 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. diff --git a/packages/docs/providers.mdx b/packages/docs/providers.mdx new file mode 100644 index 0000000000..10faab33fa --- /dev/null +++ b/packages/docs/providers.mdx @@ -0,0 +1,272 @@ +--- +title: "Providers" +description: "Connect LLM providers and configure endpoints, packages, models, and variants." +--- + +OpenCode builds its provider and model catalog from [Models.dev](https://models.dev), then applies the `providers` +overlays from your [configuration](/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}" + } + } + } +} +``` + +Do not commit API keys or authorization headers to your repository. + +## Configure providers + +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. + +### Custom 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. + +### Custom 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. + +## Custom providers and 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/llm/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/llm/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 + +`models` adds a model or overlays an existing catalog model. The object key is the model ID used in OpenCode. Set +`modelID` when the upstream API expects a different ID: + +```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", + "family": "gpt-5", + "limit": { + "context": 200000, + "input": 180000, + "output": 32000 + } + } + } + } + } +} +``` + +A model supports `modelID`, `family`, `name`, `package`, `settings`, `headers`, `body`, `capabilities`, `variants`, +`cost`, `disabled`, and `limit`. If supplied, `capabilities` requires `tools`, `input`, and `output`. `limit` may set +`context`, `input`, and `output`. Cost values are USD per million tokens: + +```jsonc +{ + "cost": { + "input": 3, + "output": 15, + "cache": { + "read": 0.3, + "write": 3.75 + } + } +} +``` + +Set `disabled: true` on a model to remove it from the available model list. V2 does not define provider-level +whitelist or blacklist fields. + +## Variants + +Variants are named request overlays for one model. They can override `settings`, `headers`, and `body`; the selected +package determines which values are meaningful. + +```jsonc title="opencode.jsonc" +{ + "$schema": "https://opencode.ai/config.json", + "providers": { + "openai": { + "models": { + "gpt-5.2": { + "variants": [ + { + "id": "fast", + "settings": { + "reasoningEffort": "low" + } + }, + { + "id": "deep", + "settings": { + "reasoningEffort": "high", + "reasoningSummary": "auto" + } + } + ] + } + } + } + } +} +``` + +Choose a variant with the TUI variant picker or `/variants`. Explicit CLI, agent, and command model references use +`provider/model#variant`; for example: + +```bash +opencode2 run --model openai/gpt-5.2#deep "Review this project" +``` + +The current V2 top-level `model` default does not retain a `#variant` selection, so choose the variant separately. +Selecting an ID that is not defined for the model fails instead of silently using the default request settings. diff --git a/packages/docs/references.mdx b/packages/docs/references.mdx new file mode 100644 index 0000000000..3fbd624274 --- /dev/null +++ b/packages/docs/references.mdx @@ -0,0 +1,177 @@ +--- +title: "References" +description: "Make local directories and Git repositories available as project context." +--- + +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" + } +} +``` + + + 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. + + +## 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//`. 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. + + + 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. + + +## 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. diff --git a/packages/docs/sharing.mdx b/packages/docs/sharing.mdx new file mode 100644 index 0000000000..5acceb7060 --- /dev/null +++ b/packages/docs/sharing.mdx @@ -0,0 +1,39 @@ +--- +title: "Session sharing" +description: "Understand the current beta status of session sharing in OpenCode V2." +--- + +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. + + + 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. + + +## 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. diff --git a/packages/docs/skills.mdx b/packages/docs/skills.mdx new file mode 100644 index 0000000000..d97c60c99a --- /dev/null +++ b/packages/docs/skills.mdx @@ -0,0 +1,228 @@ +--- +title: "Skills" +description: "Add reusable, on-demand instructions to OpenCode." +--- + +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/skill`, `~/.config/opencode/skills` | +| Global compatibility | `~/.claude/skills`, `~/.agents/skills` | +| Project | `.opencode/skill`, `.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 +`/git-release/`. 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 | +| --- | --- | +| `/git-release.md` | `git-release` | +| `/git-release/SKILL.md` | `git-release` | +| `/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/skill` and `~/.config/opencode/skills` +5. Project `.opencode/skill` and `.opencode/skills`, from the project root toward the current directory +6. Explicit `skills` config entries, in config priority and array order + +Within one `.opencode` directory, `skills` has precedence over `skill`. 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..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`. diff --git a/packages/docs/snapshots.mdx b/packages/docs/snapshots.mdx new file mode 100644 index 0000000000..022460cbf6 --- /dev/null +++ b/packages/docs/snapshots.mdx @@ -0,0 +1,109 @@ +--- +title: "Snapshots and undo" +description: "Understand filesystem snapshots, undo, redo, and message reverts in OpenCode V2." +--- + +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](/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. + + + 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. + + +## 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. + + + `/undo` and `/redo` are interactive commands in the default V2 TUI. The non-interactive `run` command and the minimal + interactive interface do not provide these slash commands. +