{ inputs, lib, ... }: { coding.agents.opencode = { enable = true; agentsInput = inputs.agents; }; coding.opencode = { enable = true; ohMyOpencodeSettings = { agents = { sisyphus.model = "litellm/claude-opus-4-6"; oracle.model = "litellm/claude-sonnet-4-6"; librarian.model = "litellm/claude-sonnet-4-6"; explore.model = "litellm/claude-haiku-4-5"; multimodal-looker.model = "litellm/gpt-5.3-codex"; prometheus.model = "litellm/claude-opus-4-6"; metis.model = "litellm/claude-opus-4-6"; momus.model = "litellm/claude-opus-4-6"; atlas.model = "litellm/claude-sonnet-4-6"; }; categories = { visual-engineering.model = "zai-coding-plan/glm-5.1"; ultrabrain.model = "litellm/claude-opus-4-6"; deep.model = "litellm/claude-sonnet-4-6"; artistry.model = "zai-coding-plan/glm-5.1"; quick.model = "litellm/claude-haiku-4-5"; unspecified-low.model = "litellm/claude-sonnet-4-6"; unspecified-high.model = "litellm/claude-opus-4-6"; writing.model = "zai-coding-plan/glm-5.1"; }; }; }; # Keep TUI settings in programs.opencode.tui to satisfy OpenCode v1.2.15+. programs.opencode.tui.theme = "opencode"; # Override legacy default settings to avoid deprecated TUI keys in settings. programs.opencode.settings = lib.mkForce { plugin = ["oh-my-openagent"]; formatter = { alejandra = { command = ["alejandra" "-q" "-"]; extensions = [".nix"]; }; }; # Security: permission hardening for OpenCode # Last matching rule wins. Glob patterns: * = any chars, ? = single char. # ~ and $HOME are expanded to the user's home directory. # external_directory gates paths outside the working directory. permission = { # External directory access: ask by default, allow safe paths "external_directory" = { "*" = "ask"; "/nix/store/**" = "allow"; "/tmp/**" = "allow"; }; # Read access: allow by default, deny sensitive paths "read" = { "*" = "allow"; "~/.ssh/**" = "deny"; "~/.gnupg/**" = "deny"; "~/.aws/**" = "deny"; "~/.kube/**" = "deny"; "~/.config/gh/**" = "deny"; "~/.config/gcloud/**" = "deny"; "~/.config/op/**" = "deny"; "~/.config/sops/**" = "deny"; "/run/agenix/**" = "deny"; "~/.pi/agent/auth.json" = "deny"; "~/.pi/agent/sessions/**" = "deny"; "*.env" = "deny"; "*.env.*" = "deny"; "*.pem" = "deny"; "*.key" = "deny"; "*.p12" = "deny"; "*.pfx" = "deny"; "*id_rsa*" = "deny"; "*id_ed25519*" = "deny"; "*id_ecdsa*" = "deny"; "*.example.env" = "allow"; "*.sample.env" = "allow"; "*.test.env" = "allow"; ".env.example" = "allow"; ".env.sample" = "allow"; ".env.test" = "allow"; "~/.ssh/*.pub" = "allow"; "*.pub" = "allow"; "*.csr" = "allow"; }; # Edit access: ask by default, deny sensitive paths "edit" = { "*" = "ask"; "~/.ssh/**" = "deny"; "~/.gnupg/**" = "deny"; "~/.aws/**" = "deny"; "~/.kube/**" = "deny"; "~/.config/gh/**" = "deny"; "~/.config/gcloud/**" = "deny"; "~/.config/op/**" = "deny"; "~/.config/sops/**" = "deny"; "/run/agenix/**" = "deny"; "~/.pi/agent/auth.json" = "deny"; "~/.pi/agent/sessions/**" = "deny"; "*.env" = "deny"; "*.env.*" = "deny"; "*.pem" = "deny"; "*.key" = "deny"; "*.p12" = "deny"; "*.pfx" = "deny"; "*id_rsa*" = "deny"; "*id_ed25519*" = "deny"; "*id_ecdsa*" = "deny"; "~/.ssh/*.pub" = "allow"; "*.pub" = "allow"; "*.csr" = "allow"; }; # Glob patterns: same rules as read for file matching "glob" = { "*" = "allow"; "~/.ssh/**" = "deny"; "~/.gnupg/**" = "deny"; "/run/agenix/**" = "deny"; "*.env" = "deny"; "*.env.*" = "deny"; "*.pem" = "deny"; "*.key" = "deny"; "*.p12" = "deny"; "*.pfx" = "deny"; }; # Grep: allow search, but deny searching for secrets "grep" = { "*" = "allow"; "~/.ssh/**" = "deny"; "~/.gnupg/**" = "deny"; "/run/agenix/**" = "deny"; "*PASSWORD*" = "ask"; "*SECRET*" = "ask"; "*API_KEY*" = "ask"; "*PRIVATE_KEY*" = "ask"; }; # Bash: ask by default, deny dangerous and env-leak commands "bash" = { "*" = "ask"; "git status*" = "allow"; "git diff*" = "allow"; "git log*" = "allow"; "git branch*" = "allow"; "git show*" = "allow"; "git remote*" = "allow"; "nix --version" = "allow"; "nix eval*" = "allow"; "nix build*" = "allow"; "nix develop*" = "allow"; "nix shell*" = "allow"; "nix search*" = "allow"; "alejandra*" = "allow"; "git add*" = "allow"; "git commit*" = "allow"; "git push*" = "ask"; "git pull*" = "allow"; "rm *" = "ask"; "rm -rf *" = "deny"; "sudo *" = "ask"; "env" = "deny"; "printenv" = "deny"; "cat /proc/*/environ" = "deny"; "gpg *--export-secret*" = "deny"; "ssh-add -D" = "deny"; "docker run --privileged*" = "deny"; "curl *| *sh" = "deny"; "wget *| *sh" = "deny"; }; # Web fetch: ask for sensitive URLs "webfetch" = { "*" = "ask"; "https://api.github.com*" = "allow"; "https://search.nixos.org*" = "allow"; }; # Doom loop guard "doom_loop" = "ask"; }; # AZ-Gruppe LiteLLM endpoint + available models provider = { litellm = { npm = "@ai-sdk/openai-compatible"; name = "LiteLLM (AZ-Gruppe)"; options.baseURL = "https://llm.az-gruppe.com/v1"; models = { "gpt-5.2" = { name = "GPT-5.2"; limit = { context = 400000; output = 128000; }; }; "gpt-5.3-codex" = { name = "GPT-5.3 Codex"; limit = { context = 400000; output = 128000; }; }; "claude-haiku-4-5" = { name = "Claude Haiku 4.5"; options = { thinking = { type = "enabled"; budget_tokens = 16000; }; }; limit = { context = 200000; output = 64000; }; }; "claude-sonnet-4-6" = { name = "Claude Sonnet 4.6"; options = { thinking = { type = "enabled"; budget_tokens = 16000; }; }; limit = { context = 200000; output = 64000; }; }; "claude-opus-4-6" = { name = "Claude Opus 4.6"; options = { thinking = { type = "enabled"; budget_tokens = 16000; }; }; limit = { context = 200000; output = 128000; }; }; }; }; }; }; }