Skip to content

Config Files

Most of a garden’s behavior is convention, not configuration. These files hold the few things that genuinely vary per device or per deployment. Files under config/ are garden content: encrypted at rest, versioned, and carried by backup. Files under .softfig/ are local to the device.

File Where Read Purpose
.softfig/keeper.toml local, plaintext before unlock Boot pointer and the relock opt-in.
config/keeper.toml in the garden each unlock Networking, relay, replica, reveal policy.
config/growlight.toml in the garden by growlightd at start Fleet gate, roster, build caps, queue mode.
config/deploy.toml in the garden by softfig deploy Dotfile source→target table.
config/peers.toml in the garden by the daemon The device trust ring.
config/shared-subtrees.toml in the garden by the daemon Shared-subtree membership.
Other state files .softfig/ by the daemon Runtime state; not hand-edited.

The daemon’s configuration is split across two files, by when it is read. Both reject unknown keys, so a typo fails loudly instead of being ignored.

<garden>/.softfig/keeper.toml is a small plaintext file beside the store (onboarding also writes a copy under the state root; the daemon reads this one). It holds only what the daemon needs to boot, plus one security opt-in. It is deliberately not garden content, so an agent working in the garden cannot edit it.

Key Type Default Meaning
state_root path (unset) Absolute path to the relocated .softfig/ state root. When set, the daemon runs in FUSE mode and mounts the decrypted garden at the garden root.
[growlight] allow_relock bool false Permit the one-time relock token that resumes an unlocked vault across an unattended daemon restart (softfig daemon cycle). Human-set only.

The [growlight] table is shared with softfig-growlightd, so it tolerates the fleet keys that daemon reads. The pointer still accepts the [reveal], [net], [relay], and [replica] tables below for gardens not yet migrated; softfig migrate config lifts them into the garden.

<garden>/config/keeper.toml carries the post-unlock policy. It is seeded by softfig onboard and edited in place; the daemon re-reads it each time it unlocks. An absent file means the pointer’s values are used.

Table.key Type Default Meaning
[reveal] idle_seconds integer 0 Seconds after a successful reveal during which the next one may skip the passphrase prompt. 0 = always prompt.
[net] enabled bool true Host the networking instance (inbound Noise listener plus mDNS) on unlock.
[net] listen host:port 0.0.0.0:9100 Listener bind address; also the port mDNS advertises.
[net] device_name string system hostname Human-readable device name shown to peers.
[net] advertise_name bool true Publish the name in the mDNS record so peers can pick it from a list. false broadcasts the fingerprint only. Pairing is authenticated by the SAS either way.
[relay] enabled bool false Host a blind relay on this device (always-on machines).
[relay] listen host:port (unset) Relay bind address; required when enabled.
[relay] endpoint host:port (unset) A relay this device reaches as a client, as an off-LAN fallback.
[relay] static_key hex (unset) The relay’s X25519 transport public key, learned at pairing.
[replica] host bool false Store zero-knowledge ciphertext backups for ring members that have granted this device.

The owner-side list of hosts this device pushes to is runtime state, managed by softfig replica grant | revoke, not by hand.

<garden>/config/growlight.toml is the sole source of fleet configuration. softfig growlight init seeds a commented template. softfig-growlightd reads it through the mount when it starts, and keeperd re-reads the gate on each unlock to start or stop the softfig-growlightd user unit. Every failure mode is fail-closed: an absent, unreadable, or malformed file means the fleet stays off.

Key Type Default Meaning
fleet_enabled bool false The gate. false = disarmed: no agents spawn and keeperd doesn’t start the unit.
queue "legacy" | "v2" "legacy" Which queue model the fleet schedules from: the original backlog tables, or the queue.toml files (see below). An unknown value is refused and the fleet stays disarmed.
roll_grace_secs integer 20 Under queue = "v2": seconds a member may linger after being asked to roll into a fresh session before it is terminated.
max_iterations integer ≥ 1 (unbounded) Stop the fleet cleanly after this many completed work chunks. 1 is single-shot. 0 is rejected. Read once at arm time.
claude_bin string claude Binary a Claude member runs.
opencode_bin string opencode Binary an opencode member runs.
prompt string built-in The per-agent turn kick. The boot hook injects the protocol and baton regardless.
[build_caps] cargo_build_jobs integer 2 CARGO_BUILD_JOBS for each agent’s scope.
[build_caps] memory_high string "3G" systemd MemoryHigh soft throttle (e.g. "4G", "70%"). There is deliberately no hard cap.
[build_caps] cpu_weight integer 1–10000 50 systemd CPUWeight.

Adjust the build caps on a running fleet with softfig growlight resources set.

One block per agent. Unknown keys inside a [[fleet]] block are an error.

Key Type Default Meaning
agent slug (required) The agent id: lowercase letters, digits, -; unique.
pin string (unset) Bind the member to one queue. Omit for a fallback-only member.
backend "claude" | "opencode" "claude" Which agent backend the member runs on. Anything else is refused.
model provider/model (none) opencode only, required there. Passed on argv so a bad id fails closed.
variant string (none) opencode only, optional reasoning variant.

model or variant on a Claude member is refused rather than ignored, because the member would otherwise run on a pool you did not choose.

Under queue = "v2" the work list lives in garden files that you edit through the queue verbs or softfig growlight queue, not by hand:

  • growlight/backlog/queue.toml — [[project]] rows (name, repo, main) and [[entry]] rows (id, kind, title, project, lane, status, after links, and stack bookkeeping).
  • growlight/backlog/queue-archive.toml — finished and dropped entries.
  • growlight/backlog/milestones/<id>/slices.toml — a milestone’s ordered slice list.

All three carry schema = 1 and reject unknown fields.

Location: <garden>/config/deploy.toml. Purpose: the declarative source→target table that softfig deploy materializes. A single [dots] table of named entries, so plan order is stable (by name):

[dots]
bashrc = { source = "bashrc", target = ".bashrc" }
wayfire = { source = "wayfire.ini", target = ".config/wayfire.ini", method = "symlink" }
mimeapps = { source = "mimeapps.list", target = ".config/mimeapps.list", method = "copy" }
Field Type Default Meaning
source string (required) Path within config/source/.
target string (required) $HOME-relative (or absolute-under-$HOME) destination.
method symlink | copy symlink symlink materializes to a stable deploy cache and links the target to it (the FUSE view is ephemeral, so the link points at the cache). copy writes bytes straight to the target with a # managed by softfig stamp, for apps that reject symlinks.

Unknown keys are an error. This is a static table: no template rendering, variables, profiles, or hooks. Those are planned, not built. See Deploy Dotfiles.

Location: <garden>/config/peers.toml (membership, without endpoints), with a runtime copy at <state_root>/.softfig/peers.toml that also caches endpoints. Purpose: the network trust ring: “I recognize this device and hold its keys.” It is written when softfig pair completes an SAS-confirmed handshake; you don’t normally edit it. Each entry’s attestation is verified on load, so a hand-edited or swapped key is rejected.

version = 1
[[peer]]
device_id = "…" # peer's Ed25519 identity public key (hex)
name = "…" # human-readable device name (not security-bearing)
transport_pubkey = "…" # peer's X25519 transport static key (hex)
endpoints = [] # reachable host:port list; runtime copy only
attestation = "…" # peer's signature over its own transport key (hex)
paired_at = 0 # Unix seconds

Location: <garden>/config/shared-subtrees.toml. Purpose: the membership list of subtrees shared across the ring. Managed by softfig shared-subtree; listed here so you know what it is.

Field (per [[subtree]]) Meaning
id Stable share id.
mount_path This device’s garden-relative mount path. Each device chooses its own.
ref_name The ref holding the shared chain’s tip.
key_id Optional key identifier.
recommended_path The sharer’s advisory path, used as the default on accept.

Machine-specific dirs (hardware, services, os, storage, snapshots) and infrastructure dirs (config, growlight, journal, inbox) cannot be shared. Whether a share is enabled is a per-device toggle kept out of this file, in .softfig/shared-subtrees-local.toml.

Managed by the daemon; listed so you recognize them.

File Holds
.softfig/replica.toml push_to: fingerprints of hosts this device pushes backups to.
.softfig/shared-subtrees-local.toml disabled: share ids turned off on this device.
.softfig/vault/sealed-paths.toml The Layer B sealed-path globs (see Secrets).
.softfigignore (garden root) Extra top-level names excluded from the VCS. See Garden Schema.

Related: CLI Reference (the commands that read these), Garden Schema, and Deploy Dotfiles.