Editor

Configuration

Configuration

outl reads two TOML files at launch. They are read in this order; the second can override fields from the first.

LayerPathScopeWritten by
Global~/.config/outl/config.tomlThe user’s machine — every workspace, every clientThe desktop app’s Settings modal; you can also edit it by hand
Per-workspace<workspace>/.outl/config.tomlOne workspace onlyoutl init (for the actor id); hand-edit for the rest

The path layout is XDG-style on every OS — including macOS. outl is keyboard-first and CLI-friendly; the macOS-native ~/Library/Application Support/… location would split the TUI and desktop into two config files for no real benefit.

The reader for both files is the outl-config crate (crates/outl-config/). TUI and desktop import the same module so a field can’t drift between clients — extending the schema in one place lights up in both.


Global config (~/.config/outl/config.toml)

Every field is optional; missing values fall back to the documented default. A malformed file is logged and replaced with defaults rather than refused to boot — preferences aren’t worth blocking the app on.

# ~/.config/outl/config.toml — full example with every supported field

[workspace]
# Absolute path to the workspace the user last opened. The desktop
# writes this on every `set_workspace` call; the TUI / CLI read it
# when no `--workspace` flag and no positional path is given.
last = "/Users/me/iCloud/outl"

[theme]
# Palette preset name from `outl_theme::PRESETS`.
# Choices: "outl" (default), "default-dark", "light", "dracula",
#          "solarized-dark", "nord", "monokai".
preset = "outl"

[editor]
# Vim-style modal bindings (Normal / Insert / Visual). Defaults to
# `true` — outl is keyboard-first. The desktop honours this; the TUI
# is vim-style by definition and ignores the flag.
vim_mode = true

# Outline font size in pixels (desktop only — the TUI uses your
# terminal font).
font_size = 15

Field reference

[workspace]

FieldTypeDefaultRead byEffect
lastabsolute pathnonedesktop, TUI, CLIWhere the next outl (with no args) opens. The desktop persists this on every workspace switch. If the path no longer exists, every reader silently falls through to its next fallback (CLI: cwd; desktop: workspace picker).

[theme]

FieldTypeDefaultRead byEffect
presetstring"outl"TUI, desktopActive palette. Unknown names fall through to outl.

Available presets: outl, default-dark, light, dracula, solarized-dark, nord, monokai. See theming.md for the look of each.

[editor]

FieldTypeDefaultRead byEffect
vim_modebooltruedesktopWhen false, the desktop drops the modal Normal / Insert / Visual model and only listens to OS-standard chrome chords (⌘P, ⌘B, …). The TUI is vim-style by definition and ignores this.
font_sizeinteger (pixels)15desktopOutline body font size. The TUI uses the user’s terminal font; setting this has no effect there.

Per-workspace config (<workspace>/.outl/config.toml)

Written by outl init; carries the device’s per-workspace identity and (optionally) workspace-scoped overrides.

# Per-workspace config — auto-generated by `outl init`, can be
# hand-edited.

[workspace]
# The per-device-per-workspace actor id (a ULID). DO NOT copy this
# file between machines: every device needs its own id so the op
# log can attribute writes correctly.
actor_id = "01HKZX9YBPDC5XJZ3R8K2QGM7E"

[theme]
# Workspace-only override. When set, takes precedence over the
# global `[theme] preset` while you're inside this workspace.
preset = "monokai"

The [workspace] actor_id field cannot move to the global config — it’s per-device-per-workspace by design. A peer’s op log identifies writes by this id; sharing it across machines silently breaks convergence.


Precedence chains

Workspace path

When you type outl (no args):

  1. Subcommand-positional path (outl page get … <PATH>).
  2. Global flag --workspace <DIR>.
  3. [workspace] last from ~/.config/outl/config.toml.
  4. Current working directory (the cd ~/notes && outl fallback).

A path from config.toml that no longer exists on disk is skipped silently and the chain falls through to the next step.

Theme

When the TUI / desktop decides which palette to render:

  1. --theme <preset> CLI flag (TUI only).
  2. Per-workspace [theme] preset from <workspace>/.outl/config.toml.
  3. Global [theme] preset from ~/.config/outl/config.toml.
  4. Built-in default — outl.

Unknown preset names fall through to the next step rather than erroring.


Editing safely

The TOML reader (outl-config::load) is forgiving by design:

  • Missing file → defaults, no warning (first launch is normal).
  • Malformed TOML → defaults + a tracing::warn log line, the app boots normally.
  • Unknown fields → ignored. Older binaries reading a newer config don’t choke; you can add fields ahead of time.
  • Partial schema (e.g. only [theme] populated) → other sections fall back to their per-section Default.

Saving (outl-config::save) writes atomically — the new content lands in config.toml.tmp and the file is renamed on top. A crash mid-write never leaves a truncated config.


Migrating from earlier versions

The desktop briefly stored its settings as JSON at ~/Library/Application Support/app.outl.desktop/settings.json (and the actor at the same directory). That path is no longer read. If you upgrade from one of those builds:

  • The desktop picks up ~/.config/outl/config.toml (creates it on first save).
  • The actor ULID at ~/.config/outl/actor is generated fresh on first run; your local op log keeps writing under the new id.
  • Your workspace’s ops/ directory is unchanged — only the client’s identity rotates, not the workspace’s history.

If you want to preserve the old actor id, copy it from the old path into ~/.config/outl/actor before launching the desktop.