Repository navigation
Add a dedicated Kilo v2 config schema and coordinate the release URL cutover #8397
Description
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.
- Canonical
Config.Infoand its nestedconfig/*imports are the schema source. The host changes filenames, not this content contract; it adds no config-schema fields at this revision. - Existing upstream-derived generator generates
Config.Infoand then merges frozenconfig-v1.json. Reuse its codec-side generation and description handling, not the final v1/v2 merge. - Runtime parser/normalizer/decoder,
ConfigNormalize.normalize, and legacy migration explain which old aliases are migrated or ignored.
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.jsonThis 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
- Add public
GET /kilo2/config.json(for exampleapps/web/src/app/kilo2/config.json/route.ts) with the correct$id, JSON content type, editor-compatible CORS and explicit caching. - 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
$schemaURL. Do not assume there is already a URL constant to replace. - Do not add writes to config loading: the upstream regression explicitly requires loading not to inject
$schema. Also do not replace the separatecli.jsonsettings schema URL,https://opencode.ai/v2/cli.json, with this runtime-config schema. - When
kilo2becomeskilo, coordinate the endpoint mapping or the client's emitted/requested schema URL. Prefer deploying a stable versioned URL such as/v2/config.jsonfirst, then make newly generatedkilo.json(c)reference it in the release. A filename/binary rename does not change a file's$schemaURL. - Keep
/kilo2/config.jsonresolving to v2 for existing internal-release files. Keep/config.jsonworking for v1 while supported v1 files/clients reference it. If instead swapping/config.jsonto v2, establish a stable v1 URL and explicit v1-client cutover first; do not redirect all v1 requests to v2. - 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-objectmcp.servers) and do not advertise unsupported Kilo v1-only extras. - Distinguish strict canonical authoring from runtime migration.
snapshot:falseandautoupdate:falseare not canonical v2 properties but migrate tosnapshots:falseandupdate:"disable"without diagnostics. Nativesnapshotswins oversnapshotwith a conflict diagnostic. UnsupportedlogLevel/server/layoutsettings are dropped with diagnostics rather than making the whole file fatal. Do not strip deprecated properties still present inConfig.Info, such ascommands.*.subtaskorexperimental.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.tsThe 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.
Activity