OpenCode config security: agents.yaml and environment

The file that configures your coding agent is the least reviewed piece of security infrastructure on your machine. In OpenCode and similar coding CLIs, agent definitions in YAML — often agents.yaml — decide which model runs, which tools are available, which commands can execute, and which environment variables the agent inherits. That file is a trust boundary, and most people edit it once, commit it, and never look at it again.

What an agent definition controls

A typical agent definition bundles several decisions into one place:

  • Model selection. Which provider and model the agent uses for a session.
  • Tools and permissions. Which built-in tools the agent may call and with what arguments.
  • Environment. Variables made visible to the agent and to every subprocess it spawns.
  • MCP servers and external tools. Which servers the agent can reach and what credentials they use.
  • Commands. Shortcuts that expand into arbitrary shell commands.

The environment block is the part that deserves the most suspicion. Any value you put there is visible to the model, inherited by every subprocess, and one verbose error message away from appearing in tool output.

Why environment inheritance leaks

Coding agents pass their environment to the commands they run. A key in the agent definition becomes a key in the shell, in the test runner, in the debugger. Tool output that echoes the environment — env, build logs, failing connection strings — surfaces it again, this time inside the conversation, where a model can summarize and transmit it. Even values that never print can end up in the context window through tool descriptions or error handling.

Patterns that hold up

Never put values in YAML. Agent definitions should reference credentials by name, not contain them. If the file holds a key, the key travels with the repo, appears in diffs, and is readable by anyone who forks it.

Control environment inheritance. Define the smallest environment the agent needs. Prefer injecting credentials at process start over declaring them in the definition, so the file stays a manifest of names, not a vault.

Scope tools to the task. An agent that only formats code does not need file-write access across the repository. Keep tool grants narrow and review them whenever the definition changes.

Treat the definition as code. Version it, review diffs, and keep it out of the “it works, ship it” path. A one-line change that adds a broad tool grant is a security change and should be reviewed like one.

Pin what you can. Pinning model and tool versions makes behavior reproducible and reviewable. Unpinned configurations change behavior silently between sessions.

The environment is the delivery mechanism

Agent definitions are convenient precisely because they bundle model, tools, and environment into one place. That same bundling means a single careless entry can put a production credential into every session. The discipline is mechanical: the definition names the secret, the secret lives elsewhere, and the agent receives the value only at run time.

A credential broker such as trustless implements exactly that split — it reads credentials from your existing pass or Bitwarden store and injects them into subprocess environments while scrubbing them from output, so agents.yaml never has to hold a value. The command reference is in the documentation.

If your agent definition file were posted to a public repository today, what would it give away?