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. |
keeper.toml
Section titled “keeper.toml”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.
The bootstrap pointer
Section titled “The bootstrap pointer”<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.
The in-garden policy
Section titled “The in-garden policy”<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.
growlight.toml
Section titled “growlight.toml”<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.
[[fleet]] roster
Section titled “[[fleet]] roster”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.
Queue files
Section titled “Queue files”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,afterlinks, 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.
deploy.toml
Section titled “deploy.toml”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.
peers.toml
Section titled “peers.toml”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 onlyattestation = "…" # peer's signature over its own transport key (hex)paired_at = 0 # Unix secondsshared-subtrees.toml
Section titled “shared-subtrees.toml”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.
Other state files
Section titled “Other state files”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.