Skip to main content

Your .env, encrypted and off your disk, with no infrastructure to run.

Project description

notenv

CI Release Docs Go Reference Go Report Card License

Your .env, encrypted and off your disk, with no infrastructure to run.

notenv replaces .env files. Your secrets are encrypted on your machine with age, stored as ciphertext in a local vault or on storage you already own (Backblaze B2, S3, Google Drive, SFTP, WebDAV, or anything rclone speaks), and decrypted only into the environment of the process you run. Plaintext never touches your disk.

notenv setup                   # a local vault: no accounts, no dependencies, one passphrase
notenv import .env             # your existing secrets, encrypted; delete the .env after
notenv run -- npm run dev      # secrets injected as env vars, gone when the process exits

There is no server to run, no SaaS to sign up for, and nothing to install beyond notenv itself. You hold the key; storage only ever sees ciphertext. When syncing across machines starts to matter, notenv vault copy moves the same vault to a cloud remote in one command.

Documentation

Full docs live at dvgils.github.io/notenv:

Install

With uv (or pipx, or pip; the package carries the prebuilt binary, no Python code runs):

uv tool install notenv

With Go:

go install github.com/DvGils/notenv/cmd/notenv@latest

Or download a prebuilt binary for Linux, macOS, or Windows (amd64 / arm64) from the Releases page and put notenv on your PATH. Releases are reproducible, signed with cosign (keyless), and carry SLSA build provenance; the installation guide shows how to verify a download.

Quick start

notenv setup                   # 1. set up this machine once (local vault by default)
cd my-project && notenv init   # 2. declare the project (writes notenv.toml, which you commit)
notenv import .env && rm .env  # 3. import existing secrets (or `notenv set KEY` one at a time)
notenv run -- npm run dev      # 4. run anything with the secrets injected

That is the whole loop. notenv is a process wrapper, so it works with any language that reads environment variables. On a new machine, git clone the project, run notenv setup with your escrowed passphrase, and you are ready. See the quick start for the full walkthrough.

Why notenv

Your secrets are probably in a .env file right now. That means:

  • Everything on your machine can read them. Your test runner, some package's postinstall script, and any coding agent working in your checkout are one read away. An agent that opens your .env while debugging has just copied your production credentials into a model context and a transcript you don't control.
  • Sharing them means pasting them. A teammate needs the project's secrets, so the file goes over chat. Now it lives in message history, in a downloads folder, on a laptop that will eventually be sold. And when someone leaves, nothing expires: there is nothing to revoke.
  • The official fixes want you to become an operator. Run a Vault server, or create and manage a cloud account just to have somewhere to put five secrets: a subscription, IAM wiring, an SDK in your app, and a provider sitting between you and your own credentials.

notenv removes the file instead of guarding it. Secrets are encrypted on your machine, live as ciphertext in a local vault or on storage you already own, and exist in plaintext only inside the environment of the process you run, for as long as it runs. Storage means anything rclone speaks: Backblaze B2, S3, Google Drive, Dropbox, SFTP, WebDAV, dozens more. Your vault can live on the NAS under your desk, and nobody can stop you from keeping it on the SFTP server in your smart fridge. There is nothing to operate and nobody else to trust: you hold the key, storage holds ciphertext, and the threat model says precisely what that does and does not protect.

Reach for it when:

  • you're one developer who wants to do this right, without standing up an account at a cloud provider and managing it forever just to have a key vault: notenv setup is one passphrase, zero accounts, and you're done;
  • a coding agent works in your repository, and "the agent can run the app without ever seeing the database password" should be a property, not a hope;
  • a teammate needs in: onboarding is one command and a string over chat, their first use replaces it with a credential only they know, and offboarding re-encrypts everything, so leaving actually revokes;
  • CI needs thirty secrets, and the CI secret store should hold one;
  • a laptop dies, and the recovery plan should be "the passphrase in my password manager", not "which machine had the newest .env".

And honestly, when not: notenv is not a platform. There is no web console, no SSO, and access is scoped per vault rather than per secret: everyone in a vault can read that vault, and you scope by making vaults (one per project or per environment is one setup away). If your organization has a platform team running Vault, keep Vault.

How it compares

For readers who know the space: SOPS + age nail client-side encryption and process injection but leave storage and onboarding to you; Teller brokers cloud secret managers, where the provider holds your secrets. notenv is client-side encryption with the storage and the onboarding built in, and no provider in the loop.

notenv teller SOPS + age (DIY)
Plaintext on disk never never never
You hold the key yes no (provider does) yes
Storage backends local vault or any rclone remote per-provider code you wire it up
Infrastructure to run none none (uses your cloud) none
One-command onboarding yes partial no

How it works

notenv run -- cmd
  |
  |-- fetch ciphertext   <- rclone <-  your B2 / S3 / Drive / ...
  |-- unlock the master key (from your passphrase; cached after first use)
  |-- decrypt secrets in memory
  |-- build the child environment from notenv.toml
  |-- exec cmd, stream its I/O, exit with its code
        nothing written to disk

Secrets are encrypted with a random master key that never exists in plaintext at rest: a small header object holds it wrapped under one or more key slots (a person's passphrase, or a machine's age public key), the same approach LUKS and restic use. The header is authenticated and version-pinned, so a party that can write your storage but holds no key cannot tamper with it or roll it back undetected. Full detail in Concepts.

For AI agents

A .env on disk eventually enters a coding agent's context. notenv removes the file and gives the agent a verb that separates using a credential from knowing it:

  • notenv run -- cmd injects secrets into the child only; the value never appears in what the model reads, and captured output is masked.
  • notenv list tells the agent which secrets exist and what they are for, never their values.

There is also an MCP server (notenv mcp) and an installable agent skill (skills/notenv/). See the AI agents guide for the full surface and its honest limits.

Security

At rest, anywhere, only age ciphertext exists; it is useless without your key, which lives in your password manager, not on the storage backend. The threat model covers what notenv defends, against whom, and the explicit non-goals. To report a vulnerability, see SECURITY.md.

Building from source

git clone https://github.com/DvGils/notenv
cd notenv
make build       # compile ./notenv
make test        # run the test suite
make install     # install into $(go env GOPATH)/bin

Releases are produced with GoReleaser; make snapshot builds the full set of release artifacts locally without publishing.

Status

Actively developed and being tested. See the roadmap for what works today, what is planned, and the non-goals.

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

notenv-0.15.1-py3-none-win_arm64.whl (2.3 MB view details)

Uploaded Python 3Windows ARM64

notenv-0.15.1-py3-none-win_amd64.whl (2.6 MB view details)

Uploaded Python 3Windows x86-64

notenv-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl (2.5 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64musllinux: musl 1.1+ x86-64

notenv-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl (2.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64musllinux: musl 1.1+ ARM64

notenv-0.15.1-py3-none-macosx_11_0_arm64.whl (2.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

notenv-0.15.1-py3-none-macosx_10_12_x86_64.whl (2.6 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file notenv-0.15.1-py3-none-win_arm64.whl.

File metadata

  • Download URL: notenv-0.15.1-py3-none-win_arm64.whl
  • Upload date:
  • Size: 2.3 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for notenv-0.15.1-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 7928a97560d7608dbb95d0c7e318420966213bd35d193eb197223b7119e1ee26
MD5 848b5a7af05781981ef51c7cbddf6572
BLAKE2b-256 6942400cdce8f87419fbb0af430a0c6287e371976656bf8d26167787d453a0e6

See more details on using hashes here.

Provenance

The following attestation bundles were made for notenv-0.15.1-py3-none-win_arm64.whl:

Publisher: release.yml on DvGils/notenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file notenv-0.15.1-py3-none-win_amd64.whl.

File metadata

  • Download URL: notenv-0.15.1-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.6 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for notenv-0.15.1-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 b8087922fb1c396a44c735127abb5c0d8803e8fcd5ab7f78ae6acb4584de1b62
MD5 e9b69807a418820d455c16b26d927773
BLAKE2b-256 7d2a7438156e051aee49e712f5bfd679ebc36bee8c3657582f0141ce4c09be57

See more details on using hashes here.

Provenance

The following attestation bundles were made for notenv-0.15.1-py3-none-win_amd64.whl:

Publisher: release.yml on DvGils/notenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file notenv-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for notenv-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 e80aa997a329b34910953134300242a285a5460265d8431f2b478994faf8fb51
MD5 0ab9cb8256ce6cba279f696429ba498f
BLAKE2b-256 75e5dc3594869ca9524c1a5416ef1d1dc6065b5a794ffdb704c57288998e0b2c

See more details on using hashes here.

Provenance

The following attestation bundles were made for notenv-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl:

Publisher: release.yml on DvGils/notenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file notenv-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl.

File metadata

File hashes

Hashes for notenv-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
Algorithm Hash digest
SHA256 cb5a9ffbdea825bd746d194246ce38159809f6c9b15e1f26a53f11914dff422a
MD5 350efbe433285375d6206837a2680ba5
BLAKE2b-256 0ca2d001e6dceb0b6033d01c72f08d78663f2bd94996d9eca501ce197090cb89

See more details on using hashes here.

Provenance

The following attestation bundles were made for notenv-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl:

Publisher: release.yml on DvGils/notenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file notenv-0.15.1-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for notenv-0.15.1-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 324b86be1945cc98b0bb3d55cb465fb5f0fb6361f4aa8d0da2eedd471221dd1c
MD5 bc62f569d00f2967acd51372d95d668e
BLAKE2b-256 325e85666771853eacb0844a31ba9b79916ab772fc951a2923883eed3a92edb5

See more details on using hashes here.

Provenance

The following attestation bundles were made for notenv-0.15.1-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on DvGils/notenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file notenv-0.15.1-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for notenv-0.15.1-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 fd44dfb2b585ba6cd3c7e4758aeda3f9a36b7df7f4f0cf03d5bee35b3964b7f1
MD5 90a3d5cb2d77b469d8e97cfa3dd382e4
BLAKE2b-256 549a0a5092f65d52cb1bb80c5fbc84bebd07514c6b77a77be5f3c076f646556e

See more details on using hashes here.

Provenance

The following attestation bundles were made for notenv-0.15.1-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on DvGils/notenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page