Skip to content

Publish server settings schema with release versions#1593

Open
juliusmarminge wants to merge 9 commits intomainfrom
t3code/server-settings-schema
Open

Publish server settings schema with release versions#1593
juliusmarminge wants to merge 9 commits intomainfrom
t3code/server-settings-schema

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented Mar 30, 2026

Summary

  • Generate the server settings JSON Schema into the marketing app’s public assets.
  • Publish both a stable server-settings.schema.json and a versioned copy under server-settings/<version>.schema.json during release/version alignment.
  • Move shared JSON Schema conversion into @t3tools/shared/schemaJson and update server git layers to import from there.
  • Update release automation and smoke checks to include schema artifacts.
  • Add tests covering schema generation and release version updates.

Testing

  • Not run (not requested).
  • Added Vitest coverage for buildServerSettingsJsonSchema() and writeServerSettingsJsonSchemas().
  • Added Vitest coverage for updateReleasePackageVersions() writing the latest and versioned schema files.
  • Updated release smoke coverage to verify schema artifacts are produced alongside version bumps.

Note

Medium Risk
Updates release/version-bump automation and server settings persistence, so regressions could affect release commits or overwrite settings.json unexpectedly. Core runtime behavior is mostly unchanged, but schema generation and file-writing paths are new/modified.

Overview
Publishes JSON Schema artifacts for settings.json and keybindings.json as part of releases. Release/version alignment (scripts/update-release-package-versions.ts and .github/workflows/release.yml) now generates/commits latest schemas under apps/marketing/public/schemas/ plus immutable versioned snapshots (only when the latest schema changed).

Moves JSON-schema conversion/pretty JSON encoding into @t3tools/shared/schemaJson, updates Codex/Claude git text-generation layers to use it, and annotates contract schemas so generated docs include field descriptions. The server now preserves an existing top-level $schema in settings.json when rewriting, and the web settings UI pulls setting descriptions from schema metadata instead of hard-coded strings, with added tests/smoke checks covering schema generation and release bumps.

Written by Cursor Bugbot for commit 32f1d4c. This will update automatically on new commits. Configure here.

Note

Publish JSON Schemas for server settings and keybindings with each release

  • Adds a build-json-schemas.ts script and integrates it into update-release-package-versions.ts so each release writes latest and versioned JSON Schema files to apps/marketing/public/schemas/.
  • Schema files are committed as part of the release workflow alongside package version bumps; versioned snapshots (e.g. settings/0.0.15.json) are only written when the latest schema changes.
  • Adds description annotations to contract schemas (settings.ts, keybindings.ts, model.ts, orchestration.ts) so the generated JSON Schemas include human-readable field descriptions.
  • serverSettings.ts now preserves an existing top-level $schema property in settings.json when rewriting the file, and switches to a shared pretty-JSON encoder.
  • The settings UI in SettingsPanels.tsx reads field descriptions from schema annotations instead of hard-coded strings.

Macroscope summarized 32f1d4c.

- Generate the marketing schema and versioned copies during release version bumps
- Move JSON Schema export helper into shared utilities
- Update release smoke coverage and schema generation tests
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fd7c5321-0b4d-4f04-a963-bbc095961be0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/server-settings-schema

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Mar 30, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Object spread ordering may override explicit metadata
    • Moved ...schema spread before the explicit $schema, title, and description properties so the explicit metadata always takes precedence.

Create PR

Or push these changes by commenting:

@cursor push b2932708c6
Preview (b2932708c6)
diff --git a/scripts/lib/server-settings-schema.ts b/scripts/lib/server-settings-schema.ts
--- a/scripts/lib/server-settings-schema.ts
+++ b/scripts/lib/server-settings-schema.ts
@@ -21,10 +21,10 @@
   }
 
   return {
+    ...schema,
     $schema: JSON_SCHEMA_DRAFT_2020_12,
     title: "T3 Code Server Settings",
     description: "JSON Schema for the server-authoritative settings.json file consumed by T3 Code.",
-    ...schema,
   };
 }

You can send follow-ups to this agent here.

- Run the manifest merge script with `process.execPath` instead of `bun`
- Keeps the smoke test aligned with the current Node runtime
- Add marketing JSON Schema artifacts for keybindings
- Reuse shared JSON schema writer for server settings and keybindings
- Preserve top-level `$schema` when rewriting settings
Comment on lines +24 to +29
return {
$schema: JSON_SCHEMA_DRAFT_2020_12,
title: options.title,
description: options.description,
...jsonSchema,
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium lib/json-schema.ts:24

The spread ...jsonSchema is placed after the explicit $schema, title, and description properties, so if toJsonSchemaObject(schema) returns an object containing any of those keys (common for Effect schemas with annotations), those values will silently override the options.title and options.description parameters passed to the function. Place the spread first so explicit parameters take precedence.

-  return {
-    $schema: JSON_SCHEMA_DRAFT_2020_12,
-    title: options.title,
-    description: options.description,
-    ...jsonSchema,
-  };
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file scripts/lib/json-schema.ts around lines 24-29:

The spread `...jsonSchema` is placed after the explicit `$schema`, `title`, and `description` properties, so if `toJsonSchemaObject(schema)` returns an object containing any of those keys (common for Effect schemas with annotations), those values will silently override the `options.title` and `options.description` parameters passed to the function. Place the spread first so explicit parameters take precedence.

Evidence trail:
scripts/lib/json-schema.ts lines 22-27 (at REVIEWED_COMMIT) show the object literal with `...jsonSchema` spread after explicit properties `$schema`, `title`, `description`. JavaScript object spread semantics (MDN, ECMAScript spec) confirm that later properties override earlier ones, so if `jsonSchema` contains these keys, they will override the explicit values passed via `options`.

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Spread ordering lets schema override explicit metadata
    • Moved the ...jsonSchema spread before the explicit $schema, title, and description properties so the explicit metadata always wins.

Create PR

Or push these changes by commenting:

@cursor push 782716bd83
Preview (782716bd83)
diff --git a/scripts/lib/json-schema.ts b/scripts/lib/json-schema.ts
--- a/scripts/lib/json-schema.ts
+++ b/scripts/lib/json-schema.ts
@@ -22,10 +22,10 @@
   }
 
   return {
+    ...jsonSchema,
     $schema: JSON_SCHEMA_DRAFT_2020_12,
     title: options.title,
     description: options.description,
-    ...jsonSchema,
   };
 }

You can send follow-ups to this agent here.

title: options.title,
description: options.description,
...jsonSchema,
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spread ordering lets schema override explicit metadata

Medium Severity

In buildJsonSchemaDocument, the ...jsonSchema spread comes after the explicit $schema, title, and description properties. In JavaScript, later properties override earlier ones, so if toJsonSchemaObject returns an object containing title or description (which Effect Schema includes when .annotations({ title: "..." }) is set on the schema), those would silently override the intended values from options. The spread needs to come first so the explicit metadata always wins.

Fix in Cursor Fix in Web

- Add schema descriptions for editor tooling and generated JSON schemas
- Update published keybindings and server settings schema docs
@github-actions github-actions bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Mar 30, 2026
- Reflow schema arrays and required lists
- Keep published server settings and keybindings schemas normalized
- Centralize settings copy in schema annotations
- Reuse schema descriptions in the settings UI
- Refresh generated server settings schema output
const makeTrimmedStringSetting = (description: string) =>
Schema.String.annotate({ description }).pipe(
Schema.decodeTo(TrimmedString, SchemaTransformation.passthrough()),
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trimming behavior lost via passthrough transformation

Medium Severity

makeTrimmedStringSetting uses Schema.decodeTo(TrimmedString, SchemaTransformation.passthrough()), where passthrough() is an identity transformation that does not apply TrimmedString (Schema.Trim)'s whitespace-trimming decode logic. The old makeBinaryPathSetting started directly from TrimmedString, so strings were trimmed before the fallback check. Now binaryPath and homePath settings pass untrimmed values through, meaning a whitespace-only input like " " would no longer fall back to the default and could cause binary resolution failures.

Fix in Cursor Fix in Web

- Move server settings and keybindings schema URLs to shorter `.json` paths
- Update release tooling, docs, and tests to match the new schema locations
- Avoid writing versioned schema snapshots when the latest schema content did not change
- Add coverage for keybindings, server settings, and release version updates
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stale $schema ref not reset on parse failure
    • Added the missing else branch to reset schemaDeclarationRef to undefined when UnknownJson decoding fails, consistent with the file-not-found case.

Create PR

Or push these changes by commenting:

@cursor push 0e0490b6b1
Preview (0e0490b6b1)
diff --git a/apps/server/src/serverSettings.ts b/apps/server/src/serverSettings.ts
--- a/apps/server/src/serverSettings.ts
+++ b/apps/server/src/serverSettings.ts
@@ -228,6 +228,8 @@
           ? valueRecord[SETTINGS_SCHEMA_DECLARATION_KEY]
           : undefined;
       yield* Ref.set(schemaDeclarationRef, schemaDeclaration);
+    } else {
+      yield* Ref.set(schemaDeclarationRef, undefined);
     }
 
     const decoded = Schema.decodeUnknownExit(ServerSettingsJson)(raw);

You can send follow-ups to this agent here.

? valueRecord[SETTINGS_SCHEMA_DECLARATION_KEY]
: undefined;
yield* Ref.set(schemaDeclarationRef, schemaDeclaration);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale $schema ref not reset on parse failure

Low Severity

When UnknownJson decoding fails (completely malformed file), schemaDeclarationRef is not reset to undefined. On a file-watcher reload, a stale $schema value from a previous successful load survives and gets written into the next updateSettings call, even though the current file no longer contains that declaration. The else branch for rawJson._tag === "Failure" is missing a Ref.set(schemaDeclarationRef, undefined).

Fix in Cursor Fix in Web

@cursor
Copy link
Copy Markdown
Contributor

cursor bot commented Mar 30, 2026

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Trimming behavior lost via passthrough transformation
    • Replaced Schema.String.pipe(Schema.decodeTo(TrimmedString, SchemaTransformation.passthrough())) with TrimmedString.annotate({ description }) so that Schema.Trim's whitespace-trimming decode logic is actually applied.

Create PR

Or push these changes by commenting:

@cursor push 1b6e8ab339
Preview (1b6e8ab339)
diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts
--- a/packages/contracts/src/settings.ts
+++ b/packages/contracts/src/settings.ts
@@ -23,10 +23,7 @@
 export type SidebarThreadSortOrder = typeof SidebarThreadSortOrder.Type;
 export const DEFAULT_SIDEBAR_THREAD_SORT_ORDER: SidebarThreadSortOrder = "updated_at";
 
-const makeTrimmedStringSetting = (description: string) =>
-  Schema.String.annotate({ description }).pipe(
-    Schema.decodeTo(TrimmedString, SchemaTransformation.passthrough()),
-  );
+const makeTrimmedStringSetting = (description: string) => TrimmedString.annotate({ description });
 
 export const ClientSettingsSchema = Schema.Struct({
   confirmThreadArchive: Schema.Boolean.annotate({

You can send follow-ups to this agent here.

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

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant