Files
CherryHQ-cherry-studio/docs/references/data/boot-config-schema-guide.md
fullex c514dcc049 refactor(shared): move packages/shared to src/shared
packages/shared was never a real pnpm workspace package (no package.json); it was referenced only through the @shared TypeScript path alias. Relocate it under src/ via git mv (143 files, detected as pure renames).

Repoint the @shared alias and include globs to src/shared across electron.vite.config.ts, tsconfig.{json,node,web}.json and vitest.config.ts; update scripts/check-custom-exts.ts, scripts/update-languages.ts, the eslint.config.mjs generated-file globs, the data-classify generator output targets, .github/CODEOWNERS path rules, and CLAUDE.md/docs/source-comment references.

The @shared alias name is unchanged, so all 1403 @shared/* import sites resolve without modification. Verified with typecheck:node, typecheck:web and the full test suite (700 files, 9739 tests passing).
2026-05-28 21:02:49 -07:00

10 KiB

Boot Config Schema Guide

This guide explains how to add new boot config keys and covers the V1-to-V2 data migration pipeline.

When to Use BootConfig

BootConfig is for a very narrow set of configuration items. Before adding a key here, ask:

Question If Yes If No
Must it load before the lifecycle system takes over? BootConfig Preference
Does it affect process-level behavior (Chromium flags, data directory)? BootConfig Preference
Can it wait for the BeforeReady lifecycle phase? Preference BootConfig
Can it be changed at runtime without restart? Preference BootConfig

Rule of thumb: If the setting can wait until the lifecycle's BeforeReady phase, it belongs in Preference. BootConfig is only for settings that must be available before the lifecycle system even starts. Keep it minimal.

Key Naming Conventions

Boot config keys follow the same naming convention as preferences.

Format

namespace.key_name — at least 2 segments separated by dots.

Rules:

  • Lowercase letters, numbers, and underscores only
  • Pattern: /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/
  • Use dots for hierarchy, underscores for multi-word names

Examples

Valid Invalid Reason
app.disable_hardware_acceleration disableHardwareAcceleration Missing dot separator
app.user_data_path App.userDataPath Uppercase, camelCase
chromium.gpu_compositing gpu Single segment

Adding a New Boot Config Key

Step 1: Add to Schema Interface

File: src/shared/data/bootConfig/bootConfigSchemas.ts

The schema interface and defaults live side by side. The current shape looks like this — follow the same pattern for any new key (matching naming convention, matching entry in DefaultBootConfig):

export interface BootConfigSchema {
  'app.disable_hardware_acceleration': boolean
  'app.user_data_path': Record<string, string>
}

export const DefaultBootConfig: BootConfigSchema = {
  'app.disable_hardware_acceleration': false,
  'app.user_data_path': {}
}

Note: If this file is currently auto-generated by the V1-to-V2 migration pipeline, add your key outside the === AUTO-GENERATED CONTENT === markers, or coordinate with the migration toolchain (see V1 to V2 Data Migration below).

Step 2: Add Custom Types (if needed)

File: src/shared/data/bootConfig/bootConfigTypes.ts

For simple types (boolean, string, number), no changes needed — the type is inferred from the schema. For custom types, define them alongside BootConfigKey:

export type BootConfigKey = keyof BootConfigSchema

// Custom types if needed
export type GpuMode = 'auto' | 'disabled' | 'software'

Step 3: Use in Early Boot Code (if needed)

Only for settings that must take effect before lifecycle:

File: src/main/index.ts

import { bootConfigService } from '@main/data/bootConfig'

// Apply before app.whenReady()
if (bootConfigService.get('app.disable_hardware_acceleration')) {
  app.disableHardwareAcceleration()
}

Step 4: Access from Renderer / Lifecycle Services

No additional wiring needed. The BootConfigPreferenceKeys mapped type automatically adds the BootConfig. prefix, making the key available through the unified preference API:

// Renderer — works immediately after adding to schema
const [disableHardwareAcceleration, setDisableHardwareAcceleration] = usePreference(
  'BootConfig.app.disable_hardware_acceleration'
)

// Main process lifecycle service
const disableHardwareAcceleration = preferenceService.get('BootConfig.app.disable_hardware_acceleration')

For detailed usage of usePreference, see Preference Usage Guide.

V1 to V2 Data Migration

This section covers the migration toolchain used to move legacy data from V1 (Redux/ElectronStore/Dexie) into the V2 boot config system. This is not the regular path for adding new keys.

Overview

The v2-refactor-temp/tools/data-classify/ directory contains the code generation pipeline for migrating legacy data into V2 systems. classification.json is the single source of truth that classifies every legacy key into its target system (Preference, BootConfig, Cache, or DataApi).

How It Works

  1. Each item in classification.json with "category": "bootConfig" maps a legacy key to a boot config key
  2. The generator reads these classifications and produces:
    • src/shared/data/bootConfig/bootConfigSchemas.ts — schema interface and defaults
    • src/main/data/migration/v2/migrators/mappings/BootConfigMappings.ts — legacy-to-new key mappings
  3. At migration time, BootConfigMigrator reads values from legacy sources (Redux, ElectronStore, Dexie settings, localStorage, and the legacy home config file) and writes them to bootConfigService

Migration Sources

Source Accessor Example
Redux Store ReduxStateReader with category + dot-path settings.disableHardwareAcceleration
ElectronStore ConfigManager.get(key) Direct key lookup
Dexie settings Key-value table Direct key lookup
localStorage localStorage.getItem(key) Direct key lookup
Legacy home config file LegacyHomeConfigReader ~/.cherrystudio/config/config.json (appDataPath field only)

Config-file source mappings are manually maintained. The data-classify toolchain's classification.json doesn't model config-file sources yet. In two places, a small hand-maintained list complements the classification-driven pipeline:

  • Schema keys: MANUAL_BOOT_CONFIG_ITEMS at the top of v2-refactor-temp/tools/data-classify/scripts/generate-boot-config.js — these items are merged with the classification-derived items and emitted into bootConfigSchemas.ts as part of the normal auto-generated output. The resulting schema file is fully auto-generated (no manual sections).
  • Mappings: inline configFileMappings inside BootConfigMigrator.loadMigrationItems() — a small ReadonlyArray<{ originalKey: string; targetKey: BootConfigKey }> whose BootConfigKey annotation is the regen safety net: if the schema loses app.user_data_path, this array fails to compile at its declaration site.

To add a new config-file-sourced key in the future: add an entry to MANUAL_BOOT_CONFIG_ITEMS in the generator, add the matching entry to BootConfigMigrator.loadMigrationItems()'s configFileMappings, and run npm run generate.

Adding a Migration Mapping

To migrate a legacy key to boot config:

  1. Add or update the item in classification.json:
{
  "originalKey": "disableHardwareAcceleration",
  "source": "redux",
  "category": "bootConfig",
  "status": "classified",
  "targetKey": "app.disable_hardware_acceleration",
  "targetType": "boolean",
  "defaultValue": false,
  "reduxCategory": "settings"
}
  1. Regenerate mappings:
cd v2-refactor-temp/tools/data-classify && npm run generate
  1. Verify the generated output in BootConfigMappings.ts

Current Mappings

Legacy Source Legacy Key Target Key
Redux (settings) disableHardwareAcceleration app.disable_hardware_acceleration
Config file (~/.cherrystudio/config/config.json) appDataPath app.user_data_path

Known Limitation: AppImage / Windows Portable Executable Path

The v1 ~/.cherrystudio/config/config.json stores appDataPath as an array of { executablePath, dataPath } entries keyed by executable path. On AppImage Linux builds and Windows portable builds, src/main/utils/init.ts:51-60 writes a special executablePath that differs from app.getPath('exe'):

  • AppImage: path.dirname(process.env.APPIMAGE) + '/cherry-studio.appimage'
  • Windows portable: process.env.PORTABLE_EXECUTABLE_DIR + '/cherry-studio-portable.exe'

LegacyHomeConfigReader does NOT reproduce this normalization — array entries are migrated verbatim with their original executablePath key, and the legacy-string fallback uses the raw app.getPath('exe'). This is harmless in the current PR because nothing yet reads app.user_data_path. But the follow-up PR that rewires initAppDataDir() to consume it MUST normalize the exe path using the same logic in src/main/utils/init.ts:51-60, otherwise migrated records under AppImage/portable will never match the lookup key.

File Structure

File Purpose
src/shared/data/bootConfig/bootConfigSchemas.ts Schema interface and default values
src/shared/data/bootConfig/bootConfigTypes.ts BootConfigKey type, BootConfigPreferenceKeys mapped type
src/main/data/bootConfig/BootConfigService.ts Service implementation
src/main/data/bootConfig/types.ts BootConfigLoadError type
v2-refactor-temp/tools/data-classify/data/classification.json Migration source of truth
v2-refactor-temp/tools/data-classify/scripts/generate-boot-config.js Schema generator (migration)
src/main/data/migration/v2/migrators/BootConfigMigrator.ts Migration executor
src/main/data/migration/v2/migrators/mappings/BootConfigMappings.ts Auto-generated migration mappings

Best Practices

  1. Keep BootConfig minimal — most settings belong in Preference. Only use BootConfig for settings that must load before the lifecycle system takes over.
  2. Provide sensible defaults — BootConfigService uses defaults on first launch (missing file). A missing default means the key is unusable on first launch.
  3. Follow naming conventions — use the same namespace.key_name pattern as preferences for consistency.
  4. Process-level settings require restart — document this in the UI when exposing boot config settings to users.