Run any command with your secrets. No leaks. No drama.
with exec -- curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/modelsYour API keys stay encrypted, never touch your shell history, and vanish after the command runs.
- 🔐 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
- 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
go install github.com/Grovy-3170/cli-with/cmd/with@latestNote: This installs to
$(go env GOPATH)/bin. Add it to your PATH:# Add to ~/.zshrc or ~/.bashrc export PATH="$PATH:$(go env GOPATH)/bin"Then run
source ~/.zshrcor restart your terminal.
git clone https://github.com/Grovy-3170/cli-with.git
cd cli-with
make buildThe binary will be created at ./with. Install it system-wide with:
make installDownload pre-built binaries from the Releases page.
# 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# If installed via go install
rm $(go env GOPATH)/bin/with
# If built from source
make uninstallInteractive mode (prompts for username):
with initExplicit username:
with init --user aliceYou'll be prompted to create a master password. This password encrypts all your API keys.
with set --user alice OPENAI_API_KEYor
with set OPENAI_API_KEYYou'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"with listor
with list --user aliceThis shows the names of all stored keys (not their values).
with exec -- curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/modelsWith explicit user:
with exec --user alice -- curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/modelsThe $OPENAI_API_KEY environment variable is available inside the command, but never exposed to your shell history or parent process.
with get --user alice OPENAI_API_KEYRemove a specific key:
with remove --user alice OLD_API_KEYRemove entire vault:
with remove --user alice| Flag | Description |
|---|---|
--user string |
Username for the vault (prompts interactively if not provided) |
--password string |
Vault password (use for scripting; takes precedence over --password-file) |
--password-file string |
Path to file containing the vault password |
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.
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.
Retrieve the value of a specific key.
with get --user <username> <KEY_NAME>List all key names stored in the vault.
with list --user <username>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'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>Print the version number.
with versionFor CI/CD or automation, avoid interactive prompts using either --password or --password-file.
Inline password (simplest):
with --user alice --password "my-secure-password" listPassword file (preferred for shared environments):
# 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--password takes precedence over --password-file if both are provided.
Warning: Password files should have strict permissions (0600) and be deleted after use. Prefer --password-file over --password when the password may appear in process listings.
Set the WITH_VAULT_DIR environment variable to change where vaults are stored:
export WITH_VAULT_DIR=/secure/vault-location
with init --user alice- 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
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/*.vaultWhen 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
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_KEYOn 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
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 XRun with init --user X first to create the vault.
During with init, the password and confirmation must match exactly. Try again.
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 aliceOn 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 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
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/usersWhen using with exec, the command must be in PATH. Use the full path if needed:
with exec --user alice -- /usr/bin/curl https://example.comWhen 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'- 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
git clone https://github.com/Grovy-3170/cli-with.git
cd cli-with
go mod download
make testMIT License - see LICENSE file for details.