Self-hosted coding agents: secret hygiene for your own infrastructure
Self-hosted coding agents — opencode, Claude Code, and their peers — are attractive precisely because everything stays on your machine: your code, your model access, your data. The flip side is that the secrets are yours to protect. There is no managed SaaS boundary between the agent and your API keys; they sit in the same home directory, on the same disk, under the same user.
Where secrets accumulate
Before fixing anything, find the hiding places:
.envfiles in repos and home directories — the classic, and still the most common.- Agent config files — API keys in
config.yaml,auth.json, and the~/.configtrees of whatever agent you run. - Shell rc files and exported variables — keys that every interactive session inherits.
- Git history and backups — committed secrets, tarballs, and editor session files that outlive the config that contained them.
- Agent context and transcripts — session logs where a key was once printed and never scrubbed.
The hygiene baseline
A workable checklist for a self-hosted agent machine:
- Get secrets out of the agent’s context. Agents should reference credentials by name; values get resolved at execution time, never pasted into prompts.
- Import existing
.envfiles safely. A setup wizard should scan the usual directories, parseKEY=VALUElines, and back up the originals before touching them — importing is not a destructive migration. - Move values into a real store.
pass(GPG-encrypted files) or Bitwarden both work; the store you already have is the right one, because there is no new vault format to learn and no migration to run. - Inject at spawn, not into the prompt. The command gets its secrets as environment variables at start, and its output is sanitized so values cannot leak back into agent-visible logs.
- Scrub what already leaked. Database-backed stores and SQLite files need deliberate erasure: redact known values and secret-shaped patterns, dry-run first, back up before applying, and rebuild indexes afterward — a plain delete does not erase.
- Verify the whole setup. A health check should cover GPG key validity,
store health, the agent daemon, leftover
.envscans, and proxy certificate state, with machine-readable output for automation.
Verify, don’t assume
Hygiene decays silently: a GPG key expires, gpg-agent stops responding, a
new tool writes a fresh .env file, a config edit disables the proxy. Run
the health check after every change, not just at setup time. --json output
matters here — “agent integration: ok” should be a fact your monitoring can
consume, not a feeling you have on a good day.
The same goes for the import step: an importer that scans directories for key-value pairs is only safe if it proves it backed up the originals and skips anything ambiguous.
The payoff
Good hygiene turns your self-hosted agent from “my keys live wherever the agent happened to put them” into “keys live in one store, reach the agent as injected environment variables, and leave a trace when accessed.” That is the difference between an incident you can explain and one you discover by invoice.
trustless is a zero-dependency Go
CLI built around this checklist: a setup wizard that imports .env files
with backups, a doctor command that verifies GPG, store health, agent
integration, and leftover .env files with --json and --fix, and
dry-run-first scrubbing for databases. The command reference is in the
docs.
When did you last verify that your agent’s environment is free of plaintext keys — and can you prove it with a command?