Skip to content

Seal & Reveal Secrets

A garden is encrypted at rest, but the moment it’s unlocked the whole plaintext view is readable — by you, by your editor, by a Claude session. That’s fine for notes and config commentary; it’s wrong for an API token. Layer B is the answer: it keeps chosen secrets encrypted even inside the unlocked view, so they never appear in the mounted tree and never reach the assistant. This guide is the day-to-day mechanics of sealing and revealing them.

You can seal at two levels, and they compose:

  • Whole files, matched by glob — the entire file is Layer-B ciphertext.
  • Inline regions inside an otherwise-plaintext file — wrap a single secret in <vault id="…">…</vault> and only that span is sealed, while the rest of the file stays readable.

Inline regions are the ones to reach for most: you keep a file legible and reviewable, with just the credential blacked out. Wrap the secret in the tag, giving it an id you’ll use later to reveal it:

# an .env-style file — readable, except the one secret
API_ENDPOINT=https://api.example.com
API_KEY=<vault id="example-key">sk-live-abc123…</vault>

Once sealed, the FUSE mount never shows the plaintext. Instead you see placeholders:

  • a sealed file reads as [sealed:<path>];
  • a sealed region reads as <vault id="x">[encrypted]</vault>.

That’s exactly what a Claude session sees too. The MCP write verbs also refuse to edit sealed content, so an assistant can neither read a secret nor overwrite one by accident. (The boundary from the assistant’s side is described in Working with Claude.)

softfig vault seal appends a glob to the vault’s sealed-paths list; the daemon commits the change and auto-encrypts every tracked file that matches. It talks to the running daemon, so the garden must be unlocked.

Terminal window
softfig vault seal 'secrets/**'

Globs support **, *, ?, […], and {a,b}. Quote them so your shell doesn’t expand them first. The command reports the schema change, the seal commit, and every file newly sealed:

schema_change 3f9a…
vault_seal c17b…
newly sealed (2):
secrets/tokens.toml
secrets/deploy.env

If no tracked file matches yet, it just records the glob — anything you add later that matches gets sealed automatically.

Terminal window
softfig vault list-sealed

Prints the active globs and the tracked files currently matching them — your audit of what Layer B is protecting.

Turning a secret back into plaintext is a deliberate, human-only action:

Terminal window
softfig reveal secrets/tokens.toml

It does not print the secret. It writes the plaintext to a mode-0600 temp file under $XDG_RUNTIME_DIR and prints only that path — keeping the secret out of your shell history, terminal scrollback, and any log forwarder. You then open, less, or pipe the file yourself:

Terminal window
less "$(softfig reveal secrets/tokens.toml)"

To reveal a single inline region instead of a whole file, name its id — repeat --id for several, and you get one temp file per id in the order given:

Terminal window
softfig reveal services/example.env --id example-key

reveal asks the daemon, which prompts for your master password (once per invocation, even with several --ids), so the garden must be unlocked and the daemon running. Each reveal is recorded as an audit commit. Delete the temp file when you’re done; it lives on tmpfs under $XDG_RUNTIME_DIR.

Removing a glob stops future matches from being sealed, but does not bulk-decrypt blobs that are already sealed on disk:

Terminal window
softfig vault unseal 'secrets/**'

If you want the file back as ordinary garden content, reveal it and rewrite it through the mount after unsealing. unseal on a pattern that isn’t present is a no-op.

Sometimes the cleanest move isn’t to seal a secret into the garden at all, but to keep it out and point at where it really lives — an encrypted secrets.toml in your dotfiles, a password manager, a hardware token. The garden convention is pointer-or-seal, never plaintext: either seal it with Layer B, or store a one-line note saying where the real thing is. Reach for a seal when the secret genuinely belongs in the garden’s history; reach for a pointer when it belongs somewhere else and the garden only needs to remember that.

softfig deploy decrypts a sealed source to plaintext in the target and in its deploy cache (both owner-only, outside the vault). That is a deliberate declassification; see Deploy Dotfiles. Rendering secrets into configs at deploy time is planned, not built.

Sealed content is only as recoverable as your vault. Read Recovery & escrow before you seal anything you can’t lose.


Related: Deploy Dotfiles, Reference → Crypto for the primitives, and Internals → Vault for how the two layers are built.