Break long lines in function signatures and strings to comply with the 120 character line length limit by using multi-line formatting and extracting variables where appropriate. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>  | 
			||
|---|---|---|
| .claude | ||
| cmd/secret | ||
| internal | ||
| pkg | ||
| .cursorrules | ||
| .gitignore | ||
| .golangci.yml | ||
| AGENTS.md | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| TODO.md | ||
Secret - Hierarchical Secret Manager
Secret is a modern, secure command-line secret manager that implements a hierarchical key architecture for storing and managing sensitive data. It supports multiple vaults, various unlock mechanisms, and provides secure storage using the Age encryption library.
Core Architecture
Three-Layer Key Hierarchy
Secret implements a sophisticated three-layer key architecture:
- Long-term Keys: Derived from BIP39 mnemonic phrases, these provide the foundation for all encryption
 - Unlockers: Short-term keys that encrypt the long-term keys, supporting multiple authentication methods
 - Version-specific Keys: Per-version keys that encrypt individual secret values
 
Version Management
Each secret maintains a history of versions, with each version having:
- Its own encryption key pair
 - Encrypted metadata including creation time and validity period
 - Immutable value storage
 - Atomic version switching via symlink updates
 
Vault System
Vaults provide logical separation of secrets, each with its own long-term key and unlocker set. This allows for complete isolation between different contexts (work, personal, projects).
Installation
Build from source:
git clone <repository>
cd secret
make build
Quick Start
- 
Initialize the secret manager:
secret initThis creates the default vault and prompts for a BIP39 mnemonic phrase.
 - 
Generate a mnemonic (if needed):
secret generate mnemonic - 
Add a secret:
echo "my-password" | secret add myservice/password - 
Retrieve a secret:
secret get myservice/password 
Commands Reference
Initialization
secret init
Initializes the secret manager with a default vault. Prompts for a BIP39 mnemonic phrase and creates the initial directory structure.
Environment Variables:
SB_SECRET_MNEMONIC: Pre-set mnemonic phraseSB_UNLOCK_PASSPHRASE: Pre-set unlock passphrase
Vault Management
secret vault list [--json]
Lists all available vaults.
secret vault create <name>
Creates a new vault with the specified name.
secret vault select <name>
Switches to the specified vault for subsequent operations.
Secret Management
secret add <secret-name> [--force]
Adds a secret to the current vault. Reads the secret value from stdin.
--force, -f: Overwrite existing secret
Secret Name Format: [a-z0-9\.\-\_\/]+
- Forward slashes (
/) are converted to percent signs (%) for storage - Examples: 
database/password,api.key,ssh_private_key 
secret get <secret-name> [--version <version>]
Retrieves and outputs a secret value to stdout.
--version, -v: Get a specific version (default: current)
secret list [filter] [--json] / secret ls
Lists all secrets in the current vault. Optional filter for substring matching.
Version Management
secret version list <secret-name>
Lists all versions of a secret showing creation time, status, and validity period.
secret version promote <secret-name> <version>
Promotes a specific version to current by updating the symlink. Does not modify any timestamps, allowing for rollback scenarios.
Key Generation
secret generate mnemonic
Generates a cryptographically secure BIP39 mnemonic phrase.
secret generate secret <name> [--length=16] [--type=base58] [--force]
Generates and stores a random secret.
--length, -l: Length of generated secret (default: 16)--type, -t: Type of secret (base58,alnum)--force, -f: Overwrite existing secret
Unlocker Management
secret unlockers list [--json]
Lists all unlockers in the current vault with their metadata.
secret unlockers add <type> [options]
Creates a new unlocker of the specified type:
Types:
passphrase: Traditional passphrase-protected unlockerpgp: Uses an existing GPG key for encryption/decryption
Options:
--keyid <id>: GPG key ID (required for PGP type)
secret unlockers rm <unlocker-id>
Removes an unlocker.
secret unlocker select <unlocker-id>
Selects an unlocker as the current default for operations.
Import Operations
secret import <secret-name> --source <filename>
Imports a secret from a file and stores it in the current vault under the given name.
secret vault import [vault-name]
Imports a mnemonic phrase into the specified vault (defaults to "default").
Encryption Operations
secret encrypt <secret-name> [--input=file] [--output=file]
Encrypts data using an Age key stored as a secret. If the secret doesn't exist, generates a new Age key.
secret decrypt <secret-name> [--input=file] [--output=file]
Decrypts data using an Age key stored as a secret.
Storage Architecture
Directory Structure
~/.local/share/secret/
├── vaults.d/
│   ├── default/
│   │   ├── unlockers.d/
│   │   │   ├── passphrase/              # Passphrase unlocker
│   │   │   └── pgp/                     # PGP unlocker
│   │   ├── secrets.d/
│   │   │   ├── api%key/                 # Secret: api/key
│   │   │   │   ├── versions/
│   │   │   │   │   ├── 20231215.001/   # Version directory
│   │   │   │   │   │   ├── pub.age     # Version public key
│   │   │   │   │   │   ├── priv.age    # Version private key (encrypted)
│   │   │   │   │   │   ├── value.age   # Encrypted value
│   │   │   │   │   │   └── metadata.age # Encrypted metadata
│   │   │   │   │   └── 20231216.001/   # Another version
│   │   │   │   └── current -> versions/20231216.001
│   │   │   └── database%password/       # Secret: database/password
│   │   │       ├── versions/
│   │   │       └── current -> versions/20231215.001
│   │   ├── vault-metadata.json          # Vault metadata
│   │   ├── pub.age                      # Long-term public key
│   │   └── current-unlocker -> ../unlockers.d/passphrase
│   └── work/
│       ├── unlockers.d/
│       ├── secrets.d/
│       ├── vault-metadata.json
│       ├── pub.age
│       └── current-unlocker
└── currentvault -> vaults.d/default
Key Management and Encryption Flow
Long-term Keys
- Source: Derived from BIP39 mnemonic phrases using hierarchical deterministic (HD) key derivation
 - Purpose: Master keys for each vault, used to encrypt secret-specific keys
 - Storage: Public key stored as 
pub.age, private key encrypted by unlockers 
Unlockers
Unlockers provide different authentication methods to access the long-term keys:
- 
Passphrase Unlockers:
- Encrypted with user-provided passphrase
 - Stored as encrypted Age keys
 - Cross-platform compatible
 
 - 
PGP Unlockers:
- Uses existing GPG key infrastructure
 - Leverages existing key management workflows
 - Strong authentication through GPG
 
 
Each vault maintains its own set of unlockers and one long-term key. The long-term key is encrypted to each unlocker, allowing any authorized unlocker to access vault secrets.
Secret-specific Keys
- Each secret has its own encryption key pair
 - Private key encrypted to the vault's long-term key
 - Provides forward secrecy and granular access control
 
Environment Variables
SB_SECRET_STATE_DIR: Custom state directory locationSB_SECRET_MNEMONIC: Pre-set mnemonic phrase (avoids interactive prompt)SB_UNLOCK_PASSPHRASE: Pre-set unlock passphrase (avoids interactive prompt)SB_GPG_KEY_ID: GPG key ID for PGP unlockers
Security Features
Encryption
- Uses the Age encryption library with X25519 keys
 - All private keys are encrypted at rest
 - No plaintext secrets stored on disk
 
Access Control
- Multiple authentication methods supported
 - Hierarchical key architecture provides defense in depth
 - Vault isolation prevents cross-contamination
 
Forward Secrecy
- Per-version encryption keys limit exposure if compromised
 - Each version is independently encrypted
 - Long-term keys protected by multiple unlocker layers
 - Historical versions remain encrypted with their original keys
 
Hardware Integration
- Hardware token support via PGP/GPG integration
 
Examples
Basic Workflow
# Initialize with a new mnemonic
secret generate mnemonic  # Copy the output
secret init              # Paste the mnemonic when prompted
# Add some secrets
echo "supersecret123" | secret add database/prod/password
echo "api-key-xyz" | secret add services/api/key
echo "ssh-private-key-content" | secret add ssh/servers/web01
# List and retrieve secrets
secret list
secret get database/prod/password
secret get services/api/key
Multi-vault Setup
# Create separate vaults for different contexts
secret vault create work
secret vault create personal
# Work with work vault
secret vault select work
echo "work-db-pass" | secret add database/password
secret unlockers add passphrase  # Add passphrase authentication
# Switch to personal vault
secret vault select personal
echo "personal-email-pass" | secret add email/password
# List all vaults
secret vault list
Advanced Authentication
# Add multiple unlock methods
secret unlockers add passphrase              # Password-based
secret unlockers add pgp --keyid ABCD1234    # GPG key
# List unlockers
secret unlockers list
# Select a specific unlocker
secret unlocker select <unlocker-id>
Encryption/Decryption with Age Keys
# Generate an Age key and store it as a secret
secret generate secret encryption/mykey
# Encrypt a file using the stored key
secret encrypt encryption/mykey --input document.txt --output document.txt.age
# Decrypt the file
secret decrypt encryption/mykey --input document.txt.age --output document.txt
Technical Details
Cryptographic Primitives
- Key Derivation: BIP32/BIP39 hierarchical deterministic key derivation
 - Encryption: Age (X25519 + ChaCha20-Poly1305)
 - Key Exchange: X25519 elliptic curve Diffie-Hellman
 - Authentication: Poly1305 MAC
 - Hashing: Double SHA-256 for public key identification
 
File Formats
- Age Files: Standard Age encryption format (.age extension)
 - Metadata: JSON format with timestamps and type information
 - Vault Metadata: JSON containing vault name, creation time, derivation index, and public key hash
 
Vault Management
- Derivation Index: Each vault uses a unique derivation index from the mnemonic
 - Public Key Hash: Double SHA-256 hash of the index-0 public key identifies vaults from the same mnemonic
 - Automatic Key Derivation: When creating vaults with a mnemonic, keys are automatically derived
 
Cross-Platform Support
- macOS: Full support including Keychain integration
 - Linux: Full support (excluding Keychain features)
 - Windows: Basic support (filesystem operations only)
 
Security Considerations
Threat Model
- Protects against unauthorized access to secret values
 - Provides defense against compromise of individual components
 - Supports hardware-backed authentication where available
 
Best Practices
- Use strong, unique passphrases for unlockers
 - Enable hardware authentication (Keychain, hardware tokens) when available
 - Regularly audit unlockers and remove unused ones
 - Keep mnemonic phrases securely backed up offline
 - Use separate vaults for different security contexts
 
Limitations
- Requires access to unlockers for secret retrieval
 - Mnemonic phrases must be securely stored and backed up
 - Hardware features limited to supported platforms
 
Development
Building
make build    # Build binary
make test     # Run tests
make lint     # Run linter
Testing
The project includes comprehensive tests:
make test     # Run all tests
go test ./... # Unit tests
go test -tags=integration -v ./internal/cli  # Integration tests
Features
- Multiple Authentication Methods: Supports passphrase-based and PGP-based unlockers
 - Vault Isolation: Complete separation between different vaults
 - Per-Secret Encryption: Each secret has its own encryption key
 - BIP39 Mnemonic Support: Keyless operation using mnemonic phrases
 - Cross-Platform: Works on macOS, Linux, and other Unix-like systems