runx is an environment-aware command proxy managerβa cross-platform tool that creates command proxies (wrappers) that automatically load environment variables from files before executing commands. Useful for managing cloud profiles, API keys, runtime settings, or any directory-scoped configuration.
- π§ Cross-Platform: Works on Windows, Linux, and macOS
- π¦ Single Binary, No Runtime Required: Just one executable, no separate runtime installation needed
- π Directory-Based Context: Automatically searches for environment files from current directory to root, then home directory
- π Multiple Environment Files: Merge multiple
.envfiles with later values overriding earlier ones - π― Command Proxies: Create persistent command wrappers that automatically load the correct environment
- π Shell Support: Bash, Zsh, Fish on Linux/macOS; CMD on Windows
- π Windows PATH Management: Smart User/Machine PATH detection with automatic privilege escalation when needed
- π Debug Mode: Set
RUNX_DEBUG=1orRUNX_DEBUG=2for detailed environment file resolution tracing
There are already several strong tools in this space, each with a proven workflow.
direnv: A widely trusted option that automatically loads and unloads environment variables when you enter or leave directories via shell hooks. It is excellent for full directory-level automation.dotenv-cli/dotenvxstyle tools: Reliable and practical tools for explicit one-off command execution with env files (for example,dotenv -e .env -- cmd).
Compared to those approaches, runx focuses on a different operating model: persistent command proxies managed with add/list/remove, command-time environment application (instead of always-on directory hooks), consistent cross-platform behavior, and built-in Windows PATH handling.
Download artifacts from GitHub Releases:
https://github.com/horihiro/runx/releases
curl -LO https://github.com/horihiro/runx/releases/download/v<version>/runx_<version>_<arch>.deb
sudo apt install ./runx_<version>_<arch>.deb
runx --versionUninstall:
sudo apt remove runxcurl -LO https://github.com/horihiro/runx/releases/download/v<version>/runx-<os>-<arch>-v<version>.tar.gz
tar xzf runx-<os>-<arch>-v<version>.tar.gz
sudo install -m 0755 runx /usr/local/bin/runx
runx --versionUninstall:
sudo rm -f /usr/local/bin/runxYou can install runx from the official winget community repository:
winget install --id horihiro.runx
runx --versionUninstall:
winget uninstall --id horihiro.runxIf you want to test a release artifact manifest locally before it is published to the official winget repository, use the following flow:
curl -LO https://github.com/horihiro/runx/releases/download/v<version>/runx-winget-manifest-v<version>.zip
mkdir .\temp
tar xzf runx-winget-manifest-v<version>.zip -C .\temp
sudo winget settings --enable LocalManifestFiles
winget install --manifest .\temp
runx --versionYou can also build runx from source instead of using release artifacts.
# From any OS to Windows
GOOS=windows GOARCH=amd64 go build -o runx.exe main.go
# From any OS to Linux
GOOS=linux GOARCH=amd64 go build -o runx main.go
# From any OS to macOS
GOOS=darwin GOARCH=arm64 go build -o runx main.goCreate a .myenv file in your project directory:
# App/runtime settings
NODE_ENV=development
API_BASE_URL=https://dev-api.example.com
LOG_LEVEL=debugOr any other name like .env, dev.env, etc.
# Create a persistent proxy
runx add node --envfile=.myenv
# Now 'node' automatically loads .myenv
node app.js
# Or
# One-time execution
runx exec --envfile=.myenv node app.jsCreate a command proxy that automatically loads specified environment files.
runx add ORIGINAL_COMMAND [--alias=PROXY_NAME] [--envfile=NAME ...] [--shell=bash|zsh|fish]Examples:
# Windows
runx add terraform --envfile=.env
# Linux/macOS (auto-detects shell from $SHELL)
runx add terraform --envfile=.env
# Specify shell explicitly
runx add kubectl --envfile=k8s.env --shell=zsh
# Multiple environment files
runx add node --envfile=base.env --envfile=dev.env
# Alias proxy name (mytf executes original terraform)
runx add terraform --alias=mytf --envfile=.envWhat happens on Windows:
- Checks if original command exists in Machine PATH or User PATH
- If in Machine PATH: Recommends creating a Machine proxy (requires admin privileges)
- If in User PATH or not found: Creates User proxy in
%LOCALAPPDATA%\runx\proxy - Automatically adds proxy directory to User PATH if needed
- Handles PATH priority conflicts intelligently
What happens on Linux/macOS:
- Creates a shell function in your shell config file (
~/.bashrc,~/.zshrc, or~/.config/fish/config.fish) - Function calls
runx execwith specified environment files - No PATH modification needed
runx add-created proxies use runx exec under the hood.
You can also run runx exec directly for one-off execution without creating a proxy.
runx exec [--envfile=NAME ...] COMMAND [ARGS...]Examples:
# One-off execution with a single environment file
runx exec --envfile=.myenv node app.js
# Multiple files (merged in order, later overrides earlier)
runx exec --envfile=base.env --envfile=dev.env node app.js
# No environment files (just pass through)
runx exec echo "Hello"Preview which environment variables are set from resolved env files at the current location.
runx env [COMMAND_OR_ALIAS] [--envfile=NAME ...] [--shell=bash|zsh|fish]Notes:
- If
COMMAND_OR_ALIASis specified, envfiles registered byrunx addare loaded first - Additional
--envfilevalues can be combined and are applied after registered envfiles - Command name/alias is optional
- Prints merged
KEY=VALUEentries resolved from the final envfile list - Prints
(none)if no entries are resolved
Examples:
# Use envfiles registered for command alias `az`
runx env az
# Check merged entries from layered env files
runx env --envfile=base.env --envfile=dev.env
# Combine registered envfiles and ad-hoc overrides
runx env az --envfile=override.env
# Minimal form (current directory tree + home resolution)
runx env --envfile=.envRemove a previously created command proxy.
runx remove COMMAND [--shell=bash|zsh|fish]Examples:
# Windows
runx remove az
# Linux/macOS
runx remove az --shell=bashList all command proxies created by runx.
runx list [--shell=bash|zsh|fish]Examples:
# Windows
runx list
# Linux/macOS
runx list --shell=zshEnvironment files use simple KEY=VALUE format:
# Comments start with #
AWS_PROFILE=staging
AWS_REGION=us-east-1
# Quotes are optional
API_BASE_URL=https://api.example.com
API_KEY="your-api-key-here"
# export prefix is supported (bash compatibility)
export NODE_ENV=production- Supported: file name (
.env,dev.env,myconfig) or absolute path (/home/user/.env,C:\config\app.env) - Not supported: relative paths with separators (
../parent.env,configs/app.env)
When you specify a file name (for example --envfile=.env), runx searches in this order:
- Current directory:
./.env - Parent directories: Searches up to filesystem root
- Home directory:
~/.env
First match wins. This allows project-specific configs to override global defaults.
When you specify an absolute path (for example --envfile=/path/to/app.env), runx checks only that file.
When multiple --envfile options are provided, runx merges variables in the order given.
- Later files override earlier files for the same key.
- Merged values override the current process environment for matching keys.
- File names and absolute paths can be mixed.
Example:
runx exec --envfile=base.env --envfile=/abs/path/override.env node app.jsIf both files define API_URL, the value from /abs/path/override.env is used because /abs/path/override.env is later.
Set RUNX_DEBUG environment variable to see detailed information:
# Level 1: Show resolved envfiles and merged variables
export RUNX_DEBUG=1
runx exec --envfile=.env terraform plan
# Level 2: Also show file search trace
export RUNX_DEBUG=2
runx exec --envfile=.env terraform planOutput example:
[runx][debug] resolved envfiles:
[runx][debug] .env: /home/user/project/.env
[runx][debug] envfile search trace:
[runx][debug] .env:
[runx][debug] - /home/user/project/subdir/.env
[runx][debug] - /home/user/project/.env
[runx][debug] merged environment entries:
[runx][debug] - AWS_PROFILE=staging (from: .env)
[runx][debug] - AWS_REGION=us-east-1 (from: .env)
# Create .env files per project
$ cat ~/project-a/.env
TF_WORKSPACE=project-a
AWS_PROFILE=project-a
$ cat ~/project-b/.env
TF_WORKSPACE=project-b
AWS_PROFILE=project-b
# Create terraform proxy
$ runx add terraform --envfile=.env
# 'terraform' now picks env from the current directory tree
$ cd ~/project-a && terraform plan # Uses project-a env
$ cd ~/project-b && terraform plan # Uses project-b env$ cat .awsenv
AWS_PROFILE=production
AWS_REGION=us-east-1
$ runx add aws --envfile=.awsenv
$ aws s3 ls # Uses production profile# base.env - shared configuration
NODE_ENV=production
LOG_LEVEL=info
API_URL=https://api.example.com
# secrets.env - sensitive overrides
API_KEY=secret-key
DB_PASSWORD=secret-password
# later file wins for duplicate keys
$ runx add node --envfile=base.env --envfile=secrets.env
$ node app.js# Create project-specific proxy name that executes terraform
runx add terraform --alias=mytf --envfile=.env
# Original 'terraform' still works normally
# 'mytf' runs original 'terraform' with environment loaded by runxrunx add kubectl --envfile=k8s.env --shell=bash
runx add kubectl --envfile=k8s.env --shell=zsh
runx add kubectl --envfile=k8s.env --shell=fish$ runx exec --envfile=test.env pytest
$ runx exec --envfile=staging.env curl https://api.example.comSee architecture details for Windows/Linux proxy behavior, including User vs Machine proxy selection on Windows:
See detailed troubleshooting guide: