Roadmap item 3.1.2 defines configuration layering rules and hot-reload
semantics. Follow these rules when adding or changing configuration settings:
Layering rules
Configuration merges in the following precedence order (highest to lowest):
- Runtime overrides (ephemeral, in-memory only, not persisted)
- User config (
config.json5) - Built-in defaults (bundled with the app)
Workspace-level overrides are deferred to a future milestone.
Merge semantics:
- Objects: deep merge (nested properties recursively merged).
- Arrays: replace (user array completely replaces default array).
Use resolveConfigLayers() from app/config/layering.ts to resolve the
effective configuration:
import {resolveConfigLayers} from './config/layering';
import type {configOptions} from '@shared/types/config';
const defaults = {} as configOptions;
const userConfig = {} as Partial<configOptions>;
const runtimeOverrides = {} as Partial<configOptions>;
const effectiveConfig = resolveConfigLayers(defaults, userConfig, runtimeOverrides);
Reloadability classification
Every configuration key must have a reloadability classification:
live: Changes apply immediately without restart (theme, fonts, keybindings).restart: Changes require application restart (shell settings, update channel).
Classify new settings in shared/src/constants/config-reloadability.ts:
// In profileConfigReloadability (or rootConfigReloadability for root keys)
newSetting: {
classification: 'live', // or 'restart'
rationale: 'Brief explanation of why this classification was chosen'
}
Classification guidelines:
| Live-reloadable | Restart-required |
|---|---|
| Theme/UI appearance (colours, padding) | Backend transport (shell, shellArgs) |
| Font settings (family, size, weight) | Update channel / auto-update settings |
| Cursor appearance (shape, blink, colour) | Environment variables (env) |
| Keybindings | WebGL renderer (deferred to CONFIG-001) |
| Custom CSS (css, termCSS) | Process-level configuration |
Detecting and handling config changes
Use createReloadHandler() from app/config/reload-handler.ts to process
config reloads with automatic classification:
import {createReloadHandler} from './config/reload-handler';
import type {configOptions} from '@shared/types/config';
const currentConfig = {} as configOptions;
const newConfig = {} as configOptions;
const handler = createReloadHandler({
getCurrentConfig: () => currentConfig,
applyLiveConfig: (config) => { /* apply live changes */ },
emitRestartWarning: (diagnostics) => { /* notify user */ }
});
const result = handler.processReload(newConfig);
// result.appliedLive: keys applied immediately
// result.restartRequired: diagnostics for keys requiring restart
Settings UI integration
When building settings UI components:
- Use
useConfigReloadability({configKey})to obtainrequiresRestartandclassificationfor a setting. - Display restart-required indicators using
RestartRequiredIndicatorcomponent, passingrequiresRestartfrom the hook. - Show inline warnings when users modify non-reloadable settings using
InlineRestartWarningcomponent, passingclassificationfrom the hook. - Use
keyRequiresRestart(key)for imperative checks outside React render.
Example:
import {RestartRequiredIndicator, InlineRestartWarning} from
'../components/restart-required-indicator';
import {useConfigReloadability} from '../hooks/use-config-reloadability';
function ShellSetting() {
const hasChanged = true; // example: derived from form state
const {requiresRestart, classification} = useConfigReloadability({configKey: 'shell'});
return (
<div>
<label>
Shell Path
<RestartRequiredIndicator
requiresRestart={requiresRestart}
tooltip="Changing the shell requires a restart to take effect."
ariaLabel="Requires restart"
/>
</label>
<input type="text" />
<InlineRestartWarning
classification={classification}
show={hasChanged}
message="This change will take effect after restarting the application."
/>
</div>
);
}
Testing requirements
Add unit tests when adding new configuration settings:
- Verify reloadability classification via
test/unit/config-reloadability.test.ts. - Validate merge semantics in
test/unit/config-layering.test.ts. - Test hot-reload detection in
test/unit/config-hot-reload.test.ts.
Deferred features
The following features are explicitly deferred:
- WebGL renderer hot-reload: Tracked under CONFIG-001 in
docs/tracking-issues.md. - Workspace-level overrides: Will be implemented in a future milestone.