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
| Data | Where it goes | Control |
|---|---|---|
| Session history | Local data directory | Delete it; never share links blindly |
| File contents and diffs | The model provider, as prompt | Choose a local provider to keep it in-house |
| Credentials | Stored locally by the auth flow | Use read-only and scoped keys |
| Share link | opencode.ai, if sharing is on | Set share to manual or disabled |
| Snapshot history | Local, alongside the project | Treat as source code |
{
"$schema": "https://opencode.ai/config.json",
"share": "manual"
}manualmeans a link is created only when you run/share.disabledremoves 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"
}
}
}| Value | Meaning | Use for |
|---|---|---|
allow | Run without asking | Read-only and reversible commands |
ask | Prompt before running | Anything that changes state |
deny | Refuse entirely | Destructive 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
- Do not paste keys into the prompt. Anything pasted is in the transcript, and the transcript is a file on disk.
- Point the agent at
.env.examplerather than.env, and name the variable it should read. - Add secret paths to
.gitignoreand to your context file's prohibition list. - Use environment variables for anything the tools need, so values are passed by the shell rather than written into a file the agent reads.
- Scope credentials to the narrowest role that works: read-only database users, tokens limited to one repository.
- 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.
Related
MCP servers and custom tools Sessions, snapshots and undo
Last refreshed 2026-09-18.