Skip to main content

notenv

CI Release Docs Go Reference Go Report Card License

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. There is no account to create, no SaaS to trust, no vendor that can read, lock, or lose your data.
  • Storage you already have. A local folder, a home NAS, B2, S3, Drive, SFTP, WebDAV, dozens more. Move a vault from a folder to a cloud remote in one command when syncing starts to matter.
  • Nothing on disk to leak. A test runner, a package 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.
  • Joining and leaving are one command. Onboard a teammate with a string sent over chat; their first run swaps it for a credential only they know. notenv key rm re-encrypts everything, so offboarding actually revokes, not just "please delete your copy."
  • Nothing to operate. notenv 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 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, 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:

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 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 shows which secrets exist and what they are for, never their values.

For a scoped session, notenv handoff -- <agent> runs the agent against an ephemeral vault holding only one namespace, so it never holds the key to the rest of your vault. An installable agent skill (skills/notenv/) teaches it the commands. See the AI agents guide.

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: key rm 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

Apache-2.0.

Metadata

Release files for notenv 0.20.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for notenv 0.20.0
File
notenv-0.20.0-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
notenv-0.20.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
notenv-0.20.0-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.20.0-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.20.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
notenv-0.20.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 15.1 MB

Release files / notenv-0.20.0-py3-none-win_arm64.whl

Download URL notenv-0.20.0-py3-none-win_arm64.whl
Size 2.4 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
425c8c260b2bd9250f5270b0cd74a30acccc4377504de12951b7464771f84699
BLAKE2b-256 checksum
How to use checksums
0d6fe4a7f3cd920bb944d90bd367d301f7a7c5722ca4ef1911ea07ba7aaef595
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 17, 2026.

Transparency log

Release files / notenv-0.20.0-py3-none-win_amd64.whl

Download URL notenv-0.20.0-py3-none-win_amd64.whl
Size 2.7 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
45c1479c5f3a4bcf34fb255fc4812c5296d4f02b69a3ec91777bd8fdfaafbb2d
BLAKE2b-256 checksum
How to use checksums
1fbe4205e3f465339284a9369214274c7f424f9820af1131b333427032f296c0
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 17, 2026.

Transparency log

Release files / notenv-0.20.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl

Download URL notenv-0.20.0-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
b02a497f2de730580f44bbaaac3d4f5f3ef8a3d88140529ea415a5324adebbcf
BLAKE2b-256 checksum
How to use checksums
299ad659c092f748d104eae1a42ac3c4b4704d9867137d048b34a32c30c7c501
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 17, 2026.

Transparency log

Release files / notenv-0.20.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl

Download URL notenv-0.20.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
Size 2.3 MB
Tags Linux glibc 2.17+ ARM64 Linux musl 1.1+ ARM64 Python 3
SHA-256 checksum
How to use checksums
adc126d3076a09797a90bc7143ef35051a73f1f7990a95f3344b65e6bdb444fd
BLAKE2b-256 checksum
How to use checksums
c33da7b971da658c47f664c9f13d54d4430e6564db85e0f96c701e1e5b57c104
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 17, 2026.

Transparency log

Release files / notenv-0.20.0-py3-none-macosx_11_0_arm64.whl

Download URL notenv-0.20.0-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
b723cbe17fbbc6f86583800e071f01529e78773f4983a79191c9f92e616d47a4
BLAKE2b-256 checksum
How to use checksums
850561c11df0a6074684b07df83117b72adbed1f94e23b5775cd1c3c4fbfc817
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 17, 2026.

Transparency log

Release files / notenv-0.20.0-py3-none-macosx_10_12_x86_64.whl

Download URL notenv-0.20.0-py3-none-macosx_10_12_x86_64.whl
Size 2.6 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
8486f8e1f724bcc7af294af2827cf144d98471245c46ab2914b07c5c12dfe762
BLAKE2b-256 checksum
How to use checksums
8a022678da7a7064a7f9c5fbc9d2cb7ca7ebf946231778795458bc017069acdd
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 17, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.4

6 release files

1.0.3

6 release files

1.0.2

6 release files

1.0.1

6 release files

1.0.0

6 release files

0.21.3

6 release files

0.21.2

6 release files

0.21.1

6 release files

0.21.0

6 release files

0.20.1

6 release files

This release

0.20.0 This release

6 release files

0.19.1

6 release files

0.19.0

6 release files

0.18.0

6 release files

0.17.1

6 release files

0.17.0

6 release files

0.16.0

6 release files

0.15.2

6 release files

0.15.1

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page