a dotfile but it's really big

langrules opencode

karitham.dev 4e35a855 533929ff

verified
+663 -183
+40 -40
flake.lock
··· 7 7 ] 8 8 }, 9 9 "locked": { 10 - "lastModified": 1769432988, 11 - "narHash": "sha256-q4arZjXnLiuMnLzO972lrXIGdzyGb4DGaIt69CcCYdE=", 10 + "lastModified": 1769946009, 11 + "narHash": "sha256-cjPsPx3qlP7RW78lcGJoTP/B6yqY6BJJjwT7QUg8ByY=", 12 12 "owner": "catppuccin", 13 13 "repo": "nix", 14 - "rev": "d7a8632c0d8d144478aac1a8c8d5083b770cbb03", 14 + "rev": "ff59ad5085b7d71705ea1f019c02b08dfe40d9c8", 15 15 "type": "github" 16 16 }, 17 17 "original": { ··· 111 111 ] 112 112 }, 113 113 "locked": { 114 - "lastModified": 1768135262, 115 - "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", 114 + "lastModified": 1769996383, 115 + "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", 116 116 "owner": "hercules-ci", 117 117 "repo": "flake-parts", 118 - "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", 118 + "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", 119 119 "type": "github" 120 120 }, 121 121 "original": { ··· 173 173 "zon2nix": "zon2nix" 174 174 }, 175 175 "locked": { 176 - "lastModified": 1769535559, 177 - "narHash": "sha256-/tFsaoKUGoyQKWQbFPtQOge+azCP3hPfzl7Yu1AW58Y=", 176 + "lastModified": 1770004164, 177 + "narHash": "sha256-viXsdAhYtEO19D2i3mgm09DuFDK6QF8s5weLoMjqVXg=", 178 178 "owner": "ghostty-org", 179 179 "repo": "ghostty", 180 - "rev": "685daee01bbd18dc50c066ccfa85828509068a99", 180 + "rev": "1b7a15899ad40fba4ce020f537055d30eaf99ee8", 181 181 "type": "github" 182 182 }, 183 183 "original": { ··· 214 214 "rust-overlay": "rust-overlay" 215 215 }, 216 216 "locked": { 217 - "lastModified": 1769605306, 218 - "narHash": "sha256-xmf4NL+iT4iLflhE04/D4P83/37cd2/LotQlV78OTiE=", 217 + "lastModified": 1769959637, 218 + "narHash": "sha256-4vz/KMdA1zatjoh1KsL6diCyhCT6hRwx+KColuh14VU=", 219 219 "owner": "helix-editor", 220 220 "repo": "helix", 221 - "rev": "d37dc6c73b66d1f5c572f470198028c78dd2f7d3", 221 + "rev": "583dba4cc4c8d9a6963efb74d32159ef1446473d", 222 222 "type": "github" 223 223 }, 224 224 "original": { ··· 255 255 ] 256 256 }, 257 257 "locked": { 258 - "lastModified": 1769638001, 259 - "narHash": "sha256-hGwdJ/+oo+IRo2TiWV/V8BWWptQihcdFV/olTONaHqg=", 258 + "lastModified": 1769978395, 259 + "narHash": "sha256-gj1yP3spUb1vGtaF5qPhshd2j0cg4xf51pklDsIm19Q=", 260 260 "owner": "nix-community", 261 261 "repo": "home-manager", 262 - "rev": "bd9f031efc634be4b80c5090b9171cc3a9f8e49c", 262 + "rev": "984708c34d3495a518e6ab6b8633469bbca2f77a", 263 263 "type": "github" 264 264 }, 265 265 "original": { ··· 298 298 "rust-overlay": "rust-overlay_2" 299 299 }, 300 300 "locked": { 301 - "lastModified": 1769417433, 302 - "narHash": "sha256-0WZ7I/N9InaBHL96/qdiJxg8mqFW3vRla8Z062JmQFE=", 301 + "lastModified": 1769949118, 302 + "narHash": "sha256-Ue9kYZenqMw9yHGFnBpoWxQqhs2tlH/el4AxKVicXBE=", 303 303 "owner": "nix-community", 304 304 "repo": "lanzaboote", 305 - "rev": "1902463415745b992dbaf301b2a35a1277be1584", 305 + "rev": "0be0641613a13323a61a6406c46b6f28b8894395", 306 306 "type": "github" 307 307 }, 308 308 "original": { ··· 321 321 "xwayland-satellite-unstable": "xwayland-satellite-unstable" 322 322 }, 323 323 "locked": { 324 - "lastModified": 1769647464, 325 - "narHash": "sha256-SDZms/fjrXRgL+QA+RfvTMClhPGfPn1TnIdNwoujEo4=", 324 + "lastModified": 1769980417, 325 + "narHash": "sha256-BOxPHApuXJE0wFKaDK811u5Ihvn4gnsXhCABo0O/u/Q=", 326 326 "owner": "sodiboo", 327 327 "repo": "niri-flake", 328 - "rev": "e3d4bf00f7d40fca03fecab5c7a46277a6eb9fed", 328 + "rev": "ca6c544ca6a737bdb32676046bf98aca11f8f13d", 329 329 "type": "github" 330 330 }, 331 331 "original": { ··· 404 404 }, 405 405 "nixpkgs-stable": { 406 406 "locked": { 407 - "lastModified": 1769598131, 408 - "narHash": "sha256-e7VO/kGLgRMbWtpBqdWl0uFg8Y2XWFMdz0uUJvlML8o=", 407 + "lastModified": 1769900590, 408 + "narHash": "sha256-I7Lmgj3owOTBGuauy9FL6qdpeK2umDoe07lM4V+PnyA=", 409 409 "owner": "NixOS", 410 410 "repo": "nixpkgs", 411 - "rev": "fa83fd837f3098e3e678e6cf017b2b36102c7211", 411 + "rev": "41e216c0ca66c83b12ab7a98cc326b5db01db646", 412 412 "type": "github" 413 413 }, 414 414 "original": { ··· 436 436 }, 437 437 "nixpkgs_3": { 438 438 "locked": { 439 - "lastModified": 1769461804, 440 - "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", 439 + "lastModified": 1769789167, 440 + "narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=", 441 441 "owner": "NixOS", 442 442 "repo": "nixpkgs", 443 - "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", 443 + "rev": "62c8382960464ceb98ea593cb8321a2cf8f9e3e5", 444 444 "type": "github" 445 445 }, 446 446 "original": { ··· 452 452 }, 453 453 "nixpkgs_4": { 454 454 "locked": { 455 - "lastModified": 1769527094, 456 - "narHash": "sha256-wHUZguLHxHpnrVW523J8oILdQcFPIUIn+021gBYpOuY=", 457 - "rev": "afce96367b2e37fc29afb5543573cd49db3357b7", 455 + "lastModified": 1770015011, 456 + "narHash": "sha256-SYiwVUy/8bjZRMQtf760lbpATzVJDsl/6ffk0VLj03I=", 457 + "rev": "f08e6b11a5ed43637a8ac444dd44118bc7d273b9", 458 458 "type": "tarball", 459 - "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre935717.afce96367b2e/nixexprs.tar.xz?lastModified=1769527094&rev=afce96367b2e37fc29afb5543573cd49db3357b7" 459 + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre938800.f08e6b11a5ed/nixexprs.tar.xz?lastModified=1770015011&rev=f08e6b11a5ed43637a8ac444dd44118bc7d273b9" 460 460 }, 461 461 "original": { 462 462 "type": "tarball", ··· 486 486 ] 487 487 }, 488 488 "locked": { 489 - "lastModified": 1769661298, 490 - "narHash": "sha256-pch3VfwglzG43mdW7+apqN5KhE48E/Y2abZ3rB9wGeg=", 489 + "lastModified": 1770044084, 490 + "narHash": "sha256-i7EOevX0Whfxq4Krb8Jo8v0nNEbdVQ8YJ9r3o/e6LrU=", 491 491 "owner": "noctalia-dev", 492 492 "repo": "noctalia-shell", 493 - "rev": "27bee0033d8ff0374c40d7bed7d4c28c88405aaa", 493 + "rev": "168c16da7a418dad1ead2880c235a28ce26e1891", 494 494 "type": "github" 495 495 }, 496 496 "original": { ··· 607 607 ] 608 608 }, 609 609 "locked": { 610 - "lastModified": 1769469829, 611 - "narHash": "sha256-wFcr32ZqspCxk4+FvIxIL0AZktRs6DuF8oOsLt59YBU=", 610 + "lastModified": 1769921679, 611 + "narHash": "sha256-twBMKGQvaztZQxFxbZnkg7y/50BW9yjtCBWwdjtOZew=", 612 612 "owner": "Mic92", 613 613 "repo": "sops-nix", 614 - "rev": "c5eebd4eb2e3372fe12a8d70a248a6ee9dd02eff", 614 + "rev": "1e89149dcfc229e7e2ae24a8030f124a31e4f24f", 615 615 "type": "github" 616 616 }, 617 617 "original": { ··· 703 703 "xwayland-satellite-unstable": { 704 704 "flake": false, 705 705 "locked": { 706 - "lastModified": 1769356222, 707 - "narHash": "sha256-Q0BVubV9ZnmLs506EhBSPglM+YJK56wsQNbeecvWPUo=", 706 + "lastModified": 1769713942, 707 + "narHash": "sha256-0BtCSO2qzYK/akRDsERqRVLknCYD3FYErc+szreSHUo=", 708 708 "owner": "Supreeeme", 709 709 "repo": "xwayland-satellite", 710 - "rev": "cf14278b92b0a91d01587f09b4b00ea655ae24e6", 710 + "rev": "37ec78ee26e158b71f42e113e0e7dd9d5eb6bdb0", 711 711 "type": "github" 712 712 }, 713 713 "original": {
+3
modules/dev/home.nix
··· 13 13 editor 14 14 vcs 15 15 tools 16 + opencode 16 17 ; 17 18 }; 19 + 18 20 options.dev = { 19 21 enable = mkEnableOption "all development tools"; 20 22 ··· 28 30 ./editor 29 31 ./vcs 30 32 ./tools 33 + ../opencode/home.nix 31 34 ]; 32 35 }
+2
modules/dev/nixos.nix
··· 16 16 editor.enable = mkEnableOption "editor tools"; 17 17 vcs.enable = mkEnableOption "version control tools"; 18 18 tools.enable = mkEnableOption "development utilities"; 19 + opencode.enable = mkEnableOption "OpenCode"; 19 20 docker.enable = mkEnableOption "Docker"; 20 21 }; 21 22 ··· 24 25 dev.editor.enable = mkIf cfg.enable true; 25 26 dev.vcs.enable = mkIf cfg.enable true; 26 27 dev.tools.enable = mkIf cfg.enable true; 28 + dev.opencode.enable = mkIf cfg.enable true; 27 29 dev.docker.enable = mkIf cfg.enable true; 28 30 29 31 users.defaultUserShell = mkIf (cfg.enable || cfg.shell.enable) pkgs.nushell;
-1
modules/dev/tools/default.nix
··· 30 30 31 31 imports = [ 32 32 ./direnv.nix 33 - ./opencode.nix 34 33 ]; 35 34 }
-88
modules/dev/tools/opencode-agents/lead-backend-architect.md
··· 1 - --- 2 - description: LBA uses subagents and critically reviews their stuff 3 - mode: primary 4 - tools: 5 - read: true 6 - glob: true 7 - grep: true 8 - bash: false 9 - write: false 10 - edit: false 11 - permissions: 12 - bash: 13 - "git status": allow 14 - "git log": allow 15 - "*": ask 16 - --- 17 - 18 - # AGENT ROLE: LEAD BACKEND ARCHITECT (LBA) 19 - 20 - ## MISSION 21 - 22 - You are the Lead Backend Architect (LBA). Your role is purely strategic and managerial. You maintain the "Global Context" for a Go and Ruby backend codebase with strong implicit standards. You are strictly forbidden from writing implementation code or performing code reviews yourself. 23 - 24 - ## THE "CLEAN SLATE" CONSTRAINTS 25 - 26 - Every subagent you spawn starts as a blank slate with zero knowledge. You must act as their "System Prompt" by including all necessary identity, context, and requirements in your message to them. 27 - 28 - ## CORE OPERATIONAL RULES 29 - 30 - - **Strict Neutrality**: You do not suggest implementations. You do not critique code. You are the "Router" and "Context Injector." 31 - 32 - - **No Logic Leakage**: Never tell a subagent how to solve a problem. Only tell them what the problem is and which local patterns to follow. 33 - 34 - - **The Critic Barrier**: You are logically incapable of identifying bugs. If a Creator provides code, your only valid response is to spawn a Critic to find faults. 35 - 36 - ## OPERATIONAL WORKFLOW 37 - 38 - ### Phase 1: Pattern Extraction 39 - 40 - Before any work begins, analyze the codebase. Document the Implicit Standards: 41 - 42 - - **Go**: (e.g., error wrapping, receiver naming, channel usage). 43 - 44 - - **Ruby**: (e.g., service object structure, RSpec mocking style). 45 - 46 - - **Team Style**: (e.g., how telemetry/logging is integrated without docs). 47 - 48 - ### Phase 2: Spawning the Creator (BIS) 49 - 50 - When delegating implementation, your prompt to the subagent must include: 51 - 52 - - **Persona**: "You are a Senior Backend Engineer. You are the sole author of this logic." 53 - 54 - - **The Mission**: Clear technical requirements. 55 - 56 - - **Context Guardrails**: The "Implicit Standards" from Phase 1. 57 - 58 - - **Requirement**: Production code + Table-driven tests (Go) or RSpec (Ruby). 59 - 60 - ### Phase 3: Spawning the Critic (ACS) 61 - 62 - Once the Creator responds, you must not review it. You immediately spawn a second subagent with: 63 - 64 - - **Persona**: "You are a Hostile Security and Quality Auditor. Your goal is to find bugs and style violations." 65 - 66 - - **Input**: The Creator's code + The Mission + The Implicit Standards. 67 - 68 - - **Requirement**: A numbered list of defects and a PASS/FAIL grade. 69 - 70 - ### Phase 4: Convergence Loop 71 - 72 - - **If Critic says FAIL**: Take the Critic's defect list and spawn a new Creator instance (or update the current one) to fix the issues. 73 - 74 - - **If Critic says PASS**: Present the final, verified solution to the User. 75 - 76 - ## SUBAGENT PROMPT TEMPLATES (Use these when spawning) 77 - 78 - ### For the Creator (BIS): 79 - 80 - "You are a specialized Backend Engineer. You are the sole author of this implementation. You operate in a fresh context. Requirements: [X]. You MUST follow these implicit patterns: [Y]. Output: 1. Implementation Code 2. Test File 3. List of edge cases handled." 81 - 82 - ### For the Critic (ACS): 83 - 84 - "You are a Hostile Quality Auditor. Your success is defined by finding flaws the developer missed. Analyze this code: [CODE] against these requirements: [REQ]. Check for: 1. Idiomatic Go/Ruby violations 2. Nil pointers/Silent failures 3. Weak test coverage. Output: 1. List of Defects 2. Final Grade [PASS/FAIL]." 85 - 86 - ## INITIALIZATION 87 - 88 - Acknowledge your role. I will provide the codebase snippets and the first task. Do not offer solutions; wait for my patterns.
+3 -7
modules/dev/tools/opencode-agents/stack-analyst.md modules/opencode/agents/stack-analyst.md
··· 5 5 read: true 6 6 glob: true 7 7 grep: true 8 - write: true 9 - edit: false 8 + edit: true 10 9 bash: true 11 - permissions: 12 - bash: 13 - "git status": allow 14 - "git log": allow 15 - "*": ask 10 + todowrite: false 11 + todoread: false 16 12 --- 17 13 18 14 # Stack Trace Analyst
-47
modules/dev/tools/opencode.nix
··· 1 - { 2 - config, 3 - lib, 4 - pkgs, 5 - ... 6 - }: 7 - let 8 - opencodePkg = pkgs.symlinkJoin { 9 - name = "opencode.wrapped"; 10 - paths = [ 11 - pkgs.opencode 12 - pkgs.nixd 13 - ]; 14 - buildInputs = [ pkgs.makeWrapper ]; 15 - postBuild = '' 16 - wrapProgram $out/bin/opencode \ 17 - --set SHELL ${lib.getExe pkgs.bash} 18 - ''; 19 - }; 20 - in 21 - { 22 - config = lib.mkIf config.dev.tools.enable { 23 - xdg.configFile."opencode/agent" = { 24 - source = ./opencode-agents; 25 - recursive = true; 26 - }; 27 - 28 - programs.opencode = { 29 - enable = true; 30 - package = opencodePkg; 31 - enableMcpIntegration = true; 32 - settings = { 33 - theme = "catppuccin-macchiato"; 34 - mcp = { 35 - gopls = { 36 - type = "local"; 37 - enabled = true; 38 - command = [ 39 - "gopls" 40 - "mcp" 41 - ]; 42 - }; 43 - }; 44 - }; 45 - }; 46 - }; 47 - }
+7
modules/opencode/AGENTS.md
··· 1 + - **READ BEFORE WRITE**: Always read a file before editing. 2 + - **ERROR HANDLING**: No panics/crashes on bad input. 3 + - **SECURITY**: Validate inputs, parameterized queries, no hardcoded secrets. 4 + - **NO DEAD CODE**: Remove or complete incomplete code. 5 + - **FAMILIAR CODE**: All code you write should be familiar to other writers of the codebase. Reuse the existing patterns. 6 + - Be concise, both in code, comments and human interactions. 7 + - Skip "Here is the code" / "Let me..." / "I'll now..."
+57
modules/opencode/default.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + let 8 + rulesDir = ./rules; 9 + 10 + opencodePkg = pkgs.symlinkJoin { 11 + name = "opencode.wrapped"; 12 + paths = [ pkgs.opencode ]; 13 + buildInputs = [ pkgs.makeWrapper ]; 14 + postBuild = '' 15 + wrapProgram $out/bin/opencode \ 16 + --set SHELL ${lib.getExe pkgs.bash} \ 17 + --set-default LANGRULES_DIR ${rulesDir} 18 + ''; 19 + }; 20 + 21 + cfg = config.dev.opencode; 22 + in 23 + lib.mkIf cfg.enable { 24 + xdg.configFile."opencode/agents" = { 25 + source = ./agents; 26 + recursive = true; 27 + }; 28 + 29 + xdg.configFile."opencode/AGENTS.md".source = ./AGENTS.md; 30 + 31 + programs.opencode = { 32 + enable = true; 33 + package = opencodePkg; 34 + enableMcpIntegration = cfg.enableMcp; 35 + settings = { 36 + theme = cfg.theme; 37 + plugin = [ "file:///home/kar/code/langrules-opencode/src/index.ts" ]; 38 + permission = { 39 + todoread = "deny"; 40 + todowrite = "deny"; 41 + }; 42 + mcp = lib.mkIf cfg.enableMcp { 43 + gopls = { 44 + type = "local"; 45 + enabled = true; 46 + command = [ 47 + "gopls" 48 + "mcp" 49 + ]; 50 + }; 51 + }; 52 + }; 53 + }; 54 + 55 + programs.git.ignores = lib.mkIf cfg.enableLangRules [ ".rules" ]; 56 + programs.helix.ignores = lib.mkIf cfg.enableLangRules [ "!.rules" ]; 57 + }
+23
modules/opencode/home.nix
··· 1 + { lib, ... }: 2 + { 3 + options.dev.opencode = { 4 + enable = lib.mkEnableOption "OpenCode AI-assisted development environment"; 5 + enableLangRules = lib.mkOption { 6 + type = lib.types.bool; 7 + default = true; 8 + description = "LangRules plugin injects language specific context and tooling"; 9 + }; 10 + enableMcp = lib.mkOption { 11 + type = lib.types.bool; 12 + default = true; 13 + description = "MCP server integrations for enhanced language support"; 14 + }; 15 + theme = lib.mkOption { 16 + type = lib.types.str; 17 + default = "catppuccin-macchiato"; 18 + description = "OpenCode theme"; 19 + }; 20 + }; 21 + 22 + imports = [ ./default.nix ]; 23 + }
+56
modules/opencode/rules/global.md
··· 1 + # Global Coding Rules 2 + 3 + ## NO STUBS - ABSOLUTE RULE 4 + 5 + - NEVER write `TODO`, `FIXME`, `pass`, `...`, `unimplemented!()` 6 + - NEVER write empty function bodies or placeholder returns 7 + - If too complex for one turn: throw an error/exception with a clear reason 8 + 9 + ## Core Rules 10 + 11 + 1. **READ BEFORE WRITE**: Always read a file before editing. 12 + 2. **FULL FEATURES**: Complete the feature, don't stop partway. 13 + 3. **ERROR HANDLING**: No panics/crashes on bad input. 14 + 4. **SECURITY**: Validate input, parameterized queries, no hardcoded secrets. 15 + 5. **NO DEAD CODE**: Remove or complete incomplete code. 16 + 17 + ## Chainlink Lifecycle Management 18 + 19 + You MUST use Chainlink to track all work: 20 + 21 + - **Session Start**: `chainlink session start` - shows previous handoff 22 + - **Session Work**: `chainlink session work <id>` - mark current focus 23 + - **Progress**: `chainlink comment <id> "..."` - update regularly 24 + - **Session End**: `chainlink session end --notes "..."` - REQUIRED before stopping 25 + 26 + ### Handoff Notes Format 27 + 28 + ```markdown 29 + **Accomplished:** 30 + - Completed feature X 31 + - Added tests for Y 32 + 33 + **In Progress:** 34 + - Working on feature Z 35 + 36 + **Next:** 37 + - Complete feature Z 38 + - Run tests 39 + 40 + **Blockers:** 41 + - None 42 + ``` 43 + 44 + ## Code Quality Requirements 45 + 46 + - **NO DEAD CODE**: Remove unused functions, variables, imports 47 + - **NO HARDCODED SECRETS**: Use environment variables, configs 48 + - **COMMIT FREQUENTLY**: Small, focused commits 49 + - **DESCRIPTIVE COMMITS**: Explain WHY, not just WHAT 50 + 51 + ## Security 52 + 53 + - Validate ALL inputs (user, network, config) 54 + - Use parameterized queries for database access 55 + - Never log sensitive data (passwords, tokens, keys) 56 + - Follow principle of least privilege
+95
modules/opencode/rules/go.md
··· 1 + ### Go Best Practices 2 + 3 + Follow [Effective Go](https://go.dev/doc/effective_go) and [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments). 4 + 5 + #### Code Style & Structure 6 + 7 + - **Existing Style**: The best Go style is the existing style. Adapt to existing patterns and conventions in the codebase as much as possible. 8 + - **Small Interfaces**: Keep interfaces small (often 1-3 methods). "The bigger the interface, the weaker the abstraction." 9 + - **Deep Modules**: Design modules with simple interfaces that hide significant complexity (deep vs. shallow). 10 + - **Align Left**: Keep the "happy path" aligned to the left. 11 + - **Early Returns**: Use guard clauses to handle errors and edge cases early, reducing nesting. 12 + - **Avoid Else**: Avoid `else` blocks; they often indicate complex branching that can be flattened with early returns. 13 + - **No Naked Returns**: Avoid using named return parameters for actual returns. 14 + - **Latest Features**: Leverage modern Go features (generics, `any`, `net/http` routing enhancements, `log/slog`, `t.Context()`). 15 + - **Simple Functions**: Write small, focused functions that do one thing well. 16 + - **Avoid God Objects**: Don't create types that try to do everything. Use composition. 17 + - **Pure Code**: Prefer pure functions where possible. 18 + - **Easy to Mock**: Accept interfaces, return structs. Use dependency injection. 19 + 20 + #### Error Handling 21 + 22 + Always check and handle errors immediately. Wrap errors with context. 23 + 24 + ```go 25 + // GOOD: Early returns, aligned left, no else 26 + func readConfig(path string) (*Config, error) { 27 + data, err := os.ReadFile(path) 28 + if err != nil { 29 + return nil, fmt.Errorf("read config: %w", err) 30 + } 31 + 32 + var config Config 33 + if err := json.Unmarshal(data, &config); err != nil { 34 + return nil, fmt.Errorf("parse config: %w", err) 35 + } 36 + 37 + return &config, nil 38 + } 39 + 40 + // BAD: Nested, use of else, harder to follow 41 + func readConfig(path string) (*Config, error) { 42 + data, err := os.ReadFile(path) 43 + if err == nil { 44 + var config Config 45 + err = json.Unmarshal(data, &config) 46 + if err == nil { 47 + return &config, nil 48 + } else { 49 + return nil, err 50 + } 51 + } else { 52 + return nil, err 53 + } 54 + } 55 + ``` 56 + 57 + #### Concurrency & Sync 58 + 59 + - **Package sync**: Use `sync.Mutex`, `sync.RWMutex`, `sync.Once`, and `sync.Pool` extensively. 60 + - **sync.WaitGroup**: Use for waiting on multiple goroutines. 61 + - **Channels**: Use for coordination between goroutines. 62 + - **Context**: Always propagate `context.Context`. Use `t.Context()` in tests for automatic cleanup. 63 + - **Atomic**: Use `sync/atomic` for simple counter/state updates. 64 + 65 + #### Testing 66 + 67 + Use the standard `testing` package effectively. 68 + 69 + - **Table-Driven Tests**: Use anonymous structs for test cases with clear `name`, `got`, and `want` fields. 70 + - **t.Context()**: Use `t.Context()` for test-scoped context that cancels when the test finishes. 71 + - **Few Functions, Good Tables**: Prefer one robust test function with a comprehensive table over many small test functions. 72 + - **Helper Functions**: Use `t.Helper()` in functions that assist in testing to keep stack traces clean. 73 + 74 + ```go 75 + func TestSum(t *testing.T) { 76 + tests := []struct { 77 + name string 78 + args []int 79 + want int 80 + }{ 81 + {"empty", []int{}, 0}, 82 + {"single", []int{1}, 1}, 83 + {"multiple", []int{1, 2, 3}, 6}, 84 + {"negative", []int{1, -1}, 0}, 85 + } 86 + 87 + for _, tt := range tests { 88 + t.Run(tt.name, func(t *testing.T) { 89 + if got := Sum(tt.args); got != tt.want { 90 + t.Errorf("Sum() = %v, want %v", got, tt.want) 91 + } 92 + }) 93 + } 94 + } 95 + ```
+36
modules/opencode/rules/javascript.md
··· 1 + ### JavaScript Best Practices 2 + 3 + #### Code Style 4 + - Use `const` by default, `let` when needed, never `var` 5 + - Use arrow functions for callbacks 6 + - Use template literals over string concatenation 7 + - Use destructuring for object/array access 8 + 9 + #### Error Handling 10 + ```javascript 11 + // GOOD: Proper async error handling 12 + async function fetchUser(id) { 13 + try { 14 + const response = await fetch(`/api/users/${id}`); 15 + if (!response.ok) { 16 + throw new Error(`HTTP ${response.status}`); 17 + } 18 + return await response.json(); 19 + } catch (error) { 20 + console.error('Failed to fetch user:', error); 21 + throw error; // Re-throw or handle appropriately 22 + } 23 + } 24 + 25 + // BAD: Ignoring errors 26 + async function fetchUser(id) { 27 + const response = await fetch(`/api/users/${id}`); 28 + return response.json(); // No error handling 29 + } 30 + ``` 31 + 32 + #### Security 33 + - Never use `eval()` or `innerHTML` with user input 34 + - Validate all input on both client and server 35 + - Use `textContent` instead of `innerHTML` when possible 36 + - Sanitize URLs before navigation or fetch
+306
modules/opencode/rules/nix.md
··· 1 + # Nix Best Practices 2 + 3 + ## Code Style 4 + 5 + - Use `nixfmt` for formatting (set as formatter in flake, run `nix fmt` before committing) 6 + - Follow the [Nixpkgs contributing guide](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md) for style conventions 7 + - Use descriptive variable names that explain purpose 8 + - Prefer `let ... in` blocks for local bindings over deep nesting 9 + - Keep derivations and functions small and composable 10 + - Use `lib.mkIf`, `lib.mkWhen`, `lib.optionals` for conditional logic 11 + - Use `lib.getExe` and `lib.getExe'` for accessing package executables 12 + 13 + ## Error Handling 14 + 15 + ```nix 16 + # GOOD: Proper error handling with builtins.tryEval 17 + let 18 + configPath = ./config.json; 19 + config = builtins.tryEval (builtins.fromJSON (builtins.readFile configPath)); 20 + in 21 + if config.success then config.value else throw "Failed to parse config" 22 + 23 + # GOOD: Using assert statements for validation 24 + assert lib.assertMsg (cfg.port > 0 && cfg.port < 65536) "Port must be between 1 and 65535"; 25 + cfg 26 + 27 + # GOOD: Using lib.mapAttrs' with lib.nameValuePair for building attribute sets 28 + lib.mapAttrs' (argName: argValue: 29 + lib.nameValuePair "${argName}+${dir.name}" { 30 + action = { 31 + "${argValue}-${dir.value}" = [ ]; 32 + }; 33 + } 34 + ) act 35 + 36 + # BAD: Silent failures or incomplete error messages 37 + let 38 + data = builtins.readFile configPath; 39 + config = builtins.fromJSON data; # Will throw cryptic error if invalid 40 + in config 41 + ``` 42 + 43 + ## Nix Module System 44 + 45 + - Use `lib.mkOptionType`, `lib.mkDefault`, `lib.mkForce` appropriately 46 + - Prefer `mkOption` with proper `type`, `default`, and `description` fields 47 + - Use `mkIf` for conditional module options rather than deep nesting 48 + - Keep modules focused - one module per responsibility 49 + - Use `imports` to compose modules rather than duplicating code 50 + - Use `lib.getExe pkgs.packageName` for executable paths in configuration 51 + 52 + ```nix 53 + # GOOD: Well-structured module option 54 + { lib, config, ... }: 55 + { 56 + options.my.username = lib.mkOption { 57 + type = lib.types.str; 58 + description = "The username for the current user."; 59 + default = "kar"; 60 + }; 61 + 62 + config = lib.mkIf (config.my.username != "root") { 63 + users.users.${config.my.username} = { 64 + home = "/home/${config.my.username}"; 65 + initialPassword = ""; 66 + isNormalUser = true; 67 + extraGroups = [ 68 + "networkmanager" 69 + "docker" 70 + "wheel" 71 + ]; 72 + }; 73 + }; 74 + } 75 + ``` 76 + 77 + ## Flake Patterns 78 + 79 + - Use `flake-parts` for modular flake structure 80 + - Use `withSystem` for system-specific configuration 81 + - Provide `devShells`, `packages`, `checks`, `formatter` per system 82 + - Lock `nixpkgs` reference using channel URLs or specific revisions 83 + - Provide formatter and linter in `devShells` 84 + - Use `nixConfig` for Nix configuration (experimental features, substituters) 85 + 86 + ## System Management 87 + 88 + - Use `easy-hosts` for organizing hosts by class (desktop, server, wsl) and tags 89 + - Define shared modules for all systems in `config.easy-hosts.shared.modules` 90 + - Use perClass and perTag for class-specific and tag-specific modules 91 + - Use `mkSystem'` for creating individual systems with proper specialArgs 92 + 93 + ## Overlay Patterns 94 + 95 + - Use `overrideAttrs` for patching existing packages 96 + - Use `fetchurl` or `fetchFromGitHub` for patches with hash verification 97 + - Use `callPackage` to add packages to overlay 98 + - Keep overlays focused and well-documented 99 + 100 + ## Package Building 101 + 102 + - Use `pkgs.buildGoModule` for Go packages with proper vendorHash 103 + - Use `pkgs.fetchFromGitHub` for GitHub sources with hash verification 104 + - Set `env.CGO_ENABLED`, `flags`, and `ldflags` appropriately for Go 105 + - Include proper `meta` with description, homepage, license, maintainers 106 + - Use `trimpath` and static linking flags for production binaries 107 + 108 + ## Security 109 + 110 + - Never commit secrets or API keys in Nix files 111 + - Use `sops-nix` for secrets management in production 112 + - Use sandbox mode in `nix.conf` (`sandbox = true`) for builds 113 + - Review network access in derivations - use `allowedRequisites` for purity 114 + - Use `fetchFromGitHub` or `fetchurl` with hash verification 115 + 116 + ## Dependency Management 117 + 118 + - Use specific Git revisions/commits for Git dependencies (not branches) 119 + - Always include `sha256` hash for fetch functions 120 + - Use `inputs.nixpkgs.follows` to avoid duplicating inputs 121 + - Pin `nixpkgs` in production configurations using `flake.lock` 122 + - Prefer `flake-inputs` over `builtins.fetchTarball` for external sources 123 + - Use `callPackage` pattern for package dependencies 124 + 125 + ## Testing 126 + 127 + - Use `nix-instantiate --parse` to check for syntax errors 128 + - Use `nix-build` with `-A` to test specific attributes 129 + - Write checks in `perSystem.checks` for package testing 130 + - Use `nix flake check` for flake validation 131 + - Test modules with `nixos-rebuild dry-build` or `nixos-rebuild test` 132 + 133 + ## Evaluation 134 + 135 + - Use `lib.warnIf` and `lib.deprecated` for deprecation notices 136 + - Avoid `builtins.trace` in production code (use for debugging only) 137 + - Use `lib.lists.foldl'` or `lib.lists.foldl'` for strict left folds 138 + - Prefer `lib.mapAttrs` and `lib.mapAttrs'` over `builtins.map` for attribute sets 139 + - Use `lib.filterAttrs` for filtering attributes 140 + - Use `lib.mergeAttrsList` for merging lists of attribute sets 141 + - Use `lib.attrsToList` for converting attributes to list of name-value pairs 142 + 143 + ## Performance 144 + 145 + - Use `lib.optionals` and `lib.concatMap` for list operations 146 + - Avoid deep recursion - use `foldl'` for accumulation 147 + - Use `overrideAttrs` for modifying packages instead of rewriting 148 + - Prefer `stdenv.mkDerivation` over raw `derivation` for packages 149 + - Use `pkgs.callPackage` with explicit arguments for clarity 150 + 151 + ## Home-Manager Module System 152 + 153 + Home-manager modules manage user-level configuration (home directory, user packages, programs). 154 + 155 + ### Module Structure 156 + 157 + ``` 158 + modules/ 159 + dev/ 160 + home.nix # Home-manager module with osConfig parameter 161 + nixos.nix # NixOS module importing home.nix via homeModules 162 + shell/ 163 + default.nix # Imports sub-modules 164 + nushell.nix # Actual configuration 165 + ``` 166 + 167 + ### Home-Manager Module Pattern 168 + 169 + ```nix 170 + # modules/dev/shell/default.nix 171 + { 172 + imports = [ 173 + ./atuin.nix 174 + ./nushell.nix 175 + ./starship.nix 176 + ./zellij.nix 177 + ]; 178 + } 179 + ``` 180 + 181 + ### Home-Manager with osConfig 182 + 183 + ```nix 184 + # modules/dev/home.nix 185 + { 186 + osConfig ? { }, 187 + lib, 188 + ... 189 + }: 190 + let 191 + inherit (lib) mkEnableOption; 192 + in 193 + { 194 + # Inherit options from NixOS module configuration 195 + config.dev = { 196 + inherit (osConfig.dev or { }) 197 + shell 198 + editor 199 + vcs 200 + tools 201 + ; 202 + }; 203 + 204 + # Define options (mirrors NixOS module) 205 + options.dev = { 206 + enable = mkEnableOption "all development tools"; 207 + shell.enable = mkEnableOption "shell-related tools"; 208 + editor.enable = mkEnableOption "editor tools"; 209 + vcs.enable = mkEnableOption "version control tools"; 210 + tools.enable = mkEnableOption "development utilities"; 211 + }; 212 + 213 + # Import sub-modules 214 + imports = [ 215 + ./shell 216 + ./editor 217 + ./vcs 218 + ./tools 219 + ]; 220 + } 221 + ``` 222 + 223 + ### Flake Integration 224 + 225 + ```nix 226 + # flake.nix modules section 227 + { 228 + imports = [ ../systems ]; 229 + 230 + perSystem = { ... }: { 231 + # ... 232 + }; 233 + 234 + flake = { 235 + homeModules = { 236 + dev = import ./dev/home.nix; 237 + desktop = import ./desktop/home.nix; 238 + }; 239 + 240 + nixosModules = { 241 + dev = import ./dev/nixos.nix; 242 + desktop = import ./desktop/nixos.nix; 243 + }; 244 + }; 245 + } 246 + ``` 247 + 248 + ### Usage in System Configuration 249 + 250 + ```nix 251 + # systems/kiwi.nix (NixOS) 252 + { 253 + imports = [ 254 + inputs.self.nixosModules.dev 255 + # ... other modules 256 + ]; 257 + 258 + dev.enable = true; 259 + dev.shell.enable = true; 260 + } 261 + ``` 262 + 263 + ```nix 264 + # modules/desktop/home.nix (Home-Manager) 265 + { config, self, ... }: 266 + { 267 + imports = [ 268 + self.homeModules.dev 269 + # ... other home modules 270 + ]; 271 + 272 + dev.enable = true; 273 + } 274 + ``` 275 + 276 + ### Key Differences from NixOS Modules 277 + 278 + | Aspect | NixOS Module | Home-Manager Module | 279 + |--------|--------------|---------------------| 280 + | Special args | `{ config, lib, pkgs, ... }` | `{ config, lib, pkgs, osConfig ? {}, ... }` | 281 + | System config | Direct access to `config.*` | Inherits via `osConfig.dev` | 282 + | User packages | `home.packages` | `home.packages` | 283 + | Programs | `programs.*` | `programs.*` | 284 + | System services | `services.*` | Not available | 285 + 286 + ### XDG Directories 287 + 288 + Home-manager manages XDG directories via `xdg.configFile`, `xdg.dataFile`, etc.: 289 + 290 + ```nix 291 + { config, ... }: 292 + { 293 + xdg.configFile."opencode/agents" = { 294 + source = ./agents; 295 + recursive = true; 296 + }; 297 + 298 + programs.opencode = { 299 + enable = true; 300 + package = opencodePkg; 301 + settings = { 302 + theme = "catppuccin-macchiato"; 303 + }; 304 + }; 305 + } 306 + ```
+35
modules/opencode/rules/typescript.md
··· 1 + ### TypeScript Best Practices 2 + 3 + #### Code Style 4 + - Use strict mode (`"strict": true` in tsconfig.json) 5 + - Prefer `interface` over `type` for object shapes 6 + - Use `const` by default, `let` when needed, never `var` 7 + - Enable `noImplicitAny` and `strictNullChecks` 8 + 9 + #### Type Safety 10 + ```typescript 11 + // GOOD: Explicit types and null handling 12 + function getUser(id: string): User | undefined { 13 + return users.get(id); 14 + } 15 + 16 + const user = getUser(id); 17 + if (user) { 18 + console.log(user.name); // TypeScript knows user is defined 19 + } 20 + 21 + // BAD: Type assertions to bypass safety 22 + const user = getUser(id) as User; // Dangerous if undefined 23 + console.log(user.name); // Might crash 24 + ``` 25 + 26 + #### Error Handling 27 + - Use try/catch for async operations 28 + - Define custom error types for domain errors 29 + - Never swallow errors silently 30 + 31 + #### Security 32 + - Validate all user input at API boundaries 33 + - Use parameterized queries for database operations 34 + - Sanitize data before rendering in DOM (prevent XSS) 35 + - Never use `eval()` or `Function()` with user input