nixos configs

add opencode

+299 -17
+5
.editorconfig
··· 1 + root = true 2 + 3 + [*.{json,jsonc}] 4 + indent_style = space 5 + indent_size = 2
+94 -13
flake.lock
··· 45 45 "type": "github" 46 46 } 47 47 }, 48 + "blueprint": { 49 + "inputs": { 50 + "nixpkgs": [ 51 + "llm-agents", 52 + "nixpkgs" 53 + ], 54 + "systems": "systems_2" 55 + }, 56 + "locked": { 57 + "lastModified": 1771437256, 58 + "narHash": "sha256-bLqwib+rtyBRRVBWhMuBXPCL/OThfokA+j6+uH7jDGU=", 59 + "owner": "numtide", 60 + "repo": "blueprint", 61 + "rev": "06ee7190dc2620ea98af9eb225aa9627b68b0e33", 62 + "type": "github" 63 + }, 64 + "original": { 65 + "owner": "numtide", 66 + "repo": "blueprint", 67 + "type": "github" 68 + } 69 + }, 48 70 "devshell": { 49 71 "inputs": { 50 72 "nixpkgs": [ ··· 216 238 }, 217 239 "flake-utils": { 218 240 "inputs": { 219 - "systems": "systems_5" 241 + "systems": "systems_6" 220 242 }, 221 243 "locked": { 222 244 "lastModified": 1731533236, ··· 234 256 }, 235 257 "flake-utils_2": { 236 258 "inputs": { 237 - "systems": "systems_7" 259 + "systems": "systems_8" 238 260 }, 239 261 "locked": { 240 262 "lastModified": 1681202837, ··· 340 362 "type": "github" 341 363 } 342 364 }, 365 + "llm-agents": { 366 + "inputs": { 367 + "blueprint": "blueprint", 368 + "nixpkgs": [ 369 + "nixpkgs" 370 + ], 371 + "treefmt-nix": "treefmt-nix_2" 372 + }, 373 + "locked": { 374 + "lastModified": 1772634885, 375 + "narHash": "sha256-sizdR/xi8eq12PMPJ3BlGeLZ0lZ38NOra5zgNZVAG1g=", 376 + "owner": "numtide", 377 + "repo": "llm-agents.nix", 378 + "rev": "40dc5f264af66355fb609e3b444dcb8e57f6239f", 379 + "type": "github" 380 + }, 381 + "original": { 382 + "owner": "numtide", 383 + "repo": "llm-agents.nix", 384 + "type": "github" 385 + } 386 + }, 343 387 "minecraft-plymouth-theme": { 344 388 "inputs": { 345 389 "flake-parts": "flake-parts_2", 346 390 "nixpkgs": "nixpkgs_2", 347 - "systems": "systems_2" 391 + "systems": "systems_3" 348 392 }, 349 393 "locked": { 350 394 "lastModified": 1762860197, ··· 464 508 "nixpkgs": [ 465 509 "nixpkgs" 466 510 ], 467 - "systems": "systems_3" 511 + "systems": "systems_4" 468 512 }, 469 513 "locked": { 470 514 "lastModified": 1772017571, ··· 486 530 "nixpkgs": [ 487 531 "nixpkgs" 488 532 ], 489 - "systems": "systems_4" 533 + "systems": "systems_5" 490 534 }, 491 535 "locked": { 492 536 "lastModified": 1771987719, ··· 623 667 "nixpkgs": [ 624 668 "nixpkgs" 625 669 ], 626 - "systems": "systems_6" 670 + "systems": "systems_7" 627 671 }, 628 672 "locked": { 629 673 "lastModified": 1771135771, ··· 687 731 "firefox-addons": "firefox-addons", 688 732 "hammerspoon-nix": "hammerspoon-nix", 689 733 "home-manager": "home-manager", 734 + "llm-agents": "llm-agents", 690 735 "minecraft-plymouth-theme": "minecraft-plymouth-theme", 691 736 "minegrub-world-sel-theme": "minegrub-world-sel-theme", 692 737 "niri": "niri", ··· 733 778 }, 734 779 "systems_3": { 735 780 "locked": { 736 - "lastModified": 1681028828, 737 - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 738 - "owner": "nix-systems", 739 - "repo": "default", 740 - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 781 + "lastModified": 1689347949, 782 + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", 783 + "owner": "nix-systems", 784 + "repo": "default-linux", 785 + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", 741 786 "type": "github" 742 787 }, 743 788 "original": { 744 789 "owner": "nix-systems", 745 - "repo": "default", 790 + "repo": "default-linux", 746 791 "type": "github" 747 792 } 748 793 }, ··· 776 822 } 777 823 }, 778 824 "systems_6": { 825 + "locked": { 826 + "lastModified": 1681028828, 827 + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 828 + "owner": "nix-systems", 829 + "repo": "default", 830 + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 831 + "type": "github" 832 + }, 833 + "original": { 834 + "owner": "nix-systems", 835 + "repo": "default", 836 + "type": "github" 837 + } 838 + }, 839 + "systems_7": { 779 840 "locked": { 780 841 "lastModified": 1681028828, 781 842 "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", ··· 790 851 "type": "github" 791 852 } 792 853 }, 793 - "systems_7": { 854 + "systems_8": { 794 855 "locked": { 795 856 "lastModified": 1681028828, 796 857 "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", ··· 809 870 "inputs": { 810 871 "nixpkgs": [ 811 872 "hammerspoon-nix", 873 + "nixpkgs" 874 + ] 875 + }, 876 + "locked": { 877 + "lastModified": 1770228511, 878 + "narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=", 879 + "owner": "numtide", 880 + "repo": "treefmt-nix", 881 + "rev": "337a4fe074be1042a35086f15481d763b8ddc0e7", 882 + "type": "github" 883 + }, 884 + "original": { 885 + "owner": "numtide", 886 + "repo": "treefmt-nix", 887 + "type": "github" 888 + } 889 + }, 890 + "treefmt-nix_2": { 891 + "inputs": { 892 + "nixpkgs": [ 893 + "llm-agents", 812 894 "nixpkgs" 813 895 ] 814 896 },
+2
flake.nix
··· 3 3 4 4 inputs = { 5 5 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 + llm-agents.url = "github:numtide/llm-agents.nix"; 7 + llm-agents.inputs.nixpkgs.follows = "nixpkgs"; 6 8 7 9 minegrub-world-sel-theme.url = "github:Lxtharia/minegrub-world-sel-theme"; 8 10 minegrub-world-sel-theme.inputs.nixpkgs.follows = "nixpkgs";
+6 -2
home/alebat01/home.nix
··· 1 - { config, pkgs, ... }: 1 + { 2 + config, 3 + pkgs, 4 + ... 5 + }: 2 6 { 3 7 imports = [ 4 8 ./ssh.nix ··· 14 18 templates.commit_trailers = ''if(!trailers.contains_key("Change-Id"), format_gerrit_change_id_trailer(self))''; 15 19 }; 16 20 17 - ai-agent.agent = "codex"; 21 + ai-agent.agent = "opencode"; 18 22 19 23 home.stateVersion = "24.05"; 20 24
+37 -2
modules/home/ai-agent/default.nix
··· 1 1 { 2 2 lib, 3 3 pkgs, 4 + inputs, 4 5 config, 5 6 ... 6 7 }: 7 8 let 9 + llmAgentsPkgs = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}; 10 + mergeJsonc = 11 + name: base: override: 12 + pkgs.runCommand name { } '' 13 + ${ 14 + pkgs.python3.withPackages (ps: [ ps.json5 ]) 15 + }/bin/python ${./merge-jsonc.py} "${base}" "${override}" "$out" 16 + ''; 17 + mergedArmOpencodeConfig = 18 + mergeJsonc "opencode.jsonc" ./opencode/config.jsonc 19 + ./opencode/config.arm.jsonc; 20 + mergedArmOhMyOpencodeConfig = 21 + mergeJsonc "oh-my-opencode.jsonc" ./opencode/oh-my-opencode.jsonc 22 + ./opencode/oh-my-opencode.arm.jsonc; 8 23 skillsDir = 9 24 { 10 25 "claude-code" = ".claude/skills"; 11 26 "codex" = ".codex/skills"; 27 + "opencode" = ".opencode/skills"; 12 28 } 13 29 .${config.ai-agent.agent}; 14 30 ··· 33 49 type = lib.types.enum [ 34 50 "claude-code" 35 51 "codex" 52 + "opencode" 36 53 ]; 37 54 default = "claude-code"; 38 55 description = "Which AI coding agent to install."; ··· 41 58 42 59 config = { 43 60 home.packages = [ 44 - pkgs.${config.ai-agent.agent} 45 - pkgs.beads 61 + llmAgentsPkgs.${config.ai-agent.agent} 46 62 ]; 47 63 48 64 home.file.${skillsDir} = { ··· 52 68 53 69 home.file.".claude/settings.json" = lib.mkIf (config.ai-agent.agent == "claude-code") { 54 70 text = builtins.toJSON claudeSettings; 71 + }; 72 + 73 + home.file.".config/opencode/opencode.jsonc" = lib.mkIf (config.ai-agent.agent == "opencode") { 74 + source = lib.mkDefault ( 75 + if config.home.username == "alebat01" then mergedArmOpencodeConfig else ./opencode/config.jsonc 76 + ); 77 + }; 78 + 79 + home.file.".config/opencode/tui.jsonc" = lib.mkIf (config.ai-agent.agent == "opencode") { 80 + source = lib.mkDefault ./opencode/tui.jsonc; 81 + }; 82 + 83 + home.file.".config/opencode/oh-my-opencode.jsonc" = lib.mkIf (config.ai-agent.agent == "opencode") { 84 + source = lib.mkDefault ( 85 + if config.home.username == "alebat01" then 86 + mergedArmOhMyOpencodeConfig 87 + else 88 + ./opencode/oh-my-opencode.jsonc 89 + ); 55 90 }; 56 91 }; 57 92 }
+45
modules/home/ai-agent/merge-jsonc.py
··· 1 + #!/usr/bin/env python3 2 + 3 + import json 4 + import sys 5 + 6 + import json5 7 + 8 + 9 + def merge(base_value, override_value): 10 + if isinstance(base_value, dict) and isinstance(override_value, dict): 11 + merged = dict(base_value) 12 + for key, value in override_value.items(): 13 + if key in merged: 14 + merged[key] = merge(merged[key], value) 15 + else: 16 + merged[key] = value 17 + return merged 18 + 19 + return override_value 20 + 21 + 22 + def main() -> int: 23 + if len(sys.argv) != 4: 24 + print("Usage: merge-jsonc.py <base.jsonc> <override.jsonc> <out.json>", file=sys.stderr) 25 + return 2 26 + 27 + base_path, override_path, out_path = sys.argv[1:4] 28 + 29 + with open(base_path, "r", encoding="utf-8") as handle: 30 + base = json5.load(handle) 31 + 32 + with open(override_path, "r", encoding="utf-8") as handle: 33 + override = json5.load(handle) 34 + 35 + merged = merge(base, override) 36 + 37 + with open(out_path, "w", encoding="utf-8") as handle: 38 + json.dump(merged, handle, indent=2) 39 + handle.write("\n") 40 + 41 + return 0 42 + 43 + 44 + if __name__ == "__main__": 45 + raise SystemExit(main())
+32
modules/home/ai-agent/opencode/config.arm.jsonc
··· 1 + { 2 + "$schema": "https://opencode.ai/config.json", 3 + "share": "disabled", 4 + "disabled_providers": ["zen", "opencode", "openai"], 5 + "provider": { 6 + "arm": { 7 + "npm": "@ai-sdk/openai", 8 + "name": "Arm", 9 + "options": { 10 + "baseURL": "https://openai-api-proxy.geo.arm.com/api/providers/openai/v1", 11 + }, 12 + // Any needed OpenAI model can be added here 13 + "models": { 14 + "gpt-5-mini": { 15 + "id": "gpt-5-mini", 16 + }, 17 + "gpt-5.2": { 18 + "id": "gpt-5.2", 19 + }, 20 + "gpt-5.2-pro": { 21 + "id": "gpt-5.2-pro", 22 + }, 23 + "gpt-5.3-codex": { 24 + "id": "gpt-5.3-codex", 25 + }, 26 + "gpt-5.3-codex-spark": { 27 + "id": "gpt-5.3-codex-spark", 28 + }, 29 + }, 30 + }, 31 + }, 32 + }
+6
modules/home/ai-agent/opencode/config.jsonc
··· 1 + { 2 + "$schema": "https://opencode.ai/config.json", 3 + "plugin": [ 4 + "oh-my-opencode", // FIXME: does not install 5 + ], 6 + }
+43
modules/home/ai-agent/opencode/oh-my-opencode.arm.jsonc
··· 1 + { 2 + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json", 3 + 4 + // See https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/refs/heads/dev/docs/guide/agent-model-matching.md 5 + // Work machines use the Arm OpenAI proxy only 6 + // Cost is not a factor, but speed still matters for utility paths 7 + "agents": { 8 + // Sisyphus is Claude-first in upstream docs; use strongest OpenAI general model. 9 + "sisyphus": { 10 + "model": "arm/gpt-5.2-pro", 11 + "ultrawork": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" }, 12 + }, 13 + 14 + // Utility/search agents: use faster model for snappier turnaround. 15 + "librarian": { "model": "arm/gpt-5-mini" }, 16 + "explore": { "model": "arm/gpt-5-mini" }, 17 + 18 + // Deep/specialist agents. 19 + "hephaestus": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" }, 20 + "oracle": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" }, 21 + "momus": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" }, 22 + "metis": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" }, 23 + "atlas": { "model": "arm/gpt-5.2" }, 24 + 25 + // Keep the same orchestration bias tweak. 26 + "prometheus": { 27 + "prompt_append": "Leverage deep & quick agents heavily, always in parallel.", 28 + }, 29 + }, 30 + 31 + "categories": { 32 + "quick": { "model": "arm/gpt-5-mini" }, 33 + "unspecified-low": { "model": "arm/gpt-5-mini" }, 34 + "unspecified-high": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" }, 35 + "writing": { "model": "arm/gpt-5.2-pro" }, 36 + "visual-engineering": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" }, 37 + 38 + // Additional upstream-style categories mapped to OpenAI-only models. 39 + "deep": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" }, 40 + "ultrabrain": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" }, 41 + "artistry": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" }, 42 + }, 43 + }
+13
modules/home/ai-agent/opencode/oh-my-opencode.jsonc
··· 1 + { 2 + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json", 3 + "experimental": { 4 + "aggressive_truncation": true, 5 + "task_system": true, 6 + "dynamic_context_pruning": { 7 + "enabled": true, 8 + "notification": "minimal", 9 + }, 10 + }, 11 + "tmux": { "enabled": false }, 12 + "hashline_edit": true, 13 + }
+16
modules/home/ai-agent/opencode/tui.jsonc
··· 1 + { 2 + "$schema": "https://opencode.ai/tui.json", 3 + 4 + "theme": "system", 5 + 6 + //"scroll_speed": 1, // Anything higher is impossible to use with a touchpad 7 + "scroll_acceleration": { 8 + "enabled": true, 9 + }, 10 + 11 + "keybinds": { 12 + "agent_cycle_reverse": "none", 13 + "model_cycle_favorite": "shift+tab", 14 + "tool_details": "none", 15 + }, 16 + }