Multi-Language Support
Envi is language-agnostic and works with projects written in any programming language when installed globally. The tool automatically detects package names from various manifest files to organize your environment configurations.
Supported Languages
Envi automatically detects package names from the following languages and frameworks:
| Language/Framework | Manifest File | Example Package Name |
|---|---|---|
| JavaScript/TypeScript | package.json | @org/app or myapp |
| Rust | Cargo.toml | rust-app |
| Go | go.mod | go-project |
| Python | pyproject.toml | python-package |
| PHP | composer.json | vendor/package |
| Dart/Flutter | pubspec.yaml | flutter_app |
| Kotlin/Android | settings.gradle.kts | kotlin-app |
| Java (Gradle) | settings.gradle | java-app |
| Java (Maven) | pom.xml | maven-app |
How It Works
Detection Order
When you run envi capture, Envi checks for manifest files in your project root in the following order:
package.json(JavaScript/TypeScript)Cargo.toml(Rust)go.mod(Go)pyproject.toml(Python)composer.json(PHP)pubspec.yaml(Dart/Flutter)settings.gradle.kts(Kotlin)settings.gradle(Java/Gradle)pom.xml(Java/Maven)
The first file found is used to extract the package name. If no manifest file is found, Envi uses the folder name as a fallback.
Storage Organization
Configurations are stored in ~/.envi/store/ with filenames based on the detected package name:
- Scoped packages:
~/.envi/store/@org/package.maml - Unscoped packages:
~/.envi/store/package-name.maml - No manifest file:
~/.envi/store/folder-name.maml
Language-Specific Examples
JavaScript/TypeScript
File: package.json
{
"name": "@myorg/frontend",
"version": "1.0.0"
}Detected name: @myorg/frontendStorage path: ~/.envi/store/@myorg/frontend.maml
Rust
File: Cargo.toml
[package]
name = "my-rust-app"
version = "0.1.0"
edition = "2021"Detected name: my-rust-appStorage path: ~/.envi/store/my-rust-app.maml
Go
File: go.mod
module github.com/username/awesome-project
go 1.21Detected name: awesome-project (last segment of module path) Storage path: ~/.envi/store/awesome-project.maml
Python
File: pyproject.toml
[project]
name = "data-processor"
version = "1.0.0"Detected name: data-processorStorage path: ~/.envi/store/data-processor.maml
PHP
File: composer.json
{
"name": "vendor/php-library",
"description": "A PHP library"
}Detected name: vendor/php-libraryStorage path: ~/.envi/store/vendor/php-library.maml
Dart/Flutter
File: pubspec.yaml
name: my_flutter_app
description: A Flutter application
version: 1.0.0Detected name: my_flutter_appStorage path: ~/.envi/store/my_flutter_app.maml
Kotlin/Android
File: settings.gradle.kts
rootProject.name = "android-app"Detected name: android-appStorage path: ~/.envi/store/android-app.maml
Java (Gradle)
File: settings.gradle
rootProject.name = 'spring-boot-api'Detected name: spring-boot-apiStorage path: ~/.envi/store/spring-boot-api.maml
Java (Maven)
File: pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<groupId>com.example</groupId>
<artifactId>spring-service</artifactId>
<version>1.0.0</version>
</project>Detected name: spring-service (uses artifactId) Storage path: ~/.envi/store/spring-service.maml
Configuration
Viewing Current Configuration
Check which manifest files Envi is configured to detect:
# View your config file
cat ~/.envi/config.mamlBuilt-in default manifest files (checked in this order):
package.json- JavaScript/TypeScriptCargo.toml- Rustgo.mod- Gopyproject.toml- Pythoncomposer.json- PHPpubspec.yaml- Dart/Fluttersettings.gradle.kts- Kotlin/Androidsettings.gradle- Java/Gradlepom.xml- Java/Maven
Managing Manifest Files
By default, Envi checks all supported manifest files in priority order. You can customize this list using CLI commands:
List current manifest files:
envi config manifest_files listAdd a custom manifest file:
envi config manifest_files add my-custom-manifest.jsonRemove a manifest file (including defaults):
envi config manifest_files remove pom.xmlExample output:
$ envi config manifest_files list
Manifest files (in priority order):
• package.json
• Cargo.toml
• go.mod
• pyproject.toml
• composer.json
• pubspec.yaml
• settings.gradle.kts
• settings.gradle
• pom.xmlThe configuration is stored in ~/.envi/config.maml:
{
use_version_control: false
manifest_files: [
"package.json"
"Cargo.toml"
"go.mod"
# ... full list of manifest files
]
redacted_variables: ["GITHUB_PAT"]
}Note:
- Custom manifest files need built-in extractors to work for package name detection
- All manifest files (including custom ones) can be used for encryption
- You have full control - you can even remove default files if needed
Encryption Support
All supported manifest files can be used for automatic blob encryption, not just package.json!
How It Works
When you run envi pack or envi unpack, Envi:
- Checks for any supported manifest file in your repository root (in priority order)
- Generates an MD5 hash of the manifest file contents
- Uses that hash as the encryption/decryption key
- No manual secret needed if you have a supported manifest file
Supported Languages for Auto-Encryption
| Language | Manifest File | Status |
|---|---|---|
| JavaScript/TypeScript | package.json | ✅ Fully supported |
| Rust | Cargo.toml | ✅ Fully supported |
| Go | go.mod | ✅ Fully supported |
| Python | pyproject.toml | ✅ Fully supported |
| PHP | composer.json | ✅ Fully supported |
| Dart/Flutter | pubspec.yaml | ✅ Fully supported |
| Kotlin | settings.gradle.kts | ✅ Fully supported |
| Java (Gradle) | settings.gradle | ✅ Fully supported |
| Java (Maven) | pom.xml | ✅ Fully supported |
Example Workflows
Rust Project:
# Team member A creates encrypted blob (has Cargo.toml)
envi pack
# Output: Using Cargo.toml for encryption key
# Blob copied to clipboard
# Team member B decrypts blob (has same Cargo.toml)
envi unpack
# Output: Found Cargo.toml - attempting decryption
# ✔ Decryption successful using Cargo.tomlGo Project:
# Team member creates blob (has go.mod)
envi pack
# Output: Using go.mod for encryption key
# Colleague decrypts (has same go.mod)
envi unpack
# Output: Found go.mod - attempting decryption
# ✔ Decryption successful using go.modPython Project:
# Create blob with pyproject.toml
envi pack
# Output: Using pyproject.toml for encryption key
# Decrypt with same pyproject.toml
envi unpack
# Output: Found pyproject.toml - attempting decryption
# ✔ Decryption successful using pyproject.tomlImportant Notes
- Identical files required: The manifest file must be byte-for-byte identical for decryption to work
- Any change breaks decryption: Even whitespace or formatting changes will cause decryption to fail
- MD5 hash: The entire file contents are hashed with MD5 to create a consistent encryption key
- Fallback to custom secret: If no manifest found or decryption fails, you'll be prompted for a custom secret
- Custom manifest files: You can add your own manifest files using
envi config manifest_files add <filename>(see Managing Manifest Files above). All manifest files can be used for encryption.
Security Implications
The same security considerations apply to all manifest-based encryption:
⚠️ WARNING: Blobs encrypted with manifest files are only secure while your codebase remains private. Anyone with access to your repository can decrypt your blobs.
For production secrets: Use a custom secret instead of manifest-based encryption. See Pack for details.
Programmatic Usage
Using the API
import {
getPackageName,
DEFAULT_MANIFEST_FILES,
PACKAGE_EXTRACTORS,
} from "@codecompose/envi";
// Get package name from a repository
const packageName = getPackageName("/path/to/rust/project");
console.log(packageName); // "my-rust-app"
// Check default manifest files
console.log(DEFAULT_MANIFEST_FILES);
// ["package.json", "Cargo.toml", "go.mod", ...]
// Access extractors directly
for (const extractor of PACKAGE_EXTRACTORS) {
const name = extractor.extract("/path/to/project");
if (name) {
console.log(`Found ${name} from ${extractor.filename}`);
break;
}
}Custom Extractor
import type { PackageExtractor } from "@codecompose/envi";
const customExtractor: PackageExtractor = {
filename: "my-manifest.json",
extract: (repoPath) => {
// Your custom extraction logic
return "custom-package-name";
},
};Troubleshooting
Package Name Not Detected
Problem: Envi uses folder name instead of package name from manifest file.
Solution:
Verify manifest file exists in project root:
bashls -la package.json Cargo.toml go.modCheck if file is valid:
bash# For JSON files cat package.json | jq . # For TOML files cat Cargo.tomlVerify the package name field exists:
package.json:namefieldCargo.toml:[package]section withnamego.mod: First line starting withmodulepyproject.toml:[project]section withname
Wrong Language Detected
Problem: Envi detects the wrong manifest file because your project has multiple manifest files.
Solution: The default detection order prioritizes package.json first, then Cargo.toml, go.mod, etc. If you need different behavior, you have a few options:
- Accept the default - The first detected manifest file will be used
- Rename manifest files - Temporarily remove or rename unwanted manifest files during capture
- Use folder name - If no manifest file is found, Envi uses the folder name as the storage key
Note: You can fully customize the manifest file list using envi config manifest_files commands. Add custom files, remove defaults, or reorder as needed.
Monorepo with Multiple Languages
Problem: Monorepo root has manifest files for multiple languages.
Solution:
- Option A: Use the most important language first in config
- Option B: Remove manifest files from root, keep them in subdirectories
- Option C: Accept folder name as storage key (simplest)
Example: TypeScript monorepo with Rust packages:
monorepo/
├── package.json # Root package.json for workspace
├── packages/
│ ├── frontend/
│ │ ├── .env
│ │ └── package.json
│ └── backend/
│ ├── .env
│ └── Cargo.tomlRunning envi capture from root will use the root package.json name for storage. Individual packages can be captured separately by running envi capture from their directories.
Best Practices
Global Installation
For multi-language support, install Envi globally:
pnpm add -g @codecompose/enviThis allows you to use envi in projects written in any language, not just JavaScript/TypeScript projects.
Configuration Recommendations
- Use defaults - The built-in manifest files cover all supported languages
- Add custom files - Only add custom manifest files using
envi config manifest_files addif you have non-standard files - Prioritize custom files - Additional files are checked before defaults, so you can prioritize specific patterns
- Use GitHub integration - Sync your custom configuration across machines
Storage Organization
- Scoped packages (e.g.,
@org/name) automatically create subdirectories - Package names with
/(e.g., PHP'svendor/package) create subdirectories - Simple names create files directly in
~/.envi/store/
Related
- Getting Started - Installation and basic usage
- Commands - Detailed command documentation
- File Format - How Envi stores configurations
- API Reference - Programmatic usage