This document covers two core parts of the runx architecture:
- how command proxies are implemented and executed across platforms
- how env files are discovered and merged when one or more
--envfileoptions are used
runx implements command proxies differently depending on the platform. On Linux/macOS, proxies use shell functions for transparency and simplicity. On Windows, proxies use .cmd files to integrate with PATH, with support for both user-level and machine-level deployment.
On Linux/macOS, proxies are implemented as shell functions in config files (~/.bashrc, ~/.zshrc, or ~/.config/fish/config.fish):
# generated by runx add terraform --alias=mytf
mytf() {
local RUNX_PROXY_ACTIVE=1
'/path/to/runx' exec --envfile='.env' 'terraform' "$@"
}The RUNX_PROXY_ACTIVE flag tells runx exec that we're being called from a proxy function, so it uses command -v to bypass the function and find the real command.
On Windows, proxies are implemented as wrapper .cmd files in one of two proxy types—User Proxy or Machine Proxy—based on where the original command exists:
Located in %LOCALAPPDATA%\runx\proxy\, no admin privileges required:
@echo off
REM generated by runx add (user proxy)
setlocal
set "RUNX_PROXY_DIR=%~dp0"
if defined RUNX_PROXY_DIRS (set "RUNX_PROXY_DIRS=%RUNX_PROXY_DIR%;%RUNX_PROXY_DIRS%") else (set "RUNX_PROXY_DIRS=%RUNX_PROXY_DIR%")
if exist "%~dp0\\..\\runx.exe" (
"%~dp0\\..\\runx.exe" exec --envfile=.env terraform %*
exit /b %ERRORLEVEL%
)
REM Fallback to original command if runx.exe not found
where /Q terraform 2>nul
if %ERRORLEVEL% EQU 0 (
terraform %*
exit /b %ERRORLEVEL%
)
echo Error: Neither runx.exe nor original 'terraform' command found. 1>&2
exit /b 9009User proxies are added to the User PATH. They work when the original command is in User PATH or not found in Machine PATH.
Located in C:\ProgramData\runx\proxy\, requires administrator privileges.
Machine proxies are added to the Machine PATH (system-wide) and take precedence over User PATH entries. Use this when the original command is in System32 or other Machine PATH locations.
Windows has two PATH types with different precedence:
- Machine PATH: System-wide, requires admin privileges, higher priority
- User PATH: Per-user, no admin needed, lower priority
| Scenario | Proxy Type | Reason |
|---|---|---|
| Original in System32 | Machine Proxy | Required: User Proxy cannot override Machine PATH |
| Original in User PATH | User Proxy | Same priority level works |
| Command not found | User Proxy | Easier, no admin needed |
runx add automatically detects where the original command exists and recommends the appropriate proxy type. If the original command is found in Machine PATH, runx will prompt to create a Machine Proxy:
┌────────────────────────────────────────────────────────────────┐
│ Machine PATH Detected │
└────────────────────────────────────────────────────────────────┘
The original command is in Machine PATH:
Command: git
Location: C:\Program Files\Git\cmd\git.exe
Windows prioritizes Machine PATH over User PATH.
Creating a User proxy will not work - the Machine PATH entry will
always take precedence.
Recommendation: Create a Machine Proxy instead.
• Requires administrator privileges
• Will be placed in: C:\ProgramData\runx\proxy
• Will be added to Machine PATH (system-wide)
Create Machine proxy now? (y/N):
To prevent infinite recursion, runx exec excludes proxy directories when resolving commands:
- Uses
RUNX_PROXY_DIRandRUNX_PROXY_DIRSenvironment variables to track all proxy directories - Searches PATH while skipping these directories
- Finds the real command executable
When multiple --envfile options are provided (for example in runx add or runx exec), runx processes them from left to right in the order they were specified.
Each env file value is resolved independently:
- If the value is an absolute path, only that exact path is checked.
- If the value is a filename, lookup is performed at command execution time in this order:
- current directory
- each parent directory up to filesystem root
- home directory
Example (--envfile=.env):
/
├── workspace/
│ └── work/
│ ├── .env # checked on parent walk
│ └── project/
│ ├── .env # checked on parent walk
│ └── service/ # current working directory
│ └── (no .env)
└── home/
└── alice/
└── .env # checked last (home fallback)
If the current working directory is /workspace/work/project/service, runx checks in this order:
/workspace/work/project/service/.env/workspace/work/project/.env/workspace/work/.env/workspace/.env/home/alice/.env
In this tree, /workspace/work/project/.env is the first existing match, so that file is adopted for this envfile entry.
If a specified env file is not found, runx continues with the next specified env file. If a file is found but has invalid syntax, execution fails with an error.
Resolved env files are merged in the same left-to-right order as the CLI arguments.
- First file provides initial values.
- Later files override keys from earlier files.
- Within one file, if the same key appears multiple times, the last occurrence in that file is used.
This is a standard "later wins" merge model.
Example:
runx add az --envfile=.base.env --envfile=.team.env --envfile=.local.envFor overlapping keys, precedence is:
.base.env.team.env.local.env(highest)
Example file contents:
# .base.env
AZURE_CONFIG_DIR=~/.azure_default
AZURE_CORE_OUTPUT=table
HTTP_PROXY=http://proxy.base:8080# .team.env
AZURE_CORE_OUTPUT=json
HTTP_PROXY=http://proxy.team:8080
TEAM_NAME=platform# .local.env
AZURE_CONFIG_DIR=~/.azure_personal
TEAM_NAME=platform-devFinal merged result at execution time:
AZURE_CONFIG_DIR=~/.azure_personal
AZURE_CORE_OUTPUT=json
HTTP_PROXY=http://proxy.team:8080
TEAM_NAME=platform-devIn this result, values from later files override earlier ones, while keys that appear only once are kept as-is.