notenv
Encrypted secrets, no infrastructure, no plaintext on disk.
notenv replaces .env files: secrets are encrypted on your machine with
age, kept as ciphertext in a local vault or on storage
you already own (Backblaze B2, S3, Google Drive, SFTP, WebDAV, anything
rclone speaks), and decrypted only into the environment of the command you
run. Plaintext never touches disk.
Why
A .env file is plaintext: everything on your machine can read it, and sharing it means pasting it
somewhere it will outlive. notenv removes the file instead of guarding it.
- You hold the key, not a provider. Secrets are age-encrypted locally; storage only ever sees ciphertext. No account to create, no SaaS to trust, no vendor that can read, lock, or lose your data.
- Storage you already own. A local folder, the NAS under your desk, B2, S3, Drive, SFTP, WebDAV, dozens more, and you can move between them when syncing across machines starts to matter.
- Nothing on disk to leak. A test runner, a package's postinstall script, or a coding agent in your checkout cannot read a secret that exists only inside the process you ran, only while it runs.
- Easy to share, clean to leave. Share a vault with a collaborator in seconds, and when they leave, they can no longer read it, instead of you just hoping they deleted their copy. No lock-in either; you can leave with your secrets for a different solution easily.
- Nothing to operate. Setup is one passphrase and zero accounts. No server to stand up, patch, or pay for.
Not this if you want a platform: there is no web console or SSO, and access is scoped per vault, not per secret (everyone in a vault can read that vault). If a platform team already runs Vault, keep Vault.
Install
uv tool install notenv # also: pipx install notenv, or pip
go install github.com/DvGils/notenv/cmd/notenv@latest # with Go
Or download a prebuilt binary for Linux, macOS, or Windows (amd64 / arm64) from
Releases 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 namespace import .env && rm .env # 3. import existing secrets (or `notenv secret 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, then notenv setup with your escrowed
passphrase, and you are ready. 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:
- Quick start and installation
- Guides: share a vault with your team, cloud remotes, export or delete a vault, AI agents
- Reference: commands, configuration
- Concepts: how it works, keys and slots
- Security: threat model
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
A random master key encrypts every secret and never exists in plaintext at rest: a small header holds it wrapped under one or more key slots (a person's passphrase or a machine's age public key), the way LUKS and restic do it. The header is authenticated and version-pinned, so a party who 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 lands in a coding agent's context. notenv handoff -- <agent> runs the
agent against an ephemeral vault holding only one namespace, so it can use your secrets but never
holds the key to the rest of your vault, and injected values are masked out of its output. Inside the
session it uses notenv run -- cmd and notenv namespace inspect, never touching a raw value. Its MCP servers can
draw their own credentials from notenv too, so a token never sits in plaintext in your shell or
.mcp.json. An installable agent skill (skills/notenv/) teaches it the commands. See the
AI agents guide and
MCP servers.
How it compares
| notenv | dotenvx | 1Password (op run) |
SOPS + age | |
|---|---|---|---|---|
| Where the ciphertext lives | storage you own (B2, S3, Drive, a NAS, a folder) | committed to your git repo | 1Password's servers | a file you place yourself |
| What you depend on to read a secret | only your key | only your key | 1Password, your account and plan | only your key |
| Account or service to sign up for | none | none | required | none |
| Onboard a teammate | one command, with a verifiable vault fingerprint | hand over the private key | invite them in the app | add their key, redistribute the file |
| Offboarding actually revokes | yes: credential delete re-encrypts the vault |
rotate the key, re-encrypt by hand | remove them from the vault | rotate, re-encrypt by hand |
| Move to other storage | one command, any rclone remote | it lives in git | not applicable, it is their cloud | move the file yourself |
dotenvx and op run both nail encrypted injection; the difference is the master.
dotenvx keeps the encrypted file in your repo and leaves distributing and rotating the private key to
you; 1Password is excellent but is a service that holds your secrets and that you depend on.
SOPS + age give you the keys but leave storage and onboarding as homework. notenv
is the one combination of all three: keys you hold, storage you already own, and onboarding built in,
with nobody in the loop.
Security
At rest, anywhere, only age ciphertext exists; it is useless without your key, which lives in your password manager and never 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
Metadata
Release files for notenv 0.21.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| notenv-0.21.1-py3-none-win_arm64.whl | Python 3 | none | Windows ARM64 | Details |
| notenv-0.21.1-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| notenv-0.21.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64, Linux musl 1.1+ x86-64 | Details |
| notenv-0.21.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64, Linux musl 1.1+ ARM64 | Details |
| notenv-0.21.1-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| notenv-0.21.1-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size: 15.2 MB
Release files / notenv-0.21.1-py3-none-win_arm64.whl
| Download URL | notenv-0.21.1-py3-none-win_arm64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Python 3 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
29cc5e22102d3b044c08b4df063a38b94292f0bb306ab3b2110fb1158eddd6bb
|
|
BLAKE2b-256 checksum How to use checksums |
5ad56427f3b47a5a6664a304ac45bbb3840e696bcf98238a4fbf02cfa874b86a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.
Transparency logRelease files / notenv-0.21.1-py3-none-win_amd64.whl
| Download URL | notenv-0.21.1-py3-none-win_amd64.whl |
|---|---|
| Size | 2.7 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
0e8bd697c9c31a8167dd4698355934842d3aa2362831dc9237ae485932ba9944
|
|
BLAKE2b-256 checksum How to use checksums |
6d6190d1adb4f56c585a183975a3cf8a4912b0fa38fcbdf4810332269d0a2a74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.
Transparency logRelease files / notenv-0.21.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl
| Download URL | notenv-0.21.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | Linux glibc 2.17+ x86-64 Linux musl 1.1+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
59e005b5d035df1c6fba3a8974bc67deec6a9b8d73df82a63a65b09643a1149d
|
|
BLAKE2b-256 checksum How to use checksums |
0dc2ce32e79afd7852b1b16a634ebc615fcb574026640fe49f7610c6d9245043
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.
Transparency logRelease files / notenv-0.21.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
| Download URL | notenv-0.21.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Linux glibc 2.17+ ARM64 Linux musl 1.1+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
b5614aed879448dab68f9a215fe3cd19c496dca26acedd7788dc18f243fb0586
|
|
BLAKE2b-256 checksum How to use checksums |
2ad8ba37ed7bce0166789a81c980793df97384c9a91d57082c50868588873bd4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.
Transparency logRelease files / notenv-0.21.1-py3-none-macosx_11_0_arm64.whl
| Download URL | notenv-0.21.1-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
d7229c9c362239c5c3b7617b069779ffdaf7244b4ec58e47362030318f7f8a69
|
|
BLAKE2b-256 checksum How to use checksums |
97731033a873c915e6f7bb5d11ca1041e644ac85bf3dd8136709d4ba53d088e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.
Transparency logRelease files / notenv-0.21.1-py3-none-macosx_10_12_x86_64.whl
| Download URL | notenv-0.21.1-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 2.7 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
77d424b75e7ddc1fdc06bf07670a5f2e62692648e661ae3b62d2ebdab8f97ccc
|
|
BLAKE2b-256 checksum How to use checksums |
87e2acf4aad81482d0b7f7100083c6e27814965bf2d184c29edb5fb039d8ce8b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 21, 2026.
Transparency log