{ config, lib, pkgs, ... }: with lib; let cfg = config.programs.andrew-opencode; peonPingPkg = pkgs.peon-ping; agentcraft = pkgs.callPackage ./agentcraft.nix { }; opencodeGitlabPlugin = pkgs.callPackage ./opencode-gitlab-plugin.nix { }; ohMyOpencodeSlim = pkgs.callPackage ./oh-my-opencode-slim.nix { }; opencodeForgeSessionTitle = pkgs.callPackage ./opencode-forge-session-title.nix { }; ohMyOpencode = pkgs.callPackage ./oh-my-opencode.nix { }; openpeonDota2 = pkgs.fetchFromGitHub { owner = "kmelkon"; repo = "openpeon-dota2"; rev = "main"; hash = "sha256-21BZ+pp3N23bIaeo7EripcgilmAlz1k77GrN7sJEFns="; }; superpowers = pkgs.fetchFromGitHub { owner = "obra"; repo = "superpowers"; rev = "363923f74aa9cd7b470c0aaa73dee629a8bfdc90"; hash = "sha256-AyRGXwWI9xHGeHw9vD64cnV19txR/lOtxudcHnbV75I="; }; compoundEngineering = pkgs.fetchFromGitHub { owner = "EveryInc"; repo = "compound-engineering-plugin"; rev = "74fb71731a14485b30b8549c93ff3732b5723179"; hash = "sha256-rvPC6NWG1vZG3OFpor84wkYuAZCtLyoYtU6q1deQl1c="; }; compoundEngineeringPatched = pkgs.runCommand "compound-engineering-patched" { nativeBuildInputs = [ pkgs.gnused pkgs.findutils ]; } '' cp -r ${compoundEngineering}/. $out chmod -R u+w $out # Patch invalid color values, remove model: inherit, and fix haiku model reference find $out/plugins/compound-engineering/agents -name "*.md" -type f -exec sed -i \ -e 's/^[[:space:]]*color:[[:space:]]*blue[[:space:]]*$/color: info/' \ -e 's/^[[:space:]]*color:[[:space:]]*yellow[[:space:]]*$/color: warning/' \ -e 's/^[[:space:]]*color:[[:space:]]*cyan[[:space:]]*$/color: info/' \ -e 's/^[[:space:]]*color:[[:space:]]*purple[[:space:]]*$/color: accent/' \ -e 's/^[[:space:]]*color:[[:space:]]*violet[[:space:]]*$/color: accent/' \ -e '/^[[:space:]]*model:[[:space:]]*inherit[[:space:]]*$/d' \ -e 's/^model:[[:space:]]*haiku[[:space:]]*$/model: gitlab\/duo-chat-haiku-4-5/' \ {} + ''; cePlugin = "${compoundEngineeringPatched}/plugins/compound-engineering"; gitlabSkills = builtins.fetchGit { url = "https://gitlab.com/gitlab-org/ai/skills.git"; rev = "3c2877076d453dfa1a3ea392e1293473dcae2cd2"; narHash = "sha256-mHdoOS/LzaSyuCvTIzxjJiABXcfZA4ljVR0vaDHoTk4="; }; glSkillDirs = builtins.readDir "${gitlabSkills}/skills"; glSkillFiles = lib.mapAttrs' ( name: _: lib.nameValuePair "opencode/skills/${name}" { source = "${gitlabSkills}/skills/${name}"; } ) (lib.filterAttrs (_: type: type == "directory") glSkillDirs); ppSkillDirs = builtins.readDir "${peonPingPkg}/share/peon-ping/skills"; ppSkillFiles = lib.mapAttrs' ( name: _: lib.nameValuePair "opencode/skills/${name}" { source = "${peonPingPkg}/share/peon-ping/skills/${name}"; } ) (lib.filterAttrs (_: type: type == "directory") ppSkillDirs); # Helper to create xdg.configFile entries for all agent files ceAgentDirs = builtins.readDir "${cePlugin}/agents"; ceAgentFiles = lib.concatMapAttrs ( category: _: let categoryDir = "${cePlugin}/agents/${category}"; files = builtins.readDir categoryDir; in lib.mapAttrs' ( name: _: lib.nameValuePair "opencode/agents/${name}" { source = "${categoryDir}/${name}"; } ) (lib.filterAttrs (_: type: type == "regular") files) ) (lib.filterAttrs (_: type: type == "directory") ceAgentDirs); # Helper to create xdg.configFile entries for all skill directories ceSkillDirs = builtins.readDir "${cePlugin}/skills"; ceSkillFiles = lib.mapAttrs' ( name: _: lib.nameValuePair "opencode/skills/${name}" { source = "${cePlugin}/skills/${name}"; } ) (lib.filterAttrs (_: type: type == "directory") ceSkillDirs); in { options.programs.andrew-opencode = { enable = mkEnableOption "andrew's opencode config"; variant = mkOption { type = types.enum [ "superpowers" "compound" "omo" ]; default = "superpowers"; description = "Which opencode plugin system to use"; }; }; config = mkIf cfg.enable (mkMerge [ # Common config — all variants { home.packages = [ agentcraft ]; programs.opencode = { enable = true; settings = { theme = "stylix"; provider.gitlab.models = { "duo-chat-haiku-4-5".cost = { input = 0.8; output = 4; }; "duo-chat-sonnet-4-5".cost = { input = 3; output = 15; }; "duo-chat-opus-4-5".cost = { input = 15; output = 75; }; "duo-chat-sonnet-4-6".cost = { input = 3; output = 15; }; "duo-chat-opus-4-6".cost = { input = 15; output = 75; }; "duo-chat-gpt-5-2-codex".cost = { input = 2; output = 8; }; "duo-chat-gpt-5-mini".cost = { input = 0.4; output = 1.6; }; }; mcp.glean = { type = "remote"; url = "https://gitlab-be.glean.com/mcp/default"; }; share = "disabled"; small_model = "gitlab/duo-chat-haiku-4-5"; }; }; programs.peon-ping = { enable = true; settings = { default_pack = "peon"; volume = 0.5; enabled = true; desktop_notifications = true; pack_rotation = [ "peon" "peasant" "hd2_helldiver" "ocarina_of_time" "protoss" "dota2_witch_doctor" ]; pack_rotation_mode = "round-robin"; categories = { "session.start" = true; "task.complete" = true; "task.error" = true; "input.required" = true; "resource.limit" = true; "user.spam" = true; }; }; installPacks = [ "peon" "peasant" "hd2_helldiver" "ocarina_of_time" { name = "protoss"; src = pkgs.fetchFromGitHub { owner = "codyborn"; repo = "protoss-sounds"; rev = "v1.0.0"; hash = "sha256-uQI7YUobkfAUu/0xhM4EuCq9GQ1d87UmsNCefAg2fGs="; }; } { name = "dota2_witch_doctor"; src = "${openpeonDota2}/dota2_witch_doctor"; } ]; enableZshIntegration = true; }; xdg.configFile = { "opencode/plugins/peon-ping.ts".source = "${peonPingPkg}/share/peon-ping/adapters/opencode/peon-ping.ts"; "opencode/plugins/peon-ping-internals.ts".source = "${peonPingPkg}/share/peon-ping/adapters/opencode/peon-ping-internals.ts"; "opencode/peon-ping/config.json".source = config.home.file.".openpeon/config.json".source; "opencode/plugins/gitlab-plugin.js".source = "${opencodeGitlabPlugin}/lib/node_modules/opencode-gitlab-plugin/dist/index.js"; "opencode/plugins/forge-session-title.js".source = "${opencodeForgeSessionTitle}/lib/node_modules/opencode-forge-session-title/dist/index.js"; "opencode/skills/writing-commit-messages".source = ./skills/writing-commit-messages; } // glSkillFiles // ppSkillFiles; } # Variant: superpowers (current behavior) (mkIf (cfg.variant == "superpowers") { programs.opencode.settings = { plugin = [ ]; agent = { explore.disable = true; general.disable = true; }; }; xdg.configFile = { "opencode/oh-my-opencode-slim.jsonc".source = ./oh-my-opencode-slim.jsonc; "opencode/plugins/oh-my-opencode-slim.js".source = "${ohMyOpencodeSlim}/lib/node_modules/oh-my-opencode-slim/dist/index.js"; "opencode/plugins/superpowers.js".source = "${superpowers}/.opencode/plugins/superpowers.js"; "opencode/skills/superpowers".source = "${superpowers}/skills"; }; }) # Variant: compound engineering (mkIf (cfg.variant == "compound") { programs.opencode.settings = { plugin = [ ]; mcp.context7 = { type = "remote"; url = "https://mcp.context7.com/mcp"; }; }; xdg.configFile = ceAgentFiles // ceSkillFiles; }) # Variant: oh-my-openagent (omo) (mkIf (cfg.variant == "omo") { programs.opencode.settings.plugin = [ ]; xdg.configFile = { "opencode/oh-my-opencode.jsonc".source = ./oh-my-opencode.jsonc; "opencode/plugins/oh-my-opencode.js".source = "${ohMyOpencode}/lib/node_modules/oh-my-opencode/dist/index.js"; }; }) ]); }