runx - Environment-Aware Command Proxy Manager
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.
Features
- π§ 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
.env files 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=1 or RUNX_DEBUG=2 for detailed environment file resolution tracing
Existing Tools and Where runx Fits
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 / dotenvx style 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.
Install
Download artifacts from GitHub Releases:
https://github.com/horihiro/runx/releases
Linux (deb package)
curl -LO https://github.com/horihiro/runx/releases/download/v/runx__.deb
sudo apt install ./runx__.deb
runx --version
Uninstall:
sudo apt remove runx
Linux/macOS (tar.gz)
curl -LO https://github.com/horihiro/runx/releases/download/v/runx---v.tar.gz
tar xzf runx---v.tar.gz
sudo install -m 0755 runx /usr/local/bin/runx
runx --version
Uninstall:
sudo rm -f /usr/local/bin/runx
Windows (winget manifest artifact)
You can install runx from the official winget community repository:
winget install --id horihiro.runx
runx --version
Uninstall:
winget uninstall --id horihiro.runx
If 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/runx-winget-manifest-v.zip
mkdir .\temp
tar xzf runx-winget-manifest-v.zip -C .\temp
sudo winget settings --enable LocalManifestFiles
winget install --manifest .\temp
runx --version
Build
You can also build runx from source instead of using release artifacts.
Cross-compilation
# 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.go
Quick Start
1. Create an Environment File
Create a .myenv file in your project directory:
# App/runtime settings
NODE_ENV=development
API_BASE_URL=https://dev-api.example.com
LOG_LEVEL=debug
Or any other name like .env, dev.env, etc.
2. Run Commands with Environment
# 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.js
Commands
runx add - Create Command Proxy
Create 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=.env
What 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 exec with specified environment files
- No PATH modification needed
runx exec - Execute with Environment Directly
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"
runx env - Preview Resolved Environment Variables
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_ALIAS is specified, envfiles registered by runx add are loaded first
- Additional
--envfile values can be combined and are applied after registered envfiles
- Command name/alias is optional
- Prints merged
KEY=VALUE entries 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=.env
runx remove - Remove Command Proxy
Remove a previously created command proxy.
runx remove COMMAND [--shell=bash|zsh|fish]
Examples:
# Windows
runx remove az
# Linux/macOS
runx remove az --shell=bash
runx list - List Command Proxies
List all command proxies created by runx.
runx list [--shell=bash|zsh|fish]
Examples:
# Windows
runx list
# Linux/macOS
runx list --shell=zsh
Environment File Format
Environment 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
Envfile Argument Rules
- 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)
Search Order
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.
Merge Behavior
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.js
If both files define API_URL, the value from /abs/path/override.env is used because /abs/path/override.env is later.
Debug Mode
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 plan
Output 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)
Usage Examples
Terraform with Per-Project Environments
# 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
AWS CLI with Profile Switching
$ cat .awsenv
AWS_PROFILE=production
AWS_REGION=us-east-1
$ runx add aws --envfile=.awsenv
$ aws s3 ls # Uses production profile
Layered Environment Files (Merge)
# 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
Alias Proxy Name
# 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 runx
Shell-Specific Proxies
runx add kubectl --envfile=k8s.env --shell=bash
runx add kubectl --envfile=k8s.env --shell=zsh
runx add kubectl --envfile=k8s.env --shell=fish
One-Off Execution (No Proxy)
$ runx exec --envfile=test.env pytest
$ runx exec --envfile=staging.env curl https://api.example.com
Architecture
See architecture details for Windows/Linux proxy behavior, including User vs Machine proxy selection on Windows:
Troubleshooting
See detailed troubleshooting guide: