Skip to main content
The CLI keeps its settings in a single YAML file. Run timeless playbooks init to create it with the default playbooks, use timeless config set <key> <value> for scalar keys, or edit it by hand at any time. Every command reads it on startup and falls back to built-in defaults for anything you leave out.

Location

The config file is config.yaml inside the Timeless config directory, resolved in this order:
  1. $TIMELESS_CONFIG_DIR
  2. $XDG_CONFIG_HOME/timeless
  3. ~/.config/timeless
Values resolve lowest to highest: built-in defaults, then the config file, then a .env, then the real environment. The .env is a local-development convenience read from your current working directory — not the config directory — and it only fills in TIMELESS_* variables that are not already set, so an explicit shell export always wins. A missing .env is silently ignored.

What it contains

Keys are written with omitempty, so a freshly bootstrapped file only lists what was actually set — an absent key reads as its default rather than an empty value.

Freshness window

An event-driven pass compares each leased event’s meeting time against this window. Older events are acknowledged and skipped: consumed for good, but no playbook runs and no artifact is written, so returning after days away gets you recaps for recent meetings instead of a burst of dozens. Skips are reported as expired and are not failures — the pass still exits 0.
It is a single global window — there is no per-playbook or per-type override, though playbooks run --max-age overrides it for one pass. A malformed value (24, 1 day, -1h) stops the command rather than falling back, because silently guessing a window would destroy deliverables. Avoid going below ~4h: a transcript event fires after the meeting ends, so a long meeting’s event is already hours old when it arrives.

Logging

The CLI writes a local diagnostic log to logs/timeless.log inside the config directory, rotating at 5 MB and keeping 3 generations. It is on by default — a log you have to enable first cannot answer a question about what already happened. The logging: block is hand-edited only (not a config set key): level tunes volume, never content depth. No level records prompt text, harness output, or meeting content — that ceiling is not configurable.

Update keys are inert

update.auto, update.notify, and update.check_interval are still accepted, validated, and reported by config list, but setting them changes nothing: CLI self-update was removed. The desktop app’s updater owns updating, and the bundled binary must never swap itself — that would break the app’s signature. If you want to change update behavior, that is an app setting, not a CLI one.

Environment overrides

A few settings can be overridden per-invocation without editing the file:

What you can customize

  • Harness and model — switch the default engine or model for every playbook, or override them per playbook with its own harness / model.
  • Playbooks — change a prompt, retime a trigger (on.every, on.schedule), park one with playbooks disable, or add a playbook. See Playbooks.
  • Output mode — set output: json to always emit JSON, or leave it on auto.
  • Freshness window — widen events.max_age for a backlog, or set 0 to never skip.
  • Logging — turn the diagnostic log down to error, or off.
timeless config set accepts exactly seven keys: events.max_age, harness, harness_model, output, and the three inert update.* keys. Everything else is hand-edited — playbooks and logging are nested, and base_url is env-driven.
Because the file is plain YAML, you can ask your agent to make these changes for you — it knows the schema and the playbook contract. After editing, run timeless status --json to confirm the CLI still loads cleanly.
base_url, output, harness, and harness_model all have built-in defaults, so a minimal config file is valid — you only need to write the keys you want to change.