Permissions, privacy and secret handling

Know exactly what leaves your machine, tune the command approval policy, and keep credentials out of prompts and transcripts.

What stays local and what does not

DataWhere it goesControl
Session historyLocal data directoryDelete it; never share links blindly
File contents and diffsThe model provider, as promptChoose a local provider to keep it in-house
CredentialsStored locally by the auth flowUse read-only and scoped keys
Share linkopencode.ai, if sharing is onSet share to manual or disabled
Snapshot historyLocal, alongside the projectTreat as source code
{
  "$schema": "https://opencode.ai/config.json",
  "share": "manual"
}
  • manual means a link is created only when you run /share. disabled removes the capability entirely.
  • A share link contains the conversation, which includes whichever file excerpts the agent read. Review it before sending it to anyone.
  • If your code cannot leave the network at all, the only configuration that satisfies that is a locally served model.

Approval policy

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "edit": "ask",
    "webfetch": "ask",
    "bash": {
      "*": "ask",
      "git status*": "allow",
      "git diff*": "allow",
      "git log*": "allow",
      "cat *": "allow",
      "rm -rf *": "deny",
      "git push*": "deny",
      "curl * | sh": "deny"
    }
  }
}
ValueMeaningUse for
allowRun without askingRead-only and reversible commands
askPrompt before runningAnything that changes state
denyRefuse entirelyDestructive or exfiltrating commands
⚠️
Permission patterns are matched against the whole command string, and a shell command can be written in many equivalent ways. A deny rule for rm -rf * does not stop find . -delete. Treat the policy as a guard rail that catches the common mistake, not as a security boundary - the real boundary is the credential the process holds.

Keeping secrets out of the conversation

  1. Do not paste keys into the prompt. Anything pasted is in the transcript, and the transcript is a file on disk.
  2. Point the agent at .env.example rather than .env, and name the variable it should read.
  3. Add secret paths to .gitignore and to your context file's prohibition list.
  4. Use environment variables for anything the tools need, so values are passed by the shell rather than written into a file the agent reads.
  5. Scope credentials to the narrowest role that works: read-only database users, tokens limited to one repository.
  6. Rotate immediately if a key does reach a transcript or a share link.
# AGENTS.md

## Never
- Never read or print .env, *.pem, secrets/* or anything matching *_key.
- Never commit a value that looks like a credential.
- If a task needs a secret, reference the environment variable name only.

That prohibition belongs in the context file, but only as a second line of defence. The first is not putting the value within reach of a process you have given shell access.

FAQ

Does OpenCode send my code anywhere by default?
The prompt itself - including the file excerpts the agent reads - goes to whichever model provider you configured. Session history and snapshots stay on your machine. If the code must not leave the network, run a local model and no remote provider at all.
Is a deny rule enough to protect a production database?
No. Command patterns are string matching, and there are many ways to express the same action. Protect the database with credentials and network policy - a read-only role and no route from the developer machine - and use deny rules only to prevent everyday mistakes.

MCP servers and custom tools Sessions, snapshots and undo

Last refreshed 2026-09-18.