Advanced JSON customization
Advanced customization is an optional, local startup override for selected timer values and reminder text. It is not a plugin system: it cannot execute code, install resources, add capabilities, or change Restierβs normal settings UI.
Quick start: override one value
Create the file at the path for your operating system, add this JSON, then fully restart Restier:
{
"schemaVersion": 1,
"timers": {
"workDurationMinutes": 50
}
}
The complete, production-tested example is available at https://restier.app/docs/advanced-customization.example.json.
File location and lifecycle
The filename is exactly advanced-customization.json.
| OS | Exact path |
|---|---|
| macOS | ~/Library/Application Support/app.restier.restier/advanced-customization.json |
| Windows | %APPDATA%\app.restier.restier\advanced-customization.json |
| Linux | ${XDG_DATA_HOME:-$HOME/.local/share}/app.restier.restier/advanced-customization.json |
Create the parent directory when needed. Restier reads the file once at startup and keeps one immutable snapshot for that run. Editing, replacing, or deleting it while the app is open has no effect. Restier never writes, repairs, watches, or migrates this file.
Schema rules
The root must contain the integer "schemaVersion": 1. timers and copy are optional objects. Unknown fields are rejected at every level, and a single bad field rejects the whole fileβthere is no partial installation.
Timer overrides
All ten fields are optional integers. An omitted field uses its corresponding base setting.
| JSON field | Unit | Inclusive range |
|---|---|---|
workDurationMinutes | minutes | 1β720 |
shortBreakMinutes | minutes | 1β120 |
longBreakMinutes | minutes | 1β240 |
breaksUntilLong | breaks | 1β24 |
postureReminderMinutes | minutes | 1β240 |
postureFlashDurationMs | milliseconds | 50β10,000 |
preBreakWarningSeconds | seconds | 1β600 |
lightBreakSnoozeDurationMinutes | minutes | 1β120 |
wellnessNudgeFrequencyMinutes | minutes | 5β180 |
wellnessNudgeAutoDismissSeconds | seconds | 5β60 |
lightBreakSnoozeDurationMinutes affects only the light-break snooze duration. It does not change the fixed one-minute or five-minute postpone actions.
Base settings versus effective behavior
Your saved settings and get_settings continue to show the base values you chose in Settings. Scheduler-driven behavior uses the effective value: an override wins over its matching base setting for the rest of that run. If you change a matching setting in the UI while the override is loaded, the change remains saved as a base value but does not affect the active behavior until you remove the file and restart.
Analytics derived from the running timer use effective timer values; analytics read directly from persisted settings continue to use base values.
Customize reminder copy
Use public semantic IDs in copy.default for a locale-independent override, or in copy.locales.en-US / copy.locales.es-ES for locale-specific text. Do not use renderer keys.
| Semantic ID | Allowed placeholder | Consumers |
|---|---|---|
posture.label | None | macOS AppKit posture; Windows Win32 posture; Linux posture webview |
break.short.title | None | Fullscreen/light webview; macOS light native; Windows/Linux pre-break title adapter |
break.long.title | None | Fullscreen/light webview; macOS light native; Windows/Linux pre-break title adapter |
break.short.badge | None | Light/fullscreen webview; macOS light native; Windows/Linux pre-break badge adapter |
break.long.badge | None | Light/fullscreen webview; macOS light native; Windows/Linux pre-break badge adapter |
prebreak.short.message | Exactly one {mmss} | macOS pre-break AppKit only |
prebreak.long.message | Exactly one {mmss} | macOS pre-break AppKit only |
action.skip | None | Pre-break; fullscreen; light (label only) |
action.postpone1 | None | Pre-break; fullscreen (label only) |
action.postpone5 | None | Pre-break; fullscreen (label only) |
action.lightSnooze | None | Windows/Linux light webview; macOS light native (label only) |
Copy selection is deterministic: locale override β default override β bundled locale β bundled en-US β built-in semantic fallback.
Templates are raw scalar strings of 1β240 Unicode scalar values; no Unicode normalization occurs. Only lowercase ASCII placeholder names such as {mmss} are accepted, braces must balance, and the placeholders must match the semantic ID exactly. The loader rejects C0/C1 controls, DEL, newlines, tabs, bidi controls (U+202AβU+202E, U+2066βU+2069, U+200E, U+200F, U+061C), <, and >.
Text is displayed as inert literal text: strings that look like URLs, Markdown, CSS, or scripts are not interpreted as content. Restier supplies {mmss} at render time for the current macOS pre-break countdown. Windows and Linux pre-break surfaces use title/badge and their separate timer; they do not consume the message slots.
Complete example shape
{
"schemaVersion": 1,
"timers": {
"workDurationMinutes": 50,
"shortBreakMinutes": 5,
"longBreakMinutes": 20,
"breaksUntilLong": 4,
"postureReminderMinutes": 45,
"postureFlashDurationMs": 1500,
"preBreakWarningSeconds": 30,
"lightBreakSnoozeDurationMinutes": 10,
"wellnessNudgeFrequencyMinutes": 30,
"wellnessNudgeAutoDismissSeconds": 15
},
"copy": {
"default": {
"posture.label": "Check your posture",
"break.short.title": "Short break",
"break.long.title": "Long break",
"break.short.badge": "Short",
"break.long.badge": "Long",
"prebreak.short.message": "Short break in {mmss}",
"prebreak.long.message": "Long break in {mmss}",
"action.skip": "Skip",
"action.postpone1": "Later 1 min",
"action.postpone5": "Later 5 min",
"action.lightSnooze": "Snooze"
},
"locales": {
"es-ES": {
"break.short.title": "Descanso corto",
"break.long.title": "Descanso largo"
}
}
}
}
Failure, recovery, and safety boundary
The file must be a regular, non-symlink file no larger than 65,536 bytes. Missing, unreadable, oversized, unsafe, malformed, unknown-version, or invalid content fails closed: Restier continues with base settings and bundled copy, writes nothing, and does not partially apply valid fragments from a bad file.
The input cannot add commands, capabilities, windows, events, processes, plugins, network hooks, file includes, paths, environment interpolation, code, or new locales. Restier checks metadata before opening and verifies that the acquired handle is regular where that metadata is available. A same-user replacement after the metadata check (including a FIFO/TOCTOU race) is outside this threat model.
Roll back
- Quit Restier.
- Delete
advanced-customization.jsonfrom the applicable path above. - Start Restier again.
After that restart, Restier returns to the normal saved base settings and bundled copy.
Troubleshooting
If an override did not take effect, first confirm the filename, path, schemaVersion: 1, JSON syntax, field names, value ranges, placeholder rules, and that you restarted after saving. Startup diagnostics are deliberately redacted: they are limited to load status, schema version, bytes read, and timer/copy override counts. The status may be not_found, loaded, invalid_envelope, unsupported_version, invalid_v1, io_error, or unsafe_file_type; an oversized file is reported as io_error with file_too_large. A failed load emits at most one warning and never logs the path, username, raw JSON, custom text, effective advanced timings, or selected locale block. Correct the file or delete it and restart.
For ordinary UI configuration, use the Settings reference instead.