-
Notifications
You must be signed in to change notification settings - Fork 0
Command Reference
Complete reference for all rsenv commands.
rsenv [OPTIONS] <COMMAND>| Option | Description |
|---|---|
-v, --verbose |
Enable verbose output |
-C, --project-dir <PATH> |
Context directory (see note below) |
--version |
Show version |
--help |
Show help |
Note on -C: -C always specifies the project directory. Use --vault-base for global operations to override the vaults directory.
Some commands require an initialized vault (rsenv vault init), while others work standalone with just .env files.
| Command | Description |
|---|---|
env build |
Build environment from hierarchy |
env envrc |
Write to .envrc (requires rsenv section) |
env tree |
Show environment tree |
env select |
Interactive environment selection |
env files |
List files in hierarchy |
env link |
Link parent-child files |
env unlink |
Remove parent link |
env init |
Recreate the default env files (existing files swept to <name>.bkp.<ext>) |
env leaves |
List leaf files |
env branches |
Show all branches |
env edit |
Edit environment file |
env edit-leaf |
Edit leaf and parents |
env tree-edit |
Side-by-side editing |
vault init |
Create new vault |
config show |
Show merged configuration |
config path |
Show config file paths |
config init --global |
Create global config |
config edit --global |
Edit global config |
sops * --global |
All sops commands with --global flag |
completion |
Generate shell completions |
| Command | Description |
|---|---|
guard add |
Guard a file (move to vault) |
guard list |
List guarded files |
guard restore |
Restore guarded file |
swap init |
Initialize file for swapping |
swap in |
Swap files in |
swap out |
Swap files out |
swap diff |
Show changes since swap-in (patch by default) |
vault commit |
Commit this project's vault data (must be swapped out) |
swap delete |
Delete swap configuration |
sops encrypt |
Encrypt vault files (without --global) |
sops decrypt |
Decrypt vault files (without --global) |
sops clean |
Clean plaintext files (without --global) |
sops status |
Encryption status (without --global) |
config edit |
Edit vault config (without --global) |
info |
Show project/vault status |
vault reset |
Reset (restore files, remove symlink) |
vault reconnect |
Reconnect to existing vault |
Note: swap status and swap out --global gracefully return empty results if no vault is found.
Create, connect and commit the project's vault.
rsenv vault <COMMAND>| Command | Description |
|---|---|
init |
Create vault for project |
reset |
Undo init: restore files, remove .envrc symlink (vault kept) |
reconnect |
Reconnect project to existing vault |
commit |
Commit this project's vault data to the vault repo |
Create a vault for a project.
rsenv vault init [OPTIONS] [PROJECT]| Argument | Description |
|---|---|
PROJECT |
Project directory (defaults to current) |
| Option | Description |
|---|---|
--absolute |
Use absolute paths for symlinks (default: relative) |
Examples:
rsenv vault init
rsenv vault init ~/myproject
rsenv vault init --absoluteUndo initialization: restore guarded files, remove .envrc symlink.
rsenv vault reset [PROJECT]| Argument | Description |
|---|---|
PROJECT |
Project directory (defaults to current) |
Note: The vault directory is NOT deleted.
Reconnect a project to an existing vault (re-create .envrc symlink).
rsenv vault reconnect <ENVRC_PATH>| Argument | Description |
|---|---|
ENVRC_PATH |
Path to the dot.envrc file in the vault |
Example:
rsenv vault reconnect ~/.rsenv/vaults/myproject-abc123/dot.envrcCommit this project's vault data to the vault repo.
Requires the project to be swapped out. It does not swap anything itself — see Why it refuses below.
rsenv vault commit [OPTIONS]| Option | Description |
|---|---|
-a, --auto |
Use the generated commit message instead of opening the editor |
--push |
Push the vault repo after a successful commit |
--no-encrypt |
Skip re-encryption for this run, overriding sops.encrypt_on_commit
|
Why it exists: cd ~/.rsenv && git add . && git commit sweeps every vault on the machine
into a single commit. This makes one commit scoped to vaults/<name>-<id>/, so another
project's pending changes stay out of it even when it has some — and stamps the project's
HEAD into the message as the link back.
What it does, in order:
- verifies the project is swapped out, refusing and naming the paths otherwise
- reads the project's HEAD commit
- re-encrypts the vault (
sops.encrypt_on_commit, defaulttrue) - stages and commits only
vaults/<name>-<id>/
Why it refuses: while a file is swapped in, swap in has moved the vault bytes into the
project and left a frozen sentinel behind. Committing then would record the sentinel, not your
work. Swapping out is left to you deliberately: it is your swap out that also lets direnv
refresh RSENV_SWAPPED, which this command — being a child process — cannot do.
$ rsenv vault commit -a
error: refusing to commit while the project is swapped in:
thoughts
The vault holds frozen sentinels for these paths, so this commit would record stale
content. Run `rsenv swap out` first.
Sentinels belonging to another host do not block: they are that machine's baseline, and
swap out refuses to touch them, so there would be no way forward.
The commit message records the project's HEAD as the link between a vault state and the project state it belongs to:
vault(myproject): checkpoint @ a3bddf6
project: /home/you/dev/myproject
project-commit: a3bddf6028e11155c9f2bd66776d395a99a3ef83 (main)
M swap/thoughts/notes.md
A swap/thoughts/research/2026-09-13-ranking.md
Without -a, your editor opens with exactly this message prefilled; quitting without saving
aborts the commit, leaving the vault untouched. Variants of the project-commit: line:
| Project state | Recorded as |
|---|---|
| clean | <sha> (main) |
| uncommitted changes | <sha> (main, dirty) |
| repo without commits | (no commits yet on main) |
| not a git repo | (not a git repository) |
Encryption: step 3 runs before staging, so the .enc files committed in step 4 match the
plaintext they came from — which is already final, since the project is verified swapped out. Without it the commit stages whatever .enc happens to exist,
so a plaintext edit made while swapped in is committed as stale ciphertext. It encrypts only
what is pending or stale, so an unchanged vault produces no new blobs. Disable per vault or
globally:
[sops]
encrypt_on_commit = false--no-encrypt skips step 3 for one run whatever the config says — for checkpointing when the
key is unavailable (no GPG agent, no YubiKey plugged in). There is no matching --encrypt:
run rsenv sops encrypt before committing instead.
If no gpg_key or age_key is configured and something needs encrypting, the commit fails
with that error rather than committing stale ciphertext. Nothing is staged.
Safety: refuses to commit anything under envs/ or guarded/ that is not .enc, and
likewise a plaintext dot.envrc. The vault .gitignore covers envs/ globally, but
guarded/ relies on per-file entries written by guard add — a stale entry would otherwise
leak plaintext into a pushed repo. Nothing is committed when this fires.
Examples:
# Checkpoint with a generated message
rsenv vault commit -a
# Write your own message, prefilled with the project link
rsenv vault commit
# Checkpoint and push the vault repo
rsenv vault commit -a --push
# Checkpoint without re-encrypting (e.g. GPG key not available right now)
rsenv vault commit -a --no-encryptNotes:
- Requires the project to be swapped out; run
rsenv swap outfirst. Nothing is staged and nothing is committed when it refuses. - Leaves swap state untouched — it never swaps anything in or out.
- Exits without committing (and says so) when the vault has no changes.
- Unlike
swap statusandswap diff,-sis not an option here;-aselects the generated message, and-s/--silentkeeps its "exit code only" meaning elsewhere.
Environment variable hierarchy management.
Build hierarchical environment variables.
rsenv env build <FILE>| Argument | Description |
|---|---|
FILE |
Leaf env file to build from |
Example:
rsenv env build $RSENV_VAULT/envs/local.env
source <(rsenv env build local.env)Write environment to .envrc file (direnv integration).
rsenv env envrc <FILE> [OPTIONS]| Argument | Description |
|---|---|
FILE |
Leaf env file to build from |
| Option | Description |
|---|---|
-e, --envrc <PATH> |
Target .envrc file (default: ./.envrc) |
List all files in environment hierarchy.
rsenv env files <FILE>Interactively select an environment (fuzzy finder).
rsenv env select [DIR]| Argument | Description |
|---|---|
DIR |
Directory to search for env files |
Show environment hierarchy as tree.
rsenv env tree [DIR]Show all branches (linear representation).
rsenv env branches [DIR]Edit an environment file (FZF select).
rsenv env edit [DIR]Edit a leaf file and all its parents, in a vertical split (-O).
rsenv env edit-leaf <FILE>Edit all environment hierarchies side-by-side, arranged by a generated vimscript (-S).
rsenv env tree-edit [DIR]Both use the editor setting (rsenv config path, default $EDITOR) and require a
vim-family editor, since they drive it with vim's own flags.
List all leaf environment files.
rsenv env leaves [DIR]Link parent-child env files.
rsenv env link <FILES>...| Argument | Description |
|---|---|
FILES |
Files to link (first is root, each subsequent links to previous) |
Examples:
# Link parent to child
rsenv env link base.env local.env
# Create chain: root <- middle <- leaf
rsenv env link base.env cloud.env prod.envRemove parent link from env file.
rsenv env unlink <FILE>Recreate the six default env files in the vault's envs/ directory: none.env, local.env, test.env, int.env, e2e.env, prod.env. none.env is the hierarchy root; the other five declare it as their parent.
rsenv env init [OPTIONS]| Option | Description |
|---|---|
--clear |
Delete existing files instead of backing them up |
Requires a vault — fails with No vault found. Run 'rsenv vault init' first. otherwise. The envs/ directory is created if it is missing, so this also repairs a vault whose envs/ was deleted outright.
The sweep. Before writing the defaults, every file directly in envs/ is moved aside — not just the six defaults, and not just *.env. The marker .bkp is inserted before the extension:
local.env → local.bkp.env
custom.env → custom.bkp.env
README.md → README.bkp.md
NOTES → NOTES.bkp # no extension: marker appended
The marker goes before the extension so the backup keeps the extension of the original. Both the vault's *.env gitignore and sops.file_extensions_enc key off that extension, so a backup is still ignored by git and still encrypted by rsenv sops encrypt — a trailing local.env.bkp would be covered by neither and would wedge rsenv vault commit, which refuses any non-.enc file under envs/.
Files that are already backups are skipped by the sweep, so backups never cascade into local.bkp.bkp.env. A backup therefore holds only the immediately previous version, and a second env init overwrites it. For anything older, use the vault's git history — see Backup and Recovery.
Examples:
# Regenerate the defaults, keeping one generation of backups
rsenv env init
# Start from a clean envs/ with no backups kept
rsenv env init --clear
# Inspect what was swept aside
ls $RSENV_VAULT/envs/*.bkp.*Output:
Backed up 6 files
Initialized 6 env files in /home/user/.rsenv/vaults/myproject-abc123/envs
With --clear the first line reads Removed 6 files; it is omitted entirely when there was nothing to sweep.
Note: rsenv 6.0.0 wrote backups the other way round, as
local.env.bkp. Those files are still recognised as backups, so a sweep leaves them alone rather than burying them deeper — but their.bkpextension is outside both the gitignore and the encryption patterns, so they sit inenvs/as plaintext thatrsenv sops encryptwill not touch and that makesrsenv vault commitrefuse the whole commit. Salvage anything you need from them and delete them.
Guard sensitive files (symlink to vault).
Add a file to guard (move to vault, create symlink).
rsenv guard add <FILE> [OPTIONS]| Argument | Description |
|---|---|
FILE |
File to guard |
| Option | Description |
|---|---|
--absolute |
Use absolute paths for symlinks |
List guarded files.
rsenv guard listRestore a guarded file from vault.
rsenv guard restore <FILE>| Argument | Description |
|---|---|
FILE |
File to restore |
Swap files in/out between project and vault.
| Scope | Command | Description |
|---|---|---|
| Vault | swap out |
All files in current project's vault (default) |
| File | swap out <files> |
Operate on specific files |
| Global | swap out --global |
All vaults under base_dir/vaults |
Initialize: move project files to vault (first-time setup).
rsenv swap init <FILES>...Swap files in (replace with vault versions).
rsenv swap in <FILES>...Swap files out (restore originals).
rsenv swap out [OPTIONS] [FILES]...| Argument | Description |
|---|---|
FILES |
Files to swap out (if empty, swaps out all files in current vault) |
| Option | Description |
|---|---|
-g, --global |
Swap out all vaults |
--vault-base <PATH> |
Override vaults directory (requires --global) |
Examples:
# Vault-level (default, like sops)
rsenv swap out
# File-level
rsenv swap out config.yml docker-compose.yml
# Global (all vaults)
rsenv swap out --global
# Global with custom vault base
rsenv swap out --global --vault-base ~/my-rsenv/vaultsShow swap status.
rsenv swap status [OPTIONS]| Option | Description |
|---|---|
--absolute |
Show absolute paths (default: relative) |
-g, --global |
Show status across all vaults |
-s, --silent |
Exit code only (0=clean, 1=dirty, 2=unmanaged). With --global: 0=clean, 1=dirty |
--vault-base <PATH> |
Override vaults directory (requires --global) |
Examples:
# Project status
rsenv swap status
# Global status
rsenv swap status --global
# Script-friendly project check (0=clean, 1=dirty, 2=unmanaged)
rsenv swap status --silent; echo $?
# Script-friendly global check
rsenv swap status --global --silent && echo "All clean"Show what changed in swapped-in files since they were swapped in.
rsenv swap diff [OPTIONS] [FILES]...| Argument | Description |
|---|---|
FILES |
Paths to diff (if empty, diffs all swapped-in entries in the current vault) |
Path arguments follow git pathspec semantics: an argument selects everything at or below
it. It may name a swapped entry (thoughts), a path inside one (thoughts/concepts.md),
a subdirectory (thoughts/research), or an ancestor of several (.).
| Option | Description |
|---|---|
-p, --patch |
Show the patch — the default, as in git diff; accepted for explicitness |
--stat |
Show only the summary of changed files, without the patch |
--no-pager |
Do not pipe the patch through the pager |
--absolute |
Show absolute paths (default: relative) |
-s, --silent |
Exit code only (0=clean, 1=changes, 2=unmanaged) |
Rendering: output is git patch format, piped through the pager git var GIT_PAGER
reports ($GIT_PAGER → core.pager → $PAGER). A core.pager = delta setup renders these
diffs exactly as it renders git's. Paging is skipped when output is not a terminal, so pipes
and scripts stay plain. Patch headers are project-relative so a viewer can open them.
Why it exists: while a file is swapped in, its content lives in the project while the
vault holds only the sentinel, so neither git diff shows anything. swap diff compares the
live project content against the sentinel — the copy taken at swap-in, which is exactly what
swap out will write back into the vault.
Baseline: the swap-in snapshot. It resets on every swap out/in cycle, so this answers "what changed during this working period", not "how does my override differ from the committed original".
Change markers: A added, D deleted, M modified, T type changed (file/dir/symlink).
Examples:
# Summary of everything swapped in
rsenv swap diff
# Full unified diff for one entry
rsenv swap diff --patch thoughts
# A single file inside a swapped directory
rsenv swap diff thoughts/concepts.md
# A subdirectory of a swapped directory
rsenv swap diff --patch thoughts/research
# Script-friendly check (0=clean, 1=changes, 2=unmanaged)
rsenv swap diff --silent; echo $?
# Scoped to one path: exit 0 when that path is clean, even if others changed
rsenv swap diff --silent thoughts/concepts.md; echo $?Notes:
- Dot-file names are reported as they appear in the project (
.gitignore), not in their neutralized vault form (dot.gitignore). - Symlinks are compared by target and never followed.
- Binary files are reported as changed but never rendered as a patch.
- Entries swapped in by a different host are skipped: their sentinel describes that machine's baseline, not yours.
Delete swap files from vault (remove override + backup).
rsenv swap delete <FILES>...| Argument | Description |
|---|---|
FILES |
Files to delete from swap management |
Safety: Refuses if any file is currently swapped in. All-or-nothing validation prevents partial deletions.
SOPS encryption/decryption.
| Scope | Command | Description |
|---|---|---|
| File | sops encrypt <file> |
Encrypt/decrypt single file |
| Vault | sops encrypt |
All matching files in current vault |
| Global | sops encrypt --global |
All vaults under base_dir/vaults |
Encrypt files matching config patterns (or single file).
rsenv sops encrypt [OPTIONS] [FILE]| Argument | Description |
|---|---|
FILE |
Single file to encrypt (optional) |
| Option | Description |
|---|---|
-d, --dir <PATH> |
Directory to encrypt |
-g, --global |
Encrypt all vaults |
--vault-base <PATH> |
Override vaults directory (requires --global) |
Examples:
# Single file
rsenv sops encrypt secrets.env
# Project vault (default)
rsenv sops encrypt
# All vaults
rsenv sops encrypt --globalDecrypt .enc files (or single file).
rsenv sops decrypt [OPTIONS] [FILE]| Argument | Description |
|---|---|
FILE |
Single file to decrypt (optional) |
| Option | Description |
|---|---|
-d, --dir <PATH> |
Directory to decrypt |
-g, --global |
Decrypt all vaults |
--vault-base <PATH> |
Override vaults directory (requires --global) |
Delete plaintext files matching encryption patterns.
rsenv sops clean [OPTIONS]| Option | Description |
|---|---|
-d, --dir <PATH> |
Directory to clean |
-g, --global |
Clean all vaults |
--vault-base <PATH> |
Override vaults directory (requires --global) |
Without options: cleans project's vault only.
Show encryption status.
rsenv sops status [OPTIONS]| Option | Description |
|---|---|
-d, --dir <PATH> |
Directory to check |
-g, --global |
Check all vaults |
--check |
Exit with code 1 if files need encryption (for scripting/hooks) |
--vault-base <PATH> |
Override vaults directory (requires --global) |
Without options: shows status for project's vault only.
Status categories:
-
pending_encrypt: Plaintext without encrypted version -
stale: Encrypted exists but hash differs (modified since encryption) -
current: Encrypted with matching hash (up-to-date) -
orphaned: Encrypted without plaintext
Sync .gitignore with configured encryption patterns.
rsenv sops gitignore-sync [OPTIONS]| Option | Description |
|---|---|
-y, --yes |
Skip confirmation prompt |
--global |
Sync global gitignore only |
Without options: syncs per-vault gitignore only (requires vault).
Show gitignore sync status.
rsenv sops gitignore-status [OPTIONS]| Option | Description |
|---|---|
--global |
Show global gitignore status only |
Without options: shows per-vault gitignore status only (requires vault).
Remove rsenv-managed section from .gitignore.
rsenv sops gitignore-clean [OPTIONS]| Option | Description |
|---|---|
--global |
Clean global gitignore only |
Without options: cleans per-vault gitignore only (requires vault).
Git pre-commit hook management to prevent committing with unencrypted files.
Install pre-commit hook in a git repository.
rsenv hook install [OPTIONS]| Option | Description |
|---|---|
--dir <PATH> |
Target git repo (default: base_dir) |
-f, --force |
Force overwrite if hook exists |
Default location: base_dir (typically ~/.rsenv).
Remove rsenv pre-commit hook.
rsenv hook remove [OPTIONS]| Option | Description |
|---|---|
--dir <PATH> |
Target git repo (default: base_dir) |
Safety: Only removes hooks installed by rsenv (checks for rsenv signature).
Show hook installation status.
rsenv hook status [OPTIONS]| Option | Description |
|---|---|
--dir <PATH> |
Target git repo (default: base_dir) |
Configuration management.
Show effective configuration.
rsenv config showCreate template config file.
rsenv config init [OPTIONS]| Option | Description |
|---|---|
-g, --global |
Create global config (~/.config/rsenv/rsenv.toml) |
Without --global: creates config in project's vault directory.
Edit configuration in editor.
rsenv config edit [OPTIONS]| Option | Description |
|---|---|
-g, --global |
Edit global config (~/.config/rsenv/rsenv.toml) |
Without --global: edits vault-local config (requires initialized vault). Creates template if config doesn't exist. After editing, automatically syncs gitignore patterns.
Show config file paths.
rsenv config pathShow project and vault status.
rsenv info| Option | Description |
|---|---|
--check |
Silent mode: exit code only (0=valid vault, 1=no/invalid vault) |
Use --check for shell scripts and CI:
if rsenv info --check 2>/dev/null; then
echo "Valid vault found"
else
echo "No vault or invalid vault"
fiGenerate shell completions.
rsenv completion <SHELL>| Argument | Values |
|---|---|
SHELL |
bash, zsh, fish, powershell, elvish
|
Examples:
rsenv completion bash > ~/.local/share/bash-completion/completions/rsenv
rsenv completion zsh > ~/.zfunc/_rsenv
rsenv completion fish > ~/.config/fish/completions/rsenv.fish| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Invalid arguments |
| 64 | Usage error |
| 65 | Data error |
| 66 | No input |
| 74 | I/O error |
| 78 | Configuration error |
| Variable | Description |
|---|---|
RSENV_VAULT |
Path to current project's vault (set by rsenv) |
RSENV__BASE_DIR |
Override base directory |
RSENV__EDITOR |
Override editor |
RSENV__SOPS__GPG_KEY |
Override SOPS GPG key |
See Configuration for all environment variables.
rsenv Documentation