OpenCode + pass: injecting credentials without exposing them to the agent
OpenCode is an open-source AI coding agent that runs locally, and like every
agent it needs credentials to be useful: model API keys, registry tokens,
service accounts. The default is to export them into the environment or drop
a .env file in the project — which puts the plaintext values inside the
agent’s context window and hands them to every subprocess the agent spawns.
There’s a cleaner pattern, and it works with the password store you probably already have.
The environment variable trap
When you export ANTHROPIC_API_KEY=... or write a .env that OpenCode loads,
you’re not just giving the agent access — you’re giving access to everything
the agent touches:
- The agent’s context window (which gets summarized and sent to model APIs)
- Every subprocess it invokes (which inherits the full environment)
- Any tool that echoes or logs environment state
The blast radius is the entire session, not a single call.
The process-layer injection pattern
The alternative is to keep credentials in your existing pass store and
inject them at the moment a subprocess runs:
- The agent (or its tool wrapper) references a secret by name —
GITHUB_TOKEN,OPENAI_API_KEY, whatever the store calls it. - A broker resolves the value from
passand injects it into the subprocess environment — the child process gets the real value, the agent never does. - stdout and stderr are scrubbed after the run: raw values, base64 encodings, and URL-encoded variants of the key are redacted from anything the agent can see.
The agent can use every credential. It just can’t possess them.
Why pass is a good fit
pass (the standard unix password manager) is a plain file tree of
GPG-encrypted files — nothing exotic, no server, no proprietary vault
format. That makes it an easy backend for agent tooling: no migration, no
new storage, and the store stays fully under your control. If you’re already
on Bitwarden, the same broker pattern works there too.
The practical wrapper is a single binary that sits between the agent and its commands:
$ trustless run -s GITHUB_TOKEN -- gh pr create ...
The subprocess gets GITHUB_TOKEN injected; the output is sanitized; the
agent sees the result — never the value. For HTTP-based tools that need
headers or query parameters instead of environment variables, a local proxy
does the same injection per host.
Auditing what was accessed
One side benefit of routing credential access through a broker: every resolution lands in an append-only structured audit log. You get a record of which keys were resolved, when, and by which invocation — something environment variables can never give you.
trustless is a zero-dependency
credential broker CLI that implements exactly this pattern for OpenCode,
Claude Code, and other agents — 321 tests with -race, cosign-signed
releases with SBOM, and existing pass/Bitwarden backends with no migration.
Setup is a wizard (GPG → pass → .env import → agent config), and the
quick start walks through it.
The moment your agent’s environment stops containing plaintext keys, the biggest leak vector in the setup disappears. How does OpenCode get its credentials on your machine today?