Skip to content

Configuration

sysid edited this page Jan 17, 2026 · 4 revisions

Configuration

rsenv uses layered configuration with sensible defaults. Customize behavior through config files or environment variables.

Configuration Precedence

Configuration is loaded in order (later overrides earlier):

  1. Compiled defaults - Built into rsenv
  2. Global config (XDG compliant) - ~/.config/rsenv/rsenv.toml
  3. Local config - <vault>/.rsenv.toml
  4. Environment variables - RSENV_* prefix (override)

Merge Behavior

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.

Quick Setup

# Create global config
rsenv config init --global

# View effective config
rsenv config show

# Show config file paths
rsenv config path

Configuration File

Location

Type Path (XDG)
Global ~/.config/rsenv/rsenv.toml
Local <vault>/.rsenv.toml

Full Example

# ~/.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 = []

Configuration Options

Core Settings

Setting Default Description
base_dir ~/.rsenv Base directory (vaults stored in base_dir/vaults)
editor $EDITOR or vim Editor for rsenv env edit

SOPS Settings

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

Environment Variables

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

Array Values

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"

Examples

# 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' >> ~/.bashrc

Vault-Specific Config

Create .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.

Commands

Show Effective Configuration

rsenv config show

Output:

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"]

Show Config Paths

rsenv config path

Output:

Configuration paths:
  Global: /home/user/.config/rsenv/rsenv.toml (exists)
  Local: /home/user/.rsenv/vaults/myproject-abc123/.rsenv.toml (not found)

Initialize Config

# Create global config template
rsenv config init --global

# Create local vault config (requires initialized vault)
rsenv config init

Edit Config

# Edit global config
rsenv config edit --global

# Edit local vault config (requires initialized vault)
rsenv config edit

Opens 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.

Defaults

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 = []

Path Expansion

Paths support:

  • ~ - Home directory
  • $VAR and ${VAR} - Environment variables
base_dir = "~/my-rsenv"
base_dir = "$HOME/my-rsenv"
base_dir = "${XDG_DATA_HOME}/rsenv"

XDG Compliance

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.toml

Per-Vault Configuration

Vaults 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.

Array Merge Semantics

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.

How Vault → Global Union Works

Global config:  file_extensions_enc = ["env", "envrc"]
Vault config:   file_extensions_enc = ["yaml"]
Result:         file_extensions_enc = ["env", "envrc", "yaml"]  ← UNION

Negation Support

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"]

Complete Replacement

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 Replace

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"

Why This Design?

The layered merge semantics serve different purposes:

  1. Global REPLACES defaults: Defaults are just examples. You define your real baseline in global config.
  2. Vault UNIONS with global: Project-specific additions layer on top without losing your baseline.
  3. Fail-safe: For vault→global, union means encrypting too much (minor inconvenience) rather than too little (security risk).
  4. Negation for removal: Use !pattern in vault config to explicitly remove inherited items when needed.

Troubleshooting

Config not loading

# Check paths
rsenv config path

# Verify file syntax
cat ~/.config/rsenv/rsenv.toml

# Check effective values
rsenv config show

Environment variable not applied

# Verify export
echo $RSENV_BASE_DIR

# Check if it's in the effective config
rsenv config show | grep base_dir

Local config not found

# Local config is in the vault, not the project
echo $RSENV_VAULT
ls -la $RSENV_VAULT/.rsenv.toml

Related

rsenv Documentation

Getting Started
Features
Reference
Upgrading

Clone this wiki locally