GUIDE · COMPARISON 9 min ·

SOPS for solo devs in 2026What it handles well. Where it breaks.

SOPS solves the 'secrets in git' problem for IaC repos. It does not solve the 'AI agent reads your decrypted file' problem. Those are different problems.

TL;DR· the answer, in twenty seconds

What: SOPS encrypts YAML, JSON, and dotenv files in place and lets them commit to git safely. The standard decrypt command writes a plaintext file to disk. Any AI coding agent running in that repo can read it, and some agents persist environment state to their own config files.

Better approach: Use sops exec-env secrets.enc 'your-command' to inject secrets as environment variables into a specific child process only. Avoid sops -d file > plaintext entirely in repos where an agent runs.

Lesson: Encryption at rest protects secrets in storage. It does not protect them after decryption. The moment a plaintext file lands on disk in an agent's working tree, the encryption did its job and the problem shifted.

SOPS is good software in the wrong job. For GitOps pipelines, Kubernetes manifests, and Terraform configs, it handles a real problem cleanly: secrets commit to the repo encrypted, decrypt only where infrastructure tooling needs them, and the git history stays audit-friendly.

For a solo developer whose workflow now includes an AI coding agent, there is a gap in the standard SOPS tutorial that the documentation does not flag. The gap is not a bug. It is what happens when a tool designed for IaC pipelines meets a process that reads files from your working directory and sometimes writes context back to disk.

Mozilla transferred the project in 2023. It lives at getsops/sops on GitHub now, maintained by community contributors. The tool itself has not changed fundamentally. The reason to reconsider the solo-dev workflow has nothing to do with the fork. It is the agent sitting in your repo that changed the picture.

If you are evaluating SOPS right now, the question is not whether to use it. The question is whether your usage pattern decrypts to a file that the agent can reach. That distinction matters more in 2026 than it did when most SOPS tutorials were written.

What to know in 60 seconds

  • SOPS encrypts YAML, JSON, and ENV files in place. The file structure stays readable; only the values encrypt. Commits land encrypted in git. That part works.
  • The standard decrypt command is sops -d secrets.enc > secrets.txt. This writes a plaintext file to your working directory. Your AI coding agent can read that file.
  • Knostic disclosed in February 2026 that Claude Code's settings.local.json captures environment variables from agent sessions. A plaintext file on disk is worse than env vars: it persists across sessions and sits in the repo tree.
  • sops exec-env is a narrower option. It injects decrypted values as environment variables into one child process and cleans up. The child process is still the agent, so the agent still sees the values, but nothing lands on disk.
  • age is the right encryption backend for solo use in 2026. No keyserver. No web-of-trust. One key file. GPG still works but adds friction with no benefit for a single-operator setup.

What SOPS actually does well

SOPS encrypts individual values inside structured files, not the whole file. A YAML secret file encrypted with SOPS still has readable keys. Only the values are ciphertext. That design decision means diffs stay useful, merge conflicts stay resolvable, and the file is still parseable as YAML without decryption.

# Committed to git. Readable structure, encrypted values.
database_url: ENC[AES256_GCM,data:...,tag:...,type:str]
stripe_key: ENC[AES256_GCM,data:...,tag:...,type:str]
sops:
    age:
        - recipient: age1ql3z...
    lastmodified: '2026-03-18T14:22:01Z'
    version: 3.9.1

This is better than the alternative of keeping a plaintext .env in git with an entry in .gitignore that occasionally misses. GitGuardian's 2026 State of Secrets Sprawl found that AI-assisted commits leak secrets at roughly twice the baseline rate. A misfire on .gitignore with an agent writing files is a realistic failure mode.

SOPS supports multiple KMS backends: age, GPG, AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault. For a solo developer, age covers the whole use case. Generate a key once with age-keygen, store the private key outside the repo, reference the public key in .sops.yaml. Done.

age-keygen -o ~/.config/sops/age/keys.txt
# prints: Public key: age1ql3z...
# .sops.yaml at repo root
creation_rules:
  - path_regex: secrets\.enc\.yaml$
    age: age1ql3z...

For IaC repos, Terraform workspaces, and Kubernetes manifests, this workflow is close to ideal. The secret values never appear unencrypted in git history. Rotation means re-encrypting with a new key. Access control is the key file.

The decrypt-to-file trap

The standard SOPS tutorial ends with:

sops -d secrets.enc.yaml > secrets.yaml

or for dotenv files:

sops -d .env.enc > .env

Both of these write a plaintext file to your repo working directory. If you have a .gitignore entry for .env, the file will not commit. But it sits on disk, readable by any process running in that directory.

An AI coding agent running in the same directory reads files. That is the feature. The agent indexes your project, reads configs, traverses directories. A plaintext .env in the working tree is not hidden from it; there is no mechanism to hide it. The agent reads it.

The Knostic February 2026 disclosure showed one downstream consequence: Claude Code's settings.local.json persisted environment variables from agent sessions. A plaintext file on disk is a more direct exposure than env vars, because the file persists after the session ends and sits inside the directory the agent treats as project context. GitGuardian's 2026 State of Secrets Sprawl reported that AI-assisted commits leak secrets at roughly twice the baseline rate. A plaintext secrets file in the working tree is an obvious contributor to that pattern.

The outcome is: you encrypted secrets in git, so they are safe in git, and then you decrypted them to disk for one command, and now the agent has them and may have written something containing them to .claude/settings.local.json.

This is not a SOPS bug. The tool did what you told it to do. The problem is that "decrypt to a file" and "run an AI agent in the same directory" are now commonly combined in a workflow that was designed when agents were not part of the picture.

sops exec-env is better, not fixed

SOPS includes a subcommand that avoids writing a file:

sops exec-env .env.enc 'echo $DATABASE_URL'

exec-env decrypts the values, injects them as environment variables into the named child process, and cleans up when the process exits. Nothing writes to disk. If the child process crashes, the env vars die with it.

This is better. The values never appear as a file in your repo tree.

The catch: if the child process is your AI coding agent, the agent still receives the values as environment variables. The agent runs with a full environment that includes your secrets for the duration of the session. The Knostic disclosure showed that environment variables from agent sessions can land in persisted state. exec-env narrows the window. It does not close the exposure.

# Better than redirect to file. Still gives the agent the values.
sops exec-env .env.enc 'claude code'

For non-agent workflows, exec-env is the right approach. For agents specifically, the question is whether the agent needs the values at all, or whether a reference to a named secret would serve the same purpose.

age vs. GPG: stop using GPG for this

GPG works with SOPS. It has worked for years. For a solo developer in 2026, it adds friction with no benefit.

GPG requires a keyring, a key ID, and optional interaction with a keyserver. Key expiry, subkey management, and trust levels become things you configure. If you use GPG across multiple machines, you export and import keys. If you lose the key, you revoke it on the keyserver.

age is none of that. One key file. One public key string. No keyserver. No web-of-trust. Keys do not expire by default. The cryptography is modern (X25519 key exchange, ChaCha20-Poly1305 for encryption).

# age: generate once, store the file, done
age-keygen -o ~/.config/sops/age/keys.txt

# GPG: generate, list, find the key ID, update .sops.yaml, hope it matches
gpg --gen-key
gpg --list-secret-keys --keyid-format=long

The SOPS_AGE_KEY_FILE environment variable points SOPS at the key file. Set it once in your shell profile (pointing to a path outside any repo) and SOPS finds it automatically. For multiple machines, copy the key file. For team use, each person generates their own key and you list multiple recipients in .sops.yaml.

Use age. The GPG path still works, but the complexity has no upside at solo scale.

SOPS is fine. The plaintext file you decrypt to is the problem.

The framing that "SOPS is risky for AI agent workflows" is imprecise. SOPS encrypts files and manages key material well. The risk is in how most tutorials instruct you to use SOPS: decrypt to a file, use the file, remember to delete it.

That pattern predates AI coding agents. It was always a weaker approach than injecting values directly into the process that needs them. Agents made it worse by adding a reader that systematically traverses your working directory and may persist what it finds.

The same critique applies to any tool that writes plaintext to disk as an intermediate step. .env files loaded by dotenv packages, credential files written by AWS CLI, kubeconfig files with embedded tokens. The pattern is: encrypted or protected at rest, plaintext as a working copy, exposed to anything that reads the filesystem.

SOPS with exec-env sidesteps the file problem for the command-line case. For agent sessions that run for an hour and need access to multiple secrets across many tool calls, exec-env wrapping the entire agent session is a coarser instrument than injecting only what a specific operation needs.

Checklist: using SOPS safely in an AI-agent repo

## SOPS + AI agent safety audit

- [ ] No sops -d ... > plaintext commands in Makefiles, scripts, or shell history
- [ ] .env, secrets.yaml, and any decrypted output paths in .gitignore AND .dockerignore
- [ ] sops exec-env used instead of redirect where possible
- [ ] Agent sessions do not run with SOPS_AGE_KEY_FILE or GPG keys in the inherited environment (or at minimum, these are scoped to the session only)
- [ ] .claude/, .cursor/, .codex/ in .gitignore (agent state files should not enter the repo)
- [ ] git log --all -- '*.env' '*.yaml' clean for unencrypted secret files
- [ ] grep -r 'sops -d' . returns only exec-env or pipe-to-process calls, no redirect-to-file calls
- [ ] age key file stored outside every repo (e.g., ~/.config/sops/age/keys.txt)
- [ ] .sops.yaml committed, private keys never committed
- [ ] For IaC use (Terraform, K8s manifests): no change needed, proceed normally

What this means for your stack

SOPS does what it says: secrets commit to git encrypted, decrypt only where needed, multiple backends give you flexibility as you grow. For IaC repos without an AI agent in the loop, the workflow is sound. The gap shows up when an agent runs in the same directory where decrypted files land, and when agent tooling persists environment state to disk (as Knostic documented with Claude Code's settings.local.json in February 2026).

The category problem is that encryption at rest and runtime secret delivery are separate concerns. SOPS handles the first. Delivering secrets to a specific process at exec time, without writing to disk and without exposing them to adjacent processes, is the second. Most solo dev setups conflate the two by writing a plaintext file as the delivery mechanism.

hasp is one working implementation of the runtime side. curl -fsSL https://gethasp.com/install.sh | sh, hasp setup, connect a project, and the agent receives a reference instead of the raw value. Source-available (FCL-1.0), local-first, macOS and Linux, no account.

The durable takeaway is not tool-specific: keep encrypted at rest and delivered at runtime as separate layers. SOPS can own the first. Something else needs to own the second, especially once an agent can read your working directory.

Sources· cited above, in one place

NEXT STEP~90 seconds

Stop handing the agent your real keys.

hasp keeps secrets in one local encrypted vault, brokers them into the child process at exec, and never lets the agent read the value.

  • Local, encrypted vault — no account, no cloud, no telemetry by default.
  • Brokered run — agent gets a reference, the child process gets the value.
  • Pre-commit + pre-push hooks catch managed values before they ship.
  • Append-only HMAC audit log answers "did the agent touch the prod token?" in seconds.
→ okvault unlocked · binding ./api
→ okgrant once · pid 88421
→ okagent never read

macOS & Linux. Source-available (FCL-1.0, converts to Apache 2.0). No account.

Browse all clusters· eight threads, one index