Project

localvault

0.0
A long-lived project that still receives updates
Encrypted local vault for secrets with MCP server for AI agents. No cloud required. Powers credentials management at inventlist.com.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 5.0
~> 13.0

Runtime

~> 0.2
~> 0.2
~> 7.1
~> 1.3
 Project Readme

LocalVault

Encrypted local secrets vault with MCP server for AI agents. Zero infrastructure, zero cloud dependency.

Try the interactive demo — explore every command in your browser.

Part of InventList Tools — free, open-source developer utilities for indie builders.


Install

Homebrew (macOS / Linux)

brew install inventlist/tap/localvault

RubyGems

gem install localvault

Requires libsodium:

# macOS
brew install libsodium

# Ubuntu/Debian
sudo apt-get install libsodium-dev

# Fedora
sudo dnf install libsodium-devel

Quick Start

# Create a vault (prompts for passphrase)
localvault init

# Store secrets
localvault set OPENAI_API_KEY "sk-proj-..."
localvault set STRIPE_SECRET_KEY "sk_live_..."
localvault set DATABASE_URL "postgres://localhost/myapp"

# Retrieve a secret (raw, pipeable)
localvault get OPENAI_API_KEY

# View all secrets (masked by default)
localvault show

# Reveal values
localvault show --reveal

# Export as shell variables
eval $(localvault env)

# Run a command with secrets injected
localvault exec -- rails server

Commands

Secrets

Command Description
init [NAME] Create a vault (Argon2id key derivation)
set KEY VALUE Store a secret (supports dot-notation: project.KEY)
get KEY Retrieve a secret (raw, pipeable)
show Display all secrets in a table (masked by default)
show --reveal Display with values visible
show --group Group by dot-notation prefix (one table per project)
list List key names only
delete KEY Remove a secret
rename OLD NEW Rename a secret key
copy KEY --to VAULT Copy a secret to another vault
import FILE Bulk-import from .env / .json / .yml
env Export as export KEY="value" lines
exec -- CMD Run a command with secrets injected as env vars

Vault Management

Command Description
vaults List all vaults with secret counts
switch [VAULT] Switch default vault
unlock Cache passphrase for the session
lock [NAME] Clear cached passphrase
rekey [NAME] Change vault passphrase (re-encrypts all secrets)
reset [NAME] Destroy and reinitialize a vault

Sync & Login

Command Description
login [TOKEN] Log in to InventList — auto-generates X25519 keypair + publishes public key
login --status Show current login status
logout Clear stored credentials
sync Sync all vaults bidirectionally (push local, pull remote, detect conflicts)
sync --dry-run Preview what sync would do without making changes
sync push [NAME] Push one vault to cloud
sync pull [NAME] Pull one vault from cloud (auto-unlocks if you have a key slot)
sync status Show sync state for all vaults
config set server URL Point at a custom server (default: inventlist.com)

Team Sharing (v1.3.0)

Vault-level operations live under team. Person operations (the @handle already signals a person) are top-level.

Command Description
team init Convert vault to team vault (sets you as owner, SyncBundle v3)
team list List vault members
team rotate Re-key vault with new passphrase, keep all members
verify @handle Check if a user has a published public key (dry-run)
add @handle Add teammate with full vault access
add @handle --scope KEY... Add teammate with access to specific keys only
remove @handle Remove teammate's access
remove @handle --scope KEY Remove one scoped key (keeps other scopes)
remove @handle --rotate Full revocation + re-encrypt with new passphrase

The team add, team remove, and team verify aliases still work for backward compatibility but the top-level forms are preferred.

Keys

Command Description
keys generate Generate X25519 identity keypair
keys show Display your public key
keys publish Upload public key to InventList (required before others can add you)

AI / MCP

Command Description
install-mcp [CLIENT] Configure MCP server in claude-code, cursor, windsurf, or zed
mcp Start MCP server (stdio transport)

All commands accept --vault NAME (or -v NAME) to target a specific vault. Default vault is default.

Personal Sync

Sync your vaults between machines — same passphrase, no team features needed:

# Machine A: push all your vaults at once
localvault sync

# Machine B: install, login, sync
brew install inventlist/tap/localvault
localvault login YOUR_TOKEN
localvault sync                # pulls everything, pushes local-only vaults
localvault show                # enter your passphrase — same secrets

Or push/pull individual vaults:

localvault sync push production    # push one vault
localvault sync pull production    # pull one vault
localvault sync status             # check what's synced vs local-only

Preview before syncing:

localvault sync --dry-run
#   Vault         Action    Reason
#   default       skip      up to date
#   production    push      local changes
#   staging       pull      remote changes

Team Sharing

Share vault access with teammates using X25519 asymmetric encryption. The server never sees plaintext.

# 1. Convert to team vault (required first)
localvault team init -v production

# 2. Verify teammate has a published key
localvault verify @alice

# 3. Add with full access
localvault add @alice -v production

# 4. Or scoped — they only see specific keys
localvault add @bob -v production --scope STRIPE_KEY WEBHOOK_SECRET

# 5. When Alice pulls, auto-unlocks via her identity key
# (on Alice's machine)
localvault sync pull production
# => Unlocked via your identity key.

# 6. Scoped members can't push
# (on Bob's machine)
localvault sync push production
# => Error: You have scoped access. Only the owner can push.

# 7. Rotate without removing anyone
localvault team rotate -v production

# 8. Full revocation + re-key
localvault remove @alice -v production --rotate

Prerequisites: Teammates must have a published public key. localvault login does this automatically, or: localvault keys generate && localvault keys publish.

MCP Server (AI Agents)

Give AI agents safe secret access. Keys never appear in agent context or config files.

# One-command install for Claude Code
localvault install-mcp claude-code
# Also supports: cursor, windsurf, zed

# Unlock your vault for the session
localvault unlock

# MCP tools available to the agent:
#   get_secret(key, vault?)      — read a secret
#   list_secrets(vault?, prefix?) — list key names
#   set_secret(key, value, vault?) — store a secret
#   delete_secret(key, vault?)   — remove a secret

exec_action — agent declares intent, LocalVault executes with secrets injected. The agent never sees the key:

localvault exec_action -- curl -s https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY"

Multi-Project Vaults

One vault, many projects. Dot-notation keeps secrets organized:

# Store with project prefix
localvault set myapp.DATABASE_URL postgres://localhost/myapp -v work
localvault set api.DATABASE_URL postgres://localhost/api -v work

# View grouped by project
localvault show --group -v work

# Filter to one project
localvault show -p myapp -v work

# Export one project
eval $(localvault env -p myapp -v work)

# Bulk import
localvault import .env --prefix myapp -v work

Session Caching

Avoid typing your passphrase repeatedly:

eval $(localvault unlock)

# All subsequent commands skip the passphrase prompt
localvault get API_KEY
localvault exec -- rails server

Session lives in LOCALVAULT_SESSION — disappears when the terminal closes.

Security

Crypto Stack

Layer Algorithm Purpose
Key derivation Argon2id (64 MB, 3 iterations) Passphrase → master key
Encryption XSalsa20-Poly1305 Authenticated encryption
Key exchange X25519 Team key slots + vault sharing
  • Random 24-byte nonce per encryption
  • Poly1305 authentication prevents tampering
  • Argon2id is memory-hard (GPU/ASIC resistant)
  • All crypto via libsodium (RbNaCl bindings)
  • SyncBundle v3 for team vaults (owner field + per-member key slots)

Storage Layout

~/.localvault/
├── config.yml              # Default vault, server URL, token
├── identity.key            # X25519 private key (encrypted at rest)
├── identity.pub            # X25519 public key (safe to share)
├── vaults/
│   ├── default/
│   │   ├── meta.yml        # Salt, creation date, version
│   │   └── secrets.enc     # Encrypted JSON blob
│   └── production/
│       ├── meta.yml
│       └── secrets.enc

Server Independence

LocalVault is server-agnostic. It ships configured for inventlist.com but works with any host that implements the protocol (4 endpoints):

# Use a different server
localvault config set server https://vaulthost.example

# Or override per-login
localvault login --server https://vaulthost.example

Development

git clone https://github.com/inventlist/localvault.git
cd localvault
bundle install
bundle exec rake test  # 463 tests, 918 assertions

Used by

Powers credentials management at InventList — where indie builders ship, share, and get discovered.

License

Apache 2.0 — see LICENSE. Built by the InventList team.