Skip to content

Add a dedicated Kilo v2 config schema and coordinate the release URL cutover #8397

Open

Description

@marius-kilocode

Implement

Add a dedicated, public Kilo v2 configuration JSON Schema endpoint at https://app.kilo.ai/kilo2/config.json. Serve a generated JSON artifact from a pinned Kilo source checkout. Do not change the existing v1-facing /config.json route, and do not fetch the live OpenCode schema on each request.

The schema is for editor validation/autocomplete, not a user's configuration data. Runtime loading remains local. No database, session-store or user-config migration is needed for this issue.

Related code: Kilo-Org/kilocode#15282. Internal v2 uses kilo2.json(c) and .kilo2/; release naming will become kilo.json(c) and .kilo/. Both the initial client URL and release cutover are in scope below.

Exact References

Cloud references are pinned to 861ea58af7b9873942a4f5176ba1845166836c1c:

  • Existing route and merge: live upstream fetch, Kilo overlay, one-hour cache and CORS. Preserve this route for v1.
  • V1 Kilo extras: includes remote_control, reasoning_display, memory_model, etc. Do not copy the whole overlay into the v2 endpoint.
  • Existing tests: preserve the v1 merge behavior and add separate v2 contract tests.

Kilo runtime references are pinned to b51372ddb24259d85f8771037cbf19fc5137d2db (the config PR's current head). Its upstream sync base is OpenCode v2.1.0, 9d90d892dcbfc52b47e95b2ea31b8aba877128fd. Verify the landed/supported internal build before choosing the artifact's final pin.

Reuse Upstream, But Not Its Live Endpoint

Most canonical v2 fields are upstream: agents, commands, providers, permissions, policies, plugins, references and mcp.servers.

However, https://opencode.ai/config.json deliberately combines v1 and v2 properties/types. Its live output also already contains experimental.location_idle_timeout, absent from the Kilo revision above. Proxying it unchanged would advertise both legacy fields and features ahead of our runtime. The current Kilo URL adds v1 extras and still has an upstream $id.

Generate from the pinned encoded/input Config.Info codec. Do not generate the validation shape from Schema.toType(Config.Info), which exposes decoded model/duration objects instead of user-facing strings. Copy only descriptions from the type-side schema, as upstream does.

Generate Now Without A Published CLI

No released binary or npm package is required. From packages/schema in the pinned checkout, after installing its locked workspace dependencies:

env BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 bun --no-env-file -e '
import { Schema } from "effect"
import { Config } from "./src/config.ts"
function document(schema) {
  const result = Schema.toJsonSchemaDocument(schema, { onExcessProperty: "error" })
  if (typeof result.schema.$ref !== "string") return { root: result.schema, definitions: result.definitions }
  const { [result.schema.$ref.replace("#/$defs/", "")]: root, ...definitions } = result.definitions
  return { root, definitions }
}
const { root, definitions } = document(Config.Info)
const descriptions = document(Schema.toType(Config.Info)).root.properties
console.log(JSON.stringify({
  $schema: "https://json-schema.org/draft/2020-12/schema",
  $id: "https://app.kilo.ai/kilo2/config.json",
  ...root,
  properties: Object.fromEntries(Object.entries(root.properties).map(([key, value]) => [
    key, { ...value, description: descriptions[key]?.description ?? value.description }
  ])),
  $defs: definitions,
  allowComments: true,
  allowTrailingCommas: true,
}, null, 2))
' > /tmp/kilo2-config.schema.json

This source-only generation was tested: Ajv draft 2020-12 compilation and validateSchema() passed, with 29 properties, 35 nested definitions and no remote $refs at this pin. Counts are observations, not permanent assertions. allowComments and allowTrailingCommas are editor hints, not standard validation keywords.

Check the artifact into cloud with its source SHA, upstream pin, generation command and checksum. Add a repeatable refresh/diff check. The route should serve that artifact without requiring the CLI, auth, a database or live upstream availability.

Client URL And Release Cutover

  1. Add public GET /kilo2/config.json (for example apps/web/src/app/kilo2/config.json/route.ts) with the correct $id, JSON content type, editor-compatible CORS and explicit caching.
  2. After backend deployment, track a paired CLI change to emit the internal URL in newly created v2 config/templates/docs. Existing MCP, plugin and server config writers do not currently inject a runtime-config $schema URL. Do not assume there is already a URL constant to replace.
  3. Do not add writes to config loading: the upstream regression explicitly requires loading not to inject $schema. Also do not replace the separate cli.json settings schema URL, https://opencode.ai/v2/cli.json, with this runtime-config schema.
  4. When kilo2 becomes kilo, coordinate the endpoint mapping or the client's emitted/requested schema URL. Prefer deploying a stable versioned URL such as /v2/config.json first, then make newly generated kilo.json(c) reference it in the release. A filename/binary rename does not change a file's $schema URL.
  5. Keep /kilo2/config.json resolving to v2 for existing internal-release files. Keep /config.json working for v1 while supported v1 files/clients reference it. If instead swapping /config.json to v2, establish a stable v1 URL and explicit v1-client cutover first; do not redirect all v1 requests to v2.
  6. Test the old v1 URL, old internal-v2 URL and new stable-v2 URL together before release, including $id/relative-reference behavior. Rollback changes only endpoint/client URL mapping, not user config or databases. HTTP schema requests do not include the binary/config filename, so do not infer schema version from them.

Acceptance Tests

  • Validate the document as draft 2020-12 and resolve every $ref; tolerate known editor annotations without disabling data validation.
  • Validate real canonical v2 data, including model shorthand and string durations. This starting fixture passed generated-schema validation and runtime normalization/decoding:
{
  "$schema": "https://app.kilo.ai/kilo2/config.json",
  "model": "kilo/kilo-auto/free",
  "update": "notify",
  "agents": { "reviewer": { "system": "Review changes.", "mode": "primary", "steps": 12 } },
  "permissions": [{ "action": "shell", "resource": "*", "effect": "ask" }],
  "mcp": {
    "servers": { "docs": { "type": "remote", "url": "https://example.com/mcp", "disabled": true } },
    "timeout": { "catalog": 5000 }
  },
  "warming": { "interval": "4 minutes", "duration": "30 minutes" }
}
  • Reject invalid nested values (model: 42, a non-object mcp.servers) and do not advertise unsupported Kilo v1-only extras.
  • Distinguish strict canonical authoring from runtime migration. snapshot:false and autoupdate:false are not canonical v2 properties but migrate to snapshots:false and update:"disable" without diagnostics. Native snapshots wins over snapshot with a conflict diagnostic. Unsupported logLevel/server/layout settings are dropped with diagnostics rather than making the whole file fatal. Do not strip deprecated properties still present in Config.Info, such as commands.*.subtask or experimental.policies.
  • Keep old v1 route/overlay/producer behavior unchanged for the same mocked upstream input. New endpoint works anonymously and still serves the pinned artifact if OpenCode is unavailable or changes its live schema.
  • Track/test the initial client URL wiring and the later endpoint/client URL cutover above; endpoint existence alone does not make editors use it.
  • Verification never reads or modifies real user configuration, databases or sessions.

Reference tests: schema acceptance, normalization/aliases, native precedence, unsupported diagnostics.

Cloud focused test starting command:

pnpm --filter web test --runInBand src/tests/cli-config-schema.test.ts src/tests/cli-config-v2-schema.test.ts

The second path is proposed. Follow cloud's verification guidance for setup, add an anonymous HTTP check, and run relevant type/lint checks.

Do Not Duplicate Other Work

The endpoint and paired schema-URL wiring are the only work requested here. kilocode#15324 owns remaining rebranding, and kilocode#15325 owns fail-closed store protection/preflight. kilocode#15290 proposes a settings RPC/import change; coordinate producer wiring with it, but do not implement another settings API or import mechanism here. The newer internal .kilo2 decision in the config PR supersedes its older .kilo/.kilocode text.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions