Manage and switch environment profiles across dimensions.
Mux makes it easy to configure and switch between different environment settings (like Kubeconfigs, cloud credentials, etc.) organized by "dimensions" (e.g., kubernetes, aws).
-
Install Prerequisites:
Install poetry and pipx (dependency management):
# macOS brew install poetry pipx # Linux (Debian/Ubuntu) curl -sSL https://install.python-poetry.org | python3 - pip install pipx
Install fzf (fuzzy finder):
# macOS brew install fzf # Linux (Debian/Ubuntu) sudo apt-get install fzf
-
Installation:
# Clone the repository (if you haven't already) git clone git@github.com:teddyknox/mux.git cd mux # Install dependencies using Poetry poetry install # Use pipx to install globally and make the 'mux' command available in your PATH. pipx install -e .
-
Initialize Configuration: Create the basic Mux setup in your home directory:
mux init # Or initialize with examples: mux init --with-examplesThis creates the
~/.mux/dims/directory where you'll define your dimensions and profiles. -
Shell Integration (Essential for
switch): Commands likemux switchwork by printing shell commands (export,unset). To make them affect your current shell, you must evaluate their output.Add the Mux hook to your shell configuration file (
~/.zshrc,~/.bashrc,~/.config/fish/config.fish):- Zsh:
eval "$(mux hook zsh)" - Bash:
eval "$(mux hook bash)" - Fish:
mux hook fish | source
Restart your shell or source your config file (e.g.,
source ~/.zshrc). This also enables automatic profile switching based on.muxrcfiles in your project directories. - Zsh:
-
Basic Usage:
- See current status:
mux status - Select profiles interactively:
mux switch(Usesfzf. The hook will apply changes on the next prompt/directory change.) - Select a specific profile:
mux switch <dimension_path> <profile_name>(e.g.,mux switch kubernetes dev-cluster. The hook applies the change.) - Set the default profile for a dimension:
mux set-default <dimension_path> <profile_name>(Sets the default directly)mux set-default(Select dimension and profile interactively usingfzf) (This command updates the dimension'sdefault.txtfile.)
- See current status:
- Dimensions: Categories for your profiles (e.g.,
kubernetes,aws,gcp). Defined as directories under~/.mux/dims/. Dimensions can be nested (e.g.,kubernetes/cluster-a). - Profiles: Specific configurations within a dimension (e.g.,
dev-cluster,prod-account). Defined by environment variables. .muxrcFiles: Place a.muxrcfile in a project directory to automatically activate specific dimension profiles when youcdinto it. Example:# project/.muxrc kubernetes=dev-cluster aws=work-account
Profiles are defined inside dimension directories (~/.mux/dims/<dimension>/). Mux uses the first method it finds in the order: script > YAML > .env files.
Simple .env files in a profiles/ subdirectory (e.g., profiles/dev.env).
Example directory structure:
mux $ tree ~/.mux
/Users/edward/.mux
├── defaults
│ └── eth_rpc
└── dims
└── kubernetes
├── default.txt
└── profiles
├── a.env
├── b.env
└── c.envExample .env file ~/.mux/dims/kubernetes/profiles/a.env:
# Comments are allowed
KUBECONFIG=~/.kube/config-dev
K8S_NAMESPACE=development
K8S_CONTEXT=dev-clusterA single profiles.yaml file listing multiple profiles.
Example ~/.mux/dims/aws/profiles.yaml:
dev:
AWS_PROFILE: development
AWS_REGION: us-west-2
AWS_ACCOUNT_ID: "123456789012"
prod:
AWS_PROFILE: production
AWS_REGION: us-east-1
AWS_ACCOUNT_ID: "987654321098"An executable profiles.py script for dynamic generation (outputs JSON).
Example ~/.mux/dims/blockchain/profiles.py:
#!/usr/bin/env python3
import json
import os
# Example: Generate profiles dynamically
networks = {
"mainnet": {
"RPC_URL": "https://mainnet.infura.io/v3/" + os.environ.get("INFURA_KEY", ""),
"CHAIN_ID": "1"
},
"sepolia": {
"RPC_URL": "https://sepolia.infura.io/v3/" + os.environ.get("INFURA_KEY", ""),
"CHAIN_ID": "11155111"
}
}
# The script MUST output a JSON object to stdout
print(json.dumps(networks))(Remember to make the script executable: chmod +x ~/.mux/dims/blockchain/profiles.py)
Set a default profile for a dimension using mux set-default <dimension> <profile> or interactively with mux set-default. This creates a default.txt file.
For detailed configuration options and advanced usage, please refer to the project documentation or code comments.
Mux supports hierarchical dimensions, allowing you to organize related configuration aspects in parent-child relationships. This is useful for scenarios where one configuration depends on another.
- Dimensions can have subdimensions, stored in a
dims/directory within the parent dimension - When you switch a parent dimension, all its child dimensions are automatically deactivated
- Child dimensions can access their parent's active profile (when using dynamic scripts)
- Subdimensions are referenced using path notation (e.g.,
kubernetes/namespace)
A common use case is managing Kubernetes contexts (clusters) as the parent dimension and namespaces as the child dimension:
mux $ tree ~/.mux/dims/kubernetes
/Users/edward/.mux/dims/kubernetes
├── default.txt # Contains default context: "dev"
├── profiles.yaml # Defines context profiles
└── dims/ # Subdimensions directory
└── namespace/ # Namespace subdimension
├── default.txt # Default namespace: "default"
└── profiles.yaml # Namespace profilesParent dimension (kubernetes contexts):
~/.mux/dims/kubernetes/profiles.yaml:
dev:
KUBECONFIG: ~/.kube/config
KUBE_CONTEXT: dev-cluster
staging:
KUBECONFIG: ~/.kube/config
KUBE_CONTEXT: staging-cluster
prod:
KUBECONFIG: ~/.kube/config
KUBE_CONTEXT: production-clusterChild dimension (kubernetes namespaces):
~/.mux/dims/kubernetes/dims/namespace/profiles.yaml:
default:
KUBE_NAMESPACE: default
app:
KUBE_NAMESPACE: my-application
monitoring:
KUBE_NAMESPACE: monitoringUsing dynamic scripts with parent context:
For more advanced use cases, you can create a script that dynamically generates profiles based on the parent dimension's active profile:
~/.mux/dims/kubernetes/dims/namespace/profiles.py:
#!/usr/bin/env python3
import json
import sys
# Get parent profile (context) if available
parent_profile = sys.argv[1] if len(sys.argv) > 1 else None
# Base namespaces available in all contexts
namespaces = {
"default": {"KUBE_NAMESPACE": "default"},
"kube-system": {"KUBE_NAMESPACE": "kube-system"}
}
# Add context-specific namespaces
if parent_profile == "dev":
namespaces["dev-app"] = {"KUBE_NAMESPACE": "dev-application"}
elif parent_profile == "staging":
namespaces["staging-app"] = {"KUBE_NAMESPACE": "staging-application"}
elif parent_profile == "prod":
namespaces["prod-app"] = {"KUBE_NAMESPACE": "production-application"}
namespaces["monitoring"] = {"KUBE_NAMESPACE": "monitoring"}
print(json.dumps(namespaces))Switching parent dimensions:
# Switch kubernetes context to dev
mux switch kubernetes dev
# This automatically deactivates any active kubernetes/namespaceSwitching child dimensions:
# After setting kubernetes context, set the namespace
mux switch kubernetes/namespace appUsing .muxrc with hierarchical dimensions:
Add both parent and child dimensions to your .muxrc:
# project/.muxrc
kubernetes=dev
kubernetes/namespace=app
This will activate both the dev kubernetes context and the app namespace when you enter the project directory.
Viewing status:
mux statusShows the hierarchical structure with active profiles for each dimension level.
This project is licensed under the MIT License - see the LICENSE file for details.
