Skip to content

create-key

Generate a per-repository key that gives envi pack / envi unpack a stable shared secret and adds opt-in at-rest encryption to ~/.envi/store/.

Usage

bash
envi create-key
envi create-key --force

Description

create-key generates a cryptographically random key and writes it to envi.config.maml at the repository root. envi.config.maml is meant to be committed to the repository so every collaborator inherits the key automatically.

This is a convenience feature, not a security one. It exists to solve two specific annoyances:

  • envi pack / envi unpack get a key that doesn't change when your manifest does, so blobs don't break the next time someone runs pnpm install.
  • envi capture writes encrypted entries to ~/.envi/store/ instead of plaintext — mainly useful when you back that store up to GitHub via envi global github enable, so a leak of the backup doesn't expose env values without also leaking the source repo.

If neither of those bothers you, you don't need envi.config.mamlenvi pack / envi unpack work fine using a manifest-derived key, and envi capture is fine writing plaintext locally.

Why a Key File?

The two situations where running create-key is worth it:

  • Shared blobs that outlive dependency updates. The default for envi pack derives the key from package.json / Cargo.toml / etc., so the key changes on every dependency bump. A committed envi.config.maml is stable across those changes.
  • Encrypted GitHub backup. When ~/.envi/store/ is pushed to GitHub via envi global github enable, envi.config.maml makes the backup encrypted instead of plaintext. The source repo holds the key, so a backup-only leak isn't enough to decrypt.
  • No secret to share. Every collaborator who clones the repo automatically has the key — no out-of-band exchange.

What It Does

  1. Finds repository root - Same logic as capture/restore
  2. Refuses if already set - If envi.config.maml already contains an encryption_key, the command exits unless --force is passed
  3. Generates 32 bytes of random data as a base64url string
  4. Writes envi.config.maml - Creates a new file with a header comment, or inserts the key into an existing envi.config.maml while preserving other content

File Format

A freshly created envi.config.maml looks like:

maml
{
  # Generated by `envi create-key`. Team-shared encryption key meant to be
  # committed. Convenience, not security: gives `envi pack` / `envi unpack`
  # a stable key that survives manifest changes (so shared blobs don't
  # break after `pnpm install`), and encrypts `~/.envi/store/` — mainly
  # useful with the GitHub backup (`envi global github enable`).
  #
  # Anyone with repo access can decrypt, so this repo should be private.
  # On a public repo this gives no confidentiality; use a custom secret
  # with `envi pack` instead.
  #
  # See: https://envi.codecompose.dev/commands/create-key
  encryption_key: "u3qZKY9GgqOMcKQ9s51G81HjpIB4WuKkn9Zh1Qkon_0"
}

envi.config.maml is also where per-repo Envi configuration lives — for example, the optional capture_patterns array that extends which files envi capture picks up.

Legacy filename

Earlier versions of Envi called this file envi.maml (no config segment). The legacy filename is still read so already-committed files keep working — Envi prints a one-line hint suggesting you rename to envi.config.maml the first time it sees the legacy file in a session. New files written by envi create-key always use the canonical name; if you have a legacy file checked in, edit it in place or rename and commit envi.config.maml whenever it's convenient.

Examples

First-time setup

bash
$ envi create-key
 Finding repository root...
 Repository root: /Users/you/projects/myapp
 Wrote encryption_key to envi.config.maml

 Next steps:
   1. Commit envi.config.maml so collaborators can decrypt.
      Do NOT add envi.config.maml to .gitignore it must be tracked.
   2. Make sure this repository is private. Anyone with read access
      can decrypt env values captured with this key.
   3. Run `envi capture` to write encrypted env values.

Refusing to overwrite

bash
$ envi create-key
 Repository root: /Users/you/projects/myapp

 ERROR  envi.config.maml already contains an encryption_key. Re-run with --force to replace it.

 WARN   Replacing the key will make any previously captured stores unreadable until re-captured.

Forced rotation

bash
$ envi create-key --force
 Repository root: /Users/you/projects/myapp
 Wrote encryption_key to envi.config.maml

After rotating the key, run envi capture to re-encrypt the store with the new key. Any previously stored data encrypted with the old key cannot be restored.

Security Considerations

Repo visibility matters

Anyone with read access to the source repository can decrypt env values captured with this key, so the repo should be private (and you should trust the access list).

On a public repo this key offers no confidentiality — anyone who can read the repo can read the key. The manifest-derived fallback used by envi pack / envi unpack doesn't fix this either: it's md5(package.json) (or Cargo.toml, etc.), which is also publicly computable. For real shared-blob confidentiality on a public repo, use a custom secret with envi pack and distribute it out of band.

Skipping create-key also means envi capture / envi restore won't encrypt ~/.envi/store/ at rest. That mostly only matters when you also use envi global github enable — see GitHub Integration → Defense in Depth.

Key rotation

The key is 32 bytes of cryptographically random data. There's no built-in incremental rotation — --force generates a brand-new key and any data captured under the old key becomes unreadable. After rotating, re-run envi capture from a checkout that has the original env files.

  • envi capture - Encrypts when envi.config.maml is present
  • envi restore - Decrypts using envi.config.maml
  • envi pack - Prefers envi.config.maml over manifest-derived keys
  • envi unpack - Tries envi.config.maml first when decrypting

See Also

Released under the MIT License.