01 / Declaration

The AI manages your secrets. It never reads them.

Tell your assistant to add, generate, check, copy or remove a key in .env, JSON, YAML or TOML. When a value is needed, nfi opens a browser prompt and you paste it there. The AI only ever learns the key name.

$ npm install -g nfi-tools
.envSealed
# app
PORT=3000
DATABASE_URL=postgres://localhost/app
STRIPE_SECRET_KEY=

All the AI saw of that last line was STRIPE_SECRET_KEY and a confirmation, with nothing after the equals sign.

02 / How it works

The assistant asks for the value and you enter it somewhere the assistant can't see.

The exchange between you, the assistant and nfi
LnPartyEntry
01you"Add my Stripe secret key to .env."
02assistantnfi set .env STRIPE_SECRET_KEY
03nfi
STRIPE_SECRET_KEY
••••••••••••••••••••pasted
Save to .env
04nfiWrote 1 secret to .env
05assistant"Done. STRIPE_SECRET_KEY is set."

The prompt is served from a temporary localhost server with a one-time token. The value goes from that page to the file and nowhere else: not stdout, not stderr, not the tool result, not the context window.

03 / Commands

Everything you'd do to a secrets file, without looking at the secrets.

03.1set

nfi set .env STRIPE_SECRET_KEY nfi set .env STRIPE_SECRET_KEY DATABASE_URL nfi set config.json database.password

One form covers several keys, and dot notation reaches into JSON, YAML and TOML.

03.2generate

nfi generate SESSION_SECRET .env nfi generate APP_KEY .env --template uuid nfi generate TOKEN .env --template base64:32

Random secrets the AI never needs to see either, hex by default and 64 characters long.

03.3has, keys, diff

nfi has API_KEY .env nfi keys config.json --depth 1 nfi diff .env .env.example

Names, presence and gaps, but values never print.

03.4copy, remove

nfi copy DATABASE_URL .env config.json --path database.url nfi remove API_KEY .env

Move a value between files without it passing through anything that logs.

  • .env
  • .json
  • .yaml
  • .toml
  • --format to override

.env handling keeps your comments, blank lines, export prefixes and inline comments where they were.

04 / MCP

Or skip the shell: run it as an MCP server.

For clients without shell access, such as Claude Desktop or Cursor, register nfi once and the assistant gets the same operations as tools. The browser prompt still opens on your side; if it can't, you get a link to click instead.

  • store_secret
  • check_secret
  • list_keys
  • diff_keys
  • generate_secret
  • remove_secret
  • copy_secret
  • describe_capabilities
# auto-detects the client
$ nfi mcp install

# or be explicit
$ nfi mcp install --client cursor

# no install
$ npx nfi-tools set .env STRIPE_SECRET_KEY
05 / Security

The value has exactly one path, and it's short.

The browser prompt comes first, then a clickable URL if it can't open (remote session, MCP without a display), and finally a masked prompt on /dev/tty if there's no browser at all, which is the one input the assistant can't feed.

Path 01

Browser

Localhost page with password fields, so you can paste straight from your password manager.

Path 02

URL relay

Same page, delivered as a link when it can't be opened for you.

Path 03

TTY

Direct /dev/tty read with masked input, and if there's no TTY either nfi errors instead of reading stdin.

  1. Secret values never appear in stdout, stderr or tool return values.
  2. Browser input goes through a temporary localhost server with a one-time token.
  3. Token comparison is constant-time.
  4. POST submissions are checked against the Origin header.
  5. Request bodies are size-limited.
  6. TTY fallback reads /dev/tty directly, never stdin.
  7. Warns when the target file isn't covered by .gitignore.