commit fb38e970672dd26ad08b1ecacf58ca062dc595a1
parent 4af7181819438edfa77a94c3745eff1588ecf991
Author: Anders Hedman <anders.hedman01@gmail.com>
Date: Tue, 22 Sep 2026 15:26:32 +0200
chore(opencode): migrate config to V2 schema
Update opencode.jsonc to the V2 config format: providers, MCP servers,
plugins, agents, and the new ordered permission rules. Permission
semantics are preserved (secrets denied, read-only allows, mutating
commands ask).
Diffstat:
1 file changed, 166 insertions(+), 166 deletions(-)
diff --git a/.config/opencode/opencode.jsonc b/.config/opencode/opencode.jsonc
@@ -1,49 +1,57 @@
{
"$schema": "https://opencode.ai/config.json",
- "provider": {
+ "providers": {
"ollama": {
- "npm": "@ai-sdk/openai-compatible",
"name": "Ollama Local",
- "options": {
+ "package": "aisdk:@ai-sdk/openai-compatible",
+ "settings": {
"baseURL": "http://127.0.0.1:11434/v1"
},
"models": {
"gemma4:e2b": {
"name": "gemma4:e2b",
- "reasoning": true,
- "tool_call": true,
- },
+ "capabilities": {
+ "tools": true,
+ "input": ["text", "image"],
+ "output": ["text"]
+ }
+ }
}
- },
+ }
},
"mcp": {
- "gitlab": {
- "type": "remote",
- "url": "https://gitlab.com/api/v4/mcp",
- "enabled": false
- },
- "brewfather": {
- "type": "local",
- "command": ["uv", "run", "brewfather-mcp"],
- "cwd": "/home/anders/Repos/brewfather-mcp",
- "enabled": false,
- "timeout": 30000
+ "servers": {
+ "gitlab": {
+ "type": "remote",
+ "url": "https://gitlab.com/api/v4/mcp",
+ "disabled": true
+ },
+ "brewfather": {
+ "type": "local",
+ "command": ["uv", "run", "brewfather-mcp"],
+ "cwd": "/home/anders/Repos/brewfather-mcp",
+ "disabled": true,
+ "timeout": {
+ "catalog": 30000,
+ "execution": 30000
+ }
+ }
}
},
// oh-my-opencode
"lsp": true,
- "plugin": [
+ "plugins": [
"oh-my-opencode-slim"
],
- "agent": {
+ "agents": {
"explore": {
- "disable": true
+ "disabled": true
},
"general": {
- "disable": true
+ "disabled": true
},
// oh-my-opencode
@@ -53,156 +61,148 @@
"slim-shady": {
"description": "Slim prompt agent for general questions",
"mode": "primary",
- "prompt": "You are a helpful assistant",
- "tools": {
- "*": false
- }
+ "system": "You are a helpful assistant",
+ "permissions": [
+ { "action": "*", "resource": "*", "effect": "deny" }
+ ]
}
},
- "permission": {
+ // V2: ordered rules, last matching rule wins (broad first, exceptions after)
+ "permissions": [
// Read-only tools: ask for anything, but never touch .env / .envrc
- "read": {
- "*": "ask",
- "*.env": "deny",
- "*.envrc": "deny",
- "cloud.conf": "deny",
- "secret*": "deny",
- "terraform.tfstate*": "deny"
- },
- "glob": {
- "*": "ask",
- "*.env": "deny",
- "*.envrc": "deny",
- "cloud.conf": "deny",
- "secret*": "deny",
- "terraform.tfstate*": "deny"
- },
- "grep": {
- "*": "ask",
- "*.env": "deny",
- "*.envrc": "deny",
- "cloud.conf": "deny",
- "secret*": "deny",
- "terraform.tfstate*": "deny"
- },
- "list": "allow",
- "lsp": "allow",
- "task": "allow",
- "skill": "allow",
- "todowrite": "allow",
- "question": "allow",
- "webfetch": "allow",
- "websearch": "allow",
+ { "action": "read", "resource": "*", "effect": "ask" },
+ { "action": "read", "resource": "*.env", "effect": "deny" },
+ { "action": "read", "resource": "*.envrc", "effect": "deny" },
+ { "action": "read", "resource": "cloud.conf", "effect": "deny" },
+ { "action": "read", "resource": "secret*", "effect": "deny" },
+ { "action": "read", "resource": "terraform.tfstate*", "effect": "deny" },
- "edit": "ask",
+ { "action": "glob", "resource": "*", "effect": "ask" },
+ { "action": "glob", "resource": "*.env", "effect": "deny" },
+ { "action": "glob", "resource": "*.envrc", "effect": "deny" },
+ { "action": "glob", "resource": "cloud.conf", "effect": "deny" },
+ { "action": "glob", "resource": "secret*", "effect": "deny" },
+ { "action": "glob", "resource": "terraform.tfstate*", "effect": "deny" },
- "bash": {
- "*": "ask",
- // basic inspection
- "echo *": "ask",
- "ls*": "allow",
- "pwd*": "allow",
- "cat*": "allow",
- "head*": "allow",
- "tail*": "allow",
- "find*": "allow",
- "grep*": "allow",
- "rg*": "allow",
- "diff*": "allow",
- "file*": "allow",
- "which*": "allow",
- "command -v *": "allow",
- "wc*": "allow",
- "du*": "allow",
- "df*": "allow",
- "uname*": "allow",
- "sleep *": "allow",
- // read-only git
- "git status*": "allow",
- "git diff*": "allow",
- "git log*": "allow",
- "git grep*": "allow",
- "git show*": "allow",
- "git fetch*": "allow",
- "git branch*": "allow",
- "git remote*": "allow",
- "git stash list*": "allow",
- // test / check commands
- "npm test*": "allow",
- "npm run lint*": "allow",
- "npm run typecheck*": "allow",
- "cargo check*": "allow",
- "cargo test*": "allow",
- "go vet*": "allow",
- "go test*": "allow",
- "pytest*": "allow",
- "python3 -m pytest*": "allow",
- // mutating: always confirm (must come after any matching allow)
- "git add*": "ask",
- "git commit*": "ask",
- "git push*": "ask",
- "git reset*": "ask",
- "git checkout*": "ask",
- "git clean*": "ask",
- "git rebase*": "ask",
- "npm install*": "ask",
- "npm run build*": "ask",
- "cargo build*": "ask",
- "go build*": "ask",
- "pip install*": "ask",
- "terraform plan*": "ask",
- "terraform apply*": "ask",
- "docker*": "ask",
- "curl*": "ask",
- "wget*": "ask",
- "sudo*": "ask",
- "chmod*": "ask",
- "chown*": "ask",
- "cp*": "ask",
- "mv*": "ask",
- "mkdir*": "ask",
- "touch*": "ask",
- "rm *": "ask",
- // enivronment $VAR
- "printenv *": "deny",
- "env *": "deny",
- // .env / .envrc via shell
- "cat* .env*": "deny",
- "grep* .env*": "deny",
- "rg* .env*": "deny",
- "head* .env*": "deny",
- "tail* .env*": "deny",
- // terraform.tfstate
- "cat* terraform.tfstate*": "deny",
- "grep* terraform.tfstate*": "deny",
- "rg* terraform.tfstate*": "deny",
- "head* terraform.tfstate*": "deny",
- "tail* terraform.tfstate*": "deny",
- // Sops
- "sops*": "deny",
- // destructive: never auto-run (last rules win)
- "rm -rf*": "deny",
- "rm -fr*": "deny",
- "git push --force*": "deny",
- "shutdown*": "deny",
- "reboot*": "deny",
- "mkfs*": "deny",
- "dd *": "deny"
- },
+ { "action": "grep", "resource": "*", "effect": "ask" },
+ { "action": "grep", "resource": "*.env", "effect": "deny" },
+ { "action": "grep", "resource": "*.envrc", "effect": "deny" },
+ { "action": "grep", "resource": "cloud.conf", "effect": "deny" },
+ { "action": "grep", "resource": "secret*", "effect": "deny" },
+ { "action": "grep", "resource": "terraform.tfstate*", "effect": "deny" },
+
+ { "action": "subagent", "resource": "*", "effect": "allow" },
+ { "action": "skill", "resource": "*", "effect": "allow" },
+ { "action": "question", "resource": "*", "effect": "allow" },
+ { "action": "webfetch", "resource": "*", "effect": "allow" },
+ { "action": "websearch", "resource": "*", "effect": "allow" },
+
+ { "action": "edit", "resource": "*", "effect": "ask" },
+
+ // shell (was "bash" in V1)
+ { "action": "shell", "resource": "*", "effect": "ask" },
+ // basic inspection
+ { "action": "shell", "resource": "echo *", "effect": "ask" },
+ { "action": "shell", "resource": "ls*", "effect": "allow" },
+ { "action": "shell", "resource": "pwd*", "effect": "allow" },
+ { "action": "shell", "resource": "cat*", "effect": "allow" },
+ { "action": "shell", "resource": "head*", "effect": "allow" },
+ { "action": "shell", "resource": "tail*", "effect": "allow" },
+ { "action": "shell", "resource": "find*", "effect": "allow" },
+ { "action": "shell", "resource": "grep*", "effect": "allow" },
+ { "action": "shell", "resource": "rg*", "effect": "allow" },
+ { "action": "shell", "resource": "diff*", "effect": "allow" },
+ { "action": "shell", "resource": "file*", "effect": "allow" },
+ { "action": "shell", "resource": "which*", "effect": "allow" },
+ { "action": "shell", "resource": "command -v *", "effect": "allow" },
+ { "action": "shell", "resource": "wc*", "effect": "allow" },
+ { "action": "shell", "resource": "du*", "effect": "allow" },
+ { "action": "shell", "resource": "df*", "effect": "allow" },
+ { "action": "shell", "resource": "uname*", "effect": "allow" },
+ { "action": "shell", "resource": "sleep *", "effect": "allow" },
+ // read-only git
+ { "action": "shell", "resource": "git status*", "effect": "allow" },
+ { "action": "shell", "resource": "git diff*", "effect": "allow" },
+ { "action": "shell", "resource": "git log*", "effect": "allow" },
+ { "action": "shell", "resource": "git grep*", "effect": "allow" },
+ { "action": "shell", "resource": "git show*", "effect": "allow" },
+ { "action": "shell", "resource": "git fetch*", "effect": "allow" },
+ { "action": "shell", "resource": "git branch*", "effect": "allow" },
+ { "action": "shell", "resource": "git remote*", "effect": "allow" },
+ { "action": "shell", "resource": "git stash list*", "effect": "allow" },
+ // test / check commands
+ { "action": "shell", "resource": "npm test*", "effect": "allow" },
+ { "action": "shell", "resource": "npm run lint*", "effect": "allow" },
+ { "action": "shell", "resource": "npm run typecheck*", "effect": "allow" },
+ { "action": "shell", "resource": "cargo check*", "effect": "allow" },
+ { "action": "shell", "resource": "cargo test*", "effect": "allow" },
+ { "action": "shell", "resource": "go vet*", "effect": "allow" },
+ { "action": "shell", "resource": "go test*", "effect": "allow" },
+ { "action": "shell", "resource": "pytest*", "effect": "allow" },
+ { "action": "shell", "resource": "python3 -m pytest*", "effect": "allow" },
+ // mutating: always confirm (after the matching allows above)
+ { "action": "shell", "resource": "git add*", "effect": "ask" },
+ { "action": "shell", "resource": "git commit*", "effect": "ask" },
+ { "action": "shell", "resource": "git push*", "effect": "ask" },
+ { "action": "shell", "resource": "git reset*", "effect": "ask" },
+ { "action": "shell", "resource": "git checkout*", "effect": "ask" },
+ { "action": "shell", "resource": "git clean*", "effect": "ask" },
+ { "action": "shell", "resource": "git rebase*", "effect": "ask" },
+ { "action": "shell", "resource": "npm install*", "effect": "ask" },
+ { "action": "shell", "resource": "npm run build*", "effect": "ask" },
+ { "action": "shell", "resource": "cargo build*", "effect": "ask" },
+ { "action": "shell", "resource": "go build*", "effect": "ask" },
+ { "action": "shell", "resource": "pip install*", "effect": "ask" },
+ { "action": "shell", "resource": "terraform plan*", "effect": "ask" },
+ { "action": "shell", "resource": "terraform apply*", "effect": "ask" },
+ { "action": "shell", "resource": "docker*", "effect": "ask" },
+ { "action": "shell", "resource": "curl*", "effect": "ask" },
+ { "action": "shell", "resource": "wget*", "effect": "ask" },
+ { "action": "shell", "resource": "sudo*", "effect": "ask" },
+ { "action": "shell", "resource": "chmod*", "effect": "ask" },
+ { "action": "shell", "resource": "chown*", "effect": "ask" },
+ { "action": "shell", "resource": "cp*", "effect": "ask" },
+ { "action": "shell", "resource": "mv*", "effect": "ask" },
+ { "action": "shell", "resource": "mkdir*", "effect": "ask" },
+ { "action": "shell", "resource": "touch*", "effect": "ask" },
+ { "action": "shell", "resource": "rm *", "effect": "ask" },
+ // environment $VAR
+ { "action": "shell", "resource": "printenv *", "effect": "deny" },
+ { "action": "shell", "resource": "env *", "effect": "deny" },
+ // .env / .envrc via shell
+ { "action": "shell", "resource": "cat* .env*", "effect": "deny" },
+ { "action": "shell", "resource": "grep* .env*", "effect": "deny" },
+ { "action": "shell", "resource": "rg* .env*", "effect": "deny" },
+ { "action": "shell", "resource": "head* .env*", "effect": "deny" },
+ { "action": "shell", "resource": "tail* .env*", "effect": "deny" },
+ // terraform.tfstate
+ { "action": "shell", "resource": "cat* terraform.tfstate*", "effect": "deny" },
+ { "action": "shell", "resource": "grep* terraform.tfstate*", "effect": "deny" },
+ { "action": "shell", "resource": "rg* terraform.tfstate*", "effect": "deny" },
+ { "action": "shell", "resource": "head* terraform.tfstate*", "effect": "deny" },
+ { "action": "shell", "resource": "tail* terraform.tfstate*", "effect": "deny" },
+ // Sops
+ { "action": "shell", "resource": "sops*", "effect": "deny" },
+ // destructive: never auto-run (after the broader asks above)
+ { "action": "shell", "resource": "rm -rf*", "effect": "deny" },
+ { "action": "shell", "resource": "rm -fr*", "effect": "deny" },
+ { "action": "shell", "resource": "git push --force*", "effect": "deny" },
+ { "action": "shell", "resource": "shutdown*", "effect": "deny" },
+ { "action": "shell", "resource": "reboot*", "effect": "deny" },
+ { "action": "shell", "resource": "mkfs*", "effect": "deny" },
+ { "action": "shell", "resource": "dd *", "effect": "deny" },
// Files outside the workspace: confirm, but block secrets outright
- "external_directory": {
- "*": "ask",
- "/tmp/opencode/**": "allow",
- "~/.config/opencode/skills/**": "allow",
- "~/.aws/**": "deny",
- "~/.gnupg/**": "deny",
- "~/.kube/**": "deny",
- "~/.s3cfg*": "deny",
- "~/.ssh/**": "deny",
- "~/.vault_pass.txt*": "deny",
- "~/.vault-token*": "deny"
- }
- }
+ { "action": "external_directory", "resource": "*", "effect": "ask" },
+ { "action": "external_directory", "resource": "/tmp/opencode/*", "effect": "allow" },
+ { "action": "external_directory", "resource": "~/.config/opencode/skills/*", "effect": "allow" },
+ { "action": "external_directory", "resource": "~/.aws/*", "effect": "deny" },
+ { "action": "external_directory", "resource": "~/.gnupg/*", "effect": "deny" },
+ { "action": "external_directory", "resource": "~/.kube/*", "effect": "deny" },
+ { "action": "external_directory", "resource": "~/.s3cfg*", "effect": "deny" },
+ { "action": "external_directory", "resource": "~/.ssh/*", "effect": "deny" },
+ { "action": "external_directory", "resource": "~/.vault_pass.txt*", "effect": "deny" },
+ { "action": "external_directory", "resource": "~/.vault-token*", "effect": "deny" }
+ ]
}