Skip to content

Commands

Overview

Terminal window
hush <command> [options]

Hush keeps secrets encrypted at rest. The primary way to use secrets is hush run -- <command>, which decrypts to memory and injects environment variables—secrets never touch the disk.

Command Categories

CategoryCommandsDescription
Primary (AI-Safe)run, set, edit, inspect, hasSafe for AI assistants—never expose secret values
Setupinit, encrypt, status, skillConfiguration and encryption
Deploymentpush, checkCI/CD and cloud deployment
Debuggingresolve, traceDebug secret filtering and routing

Global Options

OptionDescription
-e, --env <env>Environment: development or production (default: development)
-r, --root <dir>Root directory (default: current directory)
-h, --helpShow help message
-v, --versionShow version number

run

Run a command with secrets injected as environment variables. This is the primary way to use secrets. Secrets are decrypted to memory only—they never touch the disk.

Terminal window
# Run with development secrets (default)
hush run -- npm start
# Run with production secrets
hush run -e production -- npm build
hush run -e prod -- npm build
# Run with secrets filtered for a specific target
hush run -t api -- wrangler dev
hush run --target web -- npm start

Options

OptionDescription
-e, --env <env>Environment: development or production
-t, --target <name>Filter secrets for a specific target from hush.yaml
-- <command>The command to run (everything after --)

How It Works

  1. Decrypts secrets to memory (never written to disk)
  2. Merges shared → environment → local secrets
  3. Resolves subdirectory templates (if present)
  4. Filters root secrets based on target config (if matched)
  5. Merges template vars + filtered root secrets (additive)
  6. Spawns the child process with secrets as environment variables
  7. Inherits stdin/stdout/stderr for full interactivity

Examples

Terminal window
# Local development
hush run -- npm run dev
# Production build
hush run -e prod -- npm run build
# Wrangler with API secrets only
hush run -t api -- wrangler dev
# Docker with secrets
hush run -- docker compose up
# Any command that needs secrets
hush run -- node scripts/migrate.js

set

Set a secret. Supports inline values, interactive prompts, or piped input.

Terminal window
# Inline value (recommended for AI agents)
hush set DATABASE_URL "postgres://user:pass@host/db"
hush set STRIPE_KEY "sk_live_xxx" -e production
# Interactive prompt (for users)
hush set DATABASE_URL
hush set API_KEY -e production
# Set in local overrides (.hush.local.encrypted)
hush set MY_OVERRIDE --local
# Piped input (for scripts/automation)
echo "my-secret" | hush set MY_KEY
cat cert.pem | hush set CERTIFICATE

Options

OptionDescription
-e, --env <env>Target environment file (default: shared .hush.encrypted)
--localSet in .hush.local.encrypted (personal overrides, not committed)
--guiUse GUI dialog for input (shows value for verification)

Input Methods (Priority Order)

  1. Inline value: hush set KEY "value" - value provided directly
  2. Piped input: echo "value" | hush set KEY - reads from stdin
  3. GUI dialog: Opens when --gui flag used or no TTY available
  4. Interactive prompt: Terminal prompt with visible input

How It Works

  1. Gets value from inline arg, pipe, GUI, or prompt
  2. Decrypts the target file
  3. Sets or updates the key
  4. Re-encrypts the file
  5. Confirms success with character count (no value shown)

Example Output

$ hush set DATABASE_URL "postgres://localhost/mydb"
✓ DATABASE_URL set in .hush.encrypted (25 chars)
$ hush set API_KEY
Enter value for API_KEY: sk_test_xxx
✓ API_KEY set in .hush.encrypted (14 chars)

edit

Edit secrets in your $EDITOR. Opens the decrypted file, and re-encrypts on save.

Terminal window
# Edit shared secrets
hush edit
# Edit environment-specific secrets
hush edit development
hush edit production
hush edit dev
hush edit prod
# Edit local overrides
hush edit local

How It Works

  1. Decrypts the target file to a temporary location
  2. Opens in $EDITOR (vim, nano, code —wait, etc.)
  3. Re-encrypts when you save and close
  4. Deletes the temporary file

init

Generate a hush.yaml configuration file with auto-detected targets.

Terminal window
hush init

This command scans your monorepo for packages with package.json files and creates an initial configuration.

Example Output

# hush.yaml (generated)
sources:
shared: .hush
development: .hush.development
production: .hush.production
targets:
- name: root
path: .
format: dotenv
- name: app
path: ./packages/app
format: dotenv
- name: api
path: ./packages/api
format: wrangler

encrypt

Encrypt source .hush files to .hush.encrypted files.

Terminal window
hush encrypt

What Gets Encrypted

Based on your hush.yaml sources configuration:

  • .hush.hush.encrypted
  • .hush.development.hush.development.encrypted
  • .hush.production.hush.production.encrypted

After encryption, the plaintext .hush files are automatically deleted.


inspect

List all variables with masked values. Safe for AI agents.

Terminal window
hush inspect
hush inspect -e production

Example Output

Secrets for development:
DATABASE_URL = post****************... (45 chars)
STRIPE_SECRET_KEY = sk_t****************... (32 chars)
API_KEY = (not set)
Total: 3 variables
Target distribution:
root (.) - 3 vars
app (./app/) - 1 vars
include: EXPO_PUBLIC_*
api (./api/) - 2 vars
exclude: EXPO_PUBLIC_*

This lets AI agents reason about your configuration without seeing actual secrets.


has

Check if a specific secret exists. Returns exit code 0 if set, 1 if not.

Terminal window
# Check if a variable is set
hush has DATABASE_URL
# Quiet mode (no output, just exit code)
hush has API_KEY -q
# Use in scripts
hush has DATABASE_URL -q && echo "DB configured"

Options

OptionDescription
-q, --quietSuppress output, only return exit code

Example Output

DATABASE_URL is set (45 chars)

Or if not set:

DATABASE_URL not found

push

Push production secrets to Cloudflare (Workers and Pages).

Terminal window
# Push all configured targets
hush push
# Push a specific target
hush push -t api
hush push -t app
# Preview without pushing
hush push --dry-run
# Detailed preview showing each variable
hush push --dry-run --verbose
hush push -t app --dry-run --verbose

Options

OptionDescription
-t, --target <name>Push only the specified target
--dry-runPreview what would be pushed without making changes
--verboseShow detailed output (with --dry-run)

Supported Destinations

Target TypeConfigurationWrangler Command
Cloudflare Workersformat: wranglerwrangler secret put
Cloudflare Pagespush_to: { type: cloudflare-pages, project: ... }wrangler pages secret bulk

Configuration Examples

Cloudflare Workers (automatic with format: wrangler):

targets:
- name: api
path: ./api
format: wrangler

Cloudflare Pages (requires push_to):

targets:
- name: app
path: ./app
format: dotenv
include:
- NEXT_PUBLIC_*
push_to:
type: cloudflare-pages
project: my-pages-project # Your Pages project name

How It Works

  1. Decrypts production secrets from encrypted files
  2. Resolves subdirectory templates (if present)
  3. Filters variables per target using include/exclude patterns
  4. For Workers: Uploads each secret using wrangler secret put
  5. For Pages: Uploads all secrets at once using wrangler pages secret bulk

status

Show configuration and file status. This is the first command to run when troubleshooting.

Terminal window
hush status

Example Output

Hush Status
Config:
hush.yaml
Project: myorg/myrepo
Prerequisites:
SOPS installed
age key configured
Key Status:
Local key: ~/.config/sops/age/keys/myorg-myrepo.txt
1Password backup: synced
Source Files:
.hush.encrypted
.hush.development.encrypted
.hush.production.encrypted
.hush.local (optional, not found)
Targets:
root ./ dotenv -> .env.development
app ./packages/app dotenv -> .env.development
api ./packages/api wrangler -> .dev.vars

Troubleshooting with Status

You SeeMeaningFix
SOPS not installedMissing prerequisitebrew install sops
age not installedMissing prerequisitebrew install age
age key not foundNo local keynpx hush keys setup
age key configured but commands faildirenv not loadeddirenv allow
1Password backup: not foundKey not in 1Passwordnpx hush keys push

check

Verify encrypted files are in sync with source files. Useful for pre-commit hooks.

Terminal window
# Basic check
hush check
# Warn but don't fail
hush check --warn
# JSON output for CI
hush check --json
# Only check git-modified files
hush check --only-changed

Options

OptionDescription
--warnWarn on drift but exit 0
--jsonOutput machine-readable JSON
--quietSuppress output
--only-changedOnly check files modified in git
--require-sourceFail if source file is missing

Exit Codes

CodeMeaning
0All in sync
1Drift detected (run hush encrypt)
2Config error
3Runtime error (sops missing, decrypt failed)

Pre-commit Hook

.husky/pre-commit
npx hush check || exit 1

Bypass with: HUSH_SKIP_CHECK=1 git commit -m "message"


resolve

Show what variables a specific target will receive, with filtering details. Essential for debugging why a variable is missing from a target.

Terminal window
# Check what variables api-workers receives
hush resolve api-workers
# Check with production environment
hush resolve api-workers -e production

Options

OptionDescription
-e, --env <env>Environment: development or production

Example Output

Target: api-workers
Path: ./api/
Format: wrangler (.dev.vars)
Environment: development
✅ ROOT SECRETS (Matched Filters) (11):
SUPABASE_URL (source: .env.development)
STRIPE_SECRET_KEY (source: .env)
R2_ACCESS_KEY_ID (source: .env)
...
🚫 EXCLUDED VARIABLES (8):
EXPO_PUBLIC_API_URL (matches: EXPO_PUBLIC_*)
FASTLANE_APPLE_ID (matches: FASTLANE_*)
ASC_KEY_ID (matches: ASC_*)
...
📄 TEMPLATE EXPANSIONS (api/.hush):
DATABASE_URL ← ${DATABASE_URL}
PORT ← ${PORT:-8787}
📦 FINAL INJECTION (13 total):
DATABASE_URL (template overrides root)
PORT (template)
SUPABASE_URL (root)
...

trace

Trace a specific variable through all sources and targets. Use this to understand why a variable appears in some places but not others.

Terminal window
# Trace a variable
hush trace DATABASE_URL
# Trace with production environment
hush trace STRIPE_SECRET_KEY -e production

Options

OptionDescription
-e, --env <env>Environment: development or production

Example Output

Tracing variable: SUPABASE_URL
Source Status:
.env : ❌ Not found
.env.development : ✅ Present
.env.production : ✅ Present
.env.local : (file not found)
Target Disposition (Environment: development):
[root] : ✅ Included
[app] : 🚫 Not included (not in include: EXPO_PUBLIC_*)
[api] : ✅ Included
[api-workers] : ✅ Included
[landing] : 🚫 Not included (not in include: EXPO_PUBLIC_SUPABASE_*)

skill

Install the Claude Code / OpenCode skill for AI-safe secrets management.

Terminal window
# Interactive: choose global or local
hush skill
# Install globally (all projects)
hush skill --global
# Install locally (this project only)
hush skill --local

Options

OptionDescription
--globalInstall to ~/.claude/skills/
--localInstall to ./.claude/skills/

Global vs Local

  • Global - Works across all your projects. Recommended for personal use.
  • Local - Bundled with the project. Recommended for teams (commit .claude/ to git).

decrypt —force (Last Resort)

Write decrypted secrets to disk as plaintext files. Requires --force flag and interactive confirmation.

Terminal window
hush decrypt --force
hush decrypt --force -e production

Why This Exists

Some edge cases genuinely require plaintext files on disk:

  • Docker builds that can’t use hush run
  • Legacy tooling that reads .env files directly
  • CI systems without TTY support for hush run

Safety Features

  1. Requires --force flag - Won’t run without explicit opt-in
  2. Interactive confirmation - Must type “yes” to proceed
  3. Blocks non-TTY - Cannot be run by AI agents or in scripts

How It Works

  1. Decrypts encrypted source files
  2. Merges shared → environment → local overrides
  3. Interpolates variable references (${VAR})
  4. Filters variables per target using include/exclude patterns
  5. Writes plaintext files to each target path

list (Caution)

List all variables with their actual values.

Terminal window
hush list
hush list -e production

Troubleshooting

”no identity matched any of the recipients”

This error means SOPS cannot find your decryption key.

Most common cause: direnv not loaded.

Hush uses per-project keys at ~/.config/sops/age/keys/{project}.txt. SOPS needs the SOPS_AGE_KEY_FILE environment variable to locate them.

Terminal window
# 1. Verify direnv is installed and hooked
brew install direnv
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc # or bash
source ~/.zshrc
# 2. Allow direnv in the project
cd /path/to/project
direnv allow
# 3. Verify the env var is set
echo $SOPS_AGE_KEY_FILE
# Should output: /Users/you/.config/sops/age/keys/project-name.txt
# 4. Test
hush status
hush inspect

”age key not found”

The key file doesn’t exist at the expected location.

Terminal window
# Check where hush expects the key
hush status # Look at "Local key:" line
# Option 1: Pull from 1Password
hush keys setup
# Option 2: Get from team member and save manually
# Save to the path shown in hush status

Key exists but wrong project

If you have a key but it’s for a different project:

Terminal window
# List all local keys
hush keys list
# Pull the correct key
hush keys setup

“SOPS is not installed”

Terminal window
brew install sops age # macOS
# See Getting Started for Linux/Windows

direnv not loading automatically

Make sure you’ve added the direnv hook to your shell:

Terminal window
# For zsh (~/.zshrc)
eval "$(direnv hook zsh)"
# For bash (~/.bashrc)
eval "$(direnv hook bash)"

Then reload your shell or open a new terminal.