Skip to content

capydev42/keynest

Repository files navigation

Keynest

crates.io docs.rs License: MIT OR Apache-2.0 CI

Stop committing secrets by accident.

Inject secrets into any command — no cloud, no setup.

keynest exec -- docker compose up

Your app receives secrets via environment variables.

Table of Contents


Why Keynest?

Instead of You get
.env files Encrypted local secrets
Vault Zero setup
1Password CLI No account
Hardcoded secrets Runtime injection

Quick Start

keynest init
keynest set api_key test123
keynest exec -- printenv API_KEY

Output: test123

Demo


AI & Agent Usage

Use Keynest as a secure local secret store for AI agents.

keynest exec -- python agent.py

Access secrets via environment variables (e.g. API_KEY):

import os
api_key = os.environ["API_KEY"]

Keeps secrets out of:

  • source code
  • logs
  • prompts
  • LLM context

Works well with:

  • LangChain
  • AutoGPT
  • custom agents

Installation

Homebrew

brew tap capydev42/keynest
brew install keynest

Pre-built binaries

Download the latest release from GitHub: keynest/releases/latest

From crates.io

cargo install keynest

From source

cargo install --git https://github.com/capydev42/keynest.git

Or build locally:

cargo build --release
./target/release/keynest

Usage

# Initialize a new keystore
keynest init

# Store a secret (three ways)
keynest set github_token "ghp_xxxx"           # as argument
keynest set github_token --file secret.txt    # from file
keynest set github_token --prompt             # interactive prompt

# Retrieve a secret
keynest get github_token
keynest get github_token --clip              # copy to clipboard (auto-clears after 15s)
keynest get github_token --clip --timeout 30 # copy with custom timeout

# List all keys
keynest list

# Update a secret
keynest update github_token "ghp_yyyy"

# Remove a secret
keynest remove github_token

# Run command with secrets as environment variables
keynest exec -- docker compose up
keynest exec --only API_KEY -- \
  curl -H "Authorization: Bearer $API_KEY" https://api.example.com
keynest exec --prefix MY_ -- env
keynest exec --print

# Show keystore info (KDF params, creation date)
keynest info

# Change password (and optionally KDF parameters)
keynest rekey
keynest rekey --argon-mem 131072  # upgrade memory cost

# Import/Export secrets
keynest import .env
keynest import secrets.json
keynest import --overwrite .env
keynest export --format env
keynest export secrets.json

CLI Commands

Command Description
init Initialize a new keystore
set <key> [<value>] Store a secret (value, --file, or --prompt)
get <key> Retrieve a secret (exits 1 if not found)
get <key> --clip Copy secret to clipboard (auto-clears after 15s)
update <key> <value> Update existing secret
list [--all] List keys (--all shows values & timestamps)
remove <key> Remove a secret
exec -- <cmd> Run command with secrets as environment variables
info Show keystore information (KDF params, creation date)
rekey Change password and/or KDF parameters
import <file> Import secrets from file (env or json)
export [file] Export secrets to file or stdout

All commands support --json for structured output (get, list, info).


Security

  • Key Derivation: Argon2id with configurable parameters
  • Secure Memory: Keys and passwords are zeroized after use
  • Encryption: XChaCha20-Poly1305 AEAD

Security Notes

  • Uses well-established cryptographic primitives (Argon2id, XChaCha20-Poly1305)
  • No network access
  • No telemetry
  • Zero-config — works out of the box

CLI Options

  • --store <path> - Specify custom keystore location

KDF Options (for init/rekey)

  • --argon-mem <kb> - Memory cost in KiB (default: 65536)
  • --argon-time <n> - Time cost / iterations (default: 3)
  • --argon-parallelism <n> - Parallelism (default: 1)

Password Input

Keynest accepts passwords via:

  1. Environment variable: KEYNEST_PASSWORD="secret" keynest get key
  2. Stdin: echo "secret" | keynest get key
  3. Interactive prompt (default)

Library Usage

Add as Dependency

cargo add keynest
use keynest::{Keynest, Storage, KdfParams};
use zeroize::Zeroizing;

fn main() -> Result<()> {
    let storage = Storage::new("/path/to/keystore.db");
    let password = Zeroizing::new(String::from("my-password"));
    
    // Create new keystore with custom KDF parameters
    let kdf = KdfParams::default();
    let mut kn = Keynest::init_with_storage_and_kdf(password, storage, kdf)?;
    
    // Store secrets
    kn.set("api_token", "secret123")?;
    kn.save()?;
    
    // Later: reopen
    let kn = Keynest::open_with_storage(Zeroizing::new(String::from("my-password")), storage)?;
    assert_eq!(kn.get("api_token"), Some("secret123"));
    
    Ok(())
}

Storage Location

Default keystore locations by OS:

  • Linux: ~/.local/share/keynest/.keynest.db
  • macOS: ~/Library/Application Support/keynest/.keynest.db
  • Windows: %APPDATA%\keynest\.keynest.db

Use --store <path> to override.


Development

# Build
cargo build

# Test
cargo test

# Format
cargo fmt

# Lint
cargo clippy -- -D warnings

Star History

If you find Keynest useful, consider giving it a star ⭐


License

Licensed under either of:

at your option.

About

Simple, offline, cross-platform secrets manager written in Rust.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE_APACHE
MIT
LICENSE_MIT

Contributing

Security policy

Stars

10 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages