Skip to content

Command Reference

sysid edited this page Sep 23, 2026 · 15 revisions

Command Reference

Complete reference for all rsenv commands.

Global Options

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.

Vault Requirements

Some commands require an initialized vault (rsenv vault init), while others work standalone with just .env files.

Standalone Commands (No Vault Required)

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

Commands Requiring Vault

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.

vault

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

vault init

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 --absolute

vault reset

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

vault reconnect

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

vault commit

Commit 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:

  1. verifies the project is swapped out, refusing and naming the paths otherwise
  2. reads the project's HEAD commit
  3. re-encrypts the vault (sops.encrypt_on_commit, default true)
  4. 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-encrypt

Notes:

  • Requires the project to be swapped out; run rsenv swap out first. 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 status and swap diff, -s is not an option here; -a selects the generated message, and -s/--silent keeps its "exit code only" meaning elsewhere.

env

Environment variable hierarchy management.

env build

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)

env envrc

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)

env files

List all files in environment hierarchy.

rsenv env files <FILE>

env select

Interactively select an environment (fuzzy finder).

rsenv env select [DIR]
Argument Description
DIR Directory to search for env files

env tree

Show environment hierarchy as tree.

rsenv env tree [DIR]

env branches

Show all branches (linear representation).

rsenv env branches [DIR]

env edit

Edit an environment file (FZF select).

rsenv env edit [DIR]

env edit-leaf

Edit a leaf file and all its parents, in a vertical split (-O).

rsenv env edit-leaf <FILE>

env tree-edit

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.

env leaves

List all leaf environment files.

rsenv env leaves [DIR]

env link

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

env unlink

Remove parent link from env file.

rsenv env unlink <FILE>

env init

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 .bkp extension is outside both the gitignore and the encryption patterns, so they sit in envs/ as plaintext that rsenv sops encrypt will not touch and that makes rsenv vault commit refuse the whole commit. Salvage anything you need from them and delete them.

guard

Guard sensitive files (symlink to vault).

guard add

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

guard list

List guarded files.

rsenv guard list

guard restore

Restore a guarded file from vault.

rsenv guard restore <FILE>
Argument Description
FILE File to restore

swap

Swap files in/out between project and vault.

Scope Levels

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

swap init

Initialize: move project files to vault (first-time setup).

rsenv swap init <FILES>...

swap in

Swap files in (replace with vault versions).

rsenv swap in <FILES>...

swap out

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/vaults

swap status

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

swap diff

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.

swap delete

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

SOPS encryption/decryption.

Scope Levels

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

sops encrypt

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 --global

sops decrypt

Decrypt .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)

sops clean

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.

sops status

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

sops gitignore-sync

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

sops gitignore-status

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

sops gitignore-clean

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

hook

Git pre-commit hook management to prevent committing with unencrypted files.

hook install

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

hook remove

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

hook status

Show hook installation status.

rsenv hook status [OPTIONS]
Option Description
--dir <PATH> Target git repo (default: base_dir)

config

Configuration management.

config show

Show effective configuration.

rsenv config show

config init

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

config edit

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.

config path

Show config file paths.

rsenv config path

info

Show project and vault status.

rsenv info

Options

Option Description
--check Silent mode: exit code only (0=valid vault, 1=no/invalid vault)

Scripting

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

completion

Generate 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

Exit Codes

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

Environment Variables

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

Getting Started
Features
Reference
Upgrading

Clone this wiki locally