Skip to content

config: published schema (opencode.ai/config.json) is still V1, so editors flag valid V2 configs #50852

Closed

Description

@chuangye-gu

Summary

The schema published at https://opencode.ai/config.json — which is also what the SchemaStore opencode entry points at, so editors apply it automatically — is still the V1 root schema. V2 configs using providers / plugins / mcp.servers are therefore reported as invalid by every editor that follows it, even though V2 accepts and uses them. There is also no V2 schema at any of the obvious URLs.

Environment

  • opencode version: 2.0.13 (opencode --version → opencode v2.0.13, channel=latest local=false)
  • OS: Linux a100server 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64
  • Editor: VS Code 1.136.1 (built-in JSON language service, default SchemaStore catalog, no json.schemas overrides, no user settings.json)
  • Shell: /bin/bash
  • Install/channel: curl -fsSL https://opencode.ai/v2/install | bash
  • Active plugins: none

Reproduction

  1. Write a V2-shaped config:
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "demo": { "type": "remote", "url": "https://example.com/mcp" }
    }
  },
  "providers": {
    "custom": {
      "package": "@opencode/ai/providers/openai-compatible",
      "settings": { "baseURL": "https://example.com/v1", "apiKey": "x" },
      "models": { "m1": { "name": "m1", "limit": { "context": 100000 } } }
    }
  }
}
  1. Validate it against https://opencode.ai/config.json (or just open it in VS Code):
Additional properties are not allowed ('providers' was unexpected)
{'demo': {'type': 'remote', 'url': 'https://example.com/mcp'}} is not valid under any of the given schemas
  1. Note that V2 itself accepts this config and works: opencode debug config keeps it, the MCP server connects, the provider is usable.

Expected Behavior

The schema served at https://opencode.ai/config.json (or a new V2 URL referenced from it) should describe V2's config keys: providers (with package / settings), plugins, and mcp.servers.<name>.

Actual Behavior

The root of the published schema is the V1 shape:

  • root properties (36 total) include provider (singular), plugin, server, lsp; there is no providers and no plugins
  • the strings "providers" and "servers" appear 0 times in the file
  • mcp is the flat V1 map, with no servers key:
{"type":"object","additionalProperties":{"anyOf":[{"anyOf":[{"$ref":"#/$defs/McpLocalConfig"},{"$ref":"#/$defs/McpRemoteConfig"}]},{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"],"additionalProperties":false}]}}
  • meanwhile the $defs (McpLocalConfig / McpRemoteConfig, including enabled, oauth, timeout) do look newer than the root, so the file is internally inconsistent

Consequences:

  • VS Code (and anything else using the SchemaStore catalog) flags valid V2 configs. The catalog entry:
{
  "name": "opencode",
  "description": "opencode AI coding agent configuration file",
  "fileMatch": ["opencode.json", "opencode.jsonc", "**/.opencode/opencode.json", "**/.opencode/opencode.jsonc"],
  "url": "https://opencode.ai/config.json"
}
  • the file's own $schema cannot help either, because the only URL available serves the V1 schema; and a V2 config that omits $schema still gets the V1 schema applied automatically by the catalog
  • the documented V1 provider key is silently ignored by V2 (verified: opencode debug config drops it, no diagnostic), so the schema currently points users at a key that does nothing

Additional Context

  • No V2 schema URL found — all 404: https://opencode.ai/v2/config.json, https://opencode.ai/v2/schema.json, https://opencode.ai/config.v2.json, https://opencode.ai/schema.json. The V2 binary only references https://opencode.ai/config.json, https://opencode.ai/v2/cli.json, https://opencode.ai/v2/openapi.json.
  • Workaround in use: hand-written local schema shims (copy the published schema, add providers / plugins / mcp.servers and relax model.limit). It works, but every V2 user has to reinvent it.
  • Related: mcp: server entries with a "timeout" field are silently dropped from the normalized config #50807 (mcp.servers.<name>.timeout is silently dropped by the V2 runtime). The published schema documents timeout for both McpLocalConfig and McpRemoteConfig, which is another way the current schema misleads users about V2 behavior.

Activity

  1. github-actions commented on Sep 23, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    These issues track the same root cause: the schema served at https://opencode.ai/config.json describes a V1/hybrid shape rather than the current V2 config format.

  2. chuangye-gu commented on Sep 23, 2026

    @chuangye-gu
    Author

    Duplicate of #43748 — the published schema is still generated from the V1 shapes (root cause traced to packages/opencode/script/schema.ts:72). Also related: #50724 and #41014. Closing in favour of #43748; I moved the one extra detail I had (the SchemaStore catalog entry, which is why removing $schema does not help) over there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions