-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration
rsenv uses layered configuration with sensible defaults. Customize behavior through config files or environment variables.
Configuration is loaded in order (later overrides earlier):
- Compiled defaults - Built into rsenv
-
Global config (XDG compliant) -
~/.config/rsenv/rsenv.toml -
Local config -
<vault>/.rsenv.toml -
Environment variables -
RSENV_*prefix (override)
| Layer Transition | Arrays | Scalars |
|---|---|---|
| Defaults → Global | REPLACE (global defines baseline) | Replace if specified |
| Global → Local/Vault | UNION with negation support | Replace if specified |
| Any → Env vars | REPLACE (explicit override) | Replace |
Rationale: Compiled defaults are just examples. Global config defines the real baseline for your user/organization. Vault config adds project-specific patterns on top.
See Array Merge Semantics for details.
# Create global config
rsenv config init --global
# View effective config
rsenv config show
# Show config file paths
rsenv config path| Type | Path (XDG) |
|---|---|
| Global | ~/.config/rsenv/rsenv.toml |
| Local | <vault>/.rsenv.toml |
# ~/.config/rsenv/rsenv.toml
# Base directory for rsenv (vaults stored in base_dir/vaults)
base_dir = "~/.rsenv"
# Preferred editor
editor = "nvim"
# SOPS encryption settings
[sops]
# GPG key fingerprint
gpg_key = "12A4127E82E218297532FAB6D750B66AE08F3B90"
# Age public key (alternative to GPG)
# age_key = "age1..."
# File extensions to encrypt
file_extensions_enc = [
"env",
"envrc",
"yaml",
"yml",
"json",
]
# Specific filenames to encrypt
file_names_enc = [
"dot_pypirc",
"dot_pgpass",
"kube_config",
]
# Extensions to decrypt
file_extensions_dec = ["enc"]
# Specific filenames to decrypt
file_names_dec = []| Setting | Default | Description |
|---|---|---|
base_dir |
~/.rsenv |
Base directory (vaults stored in base_dir/vaults) |
editor |
$EDITOR or vim
|
Editor for rsenv env edit
|
| Setting | Default | Description |
|---|---|---|
sops.gpg_key |
None | GPG key fingerprint for encryption |
sops.age_key |
None | Age public key (alternative to GPG) |
sops.file_extensions_enc |
["env", "envrc"] |
Extensions to encrypt |
sops.file_names_enc |
[] |
Exact filenames to encrypt |
sops.file_extensions_dec |
["enc"] |
Extensions to decrypt |
sops.file_names_dec |
[] |
Exact filenames to decrypt |
Override any setting via environment variables with RSENV_ prefix:
| Config Key | Environment Variable |
|---|---|
base_dir |
RSENV_BASE_DIR |
editor |
RSENV_EDITOR |
sops.gpg_key |
RSENV_SOPS__GPG_KEY |
sops.age_key |
RSENV_SOPS__AGE_KEY |
sops.file_extensions_enc |
RSENV_SOPS__FILE_EXTENSIONS_ENC |
sops.file_names_enc |
RSENV_SOPS__FILE_NAMES_ENC |
For arrays, use comma-separated values:
export RSENV_SOPS_FILE_EXTENSIONS_ENC="env,yaml,json"
export RSENV_SOPS_FILE_NAMES_ENC="dot_pypirc,dot_pgpass"# Use custom base directory
export RSENV_BASE_DIR=~/my-rsenv
# Use different GPG key
export RSENV_SOPS__GPG_KEY="ABC123..."
# Add to shell config for persistence
echo 'export RSENV_BASE_DIR=~/my-rsenv' >> ~/.bashrcCreate .rsenv.toml in your vault directory to override global settings:
# ~/.rsenv/vaults/myproject-abc123/.rsenv.toml
# This vault uses a specific GPG key
[sops]
gpg_key = "VAULT_SPECIFIC_KEY"Vault config merges with global config using union semantics for arrays. See Array Merge Semantics below.
rsenv config showOutput:
Configuration:
base_dir: /home/user/.rsenv
editor: nvim
[sops]
gpg_key: 60A4127E82E218297532FAB6D750B66AE08F3B90
file_extensions_enc: ["env", "envrc", "yaml"]
file_names_enc: ["dot_pypirc"]
file_extensions_dec: ["enc"]
rsenv config pathOutput:
Configuration paths:
Global: /home/user/.config/rsenv/rsenv.toml (exists)
Local: /home/user/.rsenv/vaults/myproject-abc123/.rsenv.toml (not found)
# Create global config template
rsenv config init --global
# Create local vault config (requires initialized vault)
rsenv config init# Edit global config
rsenv config edit --global
# Edit local vault config (requires initialized vault)
rsenv config editOpens the configuration file in your configured editor ($RSENV_EDITOR, $EDITOR, or vim).
If the config file doesn't exist, creates a template first. After editing vault-local config, automatically syncs gitignore patterns.
If no configuration exists, rsenv uses these defaults:
base_dir = "~/.rsenv" # Vaults stored in base_dir/vaults
editor = "$EDITOR" # Falls back to "vim"
[sops]
gpg_key = "" # Must be set for encryption
age_key = ""
file_extensions_enc = ["env", "envrc"]
file_names_enc = []
file_extensions_dec = ["enc"]
file_names_dec = []Paths support:
-
~- Home directory -
$VARand${VAR}- Environment variables
base_dir = "~/my-rsenv"
base_dir = "$HOME/my-rsenv"
base_dir = "${XDG_DATA_HOME}/rsenv"rsenv follows XDG Base Directory spec:
| Purpose | Default Location |
|---|---|
| Config | ~/.config/rsenv/rsenv.toml |
| Base dir | ~/.rsenv |
| Vaults |
~/.rsenv/vaults (computed as base_dir/vaults) |
Set XDG_CONFIG_HOME to change config location:
export XDG_CONFIG_HOME=~/.myconfig
# Config now at ~/.myconfig/rsenv/rsenv.tomlVaults can contain a local rsenv.toml:
~/.rsenv/vaults/myproject-abc123/
├── rsenv.toml # Vault-specific overrides
├── dot.envrc
└── envs/
This is loaded when operating within that vault.
Arrays use different merge behavior depending on the layer:
| Transition | Behavior | Example |
|---|---|---|
| Defaults → Global | REPLACE | Global ["yaml"] replaces defaults ["env", "envrc"]
|
| Global → Vault | UNION | Vault ["json"] + Global ["yaml"] = ["json", "yaml"]
|
Why? Compiled defaults are just examples. Your global config defines the real baseline. Vault config adds project-specific patterns on top.
Global config: file_extensions_enc = ["env", "envrc"]
Vault config: file_extensions_enc = ["yaml"]
Result: file_extensions_enc = ["env", "envrc", "yaml"] ← UNION
Use the ! prefix to remove items inherited from global/default config:
# Global config (~/.config/rsenv/rsenv.toml)
[sops]
file_extensions_enc = ["env", "envrc"]
file_names_enc = ["dot_pypirc", "dot_pgpass"]
# Vault config (<vault>/.rsenv.toml)
[sops]
# ADDS yaml, REMOVES env from inherited patterns
file_extensions_enc = ["yaml", "!env"]
file_names_enc = ["secrets.txt"]
# Effective result:
# file_extensions_enc = ["envrc", "yaml"]
# file_names_enc = ["dot_pypirc", "dot_pgpass", "secrets.txt"]To completely replace inherited arrays, negate all inherited values:
# Vault config - completely replace with only these values
[sops]
file_extensions_enc = ["!env", "!envrc", "yaml", "json"]
# Result: ["json", "yaml"]Environment variables always replace (no merge) because they represent explicit user overrides:
# This REPLACES the entire array, not merges
export RSENV_SOPS__FILE_EXTENSIONS_ENC="yaml,json"The layered merge semantics serve different purposes:
- Global REPLACES defaults: Defaults are just examples. You define your real baseline in global config.
- Vault UNIONS with global: Project-specific additions layer on top without losing your baseline.
- Fail-safe: For vault→global, union means encrypting too much (minor inconvenience) rather than too little (security risk).
-
Negation for removal: Use
!patternin vault config to explicitly remove inherited items when needed.
# Check paths
rsenv config path
# Verify file syntax
cat ~/.config/rsenv/rsenv.toml
# Check effective values
rsenv config show# Verify export
echo $RSENV_BASE_DIR
# Check if it's in the effective config
rsenv config show | grep base_dir# Local config is in the vault, not the project
echo $RSENV_VAULT
ls -la $RSENV_VAULT/.rsenv.toml- Installation - Initial setup
- SOPS Encryption - SOPS-specific configuration
- Troubleshooting - Common issues
rsenv Documentation