granith
granith(1)

Secrets you decrypt locally, rotate from your shell, audit on the same wire.

A zero-knowledge config vault and a small Go CLI. The server stores ciphertext; your CLI does the rest.

~  ·  zsh  ·  granith run
$ go install github.com/granith/granith/cmd/granith@latest
$ export GRANITH_SERVER=https://api.granith.dev
$ export GRANITH_TOKEN=grnth_kQ8…7P.4xVm…Yz
$ granith run -- node server.js
 fetched bundle · 3 secrets · 142 bytes · etag d4f1…
 decrypted in 11ms · running command
listening on :3000
what just happened

The CLI fetched a ciphertext bundle, unwrapped the project key locally with the token, decrypted in process memory, and exec'd your command with the values as env vars. The server returned bytes; it never held a key that could read them.

subsequent polls cost nothing
$ curl -sI -H 'if-none-match: "d4f1…"' \
    -H "authorization: bearer $GRANITH_TOKEN" \
    https://api.granith.dev/api/v1/bundle
HTTP/2 304
audit

One row per bundle fetch. No secret names, no values, no labels. Enough to spot a stolen token; not enough to leak which secret your process touches when.

{
  "ts":          "2026-05-15T09:42:11Z",
  "actor_id":    "tok_d8e2…",
  "action":      "bundle.fetch",
  "ip":          "203.0.113.42",
  "user_agent":  "granith-go/0.5.0"
}
getting in

Invite-only, beta, single-user.

The internal security review is still open. We'd rather have a small honest beta than a big dishonest launch.