{ config, lib, pkgs, ... }: with lib; let cfg = config.coding.opencode; in { options.coding.opencode = { enable = mkEnableOption "opencode AI coding assistant"; agentsInput = mkOption { type = types.nullOr types.anything; default = null; description = '' The `agents` flake input (your personal AGENTS repo). When set, skills, context, commands, prompts and the agents.json are all symlinked from this input. ''; }; externalSkills = mkOption { type = types.listOf (types.submodule { options = { src = mkOption { type = types.anything; description = "Flake input pointing to a skills repository root."; }; skillsDir = mkOption { type = types.str; default = "skills"; description = '' Subdirectory inside src that contains skill folders. ''; }; selectSkills = mkOption { type = types.nullOr (types.listOf types.str); default = null; description = '' List of skill names to cherry-pick from this source. null means include every skill found in skillsDir. ''; }; }; }); default = []; description = '' External skill sources passed to mkOpencodeSkills. Each entry maps directly to an element of the externalSkills list accepted by the AGENTS flake's lib.mkOpencodeSkills. ''; example = literalExpression '' [ { src = inputs.skills-anthropic; selectSkills = [ "claude-api" ]; } { src = inputs.skills-vercel; } ] ''; }; ohMyOpencodeSettings = mkOption { type = types.attrs; default = {}; description = '' Attributes merged (via recursiveUpdate) on top of the default oh-my-opencode.json. Use this to set provider-specific model assignments per machine. ''; example = literalExpression '' { agents.sisyphus.model = "anthropic/claude-opus-4-5"; categories.ultrabrain.model = "anthropic/claude-opus-4-5"; } ''; }; extraSettings = mkOption { type = types.attrs; default = {}; description = '' Extra opencode settings merged (via mkMerge) into programs.opencode.settings. Use this to add provider configuration that is specific to a machine or organisation. ''; example = literalExpression '' { provider.anthropic = { name = "Anthropic"; models."claude-opus-4-5" = { limit.context = 200000; }; }; } ''; }; extraPlugins = mkOption { type = types.listOf types.str; default = []; description = '' Additional opencode plugins to add to the plugin list. Each entry is a path or package name passed to opencode's plugin array. ''; }; }; config = mkIf cfg.enable { # --- Skills (merged from personal AGENTS repo + optional external skills) --- xdg.configFile."opencode/skills" = mkIf (cfg.agentsInput != null) { source = cfg.agentsInput.lib.mkOpencodeSkills { inherit pkgs; customSkills = "${cfg.agentsInput}/skills"; externalSkills = map ( entry: {inherit (entry) src skillsDir;} // optionalAttrs (entry.selectSkills != null) {inherit (entry) selectSkills;} ) cfg.externalSkills; }; }; # --- Static config dirs from AGENTS repo --- xdg.configFile."opencode/context" = mkIf (cfg.agentsInput != null) { source = "${cfg.agentsInput}/context"; }; xdg.configFile."opencode/commands" = mkIf (cfg.agentsInput != null) { source = "${cfg.agentsInput}/commands"; }; xdg.configFile."opencode/prompts" = mkIf (cfg.agentsInput != null) { source = "${cfg.agentsInput}/prompts"; }; # --- Core opencode program settings --- programs.opencode = { enable = true; enableMcpIntegration = true; settings = mkMerge [ { theme = "opencode"; plugin = ["oh-my-opencode"] ++ cfg.extraPlugins; formatter = { alejandra = { command = ["alejandra" "-q" "-"]; extensions = [".nix"]; }; }; } # Load agents.json from AGENTS repo when available (mkIf (cfg.agentsInput != null) { agent = builtins.fromJSON (builtins.readFile "${cfg.agentsInput}/agents/agents.json"); }) # Machine/org-specific provider config cfg.extraSettings ]; }; # --- oh-my-opencode plugin config --- # Base defaults (no models — those must be set per machine via ohMyOpencodeSettings) home.file.".config/opencode/oh-my-opencode.json".text = builtins.toJSON ( recursiveUpdate { "$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json"; google_auth = false; disabled_mcps = ["context7" "websearch"]; } cfg.ohMyOpencodeSettings ); }; }