Friday persists user settings in the Electron store named settings.
StoreService creates that store with accessPropertiesByDotNotation: false,
so every root key is addressed as a literal top-level key.
The source of truth for this document is:
src/main/store/types.tsfor persisted schema names.src/main/store/service.tsfor normalization, defaults, and read/write behavior.- Module docs under
docs/models,docs/tasks, anddocs/channelsfor each root owner’s behavior.
Design Rules
- Use one root property per settings owner.
- Keep provider choices compact:
providerId,modelId, optionaleffort, and safeoptions. - Keep model provider credentials in
modelProviders. - Keep channel credentials under
channelaccount records. - Keep task records out of persistent settings.
- Keep schedule payloads free of credentials, provider records, and channel tokens.
- Store static labels, docs paths, and runtime status in code constants, not in user settings.
Root Schema
Target persisted shape:
interface SettingsStore {
modelProviders: ModelProviderSettings[];
llmAgent?: ModelModuleSettings;
speechToText?: ModelModuleSettings;
textToSpeech?: ModelModuleSettings;
imageCreator?: ModelModuleSettings;
textToVideo?: ModelModuleSettings;
textToSound?: ModelModuleSettings;
ocr?: OcrModuleSettings;
embedding?: EmbeddingModuleSettings;
taskScheduler?: TaskSchedulerSettings;
backgroundTask?: BackgroundTaskSettings;
heartbeat?: HeartbeatStoreState;
mcp?: McpServerConfig[];
channel?: Channel;
appSettings?: AppSettings;
appPermissions?: AppPermissionSettings;
}
Most keys are optional because older installs and fresh stores may not have written them yet. Readers must tolerate missing keys and apply module defaults. Root property names use camelCase. Product ids, provider ids, task types, and docs filenames may use kebab-case, but persisted settings keys should not.
Root Ownership
| Root key | Owner | Documentation | Persisted data |
|---|---|---|---|
modelProviders |
Provider settings | providers/index.md | Provider ids, names, base URLs, and API keys for model-backed modules. |
llmAgent |
LLM agent | large-language-model.md | Main assistant provider, model, effort, and safe agent options. |
speechToText |
Speech to text | speech-to-text.md | Live dictation and transcription provider/model settings. |
textToSpeech |
Text to speech | text-to-speech.md | Voice synthesis provider/model settings. |
imageCreator |
Text to image | text-to-image.md | Image generation/editing provider/model settings. |
textToVideo |
Text to video | text-to-video.md | Video generation provider/model settings. |
textToSound |
Text to sound | music-creator.md | Sound, audio, and music generation provider/model settings. |
ocr |
OCR | ocr.md | OCR endpoint settings or OCR provider/model settings. |
embedding |
Embedding | embedding.md | Embedding provider/model and index settings. |
taskScheduler |
Task scheduler | scheduled.md | Managed schedule state, Friday cron state, and legacy cron task state. |
backgroundTask |
Background task | background.md | Task policy settings only; task records stay in memory. |
heartbeat |
Heartbeat | tasks/scheduled.md | Heartbeat run state and last delivered heartbeat text by key. |
mcp |
MCP | tools.md | MCP server configuration records and credential references. |
channel |
Channels | channels/index.md | Channel defaults, account settings, tokens, routing, and allowlists. |
appSettings |
App settings | settings-page.md | App-level non-permission settings such as keep-awake. |
appPermissions |
App permissions | settings-page.md | User toggles for app-level microphone and camera enablement. |
Do not add new cross-module bags such as service, agent, or settings.
Add a new root key only when a module owns that data.
Model Provider Records
Model provider credentials live in modelProviders. This root contains the
private provider records used by runtime adapters.
interface ModelProviderSettings {
id: string;
name: string;
baseUrl: string;
apiKey: string;
}
StoreService normalizes provider ids to lowercase and trims provider fields
before writing them. Read APIs that expose configured providers return the
provider without apiKey.
Module settings reference model providers by id. They do not duplicate API keys or raw provider records in task, schedule, channel, MCP, or tool payloads.
Model Module Settings
Model-backed modules use this compact selection shape:
interface ModelModuleSettings {
providerId: string;
modelId: string;
effort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
options?: Record<string, unknown>;
}
The module resolves the full model provider record from modelProviders when
work starts. Module-specific runtime options belong in options only when they
are safe to store and are not credentials.
Read normalization drops invalid module settings. A module setting is valid only
when it has a non-empty providerId and modelId. providerId is trimmed and
lowercased; modelId is trimmed; effort is kept only when it is a supported
model reasoning effort.
OCR Settings
OCR can start endpoint-backed and later become provider-backed without changing its root key.
type OcrModuleSettings =
| {
mode: 'endpoint';
endpoint: string;
}
| ({
mode: 'model';
} & ModelModuleSettings);
Embedding Settings
interface EmbeddingModuleSettings extends ModelModuleSettings {
index?: {
backend: 'local' | 'external';
namespace?: string;
};
}
Embedding credentials still belong in modelProviders secret storage, not
inside embedding.
Task Scheduler Settings
interface TaskSchedulerSettings {
enabled?: boolean;
managed?: unknown;
friday?: unknown;
legacyTasks?: unknown[];
}
The task scheduler owns timing and schedule state. Scheduled payloads store only task type and sanitized task input. Provider/model settings are resolved by the module that performs the work.
StoreService stores all scheduler variants under one root:
managed: managed schedule state fromCronSchedulerService.friday: Friday cron job, state, and run history.legacyTasks: legacynode-crontask records.
Writers should patch this root rather than replacing unrelated scheduler state.
Background Task Settings
interface BackgroundTaskSettings {
allowedTaskTypes?: string[];
defaultConcurrency?: number;
}
Task records remain in memory for the current app session. They are not
persisted in the settings store. StoreService normalizes allowedTaskTypes
to non-empty strings and keeps defaultConcurrency only when it is a positive
integer.
Heartbeat State
interface HeartbeatStoreState {
version: 1;
taskState: Record<string, { lastRunMs: number }>;
lastDelivered: Record<string, { text: string; atMs: number }>;
}
Heartbeat configuration for agents is stored in llmAgent.options.agents.
The heartbeat root stores runtime state only. StoreService migrates invalid
or missing heartbeat state to an empty version 1 state.
Channel Settings
The channel root stores all channel provider settings. StoreService
hydrates defaults for every CHANNEL_PROVIDER_IDS entry, including Telegram,
WhatsApp, Discord, Slack, and the generic channel providers.
Channel records may include tokens, webhook URLs, client secrets, account allowlists, default targets, and heartbeat visibility settings. Those values belong to the channel owner. They must not be copied into task input, schedule payloads, model module options, or tool payloads.
App Settings And Permissions
interface AppSettings {
keepAwakeEnabled: boolean;
}
interface AppPermissionSettings {
microphoneEnabled: boolean;
cameraEnabled: boolean;
}
App settings and app permission toggles are separate roots. Current defaults are:
appSettings.keepAwakeEnabled:false.appPermissions.microphoneEnabled:true.appPermissions.cameraEnabled:true.
These settings are app-level preferences. System permission status is reported through platform APIs and should not be persisted in these roots.
Migration And Compatibility Rules
- Prefer tolerant readers and narrow writers. Normalize known shapes when reading, and avoid deleting unknown module-owned fields unless that module owns the migration.
- Keep legacy read helpers local to
StoreService. Do not make new writes to retired roots such asservice,agent,rag, or standalonesound. - When adding a root key, update
src/main/store/types.ts,StoreService, tests, this document, and the owning module doc in the same change. - When moving a value between roots, provide a migration or a read fallback before removing the old path.