nf

Architecture

Project Shape

nf is a Go CLI.

Project-only commands appear only when the current repo has nf.json next to .git.

Project Metadata Model

Project repositories use:

nf.json

This file is safe to commit. It must not contain API tokens, SSH keys, live database passwords, provider secrets, or mutable provider inventory.

Generated project metadata includes project.password_version: 0. Leave it at 0 for stable derived passwords; increment it to rotate derived passwords for that project/site without changing the shared NF_PASSWORD_SALT.

Default WordPress theme convention is theme/. By default, nf init derives the project slug from the current git root folder and assumes the WordPress theme lives in theme/.

Config, State, and Data Layout

Defaults:

config: ~/.config/nf/
state:  ~/.local/state/nf/
data:   ~/.local/share/nf/

Current config files:

config.json     non-secret global config, including base_domain, dnsimple_account_id, basicauth_default_user, and db_default_user
.env            secrets/account tokens
providers.json  provider check metadata and targets
sites.json      cached remote site/env records
projects.json   disposable project cache if needed

State/cache lives under:

~/.local/state/nf/
  providers.json
  sites.json
  projects.json

Local state is disposable cache, not source of truth. Provider truth is canonical remotely.

Provider, Target, and Site Model

Kinsta sites have two possible slug identities:

nf site add kinsta <project-slug> --kinsta-slug <provider-slug> creates or adopts a Kinsta site whose provider slug differs from the repo/project slug. The attached internal Kinsta domain, such as client.kinsta.nonfiction.dev, is provider-side identity data: nf site refresh can infer the canonical project slug from it even when local sites.json is rebuilt.

Password and Basic Auth Model

Password derivation uses NF_PASSWORD_SALT from the environment or ~/.config/nf/.env. Legacy NF_SECRET_SALT is accepted only as a migration fallback.

Project site passwords, including provider basic-auth passwords, also include project.password_version from nf.json when it is non-zero; missing or 0 preserves the original derivation.

basicauth_default_user belongs in config.json, defaults to nonfiction, and is used with a per-site derived basic-auth password.

db_default_user belongs in config.json, defaults to admin, and is used for Linode target database UI HTTP Basic auth, the shared MySQL admin user, and the database UI subdomain label unless nf target add linode --db-user overrides it for that target.

Safety Boundaries

Treat these as high risk:

Sync and deploy workflows must require explicit source and destination, identify provider/environment, print a reviewable plan, preserve production credentials where possible, and require confirmation for destructive changes.

Key rule: never silently clobber production credentials.