Deploy Dotfiles
A garden can hold your dotfile sources and put them where they belong on the
machine, the job GNU Stow or bombadil link does. You declare a source-to-target
table in config/deploy.toml; softfig deploy materializes it, conflict-safe
and dry-runnable. Deploy moves files as-is: there is no templating yet. See
the limits before you plan around it.
The table: config/deploy.toml
Section titled “The table: config/deploy.toml”Deploy sources live under config/source/ in the garden; the table maps each one
to a target. The schema is deliberately small — a [dots] table of named
entries:
[dots]bashrc = { source = "bashrc", target = ".bashrc" }wayfire = { source = "wayfire.ini", target = ".config/wayfire.ini" }weather = { source = "weather.conf", target = ".config/weather/weather.conf", method = "copy" }sourceis relative toconfig/source/.targetis relative to$HOME(or an absolute path under$HOME).methodissymlink(the default) orcopy.
A target that resolves inside the garden itself is refused.
Entry names may use letters, digits, ., _ and -. The plan is reported in
name order. Unknown keys in the file are rejected, so a typo fails loudly.
Symlink vs copy
Section titled “Symlink vs copy”symlink (default). The source is materialized into a stable deploy-cache
and the target becomes a symlink to it. Why the cache? The garden’s plaintext is
a FUSE mount that vanishes the instant the garden locks — a link straight into it
would dangle. The cache (0700/0600, under your data dir) is the durable thing
the link points at, so your dotfiles survive a locked garden.
copy. The bytes are written straight to the target with a
managed by softfig stamp in a leading comment, e.g.:
# managed by softfig — edits will be overwritten (source: config/source/weather.conf)Use copy for the handful of apps that refuse to follow a symlinked config. The
stamp is a warning to future-you: edits to the target get overwritten on the next
deploy, because the source is the truth.
Preview, then apply
Section titled “Preview, then apply”Always dry-run first. It prints the plan and touches nothing:
softfig deploy --dry-runPlan (3 dot(s)): symlink bashrc → /home/you/.bashrc symlink wayfire → /home/you/.config/wayfire.ini copy weather → /home/you/.config/weather/weather.conf
(dry run — nothing changed)Each row’s verb is the action apply would take: symlink, copy, replace
(refresh a managed target), skip (already up to date), or CONFLICT. When the
plan looks right, drop the flag:
softfig deployIt reports what it did (created, replaced, copied, skipped, forced) and any conflicts. Re-running is safe: up-to-date entries are skipped.
Conflicts and --force
Section titled “Conflicts and --force”deploy will not silently clobber a file it doesn’t manage. If a target already
exists as an unmanaged file, a foreign symlink, or a directory, that row is
marked CONFLICT and skipped, and the command exits non-zero. To take over such
targets, back them up and overwrite in one step:
softfig deploy --force--force moves each conflicting target to <target>.softfig-bak before writing
the new one, so nothing is lost — you can inspect or restore the .softfig-bak
copy afterward.
Paths and flags
Section titled “Paths and flags”softfig deploy [--dry-run] [--force] [--garden-root PATH] [--cache-root PATH]--garden-rootdefaults to~/soft-fig_garden(the FUSE mount to read sources and the table from).--cache-rootdefaults to$XDG_DATA_HOME/softfig/deployed(i.e.~/.local/share/softfig/deployed), wheresymlinktargets point. It must be outside the garden.
Current limits
Section titled “Current limits”$HOMEtargets only. Absolute targets outside$HOME(the/etccase) are rejected.- Files, not directories. A
sourcemust be a single file. - No templating, secrets or post-deploy hooks. Sources deploy verbatim.
Template rendering with variables, and render-time vault secrets, are planned
but not built. Don’t write
{{ }}variables in a source expecting them to render. - Sealed sources deploy as plaintext. If a source is
sealed, deploy decrypts it: the real contents land in the
deploy cache and the target, as owner-only (
0600) files outside the vault. Treat that as a deliberate declassification, and point such a dot at a target you’re comfortable with. - You create the table.
softfig onboardscaffolds aconfig/directory (daemon and growlight settings), but nodeploy.tomlorconfig/source/. Add both when you’re ready to manage a dotfile from the garden.
Related: Seal & Reveal and the CLI reference for the full command surface.