Compare commits

...

11 Commits

Author SHA1 Message Date
Dax Raad 30e10127f2 formatter config 2025-07-31 19:36:07 -04:00
Jay V 5e66fc2318 docs: edit premissions doc 2025-07-31 19:10:54 -04:00
opencode c1c99c7e0f Release v0.3.104 2025-07-31 23:02:36 +00:00
Dax Raad 04e3e83db3 allow disabling formatter 2025-07-31 18:56:04 -04:00
Dax Raad 4273714a62 fix issue with some bash commands asking for permission 2025-07-31 18:35:51 -04:00
Dax Raad a21e237706 ignore: update opencode.json 2025-07-31 18:13:40 -04:00
Dax Raad aa9105649d docs: permissions 2025-07-31 18:11:34 -04:00
Dax Raad 53be288040 docs: permissions 2025-07-31 18:11:34 -04:00
Frank 13dbf912ca Remove hardcoded vscode extension theme 2025-07-31 17:53:18 -04:00
Jay V 69966c73f8 docs: add more providers 2025-07-31 17:47:24 -04:00
opencode a00de2df08 Release v0.3.102 2025-07-31 21:25:12 +00:00
14 changed files with 424 additions and 417 deletions
+7
View File
@@ -48,6 +48,7 @@
"hono-openapi": "0.4.8",
"isomorphic-git": "1.32.1",
"jsonc-parser": "3.3.1",
"minimatch": "10.0.3",
"open": "10.1.2",
"remeda": "catalog:",
"tree-sitter": "0.22.4",
@@ -355,6 +356,10 @@
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
"@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="],
"@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
@@ -1271,6 +1276,8 @@
"miniflare": ["miniflare@4.20250730.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^7.10.0", "workerd": "1.20250730.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-avGXBStHQSqcJr8ra1mJ3/OQvnLZ49B1uAILQapAha1DHNZZvXWLIgUVre/WGY6ZOlNGFPh5CJ+dXLm4yuV3Jw=="],
"minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
"minimisted": ["minimisted@2.0.1", "", { "dependencies": { "minimist": "^1.2.5" } }, "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA=="],
+6 -4
View File
@@ -19,6 +19,12 @@
}
}
},
"formatter": {
"test": {
"extensions": [".json"],
"command": ["sed", "-i", "s/name/poop/g", "$FILE"]
}
},
"mcp": {
"context7": {
"type": "remote",
@@ -28,9 +34,5 @@
"type": "local",
"command": ["opencode", "x", "@h1deya/mcp-server-weather"]
}
},
"permission": {
"edit": "ask",
"bash": "ask"
}
}
+2 -1
View File
@@ -46,11 +46,12 @@
"hono-openapi": "0.4.8",
"isomorphic-git": "1.32.1",
"jsonc-parser": "3.3.1",
"minimatch": "10.0.3",
"open": "10.1.2",
"remeda": "catalog:",
"turndown": "7.2.0",
"tree-sitter": "0.22.4",
"tree-sitter-bash": "0.23.3",
"turndown": "7.2.0",
"vscode-jsonrpc": "8.2.1",
"xdg-basedir": "5.1.0",
"yargs": "18.0.0",
+11
View File
@@ -278,6 +278,17 @@ export namespace Config {
.optional()
.describe("Custom provider configurations and model overrides"),
mcp: z.record(z.string(), Mcp).optional().describe("MCP (Model Context Protocol) server configurations"),
formatter: z
.record(
z.string(),
z.object({
disabled: z.boolean().optional(),
command: z.array(z.string()).optional(),
environment: z.record(z.string(), z.string()).optional(),
extensions: z.array(z.string()).optional(),
}),
)
.optional(),
instructions: z.array(z.string()).optional().describe("Additional instruction files or patterns to include"),
layout: Layout.optional().describe("@deprecated Always uses stretch layout."),
permission: z
+3 -1
View File
@@ -129,7 +129,9 @@ export const clang: Info = {
command: ["clang-format", "-i", "$FILE"],
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
async enabled() {
return Bun.which("clang-format") !== null
const app = App.info()
const items = await Filesystem.findUp(".clang-format", app.path.cwd, app.path.root)
return items.length > 0
},
}
+25 -3
View File
@@ -5,20 +5,40 @@ import { Log } from "../util/log"
import path from "path"
import * as Formatter from "./formatter"
import { Config } from "../config/config"
import { mergeDeep } from "remeda"
export namespace Format {
const log = Log.create({ service: "format" })
const state = App.state("format", () => {
const state = App.state("format", async () => {
const enabled: Record<string, boolean> = {}
const cfg = await Config.get()
const formatters = { ...Formatter } as Record<string, Formatter.Info>
for (const [name, item] of Object.entries(cfg.formatter ?? {})) {
if (item.disabled) {
delete formatters[name]
continue
}
const result: Formatter.Info = mergeDeep(formatters[name] ?? {}, {
command: [],
extensions: [],
...item,
})
result.enabled = async () => true
result.name = name
formatters[name] = result
}
return {
enabled,
formatters,
}
})
async function isEnabled(item: Formatter.Info) {
const s = state()
const s = await state()
let status = s.enabled[item.name]
if (status === undefined) {
status = await item.enabled()
@@ -28,8 +48,10 @@ export namespace Format {
}
async function getFormatter(ext: string) {
const formatters = await state().then((x) => x.formatters)
const result = []
for (const item of Object.values(Formatter)) {
for (const item of Object.values(formatters)) {
log.info("checking", { name: item.name, ext })
if (!item.extensions.includes(ext)) continue
if (!(await isEnabled(item))) continue
result.push(item)
+2 -1
View File
@@ -7,6 +7,7 @@ import { Config } from "../config/config"
import { Filesystem } from "../util/filesystem"
import path from "path"
import { lazy } from "../util/lazy"
import { minimatch } from "minimatch"
const MAX_OUTPUT_LENGTH = 30000
const DEFAULT_TIMEOUT = 1 * 60 * 1000
@@ -84,7 +85,7 @@ export const BashTool = Tool.define("bash", {
if (!needsAsk && command[0] !== "cd") {
const ask = (() => {
for (const [pattern, value] of Object.entries(permissions)) {
if (new Bun.Glob(pattern).match(node.text)) {
if (minimatch(node.text, pattern)) {
return value
}
}
+1
View File
@@ -96,6 +96,7 @@ export const EditTool = Tool.define("edit", {
file: filePath,
})
contentNew = await file.text()
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
})()
FileTime.read(ctx.sessionID, filePath)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "0.0.0-202507312003",
"version": "0.0.0",
"type": "module",
"exports": {
".": "./dist/index.js"
+16
View File
@@ -17,6 +17,8 @@ export type Event = ({
} & EventStorageWrite) | ({
type: 'permission.updated';
} & EventPermissionUpdated) | ({
type: 'permission.replied';
} & EventPermissionReplied) | ({
type: 'file.edited';
} & EventFileEdited) | ({
type: 'session.updated';
@@ -374,6 +376,15 @@ export type Permission = {
};
};
export type EventPermissionReplied = {
type: string;
properties: {
sessionID: string;
permissionID: string;
response: string;
};
};
export type EventFileEdited = {
type: string;
properties: {
@@ -579,6 +590,11 @@ export type Config = {
type: 'remote';
} & McpRemoteConfig);
};
formatter?: {
[key: string]: {
disabled?: boolean;
};
};
/**
* Additional instruction files or patterns to include
*/
+4 -8
View File
@@ -69,12 +69,7 @@ export default defineConfig({
{
label: "Usage",
items: [
"docs/cli",
"docs/ide",
"docs/share",
"docs/github",
]
items: ["docs/cli", "docs/ide", "docs/share", "docs/github"],
},
{
@@ -86,9 +81,10 @@ export default defineConfig({
"docs/models",
"docs/themes",
"docs/keybinds",
"docs/permissions",
"docs/mcp-servers",
]
}
],
},
],
components: {
Hero: "./src/components/Hero.astro",
@@ -1,144 +1,74 @@
---
title: Permissions
description: Control what AI agents can do in your codebase.
description: Control what agents can do in your codebase.
---
The opencode permissions system provides granular control over what actions AI agents can perform in your codebase. It allows you to configure explicit approval requirements for sensitive operations like file editing, bash commands, and more.
By default, opencode **allows all operations** without requiring explicit approval.
## How it works
The permissions system provides granular control to restrict what actions AI agents can perform in your codebase, allowing you to configure explicit approval requirements for sensitive operations like file editing, bash commands, and more.
The permissions system works by intercepting tool calls and checking if user approval is required before executing potentially sensitive operations. When a tool requests permission, it creates a permission request that must be approved by the user.
---
```typescript
// Example of how a tool requests permission
await Permission.ask({
type: "edit",
sessionID: ctx.sessionID,
messageID: ctx.messageID,
callID: ctx.callID,
title: "Edit this file: " + filePath,
metadata: {
filePath,
diff,
},
})
```
## Configure
When a permission is requested, the system checks the configuration to determine if approval is needed. If approval is required, the user is prompted to allow or deny the action.
Permissions are configured in your `opencode.json` file under the `permission` key. Here are the available options.
## Configuration
---
Permissions are configured in your `opencode.json` file under the `permission` key. Here are the available options:
### edit
### permission.edit
Use the `permission.edit` key to control whether file editing operations require user approval.
Controls whether file editing operations require user approval.
- `"ask"` - Prompt for approval before editing files
- `"allow"` - Allow all file editing operations without approval
```json title="opencode.json"
```json title="opencode.json" {4}
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"edit": "ask"
}
}
```
- `"ask"` - Prompt user for approval before editing files
- `"allow"` - Allow all file editing operations without approval
---
### permission.bash
### bash
Controls whether bash commands require user approval. This can be configured globally or with specific patterns.
Controls whether bash commands require user approval.
```json title="opencode.json"
{
"permission": {
"bash": "ask"
}
}
```
:::tip
You can specify which commands you want to have run without approval.
:::
Or with specific patterns:
This can be configured globally or with specific patterns. Setting this to `"ask"` is the strictest mode, requiring approval for all bash commands.
```json title="opencode.json"
{
"permission": {
"bash": {
"git *": "allow",
"npm install": "ask",
"*": "ask"
For example.
- **Ask for approval for all commands**
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"bash": "ask"
}
}
}
```
```
## Configuration examples
- **Approve specific commands**
### Basic permission configuration
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"edit": "ask",
"bash": "ask"
}
}
```
### Advanced bash permission configuration
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"edit": "ask",
"bash": {
"git status": "allow",
"git diff": "allow",
"git add *": "ask",
"git commit*": "ask",
"npm install": "ask",
"npm run build": "allow",
"ls": "allow",
"pwd": "allow",
"*": "ask"
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"bash": {
"git status": "allow",
"git diff": "allow",
"npm run build": "allow",
"ls": "allow",
"pwd": "allow"
}
}
}
}
```
### Permissive configuration (development only)
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"edit": "allow",
"bash": "allow"
}
}
```
### Strict configuration
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"edit": "ask",
"bash": {
"*": "ask"
}
}
}
```
## Best practices
1. **Start with "ask"**: Begin with asking for permissions and adjust based on your workflow
2. **Use patterns wisely**: Create specific patterns for commands you trust
3. **Review regularly**: Periodically review your permission settings
4. **Be specific**: Use specific patterns rather than broad wildcards when possible
5. **Document exceptions**: Comment your configuration to explain why certain permissions are set
This permissions system ensures that you maintain control over what AI agents can do in your codebase while providing flexibility for trusted operations.
```
+302 -284
View File
@@ -45,6 +45,126 @@ You can customize the base URL for any provider by setting the `baseURL` option.
---
## Custom provider
To add any **OpenAI-compatible** provider that's not listed in `opencode auth login`:
:::tip
You can use any OpenAI-compatible provider with opencode. Most modern AI providers offer OpenAI-compatible APIs.
:::
1. Run `opencode auth login` and scroll down to **Other**.
```bash
$ opencode auth login
┌ Add credential
◆ Select provider
│ ...
│ ● Other
```
2. Enter a unique ID for the provider.
```bash
$ opencode auth login
┌ Add credential
◇ Enter provider id
│ myprovider
```
:::note
Choose a memorable ID, you'll use this in your config file.
:::
3. Enter your API key for the provider.
```bash
$ opencode auth login
┌ Add credential
▲ This only stores a credential for myprovider - you will need configure it in opencode.json, check the docs for examples.
◇ Enter your API key
│ sk-...
```
4. Create or update your `opencode.json` file in your project directory:
```json title="opencode.json" ""myprovider"" {5-15}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"myprovider": {
"npm": "@ai-sdk/openai-compatible",
"name": "My AI ProviderDisplay Name",
"options": {
"baseURL": "https://api.myprovider.com/v1"
},
"models": {
"my-model-name": {
"name": "My Model Display Name"
}
}
}
}
}
```
Here are the configuration options:
- **npm**: AI SDK package to use, `@ai-sdk/openai-compatible` for OpenAI-compatible providers
- **name**: Display name in UI.
- **models**: Available models.
- **options.baseURL**: API endpoint URL.
- **options.apiKey**: Optionally set the API key, if not using auth.
- **options.headers**: Optionally set custom headers.
More on the advanced options in the example below.
5. Run the `/models` command and your custom provider and models will appear in the selection list.
---
##### Example
Here's an example setting the `apiKey` and `headers` options.
```json title="opencode.json" {9,11}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"myprovider": {
"npm": "@ai-sdk/openai-compatible",
"name": "My AI ProviderDisplay Name",
"options": {
"baseURL": "https://api.myprovider.com/v1",
"apiKey": "{env:ANTHROPIC_API_KEY}",
"headers": {
"Authorization": "Bearer custom-token"
}
},
"models": {
"my-model-name": {
"name": "My Model Display Name"
}
}
}
}
}
```
We are setting the `apiKey` using the `env` variable syntax, [learn more](/docs/config#env-vars).
---
## Directory
Let's look at some of the providers in detail. If you'd like to add a provider to the
@@ -117,8 +237,30 @@ $ opencode auth login
```
This will ask you login with your Anthropic account in your browser. Now all the
the Anthropic models should be available when you use the `/models` command.
Here you can select the **Claude Pro/Max** option and it'll open your browser
and ask you to authenticate.
```bash
$ opencode auth login
┌ Add credential
◇ Select provider
│ Anthropic
◆ Login method
│ ● Claude Pro/Max
│ ○ Create API Key
│ ○ Manually enter API Key
```
Now all the the Anthropic models should be available when you use the `/models` command.
##### Using API keys
You can also select **Create API Key** if you don't have a Pro/Max subscription. It'll also open your browser and ask you to login to Anthropic and give you a code you can paste in your terminal.
Or if you already have an API key, you can select **Manually enter API Key** and paste it in your terminal.
---
@@ -185,6 +327,78 @@ the Anthropic models should be available when you use the `/models` command.
---
### DeepSeek
1. Head over to the [DeepSeek console](https://platform.deepseek.com/), create an account, and click **Create new API key**.
2. Run `opencode auth login` and select **DeepSeek**.
```bash
$ opencode auth login
┌ Add credential
◆ Select provider
│ ● DeepSeek
│ ...
```
3. Enter your DeepSeek API key.
```bash
$ opencode auth login
┌ Add credential
◇ Select provider
│ DeepSeek
◇ Enter your API key
│ _
```
4. Run the `/models` command to select a DeepSeek model like _DeepSeek Reasoner_.
---
### Fireworks AI
1. Head over to the [Fireworks AI console](https://app.fireworks.ai/), create an account, and click **Create API Key**.
2. Run `opencode auth login` and select **Fireworks AI**.
```bash
$ opencode auth login
┌ Add credential
◆ Select provider
│ ● Fireworks AI
│ ...
```
3. Enter your Fireworks AI API key.
```bash
$ opencode auth login
┌ Add credential
◇ Select provider
│ Fireworks AI
◇ Enter your API key
│ _
```
4. Run the `/models` command to select a model like _Kimi K2 Instruct_.
---
### GitHub Copilot
To use your GitHub Copilot subscription with opencode:
@@ -290,6 +504,78 @@ In this example:
---
### Moonshot AI
To use Kimi K2 from Moonshot AI:
1. Head over to the [Moonshot AI console](https://platform.moonshot.ai/console), create an account, and click **Create API key**.
2. Run `opencode auth login` and select **Other**.
```bash
$ opencode auth login
┌ Add credential
◆ Select provider
│ ...
│ ● Other
```
3. Enter `moonshot` as the provider ID.
```bash
$ opencode auth login
┌ Add credential
◇ Select provider
│ Other
◇ Enter provider id
│ moonshot
```
4. Enter your Moonshot API key.
```bash
$ opencode auth login
┌ Add credential
◇ Enter your API key
│ sk-...
```
5. Configure Moonshot in your opencode config.
```json title="opencode.json" "\"moonshot\"" {5-15}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"moonshot": {
"npm": "@ai-sdk/openai-compatible",
"name": "Moonshot AI",
"options": {
"baseURL": "https://api.moonshot.ai/v1"
},
"models": {
"kimi-k2-0711-preview": {
"name": "Kimi K2"
}
}
}
}
}
```
6. Run the `/models` command to select _Kimi K2_.
---
### Ollama
You can configure opencode to use local models through Ollama.
@@ -435,8 +721,12 @@ https://platform.openai.com/api-keys
}
```
{ /*
---
TODO: Test a model that actually works, currently getting errors form the API
for Qwen non-thinking models.
### Cerebras
Cerebras offers fast inference with generous free tiers and competitive pricing.
@@ -510,15 +800,15 @@ Cerebras offers fast inference with generous free tiers and competitive pricing.
6. Run the `/models` command to select a Cerebras model.
*/ }
---
### DeepSeek
### Together AI
DeepSeek offers powerful reasoning models at competitive prices.
1. Head over to the [Together AI console](https://api.together.ai), create an account, and click **Add Key**.
1. Head over to the [DeepSeek console](https://platform.deepseek.com/), create an account, and generate an API key.
2. Run `opencode auth login` and select **Other**.
2. Run `opencode auth login` and select **Together AI**.
```bash
$ opencode auth login
@@ -526,12 +816,12 @@ DeepSeek offers powerful reasoning models at competitive prices.
┌ Add credential
◆ Select provider
│ ● Together AI
│ ...
│ ● Other
```
3. Enter `deepseek` as the provider ID.
3. Enter your Together AI API key.
```bash
$ opencode auth login
@@ -539,286 +829,14 @@ DeepSeek offers powerful reasoning models at competitive prices.
┌ Add credential
◇ Select provider
Other
◇ Enter provider id
│ deepseek
```
4. Enter your DeepSeek API key.
```bash
$ opencode auth login
┌ Add credential
Together AI
◇ Enter your API key
sk-...
_
```
5. Configure DeepSeek in your opencode config.
```json title="opencode.json" "deepseek" {5-17}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"deepseek": {
"npm": "@ai-sdk/openai-compatible",
"name": "DeepSeek",
"options": {
"baseURL": "https://api.deepseek.com/v1"
},
"models": {
"deepseek-reasoner": {
"name": "DeepSeek Reasoner"
}
}
}
}
}
```
6. Run the `/models` command to select a DeepSeek model.
---
### Moonshot AI (Kimi)
Moonshot AI offers the Kimi models with long context capabilities.
1. Head over to the [Moonshot AI console](https://platform.moonshot.cn/), create an account, and generate an API key.
2. Run `opencode auth login` and select **Other**.
```bash
$ opencode auth login
┌ Add credential
◆ Select provider
│ ...
│ ● Other
```
3. Enter `moonshot` as the provider ID.
```bash
$ opencode auth login
┌ Add credential
◇ Select provider
│ Other
◇ Enter provider id
│ moonshot
```
4. Enter your Moonshot API key.
```bash
$ opencode auth login
┌ Add credential
◇ Enter your API key
│ sk-...
```
5. Configure Moonshot in your opencode config.
```json title="opencode.json" "moonshot" {5-17}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"moonshot": {
"npm": "@ai-sdk/openai-compatible",
"name": "Moonshot AI",
"options": {
"baseURL": "https://api.moonshot.cn/v1"
},
"models": {
"kimi-k2-0711-preview": {
"name": "Kimi K2"
}
}
}
}
}
```
6. Run the `/models` command to select a Kimi model.
---
### Custom
To add any **OpenAI-compatible** provider that's not listed in `opencode auth login`:
:::tip
You can use any OpenAI-compatible provider with opencode. Most modern AI providers offer OpenAI-compatible APIs.
:::
1. Run `opencode auth login` and scroll down to **Other**.
```bash
$ opencode auth login
┌ Add credential
◆ Select provider
│ ...
│ ● Other
```
2. Enter a unique ID for the provider.
```bash
$ opencode auth login
┌ Add credential
◇ Enter provider id
│ myprovider
```
:::note
Choose a memorable ID, you'll use this in your config file.
:::
3. Enter your API key for the provider.
```bash
$ opencode auth login
┌ Add credential
▲ This only stores a credential for myprovider - you will need configure it in opencode.json, check the docs for examples.
◇ Enter your API key
│ sk-...
```
4. Create or update your `opencode.json` file in your project directory:
```json title="opencode.json" ""myprovider"" {5-15}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"myprovider": {
"npm": "@ai-sdk/openai-compatible",
"name": "My AI ProviderDisplay Name",
"options": {
"baseURL": "https://api.myprovider.com/v1"
},
"models": {
"my-model-name": {
"name": "My Model Display Name"
}
}
}
}
}
```
Here are the configuration options:
- **npm**: AI SDK package to use, `@ai-sdk/openai-compatible` for OpenAI-compatible providers
- **name**: Display name in UI.
- **models**: Available models.
- **options.baseURL**: API endpoint URL.
- **options.apiKey**: Optionally set the API key, if not using auth.
- **options.headers**: Optionally set custom headers.
More on the advanced options in the example below.
5. Run the `/models` command and your custom provider and models will appear in the selection list.
---
##### Example
Here's an example setting the `apiKey` and `headers` options.
```json title="opencode.json" {9,11}
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"myprovider": {
"npm": "@ai-sdk/openai-compatible",
"name": "My AI ProviderDisplay Name",
"options": {
"baseURL": "https://api.myprovider.com/v1",
"apiKey": "{env:ANTHROPIC_API_KEY}",
"headers": {
"Authorization": "Bearer custom-token"
}
},
"models": {
"my-model-name": {
"name": "My Model Display Name"
}
}
}
}
}
```
We are setting the `apiKey` using the `env` variable syntax, [learn more](/docs/config#env-vars).
#### Common Examples
**Together AI:**
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"together": {
"npm": "@ai-sdk/openai-compatible",
"name": "Together AI",
"options": {
"baseURL": "https://api.together.xyz/v1"
},
"models": {
"meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo": {
"name": "Llama 3.2 11B Vision"
}
}
}
}
}
```
**Fireworks AI:**
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"fireworks": {
"npm": "@ai-sdk/openai-compatible",
"name": "Fireworks AI",
"options": {
"baseURL": "https://api.fireworks.ai/inference/v1"
},
"models": {
"accounts/fireworks/models/llama-v3p1-70b-instruct": {
"name": "Llama 3.1 70B"
}
}
}
}
}
```
4. Run the `/models` command to select a model like _Kimi K2 Instruct_.
---
+1 -1
View File
@@ -57,7 +57,7 @@ export function activate(context: vscode.ExtensionContext) {
})
terminal.show()
terminal.sendText(`OPENCODE_THEME=system OPENCODE_CALLER=vscode opencode --port ${port}`)
terminal.sendText(`OPENCODE_CALLER=vscode opencode --port ${port}`)
const fileRef = getActiveFile()
if (!fileRef) return