envi unpack
Decrypt and restore environment configuration from an encrypted blob shared by a team member.
Usage
# Reads from clipboard automatically
envi unpack
# Or provide blob as argument
envi unpack <blob>Arguments
<blob> (optional)
The encrypted blob to unpack. If not provided, the blob is automatically read from your clipboard.
The parser is resilient to formatting issues - whitespace, newlines, and indentation are automatically handled. This means the blob will work even if it's been:
- Reformatted by chat applications (Slack, Teams, Discord)
- Copy-pasted with extra spacing
- Modified with different line endings (Windows/Unix)
You can pass the blob as:
- No argument (reads from clipboard):
envi unpack - A single argument:
envi unpack "$(cat blob.txt)" - Multi-line with any formatting
Description
The unpack command decrypts an encrypted blob (from clipboard or argument) and:
- First prompts to restore the environment files directly to your repository
- Then optionally prompts to save to your global storage (
~/.envi/store/)
Note: Unpack works completely independently of capture and storage. It decrypts the blob and restores files directly to your repository - no need to use global storage at all! Saving to storage is optional and only useful if you want to use
envi restorelater.
Clipboard Feature
When no blob argument is provided, unpack automatically reads from your clipboard:
- Copy a blob shared by a team member (from Slack, email, etc.)
- Run
envi unpack(no arguments!) - The blob is automatically read from clipboard and decrypted
This makes sharing incredibly seamless - your team member runs envi pack, you copy the blob they paste, and run envi unpack.
Decryption Methods
unpack tries decryption keys in this order:
envi.config.mamlwithencryption_key(preferred) - Ifenvi.config.mamlis committed in the repo, this is the first thing tried.- Manifest-derived key - For each configured manifest file (
package.json,Cargo.toml,go.mod,pyproject.toml,composer.json,pubspec.yaml,pom.xml,settings.gradle.kts,settings.gradle),unpackderives an MD5-hash key and tries it. Custom manifests can be added viaenvi config manifest_files add <filename>- see Multi-Language Support. - Custom secret prompt - If none of the above succeed, you'll be prompted to enter a secret. This is the path used for blobs encrypted with a custom secret on the sender's side.
The recipient typically doesn't need to think about this — if the sender used envi pack from a checkout with envi.config.maml, every collaborator with the same checkout decrypts automatically. If they used a manifest-derived key, anyone in the same codebase decrypts automatically. If they used a custom secret, the sender shares it via a separate secure channel.
Examples
Projects with envi.config.maml
When the sender used envi create-key and committed envi.config.maml, decryption is automatic:
envi unpackOutput:
✔ Reading blob from clipboard...
✔ Blob loaded from clipboard
✔ Parsing blob...
Blob format validated
✔ Finding repository root...
Repository root: /Users/you/projects/myapp
ℹ Found encryption_key in envi.config.maml - attempting decryption
✔ Decrypting configuration...
✔ Decryption successful using envi.config.mamlProjects with Manifest Files (from clipboard)
If the sender packed without envi.config.maml, manifest-derived decryption is the next fallback (works with JavaScript/TypeScript, Rust, Go, Python, PHP, etc.):
envi unpackInteractive flow:
✔ Reading blob from clipboard...
✔ Blob loaded from clipboard
✔ Parsing blob...
Blob format validated
✔ Finding repository root...
Repository root: /Users/you/projects/myapp
Found package.json - attempting decryption
✔ Decrypting configuration...
✔ Decryption successful using package.json
✔ Validating configuration...
Found 3 file(s) in blob
? Restore environment files to this repository? › (Y/n)
✔ Restore complete!
Restored 3 file(s):
✓ .env
✓ .env.local
✓ apps/api/.env
? Save these environment files to global storage? › (y/N)
✔ Unpack complete!Note: The output will mention the specific manifest file found (package.json, Cargo.toml, go.mod, etc.). The decryption key is derived from that file's contents.
Projects with Manifest Files (with blob argument)
You can also provide the blob as an argument:
envi unpack "__envi_start__
A7s9+kF3...
__envi_end__"The flow is the same, but skips reading from clipboard.
Projects without Supported Manifest Files (from clipboard)
For projects without a supported manifest file, copy the blob and run:
envi unpackInteractive flow:
✔ Reading blob from clipboard...
✔ Blob loaded from clipboard
✔ Parsing blob...
Blob format validated
✔ Finding repository root...
Repository root: /Users/you/projects/myapp
No supported manifest file found - this is expected for some project types
? Enter the decryption secret: ********
✔ Decrypting configuration...
✔ Decryption successful
✔ Validating configuration...
Found 3 file(s) in blob
? Restore environment files to this repository? › (Y/n)
✔ Restore complete!
Restored 3 file(s):
✓ .env
✓ .env.test
✓ config/.env.local
? Save these environment files to global storage? › (y/N)
✔ Unpack complete!Declining Prompts
You can decline any of the interactive prompts:
- Decline restoring: The files won't be written to your repository (you can still save to storage if you want)
- Decline saving to storage: The files are restored to your repository but not saved to
~/.envi/store/(most common - storage is optional!)
How It Works
- Reads blob - From clipboard if no argument provided, or from the argument
- Validates blob format - Strips whitespace and checks for
__envi_start__and__envi_end__delimiters - Finds project root - Locates your project root (looks for version control markers:
.git,.jj,.hg,.svn, or prompts for confirmation) - Attempts decryption in priority order:
- If
envi.config.mamlexists withencryption_key, try it first - Otherwise (or if that fails) walk through configured manifest files (package.json, Cargo.toml, go.mod, pyproject.toml, composer.json, pubspec.yaml, pom.xml, settings.gradle.kts, settings.gradle), deriving an MD5 key from each
- Otherwise prompt for a custom secret
- If
- Decrypts data - Uses AES-256-GCM decryption with the derived key
- Validates configuration - Ensures decrypted data is valid envi format
- Prompts to restore - Asks if you want to write environment files to repository (with overwrite confirmation for existing files)
- Optionally saves to storage - Asks if you also want to save to
~/.envi/store/(defaults to No)
Error Handling
Invalid Blob Format
If the blob format is invalid:
✗ Invalid blob format
Expected format:
__envi_start__
[encrypted data]
__envi_end__Solution: Ensure you copied the entire blob including both __envi_start__ and __envi_end__ markers with the encrypted data between them.
Note: The parser automatically handles whitespace, newlines, and formatting issues from chat applications, so the exact formatting doesn't matter. As long as both markers and the encrypted data are present, it should work.
Decryption Failed
If automatic decryption fails, you'll be prompted for a secret:
Found package.json - attempting decryption
⚠ Failed to decrypt with manifest file
This blob may have been encrypted with a custom secret
? Enter the decryption secret: ________If the provided secret is also incorrect:
✗ Failed to decrypt blob with provided secret
This could mean:
- The secret is incorrect
- The blob is corrupted
- The blob was encrypted with a different manifest fileSolutions:
- Ask the sender which secret they used
- Verify you have the correct blob (not corrupted during copy-paste)
- For manifest-encrypted blobs, ensure you have the same manifest file as the sender (package.json, Cargo.toml, etc.)
No Supported Manifest File Found
No supported manifest file found - this is expected for some project types
? Enter the decryption secret: ________Solution: Enter the secret that was used when creating the blob. The sender should have shared this with you.
Security Considerations
⚠️ Important: Blob Security
Before accepting and unpacking a blob, understand the security implications:
If Encrypted with Manifest File (Automatic Encryption)
- The blob can be decrypted by anyone with access to the codebase
- If the codebase ever becomes public or is compromised, the blob can be decrypted
- Only unpack blobs from trusted sources and shared through secure channels
- Applies to: JavaScript/TypeScript (package.json), Rust (Cargo.toml), Go (go.mod), Python (pyproject.toml), PHP (composer.json), Dart (pubspec.yaml), Java (pom.xml, settings.gradle), and all other manifest-based encryption
If Encrypted with Custom Secret
- The blob is secure as long as the secret remains private
- Ensure the secret was shared through a secure, separate channel (not the same place as the blob)
- Use strong secrets for sensitive data
General Security
- Verify the source - Only unpack blobs from team members you trust
- Check what you're restoring - Review which files will be overwritten before confirming
- Audit blob contents - After unpacking, review the restored
.envfiles to ensure they contain expected values - Don't blindly accept - If a blob appears in an untrusted channel, don't unpack it
See the Sharing Environment Configurations guide for comprehensive security information.
Related Commands
envi pack- Create an encrypted blob for sharingenvi create-key- Generateenvi.config.mamlso pack/unpack share a stable keyenvi restore- Restore files from storageenvi capture- Capture files to storage
See Also
- Sharing Environment Configurations - Complete guide to sharing configs