Product guide

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.

OSExact 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 fieldUnitInclusive range
workDurationMinutesminutes1–720
shortBreakMinutesminutes1–120
longBreakMinutesminutes1–240
breaksUntilLongbreaks1–24
postureReminderMinutesminutes1–240
postureFlashDurationMsmilliseconds50–10,000
preBreakWarningSecondsseconds1–600
lightBreakSnoozeDurationMinutesminutes1–120
wellnessNudgeFrequencyMinutesminutes5–180
wellnessNudgeAutoDismissSecondsseconds5–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 IDAllowed placeholderConsumers
posture.labelNonemacOS AppKit posture; Windows Win32 posture; Linux posture webview
break.short.titleNoneFullscreen/light webview; macOS light native; Windows/Linux pre-break title adapter
break.long.titleNoneFullscreen/light webview; macOS light native; Windows/Linux pre-break title adapter
break.short.badgeNoneLight/fullscreen webview; macOS light native; Windows/Linux pre-break badge adapter
break.long.badgeNoneLight/fullscreen webview; macOS light native; Windows/Linux pre-break badge adapter
prebreak.short.messageExactly one {mmss}macOS pre-break AppKit only
prebreak.long.messageExactly one {mmss}macOS pre-break AppKit only
action.skipNonePre-break; fullscreen; light (label only)
action.postpone1NonePre-break; fullscreen (label only)
action.postpone5NonePre-break; fullscreen (label only)
action.lightSnoozeNoneWindows/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

  1. Quit Restier.
  2. Delete advanced-customization.json from the applicable path above.
  3. 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.