From e4d3b81b0e64442bedae267a78c374a6d8b0b7e5 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Sat, 30 May 2026 04:07:26 +0000 Subject: [PATCH] chore: generate --- packages/core/src/config.ts | 21 ++-- packages/core/src/plugin/boot.ts | 8 +- packages/core/src/state.ts | 6 +- packages/core/test/agent.test.ts | 4 +- packages/core/test/config/config.test.ts | 17 ++- .../test/provider/header-timeout.test.ts | 7 +- packages/sdk/js/src/v2/gen/types.gen.ts | 33 ++++-- packages/sdk/openapi.json | 71 ++++++++++-- packages/web/src/content/docs/policies.mdx | 6 +- specs/v2/catalog-config-plugin-lifecycle.md | 6 +- specs/v2/config.md | 107 +++++++++--------- 11 files changed, 182 insertions(+), 104 deletions(-) diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 88ff2ef91e..c9e1396739 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -32,17 +32,21 @@ export class Info extends Schema.Class("Config.Info")({ model: Schema.String.pipe(Schema.optional).annotate({ description: "Default model to use when no session or agent model is selected", }), - autoupdate: Schema.Union([Schema.Boolean, Schema.Literal("notify")]).pipe(Schema.optional).annotate({ - description: "Automatically update or notify when a new version is available", - }), + autoupdate: Schema.Union([Schema.Boolean, Schema.Literal("notify")]) + .pipe(Schema.optional) + .annotate({ + description: "Automatically update or notify when a new version is available", + }), share: Schema.Literals(["manual", "auto", "disabled"]).pipe(Schema.optional).annotate({ description: "Control whether sessions may be shared manually, automatically, or not at all", }), enterprise: Schema.Struct({ url: Schema.String.pipe(Schema.optional), - }).pipe(Schema.optional).annotate({ - description: "Enterprise sharing service configuration", - }), + }) + .pipe(Schema.optional) + .annotate({ + description: "Enterprise sharing service configuration", + }), username: Schema.String.pipe(Schema.optional).annotate({ description: "Username displayed in conversations and used for telemetry identity", }), @@ -196,7 +200,4 @@ export const layer = Layer.effect( }), ) -export const defaultLayer = layer.pipe( - Layer.provide(AppFileSystem.defaultLayer), - Layer.provide(Global.defaultLayer), -) +export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer), Layer.provide(Global.defaultLayer)) diff --git a/packages/core/src/plugin/boot.ts b/packages/core/src/plugin/boot.ts index 39faa62f8d..5b70e391d7 100644 --- a/packages/core/src/plugin/boot.ts +++ b/packages/core/src/plugin/boot.ts @@ -18,7 +18,13 @@ import { ProviderPlugins } from "./provider" type Plugin = { id: PluginV2.ID effect: PluginV2.Effect< - Catalog.Service | AccountV2.Service | AgentV2.Service | Npm.Service | EventV2.Service | PluginV2.Service | Config.Service + | Catalog.Service + | AccountV2.Service + | AgentV2.Service + | Npm.Service + | EventV2.Service + | PluginV2.Service + | Config.Service > } diff --git a/packages/core/src/state.ts b/packages/core/src/state.ts index 1d67acaa92..b764699e08 100644 --- a/packages/core/src/state.ts +++ b/packages/core/src/state.ts @@ -15,11 +15,7 @@ export interface Options { export interface Interface { readonly get: () => State - readonly transform: () => Effect.Effect< - (transform: Transform) => Effect.Effect, - never, - Scope.Scope - > + readonly transform: () => Effect.Effect<(transform: Transform) => Effect.Effect, never, Scope.Scope> readonly update: (update: (editor: Editor) => Effect.Effect, reason?: string) => Effect.Effect } diff --git a/packages/core/test/agent.test.ts b/packages/core/test/agent.test.ts index 2449a91a7c..f4b7867a81 100644 --- a/packages/core/test/agent.test.ts +++ b/packages/core/test/agent.test.ts @@ -94,9 +94,7 @@ describe("AgentV2", () => { const id = AgentV2.ID.make("custom") yield* agent.update((editor) => Effect.sync(() => editor.update(id, () => {}))) - expect(yield* agent.get(id)).toEqual( - AgentV2.Info.empty(id), - ) + expect(yield* agent.get(id)).toEqual(AgentV2.Info.empty(id)) yield* agent.update((editor) => Effect.sync(() => editor.remove(id))) expect(yield* agent.get(id)).toBeUndefined() diff --git a/packages/core/test/config/config.test.ts b/packages/core/test/config/config.test.ts index 0a39ed4b3e..21f9e3e3d1 100644 --- a/packages/core/test/config/config.test.ts +++ b/packages/core/test/config/config.test.ts @@ -194,9 +194,14 @@ describe("Config", () => { }, snapshots: false, watcher: { ignore: ["node_modules/**", "dist/**", ".git"] }, - formatter: { prettier: { disabled: true }, custom: { command: ["custom-fmt", "$FILE"], extensions: [".foo"] } }, + formatter: { + prettier: { disabled: true }, + custom: { command: ["custom-fmt", "$FILE"], extensions: [".foo"] }, + }, lsp: { typescript: { disabled: true }, custom: { command: ["custom-lsp"], extensions: [".foo"] } }, - attachments: { image: { auto_resize: false, max_width: 1200, max_height: 900, max_base64_bytes: 1048576 } }, + attachments: { + image: { auto_resize: false, max_width: 1200, max_height: 900, max_base64_bytes: 1048576 }, + }, tool_output: { max_lines: 1000, max_bytes: 32768 }, mcp: { timeout: 5000, @@ -370,11 +375,15 @@ describe("Config", () => { await fs.mkdir(global, { recursive: true }) await fs.writeFile( path.join(global, "opencode.json"), - JSON.stringify({ experimental: { policies: [{ effect: "deny", action: "provider.use", resource: "openai" }] } }), + JSON.stringify({ + experimental: { policies: [{ effect: "deny", action: "provider.use", resource: "openai" }] }, + }), ) await fs.writeFile( path.join(tmp.path, "opencode.json"), - JSON.stringify({ experimental: { policies: [{ effect: "allow", action: "provider.use", resource: "openai" }] } }), + JSON.stringify({ + experimental: { policies: [{ effect: "allow", action: "provider.use", resource: "openai" }] }, + }), ) }) diff --git a/packages/opencode/test/provider/header-timeout.test.ts b/packages/opencode/test/provider/header-timeout.test.ts index 8860c39c32..0763ed2010 100644 --- a/packages/opencode/test/provider/header-timeout.test.ts +++ b/packages/opencode/test/provider/header-timeout.test.ts @@ -17,12 +17,7 @@ afterEach(async () => { }) const it = testEffect( - Layer.mergeAll( - Provider.defaultLayer, - Env.defaultLayer, - Plugin.defaultLayer, - CrossSpawnSpawner.defaultLayer, - ), + Layer.mergeAll(Provider.defaultLayer, Env.defaultLayer, Plugin.defaultLayer, CrossSpawnSpawner.defaultLayer), ) it.live("headerTimeout does not abort delayed SSE body after headers arrive", () => diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index f393b94849..cdc2f7f574 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -77,6 +77,7 @@ export type Event = | EventSessionNextCompactionStarted | EventSessionNextCompactionDelta | EventSessionNextCompactionEnded + | EventPluginAdded | EventCatalogModelUpdated | EventModelsDevRefreshed | EventAccountAdded @@ -878,6 +879,7 @@ export type GlobalEvent = { | EventSessionNextCompactionStarted | EventSessionNextCompactionDelta | EventSessionNextCompactionEnded + | EventPluginAdded | EventCatalogModelUpdated | EventModelsDevRefreshed | EventAccountAdded @@ -1316,6 +1318,7 @@ export type Config = { primary_tools?: Array continue_loop_on_deny?: boolean mcp_timeout?: number + policies?: Array } } @@ -2137,7 +2140,7 @@ export type SyncEventSessionNextModelSwitched = { model: { id: string providerID: string - variant: string + variant?: string } } } @@ -2209,7 +2212,7 @@ export type SyncEventSessionNextStepStarted = { model: { id: string providerID: string - variant: string + variant?: string } snapshot?: string } @@ -2890,7 +2893,7 @@ export type EventSessionNextModelSwitched = { model: { id: string providerID: string - variant: string + variant?: string } } } @@ -2978,7 +2981,7 @@ export type EventSessionNextStepStarted = { model: { id: string providerID: string - variant: string + variant?: string } snapshot?: string } @@ -3252,6 +3255,14 @@ export type EventSessionNextCompactionEnded = { } } +export type EventPluginAdded = { + id: string + type: "plugin.added" + properties: { + id: string + } +} + export type ModelV2Info = { id: string apiID: string @@ -3416,6 +3427,14 @@ export type EventAccountSwitched = { } } +export type PolicyEffect = "allow" | "deny" + +export type ConfigV2ExperimentalPolicy = { + action: "provider.use" + effect: PolicyEffect + resource: string +} + export type SessionInfo = { id: string parentID?: string @@ -3426,7 +3445,7 @@ export type SessionInfo = { model?: { id: string providerID: string - variant: string + variant?: string } cost: number tokens: { @@ -3472,7 +3491,7 @@ export type SessionMessageModelSwitched = { model: { id: string providerID: string - variant: string + variant?: string } } @@ -3607,7 +3626,7 @@ export type SessionMessageAssistant = { model: { id: string providerID: string - variant: string + variant?: string } content: Array snapshot?: { diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 53b8966fa6..3f626dc3ff 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -10698,6 +10698,9 @@ { "$ref": "#/components/schemas/EventSessionNextCompactionEnded" }, + { + "$ref": "#/components/schemas/EventPluginAdded" + }, { "$ref": "#/components/schemas/EventCatalogModelUpdated" }, @@ -13124,6 +13127,9 @@ { "$ref": "#/components/schemas/EventSessionNextCompactionEnded" }, + { + "$ref": "#/components/schemas/EventPluginAdded" + }, { "$ref": "#/components/schemas/EventCatalogModelUpdated" }, @@ -14330,6 +14336,12 @@ "mcp_timeout": { "type": "integer", "exclusiveMinimum": 0 + }, + "policies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigV2ExperimentalPolicy" + } } }, "additionalProperties": false @@ -16969,7 +16981,7 @@ "type": "string" } }, - "required": ["id", "providerID", "variant"], + "required": ["id", "providerID"], "additionalProperties": false } }, @@ -17201,7 +17213,7 @@ "type": "string" } }, - "required": ["id", "providerID", "variant"], + "required": ["id", "providerID"], "additionalProperties": false }, "snapshot": { @@ -19307,7 +19319,7 @@ "type": "string" } }, - "required": ["id", "providerID", "variant"], + "required": ["id", "providerID"], "additionalProperties": false } }, @@ -19570,7 +19582,7 @@ "type": "string" } }, - "required": ["id", "providerID", "variant"], + "required": ["id", "providerID"], "additionalProperties": false }, "snapshot": { @@ -20386,6 +20398,30 @@ "required": ["id", "type", "properties"], "additionalProperties": false }, + "EventPluginAdded": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["plugin.added"] + }, + "properties": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": ["id"], + "additionalProperties": false + } + }, + "required": ["id", "type", "properties"], + "additionalProperties": false + }, "ModelV2Info": { "type": "object", "properties": { @@ -20900,6 +20936,27 @@ "required": ["id", "type", "properties"], "additionalProperties": false }, + "PolicyEffect": { + "type": "string", + "enum": ["allow", "deny"] + }, + "ConfigV2ExperimentalPolicy": { + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": ["provider.use"] + }, + "effect": { + "$ref": "#/components/schemas/PolicyEffect" + }, + "resource": { + "type": "string" + } + }, + "required": ["action", "effect", "resource"], + "additionalProperties": false + }, "SessionInfo": { "type": "object", "properties": { @@ -20937,7 +20994,7 @@ "type": "string" } }, - "required": ["id", "providerID", "variant"], + "required": ["id", "providerID"], "additionalProperties": false }, "cost": { @@ -21065,7 +21122,7 @@ "type": "string" } }, - "required": ["id", "providerID", "variant"], + "required": ["id", "providerID"], "additionalProperties": false } }, @@ -21444,7 +21501,7 @@ "type": "string" } }, - "required": ["id", "providerID", "variant"], + "required": ["id", "providerID"], "additionalProperties": false }, "content": { diff --git a/packages/web/src/content/docs/policies.mdx b/packages/web/src/content/docs/policies.mdx index 0f059562e2..c2ada5d14b 100644 --- a/packages/web/src/content/docs/policies.mdx +++ b/packages/web/src/content/docs/policies.mdx @@ -42,9 +42,9 @@ A provider denied by policy is not available for model selection or model use, e OpenCode currently supports one policy action: -| Action | Resource | Description | -| -------------- | ------------------------------ | ------------------------------------------ | -| `provider.use` | Provider ID, such as `openai` | Allow or deny use of an LLM provider. | +| Action | Resource | Description | +| -------------- | ----------------------------- | ------------------------------------- | +| `provider.use` | Provider ID, such as `openai` | Allow or deny use of an LLM provider. | More policy actions may be added in the future. diff --git a/specs/v2/catalog-config-plugin-lifecycle.md b/specs/v2/catalog-config-plugin-lifecycle.md index 0781283657..986cc019a3 100644 --- a/specs/v2/catalog-config-plugin-lifecycle.md +++ b/specs/v2/catalog-config-plugin-lifecycle.md @@ -192,11 +192,7 @@ Plugins register replayable catalog transforms. Each transform receives a `Catal ```ts interface Catalog { - transform(): Effect.Effect< - (update: (catalog: Catalog.Editor) => void) => Effect.Effect, - never, - Scope.Scope - > + transform(): Effect.Effect<(update: (catalog: Catalog.Editor) => void) => Effect.Effect, never, Scope.Scope> } ``` diff --git a/specs/v2/config.md b/specs/v2/config.md index 55caf2e668..5edfc1e4dd 100644 --- a/specs/v2/config.md +++ b/specs/v2/config.md @@ -36,12 +36,12 @@ Settings that affect process startup, shell execution, or network serving. Revie Configuration that introduces location-scoped project resources or discoverable content. -| Field | Current Purpose | Status | Notes | -| -------------- | --------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------- | -| `command` | User-defined commands | remove | Do not port as v2 config; named reusable user workflows belong to skills. | -| `skills` | Additional skill locations | redesign | Replace `{ paths?, urls? }` with a single array of local path or remote URL discovery sources. | -| `reference` | Named git or local directory references | redesign | Rename to plural `references`; retain named local path and Git repository external-context entries. | -| `instructions` | Additional ambient instruction sources | keep | Keep as one array of local paths, glob patterns, or remote URLs supplying automatically included context. | +| Field | Current Purpose | Status | Notes | +| -------------- | --------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------- | +| `command` | User-defined commands | remove | Do not port as v2 config; named reusable user workflows belong to skills. | +| `skills` | Additional skill locations | redesign | Replace `{ paths?, urls? }` with a single array of local path or remote URL discovery sources. | +| `reference` | Named git or local directory references | redesign | Rename to plural `references`; retain named local path and Git repository external-context entries. | +| `instructions` | Additional ambient instruction sources | keep | Keep as one array of local paths, glob patterns, or remote URLs supplying automatically included context. | V2 does not expose separate user-authored command configuration. Skills should cover named reusable prompt workflows, whether invoked directly by the user or loaded by an agent. Internal command routing and built-in commands may remain runtime concerns without creating a `command` or `commands` config field. @@ -59,7 +59,12 @@ Keep ambient instructions separate from skills. Instructions are automatically i ```jsonc { - "instructions": ["CONTRIBUTING.md", "docs/guidelines.md", ".cursor/rules/*.md", "https://example.com/shared-rules.md"], + "instructions": [ + "CONTRIBUTING.md", + "docs/guidelines.md", + ".cursor/rules/*.md", + "https://example.com/shared-rules.md", + ], } ``` @@ -80,9 +85,9 @@ Retain the compact string entry form as well: values starting with `.`, `/`, or Plugin loading has source-path and scope-sensitive behavior, so it should be reviewed separately from other project resources. -| Field | Current Purpose | Status | Notes | -| -------- | ----------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- | -| `plugin` | User-specified plugin modules | redesign | Rename to plural `plugins`; retain ordered loading with package strings or `{ package, options? }` entries. | +| Field | Current Purpose | Status | Notes | +| -------- | ----------------------------- | -------- | ----------------------------------------------------------------------------------------------------------- | +| `plugin` | User-specified plugin modules | redesign | Rename to plural `plugins`; retain ordered loading with package strings or `{ package, options? }` entries. | Plugin order remains part of the v2 configuration contract because hook registration and execution can depend on load order. Replace legacy option tuples with readable object entries: @@ -106,14 +111,14 @@ The configured `plugins` list represents package-loaded plugins only. Local plug Settings controlling local file observation, snapshots, language tooling, and tool output behavior. -| Field | Current Purpose | Status | Notes | -| ------------- | --------------------------------------- | ------- | ----- | -| `watcher` | Ignore patterns for filesystem watching | keep | Keep `{ ignore?: string[] }`; this configures the filesystem watcher subsystem. | -| `snapshot` | Enable filesystem snapshot tracking | redesign | Rename to plural `snapshots`; controls creation of snapshots used for undo and revert behavior. | -| `formatter` | Configure formatters | keep | Keep singular `boolean \| Record` shape; it configures built-in enablement and named formatter overrides. | -| `lsp` | Configure language servers | keep | Keep singular `boolean \| Record` shape; custom servers need commands and file extensions. | +| Field | Current Purpose | Status | Notes | +| ------------- | --------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `watcher` | Ignore patterns for filesystem watching | keep | Keep `{ ignore?: string[] }`; this configures the filesystem watcher subsystem. | +| `snapshot` | Enable filesystem snapshot tracking | redesign | Rename to plural `snapshots`; controls creation of snapshots used for undo and revert behavior. | +| `formatter` | Configure formatters | keep | Keep singular `boolean \| Record` shape; it configures built-in enablement and named formatter overrides. | +| `lsp` | Configure language servers | keep | Keep singular `boolean \| Record` shape; custom servers need commands and file extensions. | | `attachment` | Configure attachment/image processing | redesign | Rename to plural `attachments`; retain `{ image?: { auto_resize?, max_width?, max_height?, max_base64_bytes? } }` for input normalization limits. | -| `tool_output` | Configure tool output truncation limits | keep | Keep `{ max_lines?, max_bytes? }`; both positive thresholds apply to saved-preview truncation behavior. | +| `tool_output` | Configure tool output truncation limits | keep | Keep `{ max_lines?, max_bytes? }`; both positive thresholds apply to saved-preview truncation behavior. | `formatter` and `lsp` configure one project tooling subsystem each, so their singular names remain appropriate. `true` enables the built-in registrations, `false` disables them, and a keyed object enables built-ins while applying named overrides or custom registrations. Custom language servers must declare `extensions` so runtime file attachment is deterministic; validation of known built-in server IDs belongs with the eventual v2 LSP integration rather than the aggregate core config schema. @@ -140,12 +145,12 @@ Rename legacy `attachment` to `attachments` in v2. This setting controls process Settings affecting sharing behavior or user/account identity rather than model execution. -| Field | Current Purpose | Status | Notes | -| ------------ | ----------------------------------------------- | ------- | ------------------------------- | -| `share` | Session sharing behavior | keep | Keep `"manual" \| "auto" \| "disabled"`; it controls manual sharing permission and automatic sharing of new sessions. | -| `autoshare` | Legacy automatic sharing flag | remove | Do not port deprecated alias; use `share: "auto"`. | +| Field | Current Purpose | Status | Notes | +| ------------ | ----------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- | +| `share` | Session sharing behavior | keep | Keep `"manual" \| "auto" \| "disabled"`; it controls manual sharing permission and automatic sharing of new sessions. | +| `autoshare` | Legacy automatic sharing flag | remove | Do not port deprecated alias; use `share: "auto"`. | | `enterprise` | Enterprise URL configuration | keep | Keep `{ url?: string }`; currently selects the legacy sharing service endpoint when no organization account is active. | -| `username` | Display username in conversations and telemetry | keep | Keep string identity override; runtime may otherwise resolve an operating-system username. | +| `username` | Display username in conversations and telemetry | keep | Keep string identity override; runtime may otherwise resolve an operating-system username. | Retain `share` as the single session-sharing setting. `"manual"` permits explicit sharing, `"auto"` shares newly created top-level sessions, and `"disabled"` prevents sharing. Legacy `autoshare: true` is only an alias for `share: "auto"`, so v2 does not expose it. @@ -163,13 +168,13 @@ Retain `enterprise.url` for legacy enterprise share hosting selection and `usern Provider catalog customization and model-choice configuration. The new core work has started here. -| Field | Current Purpose | Status | Notes | -| -------------------- | ------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------- | +| Field | Current Purpose | Status | Notes | +| -------------------- | ------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- | | `provider` | Custom provider configuration and model overrides | redesign | Rename to plural `providers` in v2; do not preserve the legacy singular key. Review nested provider/model fields separately. | -| `disabled_providers` | Disable automatically loaded providers | redesign | Replace with `experimental.policies: [{ effect: "deny", action: "provider.use", resource: "..." }]`. | -| `enabled_providers` | Restrict enabled providers to an allowlist | redesign | Replace with ordered `provider.use` allow/deny statements and wildcard resources. | -| `model` | Default model selection | keep | Keep as the fallback model when an active session or agent does not specify a model. | -| `small_model` | Small/utility model selection | remove | Do not port; its only runtime consumer is title generation, which can use an explicit `title` agent model override. | +| `disabled_providers` | Disable automatically loaded providers | redesign | Replace with `experimental.policies: [{ effect: "deny", action: "provider.use", resource: "..." }]`. | +| `enabled_providers` | Restrict enabled providers to an allowlist | redesign | Replace with ordered `provider.use` allow/deny statements and wildcard resources. | +| `model` | Default model selection | keep | Keep as the fallback model when an active session or agent does not specify a model. | +| `small_model` | Small/utility model selection | remove | Do not port; its only runtime consumer is title generation, which can use an explicit `title` agent model override. | Provider selection rules belong in `experimental.policies` rather than provider entries or repeated top-level provider fields. Initial proposed shape: @@ -221,9 +226,7 @@ Do not port legacy provider model `reasoning`, `temperature`, or `interleaved` f "api_id": "upstream-chat-model", "limit": { "output": 32768 }, "cost": { "input": 1.25, "output": 10 }, - "variants": [ - { "id": "high", "aisdk": { "request": { "reasoningEffort": "high" } } }, - ], + "variants": [{ "id": "high", "aisdk": { "request": { "reasoningEffort": "high" } } }], }, }, }, @@ -235,13 +238,13 @@ Do not port legacy provider model `reasoning`, `temperature`, or `interleaved` f Agent behavior and tool-access policy. Review together because agent configuration can contain permissions and model choices. -| Field | Current Purpose | Status | Notes | -| --------------- | --------------------------------------------------- | ------- | ------------------------------------------- | -| `default_agent` | Choose default primary agent | remove | Do not retain a separate top-level selector; default choice should be designed with the v2 agent configuration model. | -| `mode` | Legacy agent configuration alias | remove | Do not port deprecated alias; configure agents through the v2 agent surface only. | -| `agent` | Configure primary, subagent, and specialized agents | redesign | Rename to plural `agents`; retain a named map of built-in overrides and custom agent definitions. | +| Field | Current Purpose | Status | Notes | +| --------------- | --------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `default_agent` | Choose default primary agent | remove | Do not retain a separate top-level selector; default choice should be designed with the v2 agent configuration model. | +| `mode` | Legacy agent configuration alias | remove | Do not port deprecated alias; configure agents through the v2 agent surface only. | +| `agent` | Configure primary, subagent, and specialized agents | redesign | Rename to plural `agents`; retain a named map of built-in overrides and custom agent definitions. | | `permission` | Tool permission rules | redesign | Rename to plural `permissions`; replace legacy map shorthand with an ordered array of `{ permission, pattern, action }` rules. | -| `tools` | Legacy tool enable/disable map | remove | Do not port boolean enable/disable alias; express tool access through permissions. | +| `tools` | Legacy tool enable/disable map | remove | Do not port boolean enable/disable alias; express tool access through permissions. | Do not port `default_agent` ahead of the v2 agent design. The legacy runtime uses it to choose a visible, non-subagent fallback instead of `build`, but exposing that selection as an isolated top-level field would pre-commit v2 to the legacy agent model before agents and their policy surface are defined together. @@ -278,9 +281,7 @@ Retain `description`, `hidden`, and `steps`; they define an agent's discoverabil "color": "warning", "steps": 12, "disabled": false, - "permissions": [ - { "permission": "edit", "pattern": "*", "action": "deny" }, - ], + "permissions": [{ "permission": "edit", "pattern": "*", "action": "deny" }], }, }, } @@ -303,8 +304,8 @@ Rename legacy `permission` to `permissions` and expose the normalized ordered ru External protocol and server integration configuration. -| Field | Current Purpose | Status | Notes | -| ----- | ------------------------------------- | ------- | ----- | +| Field | Current Purpose | Status | Notes | +| ----- | ------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `mcp` | MCP server definitions and enablement | redesign | Keep opencode's explicit local/remote server entry format, nested under `mcp.servers`; use `disabled` for inactive entries and move timeout here. | Keep the opencode MCP server entry format instead of adopting the common `mcpServers` copy/paste shape. Local servers remain explicit `type: "local"` entries with command arrays and `environment`; remote servers remain explicit `type: "remote"` entries with `url`, `headers`, and optional `oauth`. Nest the server map under `mcp.servers` so protocol-wide settings such as default timeout can live under the same subsystem. @@ -343,8 +344,8 @@ Keep the opencode MCP server entry format instead of adopting the common `mcpSer Behavior affecting long-running conversations and context management. -| Field | Current Purpose | Status | Notes | -| ------------ | ----------------------------------------------------------- | ------- | ----- | +| Field | Current Purpose | Status | Notes | +| ------------ | ----------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------- | | `compaction` | Automatic compaction, pruning, and context reserve settings | redesign | Group retained verbatim history under `keep` and rename context headroom to `buffer`. | Retain the compaction capability but redesign the less clear limits. `keep.turns` is the maximum number of recent user turns to preserve verbatim after compaction, and `keep.tokens` is the token budget for those retained turns. `buffer` is the token headroom reserved so automatic compaction triggers before the input window is exhausted. @@ -367,15 +368,15 @@ Retain the compaction capability but redesign the less clear limits. `keep.turns Fields that should not be ported by inertia; each needs an explicit justification. -| Field | Current Purpose | Status | Notes | -| ------------------------------------ | --------------------------------------- | ------- | ------------------------------------------------------------------- | -| `layout` | Legacy layout selection | remove | Do not port deprecated option; stretch layout is always used. | -| `experimental.disable_paste_summary` | Disable pasted-content summary behavior | remove | Do not port; pasted-input presentation behavior belongs to the client/UI surface. | -| `experimental.batch_tool` | Enable batch tool | remove | Do not port; batch tool is no longer a supported feature. | -| `experimental.openTelemetry` | Enable AI SDK telemetry spans | remove | Do not port; observability is process-level and should use standard OpenTelemetry environment or declarative configuration. | -| `experimental.primary_tools` | Restrict tools to primary agents | remove | Do not port obsolete gating; agent tool access is configured through permissions. | -| `experimental.continue_loop_on_deny` | Continue loop after denied tool call | remove | Do not port legacy denied-tool loop behavior. | -| `experimental.mcp_timeout` | MCP request timeout | redesign | Move to `mcp.timeout` for the default and `mcp.servers..timeout` for per-server overrides. | +| Field | Current Purpose | Status | Notes | +| ------------------------------------ | --------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | +| `layout` | Legacy layout selection | remove | Do not port deprecated option; stretch layout is always used. | +| `experimental.disable_paste_summary` | Disable pasted-content summary behavior | remove | Do not port; pasted-input presentation behavior belongs to the client/UI surface. | +| `experimental.batch_tool` | Enable batch tool | remove | Do not port; batch tool is no longer a supported feature. | +| `experimental.openTelemetry` | Enable AI SDK telemetry spans | remove | Do not port; observability is process-level and should use standard OpenTelemetry environment or declarative configuration. | +| `experimental.primary_tools` | Restrict tools to primary agents | remove | Do not port obsolete gating; agent tool access is configured through permissions. | +| `experimental.continue_loop_on_deny` | Continue loop after denied tool call | remove | Do not port legacy denied-tool loop behavior. | +| `experimental.mcp_timeout` | MCP request timeout | redesign | Move to `mcp.timeout` for the default and `mcp.servers..timeout` for per-server overrides. | ## Review Order