Your agent doesn't need to see your secrets. s encrypts secrets with a password, injects them into subprocesses at runtime, and scrubs them from output. The agent orchestrates; s handles the secrets.
# Agent writes this:
s API_KEY -- curl -H "Authorization: Bearer $API_KEY" https://api.example.com
# Agent sees: response with [REDACTED] where the key was
# What ran: curl with the real key injecteds init # creates .senv, installs pre-commit hook
s set API_KEY # interactive (masked input: ****)
s set DB_URL --stdin # pipeds set <NAME> # add/update (interactive, masked)
s set <NAME> --stdin # add/update (piped)
s get <NAME> # show value (refuses without TTY)
s rm <NAME> # delete
s list # list names ([REDACTED] values)s API_KEY -- curl https://... # specific secrets
s API_KEY DB_URL -- ./deploy.sh # multiple secrets
s run ./deploy.sh # ALL secretsSecrets are injected as env vars. Output is scrubbed — any secret value replaced with [REDACTED].
s import .env # import from .env file
s import --stdin # import KEY=VALUE lines from stdin
s import --from-env # import all env vars
s import --from-env API_KEY # import specific env var
s export # export as KEY=VALUE (refuses without TTY)
s export --file .env # export to file (refuses without TTY)Last 2 versions kept automatically when you update a secret.
s history API_KEY # show versions
s rollback API_KEY --to 1 # restore previous versions scan # scan all git-tracked files
s scan --staged # scan only staged files (used by pre-commit hook)Checks actual secret values — no regex, no false positives.
s init installs a pre-commit hook that runs s scan --staged automatically.
The encryption password is resolved in order:
S_KEYenv var — the password directlyS_KEY="!command"— execute command (e.g.!security find-generic-password -s s-secrets -w)- TTY prompt — fallback if interactive
s getands exportrefuse without a TTY — prevents secrets leaking into agent contexts listonly shows names with[REDACTED]s run/s KEY -- cmdinject secrets but scrub all output- Pre-commit hook blocks committing leaked secret values
- Each secret is independently encrypted with ChaCha20-Poly1305
- Key derived via HKDF-SHA256 from your password + random per-value salt
.senvis safe to commit (only encrypted blobs)- No daemon, no network, no SSH keys, no keychain dependency
# Nix flake
nix profile install github:tobi/s
# Or build from source
cargo install --path .{
inputs.s.url = "github:tobi/s";
# in modules:
imports = [ inputs.s.homeModules.default ];
programs.s = {
enable = true;
passwordCommand = "security find-generic-password -s s-secrets -w"; # macOS
};
}