Skip to content

How fnox works

fnox maps a named secret in fnox.toml to a resolved value, then passes that value to a command, a shell, or stdout. Providers decide where values come from; profiles and config layering decide which definitions apply.

From configuration to command

When you run fnox exec -- npm start:

  1. Load configuration. Merge the global configuration and project files, including applicable profile and local files.
  2. Select definitions. Apply the selected profiles and their inheritance in order.
  3. Resolve values. Decrypt ciphertext, fetch provider references, or use defaults and existing environment variables.
  4. Prepare the environment. Apply field selectors, create temporary files for as_file secrets, and obtain configured credential leases.
  5. Run the command. Start npm start with the resolved environment and clean up temporary resources when it exits.

fnox exec does not change the parent shell. It inherits the existing environment and adds the configured values according to each secret's env setting.

Providers and references

A provider has an instance name, such as op, and a type, such as 1password:

toml
[providers.op]
type = "1password"
vault = "Engineering"

[secrets]
DATABASE_URL = { provider = "op", value = "Database/url" }
LOG_LEVEL = { default = "info" }

DATABASE_URL is the environment variable name. op selects the configured provider. Database/url identifies the item and field in 1Password.

For encryption providers such as age, the value field holds ciphertext generated by fnox set, rather than an item reference. You do not need to construct ciphertext by hand.

Local stores such as the OS keychain and KeePass also use references; a reference does not necessarily imply a network request. Conversely, a cloud KMS provider needs network access even though its ciphertext lives in your config.

Resolution order

For an individual secret, fnox tries:

  1. Provider value. When a sync cache exists, its encryption provider and ciphertext take the place of the original provider lookup.
  2. Default. A default value can also supply a fallback when a provider fails. Defaults can reference other secrets.
  3. Existing environment variable. Used when no provider value or default is available.

An individual provider error without a default returns an error before the environment fallback. Commands that resolve multiple secrets apply each secret's if_missing policy to decide whether to stop, warn, or skip it.

After resolution, json_path or line can select part of a provider value. These selectors are mutually exclusive.

Three kinds of cache

CacheStoresLifetimeRefresh
SyncEncrypted values in a local config fileSurvives restartsRun fnox sync again
DaemonResolved values in process memoryUntil cleared, invalidated, or the daemon exitsfnox daemon clear
Lease ledgerTemporary credentials and lease metadataUntil expiry or revocationA new lease is created as needed

These serve different purposes. Sync supports offline use with a local encryption provider. The opt-in daemon avoids repeated reads during a session. Leases replace long-lived credentials with temporary ones when the backend supports expiry.

Inspect a configuration

sh
fnox config-files   # Which files are loaded?
fnox profiles      # Which profiles exist?
fnox list --sources # Where was each secret defined?
fnox check --all         # Can the configured secrets be resolved?

See troubleshooting when the result differs from what you expect.

MIT LicenseCopyright © 2026jdx.dev