claudepass

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 24, 2026 License: MIT

README

A secret manager for AI coding agents. Free and open source under the MIT license.

The problem

Developers working with AI coding agents constantly need the agent to run commands that require secrets — deploy scripts, API calls, database migrations, cloud CLIs — and today the only way to hand one over is to paste it into the conversation or point the agent at a .env file it can read. Either way the value enters the Agent's Context: it is sent to the model provider, written into transcripts and session logs, and can be echoed back in any tool result. ClaudePass lets an Agent use a Secret at the moment a command runs — injected by a local Broker into that one child process — without the value ever entering the Agent's Context at all.

Install

Elixion-ai/claudepass is a public repository on GitHub, open source under the MIT license (see ADR-0011). Built binaries are also published at claudepass.com, so installing needs no GitHub credentials either way.

curl:

curl -fsSL https://claudepass.com/install.sh | sh

Homebrew (from the owner's tap):

brew install softorize/tap/cpass

Go (1.26 or newer, builds from source):

go install github.com/Elixion-ai/claudepass/cmd/cpass@latest

The curl and Homebrew installers download a GoReleaser-built archive and its checksums.txt straight from claudepass.com (see deploy/ for how release binaries reach the site) and verify sha256 before installing. install.sh goes further still: it cross-checks that checksums.txt against the independent copy on the GitHub Release, and opportunistically verifies a cosign signature and a build-provenance attestation when cosign/gh are on PATH — see docs/SECURITY.md "Verifying a release" for the full chain and a manual verify recipe. The release pipeline that produces them is .goreleaser.yaml and .github/workflows/release.yml at the repo root — see CLA-16. The release archives carry the tagged version via GoReleaser's ldflags; a go install .../cmd/cpass@<tag> build gets no ldflags but reports the same real version, read back from the module version Go itself embeds in the binary's build info (cpass version falls back to runtime/debug.ReadBuildInfo whenever ldflags didn't set one) — only a plain local go build with no resolved module version reports dev.

60-second quickstart

Everything below is one continuous session in a project directory: an empty Vault, one Secret, a Manifest declaring it, the Claude Code integration, and a command that uses the Secret without ever printing it.

# 1. Create a Vault. CPASS_KEY (CI) or the platform's unlock source (macOS
#    Keychain, or a passphrase on Linux) supplies the encryption key — see
#    docs/SECURITY.md for exactly where that key lives.
cpass init

# 2. Store a Secret under a Handle. The value is typed at a hidden prompt —
#    cpass add refuses without a terminal, so an Agent can never pipe a
#    value it already knows straight into the Vault.
cpass add stripe/live

# 3. Declare the Handles this project needs. No values live in this file;
#    it's meant to be committed.
cpass manifest init
cpass manifest add stripe/live

# 4. Wire up Claude Code: an Intercept hook, a Command Policy hook, and a
#    skill teaching an Agent to use cpass. Idempotent — safe to re-run.
cpass integrate claude

# 5. Run the real command. cpass run reads the Manifest, injects stripe/live
#    as $STRIPE_LIVE into this one child process, and nothing else — swap
#    the sh -c '...' below for your actual deploy/curl/psql/gcloud command;
#    the Secret reaches it the same way, by reading its own environment.
cpass run -- sh -c '[ -n "$STRIPE_LIVE" ] && echo "deploy: authenticated"'

A real session looks like this:

$ cpass init
initialised vault at /Users/you/Library/Application Support/claudepass/vault.cpv

$ cpass add stripe/live
value for stripe/live: ************************
stored stripe/live (env STRIPE_LIVE)

$ cpass manifest init
created .claudepass.toml

$ cpass manifest add stripe/live
declared stripe/live in .claudepass.toml

$ cpass integrate claude
installed the ClaudePass plugin at /Users/you/.claude/skills/claudepass
registered hook: UserPromptSubmit -> cpass intercept
registered hook: PreToolUse (Bash) -> cpass policy --hook
registered skill: claudepass
it loads as claudepass@skills-dir on the next `claude` session (or run /reload-plugins in one already open)

$ cpass run -- sh -c '[ -n "$STRIPE_LIVE" ] && echo "deploy: authenticated"'
deploy: authenticated

The value of stripe/live was never typed into a command line, never appeared in this terminal's scrollback, and — because Claude Code's plugin is now installed — never gets past a paste into the Agent's prompt either. This exact sequence runs against a freshly built binary as part of this repo's own test suite (internal/e2e/docs_test.go), so it can't drift out of date with the CLI it documents.

Either integration undoes cleanly: cpass integrate claude --remove deletes the files it installed (the plugin directory too, if nothing else ended up inside it), and cpass integrate codex --remove deletes the delimited section it wrote from AGENTS.md — the whole file too, if nothing else was in it. Both only ever touch what cpass integrate itself wrote, and are safe to run again or on a machine where nothing was ever installed.

Handles, the Manifest, Capture, and Intercept

A Secret lives in your Vault under a Handle — an opaque name like stripe/live. That Handle, never the value, is the only form in which a Secret is ever visible to an Agent. A Handle carries a default Binding (an environment variable name, or a temp file) that says how the value should land in a command's process; a project's Manifest (.claudepass.toml, safe to commit — it contains no values) declares which Handles the project needs, so an Agent runs cpass run -- <command> once and gets everything the project was told about, with no guessing and no .env file for it to read.

When a command produces a brand-new value instead of consuming one — a migration prints a generated token, a CLI mints a key — cpass capture <handle> -- <command> stores its stdout straight into the Vault as a new Secret and prints only the Handle back, so a value born in a tool's output never reaches the Agent's Context either.

And when a human pastes a real value into the conversation by mistake, Claude Code's UserPromptSubmit hook runs cpass intercept: it moves the value into the Vault before the model ever sees the prompt and tells the human which Handle to resubmit with instead. If it does go through anyway (prefixed with !!, for a false positive), the Secret is stored flagged Exposed, so cpass exposed and a one-line reminder on every later cpass run keep nagging until it's rotated.

The Broker is the one place that ever holds a Secret's raw value: it resolves a Handle at the moment cpass run spawns your command and injects it into that one child process, nowhere else. Everything the command writes to stdout and stderr passes through Redaction on the way back, which replaces the value — and its base64, base32, hex, percent- and JSON-escaped forms — with [REDACTED:<handle>] before an Agent can read it; this is honest best-effort, not a guarantee, and docs/SECURITY.md says exactly what it does and doesn't catch. Command Policy refuses, before the command even starts, anything whose only real purpose is to reveal a Secret rather than use it: env, printenv, reading a .env file, and the like.

The Global Manifest

Some Handles belong to every project on a machine, not just one — a cloud CLI's key, a package registry token. cpass add stripe/live -g (or cpass global stripe/live to promote a Handle already stored) declares it in a Global Manifest at $CPASS_HOME/global.toml, in the same no-values format as a project's own .claudepass.toml. cpass run injects it into every project that has its own Manifest, unless the walk up to that Manifest crosses a nested repository's own .git (so a dependency cloned into vendor/ never sees it) or the project opted out with cpass manifest global off; a project's own Manifest entry for a Handle always wins over the Global one. cpass local <handle> stops declaring a Handle globally without touching the stored Secret, and a Global Handle that's since vanished from the Vault is skipped with a notice rather than failing the run, unlike a Handle the project declared itself.

Documentation

  • CONTEXT.md — the vocabulary this repo and this README use throughout (Secret, Handle, Agent, Broker, Context, Redaction, Command Policy, Vault, Binding, Manifest, Global Manifest, Capture, Intercept, Exposed).
  • docs/PRD.md — the product spec.
  • docs/adr/ — the design decisions and why alternatives were rejected.
  • docs/SECURITY.md — exactly what the Vault, the Broker, both hooks, cpass run, and Redaction do and touch, every CPASS_* environment variable, and the no-telemetry guarantee.
  • docs/THREATS.md — the threat model, what's deliberately out of scope, and the leak paths that honestly remain.
  • LICENSE — MIT.
  • CONTRIBUTING.md — how to build, test, and contribute.

Build from source

go build -o cpass ./cmd/cpass
go test -race -count=1 ./...

Directories

Path Synopsis
cmd
cpass command
Command cpass is the ClaudePass CLI: a secret manager for AI coding agents.
Command cpass is the ClaudePass CLI: a secret manager for AI coding agents.
internal
atomicfile
Package atomicfile writes a file so a reader — including a crash and restart, not just a concurrent process — only ever sees the old content in full or the new content in full, never a partial write.
Package atomicfile writes a file so a reader — including a crash and restart, not just a concurrent process — only ever sees the old content in full or the new content in full, never a partial write.
broker
Package broker resolves Handles into Secret values at the moment a command runs.
Package broker resolves Handles into Secret values at the moment a command runs.
cli
Package cli implements the cpass command line.
Package cli implements the cpass command line.
detect
Package detect finds Secret-shaped values in arbitrary text: known provider-key prefixes with an inferred Handle, generic PEM private-key blocks, and a entropy check over otherwise-unrecognised long tokens.
Package detect finds Secret-shaped values in arbitrary text: known provider-key prefixes with an inferred Handle, generic PEM private-key blocks, and a entropy check over otherwise-unrecognised long tokens.
dotenv
Package dotenv parses dotenv-syntax files (the format `cpass import` reads): KEY=VALUE lines, an optional "export " prefix, single- and double-quoted values, and comments.
Package dotenv parses dotenv-syntax files (the format `cpass import` reads): KEY=VALUE lines, an optional "export " prefix, single- and double-quoted values, and comments.
e2e/helper command
Command helper is the child process e2e tests run under cpass.
Command helper is the child process e2e tests run under cpass.
integrate
Package integrate holds the Agent instruction text shared by every integration target (Codex's AGENTS.md today; the Claude Code skill and the MCP server's own docs later) and the logic to write it into a delimited, idempotent section of a text file.
Package integrate holds the Agent instruction text shared by every integration target (Codex's AGENTS.md today; the Claude Code skill and the MCP server's own docs later) and the logic to write it into a delimited, idempotent section of a text file.
lockfile
Package lockfile provides a simple, blocking exclusive lock on a sidecar file, used to serialize the whole read-modify-write cycle around one of ClaudePass's on-disk stores (the Vault, the Global Manifest) across concurrent `cpass` processes.
Package lockfile provides a simple, blocking exclusive lock on a sidecar file, used to serialize the whole read-modify-write cycle around one of ClaudePass's on-disk stores (the Vault, the Global Manifest) across concurrent `cpass` processes.
manifest
Package manifest reads and writes the committed, per-project declaration of which Handles a project needs and their Bindings.
Package manifest reads and writes the committed, per-project declaration of which Handles a project needs and their Bindings.
mcp
Package mcp implements the ClaudePass MCP server: a minimal, hand-written JSON-RPC 2.0 server that speaks the Model Context Protocol over stdio, so a tool-first Agent without a shell can still go through the Broker.
Package mcp implements the ClaudePass MCP server: a minimal, hand-written JSON-RPC 2.0 server that speaks the Model Context Protocol over stdio, so a tool-first Agent without a shell can still go through the Broker.
policy
Package policy statically refuses the well-known ways a command an Agent wants to run would reveal a bound Secret or read a Secret-bearing file directly, modeling real shell syntax as far as that stays precise, and fails closed — refuses, not silently runs unchecked — on a shell-invocation shape it cannot parse (see docs/adr/0013).
Package policy statically refuses the well-known ways a command an Agent wants to run would reveal a bound Secret or read a Secret-bearing file directly, modeling real shell syntax as far as that stays precise, and fails closed — refuses, not silently runs unchecked — on a shell-invocation shape it cannot parse (see docs/adr/0013).
redact
Package redact replaces Secret values, in every recognisable encoding, with a marker in a byte stream before that stream can reach an Agent.
Package redact replaces Secret values, in every recognisable encoding, with a marker in a byte stream before that stream can reach an Agent.
run
Package run executes a command with Secrets injected by the Broker.
Package run executes a command with Secrets injected by the Broker.
vault
Package vault implements the encrypted local store where Secrets live.
Package vault implements the encrypted local store where Secrets live.
plugins
claude-code
Package pluginfiles embeds the Claude Code plugin's static files — .claude-plugin/plugin.json, hooks/hooks.json, skills/claudepass/SKILL.md — into the cpass binary, so `cpass integrate claude` can materialise them on disk regardless of how cpass itself was installed (a source checkout is not assumed to exist next to the binary).
Package pluginfiles embeds the Claude Code plugin's static files — .claude-plugin/plugin.json, hooks/hooks.json, skills/claudepass/SKILL.md — into the cpass binary, so `cpass integrate claude` can materialise them on disk regardless of how cpass itself was installed (a source checkout is not assumed to exist next to the binary).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL