README
ΒΆ
with
Run any command with your secrets. No leaks. No drama.
with exec -- curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/models
Your API keys stay encrypted, never touch your shell history, and vanish after the command runs.
Why?
- π Your secrets, your vault β encrypted locally with a master password
- π Zero config exports β no more
export API_KEY=...in your bashrc - π₯ Shared server friendly β each user gets their own isolated vault
- π§Ή Clean environment β secrets exist only in the subprocess, nowhere else
Features
- Encryption: Argon2id + AES-256-GCM (industry standard)
- Per-user vaults: Perfect for shared machines β your keys, your vault
- Minimal env inheritance: Only essential vars (PATH, HOME, etc.) pass through
- Cross-platform: Linux, macOS, Windows
Installation
Go Install
go install github.com/Grovy-3170/cli-with/cmd/with@latest
This installs the with binary to $GOPATH/bin. Make sure your Go bin directory is in your PATH.
Build from Source
git clone https://github.com/Grovy-3170/cli-with.git
cd cli-with
make build
The binary will be created at ./with. Install it system-wide with:
make install
Binary Releases
Download pre-built binaries from the Releases page.
Updating
To update to the latest version:
# If installed via go install
go install github.com/Grovy-3170/cli-with/cmd/with@latest
# If built from source
git pull
make build
make install
Quick Start
1. Initialize Your Vault
Interactive mode (prompts for username):
with init
Explicit username:
with init --user alice
You'll be prompted to create a master password. This password encrypts all your API keys.
2. Store an API Key
with set --user alice OPENAI_API_KEY
or
with set OPENAI_API_KEY
You'll be prompted to enter the key value securely (hidden input).
Alternatively, provide the value directly:
with set --user alice ANTHROPIC_API_KEY --value "your-api-key-here"
3. List Your Keys
with list
or
with list --user alice
This shows the names of all stored keys (not their values).
4. Use Keys in Commands
with exec -- curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/models
With explicit user:
with exec --user alice -- curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/models
The $OPENAI_API_KEY environment variable is available inside the command, but never exposed to your shell history or parent process.
5. Get a Key Value
with get --user alice OPENAI_API_KEY
6. Remove a Key or Vault
Remove a specific key:
with remove --user alice OLD_API_KEY
Remove entire vault:
with remove --user alice
Usage
Global Flags
| Flag | Description |
|---|---|
--user string |
Username for the vault (prompts interactively if not provided) |
--password-file string |
Path to file containing the vault password |
Commands
with init
Initialize a new user vault.
with init # Interactive - prompts for username
with init --user <username>
Creates an encrypted vault file at ~/.config/cli-with/users/<username>.vault.
with set
Add or update an API key.
with set --user <username> <KEY_NAME>
with set --user <username> <KEY_NAME> --value "secret-value"
Key names must start with a letter or underscore, followed by letters, digits, or underscores.
with get
Retrieve the value of a specific key.
with get --user <username> <KEY_NAME>
with list
List all key names stored in the vault.
with list --user <username>
with exec
Execute a command with all keys available as environment variables.
with exec -- <command> [args...]
with exec --user <username> -- <command> [args...]
The -- separator is required to distinguish command arguments from flags.
Examples:
# Run a script with your secrets
with exec -- python my_script.py
# With explicit user
with exec --user alice -- python my_script.py
# Use with curl
with exec -- curl -H "X-API-Key: $MY_API_KEY" https://api.example.com
# Chain commands
with exec -- sh -c 'echo $OPENAI_API_KEY | wc -c'
with remove
Remove a specific key or the entire vault.
# Remove a specific key
with remove --user <username> <KEY_NAME>
# Remove entire vault (prompts for confirmation)
with remove --user <username>
with version
Print the version number.
with version
Automation with Password Files
For CI/CD or automation, use --password-file to avoid interactive prompts:
# Store password securely in a temp file (restricted permissions)
echo "my-secure-password" > /tmp/vault-password
chmod 600 /tmp/vault-password
# Use in commands
with --user alice --password-file /tmp/vault-password list
# Clean up
rm /tmp/vault-password
Warning: Password files should have strict permissions (0600) and be deleted after use.
Custom Vault Location
Set the WITH_VAULT_DIR environment variable to change where vaults are stored:
export WITH_VAULT_DIR=/secure/vault-location
with init --user alice
Security Considerations
Password Best Practices
- Use strong master passwords: At least 12 characters with mixed case, numbers, and symbols
- Never share master passwords: Each user should have their own vault
- Avoid password files in production: Use only in secure, automated environments with proper access controls
- Consider a password manager: Store your master password in a password manager like 1Password or Bitwarden
File Permissions
The vault directory (~/.config/cli-with/users/) is created with 0700 permissions. Vault files have 0600 permissions. Verify these permissions:
ls -la ~/.config/cli-with/users/
If permissions are incorrect, fix them:
chmod 700 ~/.config/cli-with/users/
chmod 600 ~/.config/cli-with/users/*.vault
Environment Isolation
When using with exec or with <command>:
- Keys are injected only into the subprocess environment
- The parent shell never sees the key values
- Keys don't appear in shell history
- Only minimal environment variables (
PATH,HOME,USER,SHELL,TMPDIR) are inherited
This prevents accidental key exposure through:
- Shell history logging
- Process listing (
ps eww) - Environment dumps
- Debug output
Key Rotation
Regularly rotate your API keys:
# Update a key
with set --user alice EXISTING_KEY --value "new-secret-value"
# Remove old keys you no longer need
with remove --user alice DEPRECATED_KEY
Shared Server Considerations
On shared servers:
- Each user has a separate vault file
- File permissions prevent users from reading each other's vaults
- The master password is required to decrypt any vault
- Consider using OS keychain integration for additional security
Troubleshooting
"vault for user 'X' already exists"
You're trying to initialize a vault that already exists. Either use a different username or remove the existing vault:
with remove --user X
with init --user X
"vault for user 'X' does not exist"
Run with init --user X first to create the vault.
"passwords do not match"
During with init, the password and confirmation must match exactly. Try again.
"incorrect password" or "decrypting vault: ..."
The master password you entered is incorrect. Try again carefully. If you've forgotten your password, there's no recovery option. You must delete the vault and reinitialize:
with remove --user alice
with init --user alice
"keyring unavailable"
On Linux, the OS keychain requires a running secret service (like GNOME Keyring or KDE Wallet). If unavailable, the vault falls back to file-based encrypted storage.
Key names with special characters
Key names must follow these rules:
- Start with a letter (a-z, A-Z) or underscore (_)
- Followed by letters, digits (0-9), or underscores
Valid: API_KEY, _secret, openai2
Invalid: 2FAST, my-key, api.key
Permission denied errors
Ensure you have write access to the vault directory:
# Check directory permissions
ls -la ~/.config/cli-with/
# Fix if needed
chmod 700 ~/.config/cli-with
chmod 700 ~/.config/cli-with/users
Command not found in exec
When using with exec, the command must be in PATH. Use the full path if needed:
with exec --user alice -- /usr/bin/curl https://example.com
Environment variables not expanded in shell
When using shell variables in commands, wrap with sh -c:
# This won't work - $VAR is expanded by parent shell
with exec --user alice -- echo $MY_KEY
# This works - variable is expanded in subprocess
with exec --user alice -- sh -c 'echo $MY_KEY'
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Make your changes
- Run tests (
make test) - Run linters (
make lint) - Commit your changes
- Push to the branch
- Open a Pull Request
Development Setup
git clone https://github.com/Grovy-3170/cli-with.git
cd cli-with
go mod download
make test
License
MIT License - see LICENSE file for details.