Skip to content

Config reference

~/.config/lazy-harness/config.toml is the single source of truth for a lazy-harness install. Every command — lh run, lh deploy, lh status, lh scheduler, the hooks — reads it on each invocation. There is no daemon, no in-memory cache: edit, save, run again.

The file location follows XDG: $LH_CONFIG_DIR/config.toml, then $XDG_CONFIG_HOME/lazy-harness/config.toml, then the platform default (~/.config/lazy-harness/config.toml on macOS/Linux, %APPDATA%\lazy-harness\config.toml on Windows).

Minimal example

The smallest config that loads cleanly:

[harness]
version = "1"

[agent]
type = "claude-code"

[profiles]
default = "personal"

[profiles.personal]
config_dir = "~/.claude-personal"
roots = ["~"]

[harness].version is the only field the parser hard-requires. Everything else has a default.

Fuller example

A more realistic shape with knowledge, monitoring, scheduler jobs, hooks, and the compound loop:

[harness]
version = "1"

[agent]
type = "claude-code"

[profiles]
default = "lazy"

[profiles.lazy]
config_dir = "~/.claude-lazy"
roots = ["~/repos/lazy"]
lazynorth_doc = "LazyNorth-lazy.md"

[profiles.flex]
config_dir = "~/.claude-flex"
roots = ["~/repos/flex"]

[knowledge]
path = "~/vault/knowledge"

[knowledge.sessions]
enabled = true
subdir = "sessions"

[knowledge.learnings]
enabled = true
subdir = "learnings"

[knowledge.search]
engine = "qmd"

[monitoring]
enabled = true
db = "~/.local/share/lazy-harness/monitoring.db"

[monitoring.pricing.claude-sonnet-4-5]
input = 3.0
output = 15.0

[scheduler]
backend = "auto"

[scheduler.jobs.weekly-review]
schedule = "0 9 * * 1"
command = "lh knowledge sync"

[hooks.SessionStart]
scripts = ["lh hook session-context"]

[hooks.Stop]
scripts = ["lh hook compound-loop"]

[compound_loop]
enabled = true
model = "claude-haiku-4-5-20251001"
min_messages = 4
min_user_chars = 200

[lazynorth]
enabled = true
path = "~/vault/LazyNorth"

[context_inject]
enabled = true
max_body_chars = 3000
last_session_enabled = true

[harness]

Field Type Default Required Description
version string yes Schema version. Currently "1". Parsing fails without it.

[agent]

Field Type Default Required Description
type string "claude-code" no Agent adapter to load. Determines the config-dir env var (e.g. CLAUDE_CONFIG_DIR) and binary name lh run execs.

[profiles] and [profiles.<name>]

The [profiles] table holds one bare key (default) plus one sub-table per profile. The parser walks every key in [profiles], treats default as the default profile name, and treats every other key whose value is a table as a profile entry.

Field Type Default Required Description
default string "personal" no Name of the profile used when none resolves.

Each [profiles.<name>] sub-table:

Field Type Default Required Description
config_dir string (path) "" yes* Agent config directory for this profile. ~ is expanded.
roots list of strings [] no Filesystem roots that resolve to this profile (used by lh run and profile envrc).
lazynorth_doc string "" no Per-profile LazyNorth doc filename. Overrides [lazynorth].universal_doc.

* config_dir has no parser-level requirement, but everything downstream (lh run, lh deploy, lh profile envrc) is meaningless without it.

[knowledge] and sub-tables

Field Type Default Required Description
path string (path) "" no Root of the knowledge directory. Empty disables it.

[knowledge.sessions]:

Field Type Default Required Description
enabled bool false no Whether session export writes into the knowledge dir.
subdir string "sessions" no Subdirectory under knowledge.path.

[knowledge.learnings]:

Field Type Default Required Description
enabled bool false no Whether the compound loop persists distilled learnings.
subdir string "learnings" no Subdirectory under knowledge.path.

[knowledge.search]:

Field Type Default Required Description
engine string "qmd" no Search backend. Only qmd is implemented today.

[monitoring]

Field Type Default Required Description
enabled bool false no Whether the monitoring pipeline writes to SQLite.
db string (path) "" no Path to the monitoring DB. Empty falls back to the data dir default.
pricing table {} no Per-model pricing for cost rollups, e.g. [monitoring.pricing.<model>] with input / output USD-per-million-tokens floats.

[scheduler] and [scheduler.jobs.<name>]

Field Type Default Required Description
backend string "auto" no Scheduler backend. auto picks launchd (macOS), systemd (Linux), or cron (fallback).

Each [scheduler.jobs.<name>] sub-table:

Field Type Default Required Description
schedule string yes Cron-style schedule expression. Missing → ConfigError.
command string yes Shell command to run on each fire. Missing → ConfigError.

The job's name is the TOML key — there is no name field inside the table.

[hooks.<event>]

The [hooks] table is keyed by Claude Code hook event name (SessionStart, PreCompact, Stop, UserPromptSubmit, etc.). Each event sub-table has a single field:

Field Type Default Required Description
scripts list of strings [] no Commands to run for this event, in order. Typically lh hook <name> for built-ins.

Example:

[hooks.SessionStart]
scripts = ["lh hook session-context"]

[hooks.Stop]
scripts = ["lh hook compound-loop"]

[compound_loop]

Field Type Default Required Description
enabled bool false no Whether the compound-loop hook fires.
model string "claude-haiku-4-5-20251001" no Model used to distill learnings.
min_messages int 4 no Floor on session length before the loop runs.
min_user_chars int 200 no Floor on total user-message chars before the loop runs.
debounce_seconds int 60 no Minimum gap between two loop firings.
timeout_seconds int 120 no Hard timeout on the loop's model call.
learnings_subdir string "learnings" no Subdir under the knowledge dir where learnings are written.

[lazynorth]

Field Type Default Required Description
enabled bool false no Whether LazyNorth context injection is active.
path string (path) "" no Root of the LazyNorth directory.
universal_doc string "LazyNorth.md" no Default LazyNorth doc filename. Overridable per-profile.

[context_inject]

Field Type Default Required Description
enabled bool true no Whether the SessionStart hook injects context into the session.
max_body_chars int 3000 no Cap on injected body length.
last_session_enabled bool true no Whether to include a digest of the previous session.

Environment variable overrides

Three env vars relocate the directories lazy-harness reads and writes. They take precedence over XDG vars and platform defaults.

Env var Overrides Default (macOS/Linux)
LH_CONFIG_DIR Config directory ~/.config/lazy-harness
LH_DATA_DIR Data directory ~/.local/share/lazy-harness
LH_CACHE_DIR Cache directory ~/.cache/lazy-harness

XDG fallbacks (XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_CACHE_HOME) are honored when the explicit LH_* vars are unset.

Reloading config

There is nothing to reload — every lh invocation re-parses config.toml from disk, so saving the file is the entire reload step.