Compare commits

..

4 Commits

Author SHA1 Message Date
m3tm3re
5b204c95e4 test(rules): add final QA evidence and mark review complete
Final Review Results:
- F1 (Plan Compliance): OKAY - Must Have [12/12], Must NOT Have [8/8]
- F2 (Code Quality): OKAY - All files pass quality criteria
- F3 (Manual QA): OKAY - Scenarios [5/5 pass]
- F4 (Scope Fidelity): OKAY - No unaccounted changes

All 21 tasks complete (T1-T17 + F1-F4)
2026-02-17 19:31:24 +01:00
m3tm3re
4e9da366e4 test(rules): add integration test evidence
- All 11 rule files verified (exist, under limits)
- Full lib integration verified (11 paths returned)
- Context budget verified (975 < 1500)
- All instruction paths resolve to real files
- opencode.nix rules entry verified

Refs: T17 of rules-system plan
2026-02-17 19:18:39 +01:00
m3tm3re
8910413315 feat(rules): add initial rule files for concerns, languages, and frameworks
Concerns (6 files):
- coding-style.md (163 lines): patterns, anti-patterns, error handling, SOLID
- naming.md (105 lines): naming conventions table per language
- documentation.md (149 lines): docstrings, WHY vs WHAT, README standards
- testing.md (134 lines): AAA pattern, mocking philosophy, TDD
- git-workflow.md (118 lines): conventional commits, branch naming, PR format
- project-structure.md (82 lines): directory layout, entry points, config placement

Languages (4 files):
- python.md (224 lines): uv, ruff, pyright, pytest, pydantic, idioms, anti-patterns
- typescript.md (150 lines): strict mode, discriminated unions, satisfies, as const
- nix.md (129 lines): flake structure, module patterns, alejandra, anti-patterns
- shell.md (100 lines): set -euo pipefail, shellcheck, quoting, POSIX

Frameworks (1 file):
- n8n.md (42 lines): workflow design, node patterns, Error Trigger, security

Context budget: 975 lines (concerns + python) < 1500 limit

Refs: T6-T16 of rules-system plan
2026-02-17 19:05:45 +01:00
m3tm3re
d475dde398 feat(rules): add rules directory structure and usage documentation
- Create rules/{concerns,languages,frameworks}/ directory structure
- Add USAGE.md with flake.nix integration examples
- Add plan and notepad files for rules-system implementation

Refs: T1, T5 of rules-system plan
2026-02-17 18:59:43 +01:00
28 changed files with 2520 additions and 4 deletions

View File

@@ -1,9 +1,9 @@
{
"active_plan": "/home/m3tam3re/p/AI/AGENTS/.sisyphus/plans/opencode-memory.md",
"started_at": "2026-02-14T04:43:37.746Z",
"active_plan": "/home/m3tam3re/p/AI/AGENTS/.sisyphus/plans/rules-system.md",
"started_at": "2026-02-17T17:50:08.922Z",
"session_ids": [
"ses_3a5a47a05ffeoNYfz2RARYsHX9"
"ses_393691db2ffe4YZvieMFehJe54"
],
"plan_name": "opencode-memory",
"plan_name": "rules-system",
"agent": "atlas"
}

View File

@@ -0,0 +1 @@
{"instructions":[".opencode-rules/concerns/coding-style.md",".opencode-rules/concerns/naming.md",".opencode-rules/concerns/documentation.md",".opencode-rules/concerns/testing.md",".opencode-rules/concerns/git-workflow.md",".opencode-rules/concerns/project-structure.md"],"shellHook":"# Create/update symlink to AGENTS rules directory\nln -sfn /nix/store/wsqzf0z3hg8mhpq484f24fm72qp4k6sg-AGENTS/rules .opencode-rules\n\n# Generate opencode.json configuration file\ncat > opencode.json <<'OPENCODE_EOF'\n{\"$schema\":\"https://opencode.ai/config.json\",\"instructions\":[\".opencode-rules/concerns/coding-style.md\",\".opencode-rules/concerns/naming.md\",\".opencode-rules/concerns/documentation.md\",\".opencode-rules/concerns/testing.md\",\".opencode-rules/concerns/git-workflow.md\",\".opencode-rules/concerns/project-structure.md\"]}\nOPENCODE_EOF\n"}

View File

@@ -0,0 +1 @@
{"instructions":[".opencode-rules/concerns/coding-style.md",".opencode-rules/concerns/naming.md",".opencode-rules/concerns/documentation.md",".opencode-rules/concerns/testing.md",".opencode-rules/concerns/git-workflow.md",".opencode-rules/concerns/project-structure.md",".opencode-rules/languages/python.md"],"shellHook":"# Create/update symlink to AGENTS rules directory\nln -sfn /nix/store/4li05383sgf4z0l6bxv8hmvgs600y56x-AGENTS/rules .opencode-rules\n\n# Generate opencode.json configuration file\ncat > opencode.json <<'OPENCODE_EOF'\n{\"$schema\":\"https://opencode.ai/config.json\",\"instructions\":[\".opencode-rules/concerns/coding-style.md\",\".opencode-rules/concerns/naming.md\",\".opencode-rules/concerns/documentation.md\",\".opencode-rules/concerns/testing.md\",\".opencode-rules/concerns/git-workflow.md\",\".opencode-rules/concerns/project-structure.md\",\".opencode-rules/languages/python.md\"]}\nOPENCODE_EOF\n"}

View File

@@ -0,0 +1 @@
{"instructions":[".opencode-rules/concerns/coding-style.md",".opencode-rules/concerns/naming.md",".opencode-rules/concerns/documentation.md",".opencode-rules/concerns/testing.md",".opencode-rules/concerns/git-workflow.md",".opencode-rules/concerns/project-structure.md",".opencode-rules/languages/python.md",".opencode-rules/languages/typescript.md",".opencode-rules/languages/nix.md",".opencode-rules/languages/shell.md"],"shellHook":"# Create/update symlink to AGENTS rules directory\nln -sfn /nix/store/qzsdn3m85qwarpd43x8k28sja40r21p7-AGENTS/rules .opencode-rules\n\n# Generate opencode.json configuration file\ncat > opencode.json <<'OPENCODE_EOF'\n{\"$schema\":\"https://opencode.ai/config.json\",\"instructions\":[\".opencode-rules/concerns/coding-style.md\",\".opencode-rules/concerns/naming.md\",\".opencode-rules/concerns/documentation.md\",\".opencode-rules/concerns/testing.md\",\".opencode-rules/concerns/git-workflow.md\",\".opencode-rules/concerns/project-structure.md\",\".opencode-rules/languages/python.md\",\".opencode-rules/languages/typescript.md\",\".opencode-rules/languages/nix.md\",\".opencode-rules/languages/shell.md\"]}\nOPENCODE_EOF\n"}

View File

@@ -0,0 +1 @@
{"instructions":[".opencode-rules/concerns/coding-style.md",".opencode-rules/concerns/naming.md",".opencode-rules/concerns/documentation.md",".opencode-rules/concerns/testing.md",".opencode-rules/concerns/git-workflow.md",".opencode-rules/concerns/project-structure.md",".opencode-rules/languages/python.md",".opencode-rules/frameworks/n8n.md"],"shellHook":"# Create/update symlink to AGENTS rules directory\nln -sfn /nix/store/55brjhy9m1vcgrnd100vmwf9bycjpzpi-AGENTS/rules .opencode-rules\n\n# Generate opencode.json configuration file\ncat > opencode.json <<'OPENCODE_EOF'\n{\"$schema\":\"https://opencode.ai/config.json\",\"instructions\":[\".opencode-rules/concerns/coding-style.md\",\".opencode-rules/concerns/naming.md\",\".opencode-rules/concerns/documentation.md\",\".opencode-rules/concerns/testing.md\",\".opencode-rules/concerns/git-workflow.md\",\".opencode-rules/concerns/project-structure.md\",\".opencode-rules/languages/python.md\",\".opencode-rules/frameworks/n8n.md\"]}\nOPENCODE_EOF\n"}

View File

@@ -0,0 +1 @@
{"instructions":[".opencode-rules/concerns/coding-style.md",".opencode-rules/concerns/naming.md",".opencode-rules/concerns/documentation.md",".opencode-rules/concerns/testing.md",".opencode-rules/concerns/git-workflow.md",".opencode-rules/concerns/project-structure.md",".opencode-rules/languages/python.md",".opencode-rules/custom.md"],"shellHook":"# Create/update symlink to AGENTS rules directory\nln -sfn /nix/store/r8yfirsyyii9x05qd5kfdvzcqv7sx6az-AGENTS/rules .opencode-rules\n\n# Generate opencode.json configuration file\ncat > opencode.json <<'OPENCODE_EOF'\n{\"$schema\":\"https://opencode.ai/config.json\",\"instructions\":[\".opencode-rules/concerns/coding-style.md\",\".opencode-rules/concerns/naming.md\",\".opencode-rules/concerns/documentation.md\",\".opencode-rules/concerns/testing.md\",\".opencode-rules/concerns/git-workflow.md\",\".opencode-rules/concerns/project-structure.md\",\".opencode-rules/languages/python.md\",\".opencode-rules/custom.md\"]}\nOPENCODE_EOF\n"}

View File

@@ -0,0 +1,153 @@
# Opencode Rules Nix Module - Manual QA Results
## Test Summary
Date: 2025-02-17
Module: `/home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix`
Test Type: Manual QA (nix eval)
---
## Scenario Results
### Scenario 1: Empty Config (Defaults Only)
**Command**: `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /home/m3tam3re/p/NIX/nixpkgs/lib {lib = pkgs.lib;}; in m3taLib.opencode-rules.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; }'`
**Results**:
- ✅ Valid JSON output
- ✅ Has `$schema` field in embedded opencode.json
- ✅ Has `instructions` field
- ✅ Correct instruction count: 6 (default concerns only)
**Expected Instructions**:
1. `.opencode-rules/concerns/coding-style.md`
2. `.opencode-rules/concerns/naming.md`
3. `.opencode-rules/concerns/documentation.md`
4. `.opencode-rules/concerns/testing.md`
5. `.opencode-rules/concerns/git-workflow.md`
6. `.opencode-rules/concerns/project-structure.md`
---
### Scenario 2: Single Language (Python)
**Command**: `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /home/m3tam3re/p/NIX/nixpkgs/lib {lib = pkgs.lib;}; in m3taLib.opencode-rules.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; languages = ["python"]; }'`
**Results**:
- ✅ Valid JSON output
- ✅ Has `$schema` field in embedded opencode.json
- ✅ Has `instructions` field
- ✅ Correct instruction count: 7 (6 concerns + 1 language)
**Expected Instructions**:
- All 6 default concerns
- `.opencode-rules/languages/python.md`
---
### Scenario 3: Multi-Language
**Command**: `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /home/m3tam3re/p/NIX/nixpkgs/lib {lib = pkgs.lib;}; in m3taLib.opencode-rules.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; languages = ["python" "typescript" "nix" "shell"]; }'`
**Results**:
- ✅ Valid JSON output
- ✅ Has `$schema` field in embedded opencode.json
- ✅ Has `instructions` field
- ✅ Correct instruction count: 10 (6 concerns + 4 languages)
**Expected Instructions**:
- All 6 default concerns
- `.opencode-rules/languages/python.md`
- `.opencode-rules/languages/typescript.md`
- `.opencode-rules/languages/nix.md`
- `.opencode-rules/languages/shell.md`
---
### Scenario 4: With Frameworks
**Command**: `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /home/m3tam3re/p/NIX/nixpkgs/lib {lib = pkgs.lib;}; in m3taLib.opencode-rules.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; languages = ["python"]; frameworks = ["n8n"]; }'`
**Results**:
- ✅ Valid JSON output
- ✅ Has `$schema` field in embedded opencode.json
- ✅ Has `instructions` field
- ✅ Correct instruction count: 8 (6 concerns + 1 language + 1 framework)
**Expected Instructions**:
- All 6 default concerns
- `.opencode-rules/languages/python.md`
- `.opencode-rules/frameworks/n8n.md`
---
### Scenario 5: Extra Instructions
**Command**: `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /home/m3tam3re/p/NIX/nixpkgs/lib {lib = pkgs.lib;}; in m3taLib.opencode-rules.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; languages = ["python"]; extraInstructions = [".opencode-rules/custom.md"]; }'`
**Results**:
- ✅ Valid JSON output
- ✅ Has `$schema` field in embedded opencode.json
- ✅ Has `instructions` field
- ✅ Correct instruction count: 8 (6 concerns + 1 language + 1 custom)
**Expected Instructions**:
- All 6 default concerns
- `.opencode-rules/languages/python.md`
- `.opencode-rules/custom.md`
---
## Content Quality Spot Checks
### 1. coding-style.md (Concern Rule)
**Assessment**: ✅ High Quality
- Clear critical rules with "Always/Never" directives
- Good vs. bad code examples
- Comprehensive coverage: formatting, patterns, error handling, type safety, function design, SOLID
- Well-structured sections
### 2. python.md (Language Rule)
**Assessment**: ✅ High Quality
- Modern toolchain recommendations (uv, ruff, pyright, pytest, hypothesis)
- Common idioms with practical examples
- Anti-patterns with explanations
- Project setup structure
- Clear, actionable code snippets
### 3. n8n.md (Framework Rule)
**Assessment**: ✅ High Quality
- Concise workflow design principles
- Clear naming conventions
- Error handling patterns
- Security best practices
- Actionable testing guidelines
---
## Issues Encountered
### Socket File Issue
**Issue**: `nix eval` failed with `error: file '/home/m3tam3re/p/AI/AGENTS/.beads/bd.sock' has an unsupported type`
**Workaround**: Temporarily moved `.beads` directory outside the AGENTS tree during testing
**Root Cause**: Nix attempts to evaluate/store the `agents` path recursively and encounters unsupported socket files (Unix domain sockets)
**Recommendation**: Consider adding `.beads` to `.gitignore` and excluding it from path evaluation if possible, or document this limitation for users
---
## Final Verdict
```
Scenarios [5/5 pass] | VERDICT: OKAY
```
### Summary
- All 5 test scenarios executed successfully
- All JSON outputs are valid and properly structured
- All embedded `opencode.json` configurations have required `$schema` and `instructions` fields
- Instruction counts match expected values for each scenario
- Rule content quality is high across concern, language, and framework rules
- Shell hook properly generates symlink and configuration file
### Notes
- Socket file issue requires workaround (documented)
- Module correctly handles default concerns, multiple languages, frameworks, and custom instructions
- Code examples in rules are clear and actionable

View File

@@ -0,0 +1,6 @@
=== Context Budget ===
Concerns: 751
Python: 224
Total (concerns + python): 975
Limit: 1500
RESULT: PASS (under 1500)

View File

@@ -0,0 +1 @@
[".opencode-rules/concerns/coding-style.md",".opencode-rules/concerns/naming.md",".opencode-rules/concerns/documentation.md",".opencode-rules/concerns/testing.md",".opencode-rules/concerns/git-workflow.md",".opencode-rules/concerns/project-structure.md",".opencode-rules/languages/python.md",".opencode-rules/languages/typescript.md",".opencode-rules/languages/nix.md",".opencode-rules/languages/shell.md",".opencode-rules/frameworks/n8n.md"]

View File

@@ -0,0 +1,16 @@
=== Task 17 Integration Test ===
File Line Counts:
163 /home/m3tam3re/p/AI/AGENTS/rules/concerns/coding-style.md
149 /home/m3tam3re/p/AI/AGENTS/rules/concerns/documentation.md
118 /home/m3tam3re/p/AI/AGENTS/rules/concerns/git-workflow.md
105 /home/m3tam3re/p/AI/AGENTS/rules/concerns/naming.md
82 /home/m3tam3re/p/AI/AGENTS/rules/concerns/project-structure.md
134 /home/m3tam3re/p/AI/AGENTS/rules/concerns/testing.md
129 /home/m3tam3re/p/AI/AGENTS/rules/languages/nix.md
224 /home/m3tam3re/p/AI/AGENTS/rules/languages/python.md
100 /home/m3tam3re/p/AI/AGENTS/rules/languages/shell.md
150 /home/m3tam3re/p/AI/AGENTS/rules/languages/typescript.md
42 /home/m3tam3re/p/AI/AGENTS/rules/frameworks/n8n.md
1396 total
RESULT: All 11 files present

View File

@@ -0,0 +1,13 @@
=== Path Resolution Check ===
OK: rules/concerns/coding-style.md exists
OK: rules/concerns/naming.md exists
OK: rules/concerns/documentation.md exists
OK: rules/concerns/testing.md exists
OK: rules/concerns/git-workflow.md exists
OK: rules/concerns/project-structure.md exists
OK: rules/languages/python.md exists
OK: rules/languages/typescript.md exists
OK: rules/languages/nix.md exists
OK: rules/languages/shell.md exists
OK: rules/frameworks/n8n.md exists
RESULT: All paths resolve

View File

@@ -0,0 +1,60 @@
# Rules System - Learnings
## 2026-02-17T17:50 Session Start
### Architecture Pattern
- Nix helper lives in nixpkgs repo (not AGENTS) - follows ports.nix pattern
- AGENTS repo stays pure content (markdown rule files only)
- Pattern: `{lib}: { mkOpencodeRules = ...; }`
### Key Files
- nixpkgs: `/home/m3tam3re/p/NIX/nixpkgs/lib/ports.nix` (reference pattern)
- nixos-config: `/home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix` (deployment)
- AGENTS: `rules/` directory (content)
### mkOpencodeRules Signature
```nix
mkOpencodeRules {
agents = inputs.agents; # Non-flake input path
languages = [ "python" "typescript" ];
concerns ? [ "coding-style" "naming" "documentation" "testing" "git-workflow" "project-structure" ];
frameworks ? [ "n8n" ];
extraInstructions ? [];
}
```
### Consumption Pattern
```nix
let
m3taLib = inputs.m3ta-nixpkgs.lib.${system};
rules = m3taLib.opencode-rules.mkOpencodeRules {
agents = inputs.agents;
languages = [ "python" ];
};
in pkgs.mkShell { shellHook = rules.shellHook; }
```
### Wave 1: Directory Structure (2026-02-17T18:54)
- Successfully created rules/ directory with subdirectories: concerns/, languages/, frameworks/
- Added .gitkeep files to each subdirectory (git needs at least one file to track empty directories)
- Pattern reference: followed skills/ directory structure convention
- USAGE.md already existed in rules/ (created by previous wave)
- AGENTS repo stays pure content - no Nix files added (as planned)
- Verification: ls confirms all three .gitkeep files exist in proper locations
### Wave 2: Nix Helper Implementation (2026-02-17T19:02)
- Successfully created `/home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix`
- Followed ports.nix pattern EXACTLY: `{lib}: { mkOpencodeRules = ...; }`
- Function signature: `{ agents, languages ? [], concerns ? [...], frameworks ? [], extraInstructions ? [] }`
- Returns: `{ shellHook, instructions }`
- Instructions list built using map functions for each category (concerns, languages, frameworks, extra)
- ShellHook creates symlink `.opencode-rules``${agents}/rules` and generates `opencode.json` with `$schema`
- JSON generation uses `builtins.toJSON opencodeConfig` where opencodeConfig = `{ "$schema" = "..."; inherit instructions; }`
- Comprehensive doc comments added matching ports.nix style (multi-line comments with usage examples)
- All paths relative to project root via `.opencode-rules/` prefix
- Verification passed:
- `nix eval --impure` shows file loads and exposes `mkOpencodeRules`
- Function returns `{ instructions, shellHook }`
- Instructions list builds correctly (concerns + languages + frameworks + extra)
- `nix-instantiate --parse` validates syntax is correct
- ShellHook contains both symlink creation and JSON generation (heredoc pattern)

View File

@@ -0,0 +1,804 @@
# Centralized Rules & Per-Project Context Injection System
## TL;DR
> **Quick Summary**: Create a `rules/` directory in the AGENTS repository containing modular AI coding rules (per-concern + per-language), deployed centrally via Home Manager. A `mkOpencodeRules` Nix helper function lives in the nixpkgs repo (following the existing `ports.nix` → `mkPortHelpers` pattern), generating per-project `opencode.json` via devShell activation.
>
> **Deliverables**:
> - 6 concern rule files (coding-style, naming, documentation, testing, git-workflow, project-structure)
> - 5 language/framework rule files (python, typescript, nix, shell, n8n)
> - `lib/opencode-rules.nix` in nixpkgs repo — `mkOpencodeRules` helper function
> - Updated `lib/default.nix` in nixpkgs repo — imports opencode-rules
> - Updated `opencode.nix` in nixos-config — deploys rules/ alongside existing skills
> - `rules/USAGE.md` — per-project adoption documentation
>
> **Repos Touched**: 3 (AGENTS, nixpkgs, nixos-config)
> **Estimated Effort**: Medium (11 rule files + 3 nix changes + 1 doc)
> **Parallel Execution**: YES — 4 waves
> **Critical Path**: T1-T3 (foundation) → T6-T16 (content) → T17 (verification)
---
## Context
### Original Request
User wants to streamline their Agent workflow by centrally managing language-specific and framework-specific coding rules in the AGENTS repository, while allowing project-specific overrides. Rules should be injected per-project using Nix flakes + direnv.
### Interview Summary
**Key Discussions**:
- **Loading strategy**: Always loaded (not lazy) — rules always in context when project activates
- **Composition mechanism**: Nix flake devShell — each project declares languages/frameworks needed
- **Rule granularity**: Per concern with separate language files for deep patterns
- **Override strategy**: Project-level AGENTS.md overrides central rules (OpenCode's native precedence)
- **opencode.json**: No project-specific one exists yet — devShell generates it entirely
- **Nix helper location**: Lives in `m3ta-nixpkgs` repo at `lib/opencode-rules.nix` (follows `ports.nix` pattern)
- **AGENTS repo stays pure content**: No Nix code — only markdown rule files
**Research Findings**:
- OpenCode `instructions` field in `opencode.json` loads external .md files as always-on context
- Anthropic guide: progressive disclosure, composability, 500-line max, use TOCs for long files
- Best practices: 100-200 lines per file, imperative language, micro-examples (correct/incorrect)
- Rule files benefit from sandwich principle: critical constraints at START and END
### Metis Review
**Identified Gaps** (addressed):
- **Rule update strategy**: When rules change in AGENTS repo, projects run `nix flake update agents`. Standard Nix flow.
- **Multi-language projects**: `mkOpencodeRules { languages = [ "python" "typescript" ]; }` — list multiple.
- **Context window budget**: ~800-1300 lines total. Well under 1500-line budget.
- **Empty rules selection**: `mkOpencodeRules {}` loads only concern files (defaults to all 6).
### Architecture Decision: Nix Helper Location
**Decision**: `mkOpencodeRules` lives in **nixpkgs repo** (`/home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix`), NOT in AGENTS repo.
**Rationale**:
- nixpkgs already has `lib/ports.nix``mkPortHelpers` as an identical pattern
- nixpkgs is already consumed by all configs: `inputs.m3ta-nixpkgs.lib.${system}`
- AGENTS repo stays pure content (markdown + configs), no Nix code
- Projects already have `m3ta-nixpkgs` as a flake input — no new input needed for the helper
**Consumption pattern** (per-project):
```nix
let
m3taLib = inputs.m3ta-nixpkgs.lib.${system};
rules = m3taLib.opencode-rules.mkOpencodeRules {
agents = inputs.agents; # Non-flake input with rule content
languages = [ "python" ];
};
in pkgs.mkShell { shellHook = rules.shellHook; }
```
---
## Work Objectives
### Core Objective
Create a centralized, modular AI coding rules system managed in the AGENTS repo, with a Nix helper in nixpkgs for per-project injection via devShell + direnv.
### Concrete Deliverables
- `rules/concerns/{coding-style,naming,documentation,testing,git-workflow,project-structure}.md` — in AGENTS repo
- `rules/languages/{python,typescript,nix,shell}.md` — in AGENTS repo
- `rules/frameworks/n8n.md` — in AGENTS repo
- `rules/USAGE.md` — adoption documentation in AGENTS repo
- `lib/opencode-rules.nix` — in nixpkgs repo (`/home/m3tam3re/p/NIX/nixpkgs/`)
- Updated `lib/default.nix` — in nixpkgs repo (add import)
- Updated `opencode.nix` — in nixos-config repo (`/home/m3tam3re/p/NIX/nixos-config/home/features/coding/`)
### Definition of Done
- [ ] All 11 rule files exist and are under 250 lines each
- [ ] `lib/opencode-rules.nix` in nixpkgs exports `mkOpencodeRules` following `ports.nix` pattern
- [ ] `opencode.nix` deploys `rules/` to `~/.config/opencode/rules/`
- [ ] A project can use `m3taLib.opencode-rules.mkOpencodeRules` in devShell
### Must Have
- All rule files use imperative language ("Always use...", "Never...")
- Every rule includes micro-examples (correct vs incorrect, 2-3 lines each)
- Concern files are language-agnostic; language subsections are brief pointers
- Language files go deep into toolchain, idioms, anti-patterns
- `mkOpencodeRules` accepts: `{ agents, languages ? [], concerns ? [...], frameworks ? [], extraInstructions ? [] }`
- `mkOpencodeRules` follows `ports.nix` pattern: `{lib}: { mkOpencodeRules = ...}`
- shellHook creates `.opencode-rules` symlink + generates `opencode.json`
- Both `.opencode-rules` and `opencode.json` must be gitignored (documented in USAGE.md)
### Must NOT Have (Guardrails)
- Rule files MUST NOT exceed 250 lines
- Total loaded rules MUST NOT exceed 1500 lines for any realistic config
- Concern files MUST NOT contain language-specific implementation details
- MUST NOT put Nix code in AGENTS repo — AGENTS stays pure content
- MUST NOT add rule versioning, testing framework, or generator CLI
- MUST NOT create rules for docker, k8s, terraform — out of scope
- MUST NOT modify existing skills, agents, prompts, or commands
- MUST NOT use generic advice ("write clean code", "follow best practices")
---
## Verification Strategy (MANDATORY)
> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions.
### Test Decision
- **Infrastructure exists**: NO (config/documentation repos)
- **Automated tests**: NO
- **Framework**: none
### QA Policy
Every task MUST include agent-executed QA scenarios.
Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`.
| Deliverable Type | Verification Tool | Method |
|------------------|-------------------|--------|
| Markdown rule files | Bash (wc, grep) | Line count, micro-examples, imperative language |
| Nix expressions | Bash (nix eval) | Evaluate, check errors |
| Shell integration | Bash | Verify symlink + opencode.json generated |
| Cross-repo | Bash (grep) | Verify entries in correct files |
---
## Execution Strategy
### Parallel Execution Waves
```
Wave 1 (Foundation — 5 tasks, all parallel):
├── Task 1: Create rules/ directory structure in AGENTS repo [quick]
├── Task 2: Create lib/opencode-rules.nix in nixpkgs repo [quick]
├── Task 3: Update lib/default.nix in nixpkgs repo [quick]
├── Task 4: Update opencode.nix in nixos-config repo [quick]
└── Task 5: Create rules/USAGE.md in AGENTS repo [quick]
Wave 2 (Content — 11 rule files, all parallel):
├── Task 6: concerns/coding-style.md [writing]
├── Task 7: concerns/naming.md [writing]
├── Task 8: concerns/documentation.md [writing]
├── Task 9: concerns/testing.md [writing]
├── Task 10: concerns/git-workflow.md [writing]
├── Task 11: concerns/project-structure.md [writing]
├── Task 12: languages/python.md [writing]
├── Task 13: languages/typescript.md [writing]
├── Task 14: languages/nix.md [writing]
├── Task 15: languages/shell.md [writing]
└── Task 16: frameworks/n8n.md [writing]
Wave 3 (Verification):
└── Task 17: End-to-end integration test [deep]
Wave FINAL (Review — 4 parallel):
├── Task F1: Plan compliance audit (oracle)
├── Task F2: Code quality review (unspecified-high)
├── Task F3: Real manual QA (unspecified-high)
└── Task F4: Scope fidelity check (deep)
Critical Path: T1-T3 → T6-T16 (parallel) → T17 → F1-F4
Max Concurrent: 11 (Wave 2)
```
### Dependency Matrix
| Task | Depends On | Blocks | Wave |
|------|------------|--------|------|
| 1 | — | 5, 6-16, 17 | 1 |
| 2, 3 | — | 17 | 1 |
| 4 | — | 17 | 1 |
| 5 | 1, 2 | 17 | 1 |
| 6-16 | 1 | 17 | 2 |
| 17 | 2-5, 6-16 | F1-F4 | 3 |
| F1-F4 | 17 | — | FINAL |
### Agent Dispatch Summary
| Wave | # Parallel | Tasks and Agent Category |
|------|------------|------------------------|
| 1 | **5** | T1-T5 → `quick` |
| 2 | **11** | T6-T16 → `writing` |
| 3 | **1** | T17 → `deep` |
| FINAL | **4** | F1 → `oracle`, F2,F3 → `unspecified-high`, F4 → `deep` |
---
## TODOs
- [x] 1. Create rules/ directory structure in AGENTS repo
**What to do**:
- Create directory structure in `/home/m3tam3re/p/AI/AGENTS/`: `rules/concerns/`, `rules/languages/`, `rules/frameworks/`
- Add `.gitkeep` files to each directory so they're tracked before content is added
- This is the CONTENT repo only — NO Nix code goes here
**Must NOT do**:
- Do not create any Nix files in AGENTS repo
- Do not create rule content files (those are Wave 2)
**Recommended Agent Profile**:
- **Category**: `quick`
- **Skills**: []
**Parallelization**:
- **Can Run In Parallel**: YES
- **Parallel Group**: Wave 1 (with Tasks 2-5)
- **Blocks**: Tasks 5, 6-16, 17
- **Blocked By**: None
**References**:
- `/home/m3tam3re/p/AI/AGENTS/skills/` — existing directory structure pattern
**Acceptance Criteria**:
**QA Scenarios (MANDATORY):**
```
Scenario: Directory structure exists
Tool: Bash
Preconditions: None
Steps:
1. Run `ls /home/m3tam3re/p/AI/AGENTS/rules/concerns/.gitkeep /home/m3tam3re/p/AI/AGENTS/rules/languages/.gitkeep /home/m3tam3re/p/AI/AGENTS/rules/frameworks/.gitkeep`
Expected Result: All 3 .gitkeep files exist
Failure Indicators: "No such file or directory"
Evidence: .sisyphus/evidence/task-1-dirs.txt
Scenario: No Nix files in AGENTS repo rules/
Tool: Bash
Preconditions: Dirs created
Steps:
1. Run `find /home/m3tam3re/p/AI/AGENTS/rules/ -name '*.nix' | wc -l`
Expected Result: Count is 0
Failure Indicators: Count > 0
Evidence: .sisyphus/evidence/task-1-no-nix.txt
```
**Commit**: YES
- Message: `feat(rules): add rules directory structure`
- Files: `rules/concerns/.gitkeep`, `rules/languages/.gitkeep`, `rules/frameworks/.gitkeep`
---
- [x] 2. Create `lib/opencode-rules.nix` in nixpkgs repo
**What to do**:
- Create `/home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix`
- Follow the EXACT pattern of `lib/ports.nix`: `{lib}: { mkOpencodeRules = ...; }`
- The function must accept: `{ agents, languages ? [], concerns ? [ "coding-style" "naming" "documentation" "testing" "git-workflow" "project-structure" ], frameworks ? [], extraInstructions ? [] }`
- `agents` parameter = the non-flake input (path to AGENTS repo in Nix store)
- It must return: `{ shellHook = "..."; instructions = [...]; }`
- `shellHook` must: (a) create `.opencode-rules` symlink to `${agents}/rules`, (b) generate `opencode.json` with `$schema` and `instructions` fields using `builtins.toJSON`
- `instructions` = list of paths relative to project root via `.opencode-rules/` symlink
- Include comprehensive Nix doc comments (matching ports.nix style)
**Must NOT do**:
- Do not deviate from ports.nix pattern
- Do not put any code in AGENTS repo
**Recommended Agent Profile**:
- **Category**: `quick`
- Reason: One Nix file following established pattern
- **Skills**: []
**Parallelization**:
- **Can Run In Parallel**: YES
- **Parallel Group**: Wave 1 (with Tasks 1, 3-5)
- **Blocks**: Tasks 5, 17
- **Blocked By**: None
**References**:
**Pattern References**:
- `/home/m3tam3re/p/NIX/nixpkgs/lib/ports.nix` — MUST follow this exact pattern: `{lib}: { mkPortHelpers = portsConfig: let ... in { ... }; }`
- `/home/m3tam3re/p/NIX/nixpkgs/lib/default.nix` — shows how lib modules are imported: `import ./ports.nix {inherit lib;}`
- `/home/m3tam3re/p/NIX/nixpkgs/flake.nix:73-77` — shows how lib is exposed: `lib = forAllSystems (system: ... import ./lib {lib = pkgs.lib;});`
**External References**:
- OpenCode rules docs: `https://opencode.ai/docs/rules/` — `instructions` field accepts relative paths
**WHY Each Reference Matters**:
- `ports.nix` is the canonical pattern for lib functions in this repo — `{lib}:` signature, doc comments, nested `let ... in`
- `default.nix` shows how the new module gets wired in
- `flake.nix` confirms how consumers access it: `m3ta-nixpkgs.lib.${system}.opencode-rules.mkOpencodeRules`
**Acceptance Criteria**:
**QA Scenarios (MANDATORY):**
```
Scenario: opencode-rules.nix evaluates without errors
Tool: Bash
Preconditions: File created
Steps:
1. Run `nix eval --impure --expr 'let pkgs = import <nixpkgs> {}; lib = (import /home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix {lib = pkgs.lib;}); in builtins.attrNames lib' 2>&1`
Expected Result: Output contains "mkOpencodeRules"
Failure Indicators: "error:" in output
Evidence: .sisyphus/evidence/task-2-eval.txt
Scenario: mkOpencodeRules generates correct paths
Tool: Bash
Preconditions: File created
Steps:
1. Run `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; lib = (import /home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix {lib = pkgs.lib;}); in (lib.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; languages = ["python" "typescript"]; frameworks = ["n8n"]; }).instructions'`
Expected Result: JSON array with 9 paths (6 concerns + 2 languages + 1 framework), all starting with ".opencode-rules/"
Failure Indicators: Wrong count, wrong prefix, error
Evidence: .sisyphus/evidence/task-2-paths.txt
Scenario: Default (empty languages) works
Tool: Bash
Preconditions: File created
Steps:
1. Run `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; lib = (import /home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix {lib = pkgs.lib;}); in (lib.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; }).instructions'`
Expected Result: JSON array with 6 paths (concerns only)
Failure Indicators: Extra paths, error
Evidence: .sisyphus/evidence/task-2-defaults.txt
Scenario: shellHook generates valid JSON
Tool: Bash
Preconditions: File created
Steps:
1. Run `nix eval --impure --raw --expr 'let pkgs = import <nixpkgs> {}; lib = (import /home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix {lib = pkgs.lib;}); in (lib.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; languages = ["python"]; }).shellHook' | sh -c 'eval "$(cat)"' && python3 -m json.tool opencode.json`
Expected Result: Valid JSON output with "$schema" and "instructions" fields
Failure Indicators: JSON parse error, missing fields
Evidence: .sisyphus/evidence/task-2-json.txt
```
**Commit**: YES
- Message: `feat(lib): add opencode-rules helper for per-project rule injection`
- Files: `lib/opencode-rules.nix`
- Pre-commit: `nix eval --impure --expr '...'`
---
- [x] 3. Update `lib/default.nix` in nixpkgs repo
**What to do**:
- Add one line to `/home/m3tam3re/p/NIX/nixpkgs/lib/default.nix` to import opencode-rules:
`opencode-rules = import ./opencode-rules.nix {inherit lib;};`
- Place it after the existing `ports = import ./ports.nix {inherit lib;};` line
- Update the comment at line 10 to remove it (it's a placeholder)
**Must NOT do**:
- Do not modify the ports import
- Do not change the function signature `{lib}:`
**Recommended Agent Profile**:
- **Category**: `quick`
- **Skills**: []
**Parallelization**:
- **Can Run In Parallel**: YES (but logically pairs with Task 2)
- **Parallel Group**: Wave 1
- **Blocks**: Task 17
- **Blocked By**: Task 2 (opencode-rules.nix must exist first)
**References**:
- `/home/m3tam3re/p/NIX/nixpkgs/lib/default.nix:6-12` — current file content, add after line 8
**Acceptance Criteria**:
**QA Scenarios (MANDATORY):**
```
Scenario: default.nix imports opencode-rules
Tool: Bash
Preconditions: Both files updated
Steps:
1. Run `grep 'opencode-rules' /home/m3tam3re/p/NIX/nixpkgs/lib/default.nix`
Expected Result: Line shows `opencode-rules = import ./opencode-rules.nix {inherit lib;};`
Failure Indicators: No match
Evidence: .sisyphus/evidence/task-3-import.txt
Scenario: Full lib evaluates
Tool: Bash
Preconditions: Both files updated
Steps:
1. Run `nix eval --impure --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /home/m3tam3re/p/NIX/nixpkgs/lib {lib = pkgs.lib;}; in builtins.attrNames m3taLib' 2>&1`
Expected Result: Output includes both "ports" and "opencode-rules"
Failure Indicators: Missing "opencode-rules" or error
Evidence: .sisyphus/evidence/task-3-full-lib.txt
```
**Commit**: YES (groups with Task 2)
- Message: `feat(lib): add opencode-rules helper for per-project rule injection`
- Files: `lib/default.nix`, `lib/opencode-rules.nix`
---
- [x] 4. Update opencode.nix in nixos-config repo
**What to do**:
- Add `rules/` deployment to `xdg.configFile` in `/home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix`
- Add entry: `"opencode/rules" = { source = "${inputs.agents}/rules"; recursive = true; };`
- Place it alongside existing entries for commands, context, prompts, skills (lines 2-18)
**Must NOT do**:
- Do not modify any existing entries
- Do not change agents, MCP, providers, or oh-my-opencode config
- Do not run `home-manager switch`
**Recommended Agent Profile**:
- **Category**: `quick`
- **Skills**: []
**Parallelization**:
- **Can Run In Parallel**: YES
- **Parallel Group**: Wave 1
- **Blocks**: Task 17
- **Blocked By**: None
**References**:
- `/home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix:2-18` — existing xdg.configFile entries
**Acceptance Criteria**:
**QA Scenarios (MANDATORY):**
```
Scenario: opencode.nix contains rules entry
Tool: Bash
Preconditions: File updated
Steps:
1. Run `grep -c 'opencode/rules' /home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix`
2. Run `grep -c 'opencode/commands\|opencode/context\|opencode/prompts\|opencode/skills' /home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix`
Expected Result: Rules count is 1, existing count is 4 (all preserved)
Failure Indicators: Count mismatch
Evidence: .sisyphus/evidence/task-4-opencode-nix.txt
```
**Commit**: YES
- Message: `feat(opencode): deploy rules/ to ~/.config/opencode/rules/ via home-manager`
- Files: `opencode.nix`
---
- [x] 5. Create `rules/USAGE.md` in AGENTS repo
**What to do**:
- Document how to use `mkOpencodeRules` in a project's `flake.nix`
- Show the nixpkgs consumption pattern: `m3taLib.opencode-rules.mkOpencodeRules { agents = inputs.agents; languages = ["python"]; }`
- Complete example `flake.nix` devShell snippet showing: `inputs.agents` + `inputs.m3ta-nixpkgs` + `mkOpencodeRules` + `shellHook`
- Document `.gitignore` additions: `.opencode-rules` and `opencode.json`
- Explain project-level `AGENTS.md` overrides
- Explain update flow: `nix flake update agents`
- Keep concise: max 100 lines
**Must NOT do**:
- Do not create a README.md (repo anti-pattern)
- Do not reference `rules/default.nix` — the helper lives in nixpkgs, not AGENTS
**Recommended Agent Profile**:
- **Category**: `quick`
- **Skills**: []
**Parallelization**:
- **Can Run In Parallel**: YES
- **Parallel Group**: Wave 1
- **Blocks**: Task 17
- **Blocked By**: Tasks 1, 2 (needs to reference both structures)
**References**:
- `/home/m3tam3re/p/AI/AGENTS/AGENTS.md` — repo documentation style (concise, code-heavy)
- `/home/m3tam3re/p/NIX/nixpkgs/lib/ports.nix:1-42` — the doc comment style used for lib functions
- OpenCode rules docs: `https://opencode.ai/docs/rules/` — `instructions` field
**Acceptance Criteria**:
**QA Scenarios (MANDATORY):**
```
Scenario: USAGE.md has required content
Tool: Bash
Preconditions: File created
Steps:
1. Run `wc -l /home/m3tam3re/p/AI/AGENTS/rules/USAGE.md`
2. Run `grep -c 'm3ta-nixpkgs\|mkOpencodeRules\|gitignore\|AGENTS.md\|nix flake update' /home/m3tam3re/p/AI/AGENTS/rules/USAGE.md`
Expected Result: Under 100 lines, key terms >= 5
Failure Indicators: Over 100 lines or missing key concepts
Evidence: .sisyphus/evidence/task-5-usage.txt
```
**Commit**: YES (groups with T1)
- Message: `feat(rules): add rules directory structure and usage documentation`
- Files: `rules/USAGE.md`, `rules/concerns/.gitkeep`, `rules/languages/.gitkeep`, `rules/frameworks/.gitkeep`
---
- [x] 6. Create `rules/concerns/coding-style.md`
**What to do**:
- Write coding style rules: code formatting, patterns/anti-patterns, error handling, type safety, function design, DRY/SOLID
- Imperative language ("Always...", "Never...", "Prefer..."), micro-examples (`Correct:` / `Incorrect:`)
- Keep under 200 lines, sandwich principle (critical rules at start and end)
**Must NOT do**: No language-specific toolchain details, no generic advice ("write clean code"), max 200 lines
**Recommended Agent Profile**: `writing`, Skills: []
**Parallelization**: Wave 2, parallel with T7-T16. Blocks T17. Blocked by T1.
**References**:
- `/home/m3tam3re/p/AI/AGENTS/skills/skill-creator/SKILL.md` — documentation density example
- Awesome Cursorrules: `https://github.com/PatrickJS/awesome-cursorrules`
**Acceptance Criteria**:
```
Scenario: Quality check
Tool: Bash
Steps:
1. `wc -l` → under 200
2. `grep -c 'Correct:\|Incorrect:\|Always\|Never\|Prefer'` → >= 10
3. `grep -c '```'` → >= 6 (3+ example pairs)
4. `grep -ic 'write clean code\|follow best practices'` → 0
Evidence: .sisyphus/evidence/task-6-coding-style.txt
```
**Commit**: NO (groups with Wave 2 commit in T17)
---
- [x] 7. Create `rules/concerns/naming.md`
**What to do**:
- Naming conventions: files, variables, functions, classes, modules, constants
- Per-language table (Python=snake_case, TS=camelCase, Nix=camelCase, Shell=UPPER_SNAKE)
- Keep under 150 lines
**Must NOT do**: No toolchain details, max 150 lines
**Recommended Agent Profile**: `writing`, Skills: []
**Parallelization**: Wave 2. Blocks T17. Blocked by T1.
**References**: `/home/m3tam3re/p/AI/AGENTS/AGENTS.md:58-62` — existing naming conventions
**Acceptance Criteria**:
```
Scenario: `wc -l` → under 150, `grep -c 'snake_case\|camelCase\|PascalCase\|UPPER_SNAKE'` → >= 4
Evidence: .sisyphus/evidence/task-7-naming.txt
```
**Commit**: NO
---
- [x] 8. Create `rules/concerns/documentation.md`
**What to do**: When to document, docstring formats, inline comment philosophy (WHY not WHAT), README standards. Under 150 lines.
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**References**: `/home/m3tam3re/p/AI/AGENTS/AGENTS.md` — repo's own style
**Acceptance Criteria**: `wc -l` < 150, `grep -c 'WHY\|WHAT\|Correct:\|Incorrect:'` >= 4
**Commit**: NO
---
- [x] 9. Create `rules/concerns/testing.md`
**What to do**: Arrange-act-assert, behavior vs implementation testing, mocking philosophy, coverage, TDD. Under 200 lines.
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**References**: `/home/m3tam3re/p/AI/AGENTS/AGENTS.md:73-82` — existing test philosophy
**Acceptance Criteria**: `wc -l` < 200, `grep -ic 'arrange\|act\|assert\|mock\|behavior'` >= 4
**Commit**: NO
---
- [x] 10. Create `rules/concerns/git-workflow.md`
**What to do**: Conventional commits, branch naming, PR descriptions, squash vs merge. Under 120 lines.
**Recommended Agent Profile**: `writing`, Skills: [`git-master`]
**Parallelization**: Wave 2. Blocked by T1.
**References**: `https://www.conventionalcommits.org/en/v1.0.0/`
**Acceptance Criteria**: `wc -l` < 120, `grep -c 'feat\|fix\|refactor\|docs\|chore'` >= 5
**Commit**: NO
---
- [x] 11. Create `rules/concerns/project-structure.md`
**What to do**: Directory layout, module organization, entry points, config placement. Per-type: Python (src layout), TS (src/), Nix (modules/). Under 120 lines.
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**References**: `/home/m3tam3re/p/AI/AGENTS/AGENTS.md:24-38` — repo structure
**Acceptance Criteria**: `wc -l` < 120
**Commit**: NO
---
- [x] 12. Create `rules/languages/python.md`
**What to do**:
- Deep Python patterns: `uv` (pkg mgmt), `ruff` (lint/fmt), `pyright` (types), `pytest` + `hypothesis`, Pydantic for data boundaries
- Idioms: comprehensions, context managers, generators, f-strings
- Anti-patterns: bare except, mutable defaults, global state, star imports
- Project setup: `pyproject.toml`, src layout
- Under 250 lines with micro-examples
**Must NOT do**: No general coding style (covered in concerns/), no Django/Flask/FastAPI, max 250 lines
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**References**:
- `/home/m3tam3re/p/AI/AGENTS/AGENTS.md:60` — existing Python conventions (shebang, docstrings)
- Ruff docs: `https://docs.astral.sh/ruff/`, uv docs: `https://docs.astral.sh/uv/`
**Acceptance Criteria**: `wc -l` < 250, `grep -c 'ruff\|uv\|pytest\|pydantic\|pyright'` >= 4, `grep -c '```python'` >= 5, no "pythonic"/"best practice"
**Commit**: NO
---
- [x] 13. Create `rules/languages/typescript.md`
**What to do**:
- Strict mode (`strict: true`, `noUncheckedIndexedAccess`), discriminated unions, branded types, `satisfies`, `as const`
- Modern: `using`, `Promise.withResolvers()`, `Object.groupBy()`
- Toolchain: `bun`/`tsx`, `biome`/`eslint`
- Anti-patterns: `as any`, `@ts-ignore`, `!` assertion, `enum` (prefer union)
- Under 250 lines
**Must NOT do**: No React/Next.js, max 250 lines
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**Acceptance Criteria**: `wc -l` < 250, `grep -c 'strict\|as any\|ts-ignore\|discriminated\|satisfies'` >= 4, `grep -c '```ts'` >= 5
**Commit**: NO
---
- [x] 14. Create `rules/languages/nix.md`
**What to do**:
- Flake structure, module patterns (`{ config, lib, pkgs, ... }:`), `mkIf`/`mkMerge`
- Formatting: `alejandra`, naming: camelCase
- Anti-patterns: `with pkgs;`, `builtins.fetchTarball`, impure ops
- Home Manager patterns, overlays
- Under 200 lines
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**References**:
- `/home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix` — user's actual Nix style
- `/home/m3tam3re/p/NIX/nixpkgs/lib/ports.nix` — well-structured Nix code example
**Acceptance Criteria**: `wc -l` < 200, `grep -c 'flake\|mkShell\|alejandra\|with pkgs\|overlay'` >= 4
**Commit**: NO
---
- [x] 15. Create `rules/languages/shell.md`
**What to do**: `set -euo pipefail`, shellcheck, quoting, local vars, POSIX portability, `#!/usr/bin/env bash`. Under 120 lines.
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**References**: `/home/m3tam3re/p/AI/AGENTS/AGENTS.md:61`, `/home/m3tam3re/p/AI/AGENTS/scripts/test-skill.sh`
**Acceptance Criteria**: `wc -l` < 120, `grep -c 'set -euo pipefail\|shellcheck\|#!/usr/bin/env'` >= 2
**Commit**: NO
---
- [x] 16. Create `rules/frameworks/n8n.md`
**What to do**: Workflow design, node patterns, naming, Error Trigger, data patterns, security. Under 120 lines.
**Recommended Agent Profile**: `writing`
**Parallelization**: Wave 2. Blocked by T1.
**References**: n8n docs: `https://docs.n8n.io/`
**Acceptance Criteria**: `wc -l` < 120, `grep -c 'workflow\|node\|Error Trigger\|webhook\|credential'` >= 4
**Commit**: NO
---
- [x] 17. End-to-end integration test + commits
**What to do**:
1. Verify all 11 rule files exist and meet line count limits
2. Verify `lib/opencode-rules.nix` in nixpkgs evaluates correctly for: empty, single-lang, multi-lang, with-frameworks
3. Verify full lib import works: `m3taLib.opencode-rules.mkOpencodeRules`
4. Verify generated `opencode.json` is valid JSON with correct `instructions` paths
5. Verify all instruction paths resolve to real files in AGENTS repo rules/
6. Verify total context budget: all concerns + 1 language < 1500 lines
7. Verify `opencode.nix` has the rules deployment entry
8. Commit all Wave 2 rule files as a single commit in AGENTS repo
**Must NOT do**: Do not run `home-manager switch`, do not modify files, do not create test projects
**Recommended Agent Profile**: `deep`, Skills: [`git-master`]
**Parallelization**: Wave 3 (sequential). Blocks F1-F4. Blocked by T2-T5, T6-T16.
**References**:
- `/home/m3tam3re/p/NIX/nixpkgs/lib/opencode-rules.nix` — Nix helper to evaluate
- `/home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix` — deployment config
**Acceptance Criteria**:
**QA Scenarios (MANDATORY):**
```
Scenario: All rule files exist and meet limits
Tool: Bash
Steps:
1. For each of 11 files: `wc -l` and verify under limit
Expected Result: All 11 files present, all under limits
Evidence: .sisyphus/evidence/task-17-inventory.txt
Scenario: Full lib integration
Tool: Bash
Steps:
1. Run `nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /home/m3tam3re/p/NIX/nixpkgs/lib {lib = pkgs.lib;}; in (m3taLib.opencode-rules.mkOpencodeRules { agents = /home/m3tam3re/p/AI/AGENTS; languages = ["python" "typescript" "nix" "shell"]; frameworks = ["n8n"]; }).instructions'`
Expected Result: JSON array with 11 paths (6 concerns + 4 langs + 1 framework)
Failure Indicators: Wrong count, error
Evidence: .sisyphus/evidence/task-17-full-integration.txt
Scenario: All paths resolve to real files
Tool: Bash
Steps:
1. For each path in instructions output: verify the corresponding file exists under `rules/`
Expected Result: All paths resolve, none missing
Evidence: .sisyphus/evidence/task-17-paths-resolve.txt
Scenario: Total context budget
Tool: Bash
Steps:
1. `cat /home/m3tam3re/p/AI/AGENTS/rules/concerns/*.md | wc -l`
2. `wc -l < /home/m3tam3re/p/AI/AGENTS/rules/languages/python.md`
3. Sum must be < 1500
Expected Result: Total under 1500
Evidence: .sisyphus/evidence/task-17-budget.txt
```
**Commit**: YES
- Message: `feat(rules): add initial rule files for all concerns, languages, and frameworks`
- Files: all `rules/**/*.md` files (11 total)
- Repo: AGENTS
---
## Final Verification Wave (MANDATORY — after ALL implementation tasks)
> 4 review agents run in PARALLEL. ALL must APPROVE. Rejection → fix → re-run.
- [x] F1. **Plan Compliance Audit** — `oracle`
For each "Must Have": verify implementation exists. For each "Must NOT Have": search for violations. Check evidence files. Compare deliverables across all 3 repos.
Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT`
- [x] F2. **Code Quality Review** — `unspecified-high`
Rule files: no generic advice, has examples, consistent tone, under limits. Nix: valid syntax, correct paths, edge cases. USAGE.md: accurate.
Output: `Files [N clean/N issues] | VERDICT`
- [x] F3. **Real Manual QA** — `unspecified-high`
Run `nix eval` on opencode-rules.nix via full lib import with various configs. Verify JSON. Check rule content quality. Save to `.sisyphus/evidence/final-qa/`.
Output: `Scenarios [N/N pass] | VERDICT`
- [x] F4. **Scope Fidelity Check** — `deep`
For each task: "What to do" vs actual file. 1:1 match. No creep. Check "Must NOT do". Flag unaccounted changes across all 3 repos.
Output: `Tasks [N/N compliant] | Unaccounted [CLEAN/N files] | VERDICT`
---
## Commit Strategy
| After Task(s) | Repo | Message | Files |
|---------------|------|---------|-------|
| 1, 5 | AGENTS | `feat(rules): add rules directory structure and usage documentation` | `rules/USAGE.md`, `rules/{concerns,languages,frameworks}/.gitkeep` |
| 2, 3 | nixpkgs | `feat(lib): add opencode-rules helper for per-project rule injection` | `lib/opencode-rules.nix`, `lib/default.nix` |
| 4 | nixos-config | `feat(opencode): deploy rules/ to ~/.config/opencode/rules/` | `opencode.nix` |
| 17 | AGENTS | `feat(rules): add initial rule files for concerns, languages, and frameworks` | all `rules/**/*.md` (11 files) |
---
## Success Criteria
### Verification Commands
```bash
# All rule files exist (AGENTS repo)
ls rules/concerns/*.md rules/languages/*.md rules/frameworks/*.md
# Context budget
cat rules/concerns/*.md rules/languages/python.md | wc -l # Expected: < 1500
# Nix helper via full lib (nixpkgs)
nix eval --impure --json --expr 'let pkgs = import <nixpkgs> {}; m3taLib = import /path/to/nixpkgs/lib {lib = pkgs.lib;}; in (m3taLib.opencode-rules.mkOpencodeRules { agents = /path/to/AGENTS; languages = ["python"]; }).instructions'
# opencode.nix has rules entry (nixos-config)
grep 'opencode/rules' /home/m3tam3re/p/NIX/nixos-config/home/features/coding/opencode.nix
```
### Final Checklist
- [ ] All 11 rule files present and under line limits
- [ ] All rule files use imperative language with micro-examples
- [ ] `lib/opencode-rules.nix` in nixpkgs follows ports.nix pattern exactly
- [ ] `lib/default.nix` imports opencode-rules
- [ ] `opencode.nix` deploys rules/ alongside skills/commands/context/prompts
- [ ] `rules/USAGE.md` documents nixpkgs consumption pattern correctly
- [ ] No Nix code in AGENTS repo
- [ ] No existing files modified (except lib/default.nix +1 line, opencode.nix +3 lines)
- [ ] Total loaded context under 1500 lines for any realistic configuration

62
rules/USAGE.md Normal file
View File

@@ -0,0 +1,62 @@
# Opencode Rules Usage
Add AI coding rules to your project via `mkOpencodeRules`.
## flake.nix Setup
```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
agents = {
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
flake = false;
};
};
outputs = { self, nixpkgs, m3ta-nixpkgs, agents, ... }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
m3taLib = m3ta-nixpkgs.lib.${system};
in {
devShells.${system}.default = let
rules = m3taLib.opencode-rules.mkOpencodeRules {
inherit agents;
languages = [ "python" "typescript" ];
frameworks = [ "n8n" ];
};
in pkgs.mkShell {
shellHook = rules.shellHook;
};
};
}
```
## Parameters
- `agents` (required): Path to AGENTS repo flake input
- `languages` (optional): List of language names (e.g., `["python" "typescript"]`)
- `concerns` (optional): Rule categories (default: all standard concerns)
- `frameworks` (optional): List of framework names (e.g., `["n8n" "django"]`)
- `extraInstructions` (optional): Additional instruction file paths
## .gitignore
Add to your project's `.gitignore`:
```
.opencode-rules
opencode.json
```
## Project Overrides
Create `AGENTS.md` in your project root to override central rules. OpenCode applies project-level rules with precedence over central ones.
## Updating Rules
When central rules are updated:
```bash
nix flake update agents
```

0
rules/concerns/.gitkeep Normal file
View File

View File

@@ -0,0 +1,163 @@
# Coding Style
## Critical Rules (MUST follow)
Always prioritize readability over cleverness. Never write code that requires mental gymnastics to understand.
Always fail fast and explicitly. Never silently swallow errors or hide exceptions.
Always keep functions under 20 lines. Never create monolithic functions that do multiple things.
Always validate inputs at function boundaries. Never trust external data implicitly.
## Formatting
Prefer consistent indentation throughout the codebase. Never mix tabs and spaces.
Prefer meaningful variable names over short abbreviations. Never use single letters except for loop counters.
### Correct:
```lang
const maxRetryAttempts = 3;
const connectionTimeout = 5000;
for (let attempt = 1; attempt <= maxRetryAttempts; attempt++) {
// process attempt
}
```
### Incorrect:
```lang
const m = 3;
const t = 5000;
for (let i = 1; i <= m; i++) {
// process attempt
}
```
## Patterns and Anti-Patterns
Never repeat yourself. Always extract duplicated logic into reusable functions.
Prefer composition over inheritance. Never create deep inheritance hierarchies.
Always use guard clauses to reduce nesting. Never write arrow-shaped code.
### Correct:
```lang
def process_user(user):
if not user:
return None
if not user.is_active:
return None
return user.calculate_score()
```
### Incorrect:
```lang
def process_user(user):
if user:
if user.is_active:
return user.calculate_score()
else:
return None
else:
return None
```
## Error Handling
Always handle specific exceptions. Never use broad catch-all exception handlers.
Always log error context, not just the error message. Never let errors vanish without trace.
### Correct:
```lang
try:
data = fetch_resource(url)
return parse_data(data)
except NetworkError as e:
log_error(f"Network failed for {url}: {e}")
raise
except ParseError as e:
log_error(f"Parse failed for {url}: {e}")
return fallback_data
```
### Incorrect:
```lang
try:
data = fetch_resource(url)
return parse_data(data)
except Exception:
pass
```
## Type Safety
Always use type annotations where supported. Never rely on implicit type coercion.
Prefer explicit type checks over duck typing for public APIs. Never assume type behavior.
### Correct:
```lang
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
```
### Incorrect:
```lang
function calculateTotal(price, quantity) {
return price * quantity;
}
```
## Function Design
Always write pure functions when possible. Never mutate arguments unless required.
Always limit function parameters to 3 or fewer. Never pass objects to hide parameter complexity.
### Correct:
```lang
def create_user(name: str, email: str) -> User:
return User(name=name, email=email, created_at=now())
```
### Incorrect:
```lang
def create_user(config: dict) -> User:
return User(
name=config['name'],
email=config['email'],
created_at=config['timestamp']
)
```
## SOLID Principles
Never let classes depend on concrete implementations. Always depend on abstractions.
Always ensure classes are open for extension but closed for modification. Never change working code to add features.
Prefer many small interfaces over one large interface. Never force clients to depend on methods they don't use.
### Correct:
```lang
class EmailSender {
send(message: Message): void {
// implementation
}
}
class NotificationService {
constructor(private sender: EmailSender) {}
}
```
### Incorrect:
```lang
class NotificationService {
sendEmail(message: Message): void { }
sendSMS(message: Message): void { }
sendPush(message: Message): void { }
}
```
## Critical Rules (REPEAT)
Always write self-documenting code. Never rely on comments to explain complex logic.
Always refactor when you see code smells. Never let technical debt accumulate.
Always test edge cases explicitly. Never assume happy path only behavior.
Never commit commented-out code. Always remove it or restore it.

View File

@@ -0,0 +1,149 @@
# Documentation Rules
## When to Document
**Document public APIs**. Every public function, class, method, and module needs documentation. Users need to know how to use your code.
**Document complex logic**. Algorithms, state machines, and non-obvious implementations need explanations. Future readers will thank you.
**Document business rules**. Encode domain knowledge directly in comments. Don't make anyone reverse-engineer requirements from code.
**Document trade-offs**. When you choose between alternatives, explain why. Help future maintainers understand the decision context.
**Do NOT document obvious code**. Comments like `// get user` add noise. Delete them.
## Docstring Formats
### Python (Google Style)
```python
def calculate_price(quantity: int, unit_price: float, discount: float = 0.0) -> float:
"""Calculate total price after discount.
Args:
quantity: Number of items ordered.
unit_price: Price per item in USD.
discount: Decimal discount rate (0.0 to 1.0).
Returns:
Final price in USD.
Raises:
ValueError: If quantity is negative.
"""
```
### JavaScript/TypeScript (JSDoc)
```javascript
/**
* Validates user input against security rules.
* @param {string} input - Raw user input from form.
* @param {Object} rules - Validation constraints.
* @param {number} rules.maxLength - Maximum allowed length.
* @returns {boolean} True if input passes all rules.
* @throws {ValidationError} If input violates security constraints.
*/
function validateInput(input, rules) {
```
### Bash
```bash
#!/usr/bin/env bash
# Deploy application to production environment.
#
# Usage: ./deploy.sh [environment]
#
# Args:
# environment: Target environment (staging|production). Default: staging.
#
# Exits:
# 0 on success, 1 on deployment failure.
```
## Inline Comments: WHY Not WHAT
**Incorrect:**
```python
# Iterate through all users
for user in users:
# Check if user is active
if user.active:
# Increment counter
count += 1
```
**Correct:**
```python
# Count only active users to calculate monthly revenue
for user in users:
if user.active:
count += 1
```
**Incorrect:**
```javascript
// Set timeout to 5000
setTimeout(() => {
// Show error message
alert('Error');
}, 5000);
```
**Correct:**
```javascript
// 5000ms delay prevents duplicate alerts during rapid retries
setTimeout(() => {
alert('Error');
}, 5000);
```
**Incorrect:**
```bash
# Remove temporary files
rm -rf /tmp/app/*
```
**Correct:**
```bash
# Clear temp directory before batch import to prevent partial state
rm -rf /tmp/app/*
```
**Rule:** Describe the intent and context. Never describe what the code obviously does.
## README Standards
Every project needs a README at the top level.
**Required sections:**
1. **What it does** - One sentence summary
2. **Installation** - Setup commands
3. **Usage** - Basic example
4. **Configuration** - Environment variables and settings
5. **Contributing** - How to contribute
**Example structure:**
```markdown
# Project Name
One-line description of what this project does.
## Installation
```bash
npm install
```
## Usage
```bash
npm start
```
## Configuration
Create `.env` file:
```
API_KEY=your_key_here
```
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md).
```
**Keep READMEs focused**. Link to separate docs for complex topics. Don't make the README a tutorial.

View File

@@ -0,0 +1,118 @@
# Git Workflow Rules
## Conventional Commits
Format: `<type>(<scope>): <subject>`
### Commit Types
- **feat**: New feature
- `feat(auth): add OAuth2 login flow`
- `feat(api): expose user endpoints`
- **fix**: Bug fix
- `fix(payment): resolve timeout on Stripe calls`
- `fix(ui): button not clickable on mobile`
- **refactor**: Code refactoring (no behavior change)
- `refactor(utils): extract date helpers`
- `refactor(api): simplify error handling`
- **docs**: Documentation only
- `docs(readme): update installation steps`
- `docs(api): add endpoint examples`
- **chore**: Maintenance tasks
- `chore(deps): update Node to 20`
- `chore(ci): add GitHub actions workflow`
- **test**: Tests only
- `test(auth): add unit tests for login`
- `test(e2e): add checkout flow tests`
- **style**: Formatting, no logic change
- `style: sort imports alphabetically`
### Commit Rules
- Subject max 72 chars
- Imperative mood ("add", not "added")
- No period at end
- Reference issues: `Closes #123`
## Branch Naming
Pattern: `<type>/<short-description>`
### Branch Types
- `feature/add-user-dashboard`
- `feature/enable-dark-mode`
- `fix/login-redirect-loop`
- `fix/payment-timeout-error`
- `refactor/extract-user-service`
- `refactor/simplify-auth-flow`
- `hotfix/security-vulnerability`
### Branch Rules
- Lowercase and hyphens
- Max 50 chars
- Delete after merge
## Pull Requests
### PR Title
Follow Conventional Commit format:
- `feat: add user dashboard`
- `fix: resolve login redirect loop`
### PR Description
```markdown
## What
Brief description
## Why
Reason for change
## How
Implementation approach
## Testing
Steps performed
## Checklist
- [ ] Tests pass
- [ ] Code reviewed
- [ ] Docs updated
```
## Merge Strategy
### Squash Merge
- Many small commits
- One cohesive feature
- Clean history
### Merge Commit
- Preserve commit history
- Distinct milestones
- Detailed history preferred
### When to Rebase
- Before opening PR
- Resolving conflicts
- Keeping current with main
## General Rules
- Pull latest from main before starting
- Write atomic commits
- Run tests before pushing
- Request peer review before merge
- Never force push to main/master

105
rules/concerns/naming.md Normal file
View File

@@ -0,0 +1,105 @@
# Naming Conventions
Use consistent naming across all code. Follow language-specific conventions.
## Language Reference
| Type | Python | TypeScript | Nix | Shell |
|------|--------|------------|-----|-------|
| Variables | snake_case | camelCase | camelCase | UPPER_SNAKE |
| Functions | snake_case | camelCase | camelCase | lower_case |
| Classes | PascalCase | PascalCase | - | - |
| Constants | UPPER_SNAKE | UPPER_SNAKE | camelCase | UPPER_SNAKE |
| Files | snake_case | camelCase | hyphen-case | hyphen-case |
| Modules | snake_case | camelCase | - | - |
## General Rules
**Files**: Use hyphen-case for documentation, snake_case for Python, camelCase for TypeScript. Names should describe content.
**Variables**: Use descriptive names. Avoid single letters except loop counters. No Hungarian notation.
**Functions**: Use verb-noun pattern. Name describes what it does, not how it does it.
**Classes**: Use PascalCase with descriptive nouns. Avoid abbreviations.
**Constants**: Use UPPER_SNAKE with descriptive names. Group related constants.
## Examples
Python:
```python
# Variables
user_name = "alice"
is_authenticated = True
# Functions
def get_user_data(user_id):
pass
# Classes
class UserProfile:
pass
# Constants
MAX_RETRIES = 3
API_ENDPOINT = "https://api.example.com"
```
TypeScript:
```typescript
// Variables
const userName = "alice";
const isAuthenticated = true;
// Functions
function getUserData(userId: string): User {
return null;
}
// Classes
class UserProfile {
private name: string;
}
// Constants
const MAX_RETRIES = 3;
const API_ENDPOINT = "https://api.example.com";
```
Nix:
```nix
# Variables
let
userName = "alice";
isAuthenticated = true;
in
# ...
```
Shell:
```bash
# Variables
USER_NAME="alice"
IS_AUTHENTICATED=true
# Functions
get_user_data() {
echo "Getting data"
}
# Constants
MAX_RETRIES=3
API_ENDPOINT="https://api.example.com"
```
## File Naming
Use these patterns consistently. No exceptions.
- Skills: `hyphen-case`
- Python: `snake_case.py`
- TypeScript: `camelCase.ts` or `hyphen-case.ts`
- Nix: `hyphen-case.nix`
- Shell: `hyphen-case.sh`
- Markdown: `UPPERCASE.md` or `sentence-case.md`

View File

@@ -0,0 +1,82 @@
# Project Structure
## Python
Use src layout for all projects. Place application code in `src/<project>/`, tests in `tests/`.
```
project/
├── src/myproject/
│ ├── __init__.py
│ ├── main.py # Entry point
│ └── core/
│ └── module.py
├── tests/
│ ├── __init__.py
│ └── test_module.py
├── pyproject.toml # Config
├── README.md
└── .gitignore
```
**Rules:**
- One module per directory file
- `__init__.py` in every package
- Entry point in `src/myproject/main.py`
- Config in root: `pyproject.toml`, `requirements.txt`
## TypeScript
Use `src/` for source, `dist/` for build output.
```
project/
├── src/
│ ├── index.ts # Entry point
│ ├── core/
│ │ └── module.ts
│ └── types.ts
├── tests/
│ └── module.test.ts
├── package.json # Config
├── tsconfig.json
└── README.md
```
**Rules:**
- One module per file
- Index exports from `src/index.ts`
- Entry point in `src/index.ts`
- Config in root: `package.json`, `tsconfig.json`
## Nix
Use `modules/` for NixOS modules, `pkgs/` for packages.
```
nix-config/
├── modules/
│ ├── default.nix # Module list
│ └── my-service.nix
├── pkgs/
│ └── my-package/
│ └── default.nix
├── flake.nix # Entry point
├── flake.lock
└── README.md
```
**Rules:**
- One module per file in `modules/`
- One package per directory in `pkgs/`
- Entry point in `flake.nix`
- Config in root: `flake.nix`, shell.nix
## General
- Use hyphen-case for directories
- Use kebab-case for file names
- Config files in project root
- Tests separate from source
- Docs in root: README.md, CHANGELOG.md
- Hidden configs: .env, .gitignore

134
rules/concerns/testing.md Normal file
View File

@@ -0,0 +1,134 @@
# Testing Rules
## Arrange-Act-Assert Pattern
Structure every test in three distinct phases:
```python
# Arrange: Set up the test data and conditions
user = User(name="Alice", role="admin")
session = create_test_session(user.id)
# Act: Execute the behavior under test
result = grant_permission(session, "read_documents")
# Assert: Verify the expected outcome
assert result.granted is True
assert result.permissions == ["read_documents"]
```
Never mix phases. Comment each phase clearly for complex setups. Keep Act phase to one line if possible.
## Behavior vs Implementation Testing
Test behavior, not implementation details:
```python
# GOOD: Tests the observable behavior
def test_user_can_login():
response = login("alice@example.com", "password123")
assert response.status_code == 200
assert "session_token" in response.cookies
# BAD: Tests internal implementation
def test_login_sets_database_flag():
login("alice@example.com", "password123")
user = User.get(email="alice@example.com")
assert user._logged_in_flag is True # Private field
```
Focus on inputs and outputs. Test public contracts. Refactor internals freely without breaking tests.
## Mocking Philosophy
Mock external dependencies, not internal code:
```python
# GOOD: Mock external services
@patch("requests.post")
def test_sends_notification_to_slack(mock_post):
send_notification("Build complete!")
mock_post.assert_called_once_with(
"https://slack.com/api/chat.postMessage",
json={"text": "Build complete!"}
)
# BAD: Mock internal methods
@patch("NotificationService._format_message")
def test_notification_formatting(mock_format):
# Don't mock private methods
send_notification("Build complete!")
```
Mock when:
- Dependency is slow (database, network, file system)
- Dependency is unreliable (external APIs)
- Dependency is expensive (third-party services)
Don't mock when:
- Testing the dependency itself
- The dependency is fast and stable
- The mock becomes more complex than real implementation
## Coverage Expectations
Write tests for:
- Critical business logic (aim for 90%+)
- Edge cases and error paths (aim for 80%+)
- Public APIs and contracts (aim for 100%)
Don't obsess over:
- Trivial getters/setters
- Generated code
- One-line wrappers
Coverage is a floor, not a ceiling. A test suite at 100% coverage that doesn't verify behavior is worthless.
## Test-Driven Development
Follow the red-green-refactor cycle:
1. Red: Write failing test for new behavior
2. Green: Write minimum code to pass
3. Refactor: improve code while tests stay green
Write tests first for new features. Write tests after for bug fixes. Never refactor without tests.
## Test Organization
Group tests by feature or behavior, not by file structure. Name tests to describe the scenario:
```python
class TestUserAuthentication:
def test_valid_credentials_succeeds(self):
pass
def test_invalid_credentials_fails(self):
pass
def test_locked_account_fails(self):
pass
```
Each test should stand alone. Avoid shared state between tests. Use fixtures or setup methods to reduce duplication.
## Test Data
Use realistic test data that reflects production scenarios:
```python
# GOOD: Realistic values
user = User(
email="alice@example.com",
name="Alice Smith",
age=28
)
# BAD: Placeholder values
user = User(
email="test@test.com",
name="Test User",
age=999
)
```
Avoid magic strings and numbers. Use named constants for expected values that change often.

View File

42
rules/frameworks/n8n.md Normal file
View File

@@ -0,0 +1,42 @@
# n8n Workflow Automation Rules
## Workflow Design
- Start with a clear trigger: Webhook, Schedule, or Event source
- Keep workflows under 20 nodes for maintainability
- Group related logic with sub-workflows
- Use the "Switch" node for conditional branching
- Add "Wait" nodes between rate-limited API calls
## Node Naming
- Use verb-based names: `Fetch Users`, `Transform Data`, `Send Email`
- Prefix data nodes: `Get_`, `Set_`, `Update_`
- Prefix conditionals: `Check_`, `If_`, `When_`
- Prefix actions: `Send_`, `Create_`, `Delete_`
- Add version suffix to API nodes: `API_v1_Users`
## Error Handling
- Always add an Error Trigger node
- Route errors to a "Notify Failure" branch
- Log error details: `$json.error.message`, `$json.node.name`
- Send alerts on critical failures
- Add "Continue On Fail" for non-essential nodes
## Data Flow
- Use "Set" nodes to normalize output structure
- Reference previous nodes: `{{ $json.field }}`
- Use "Merge" node to combine multiple data sources
- Apply "Code" node for complex transformations
- Clean data before sending to external APIs
## Credential Security
- Store all secrets in n8n credentials manager
- Never hardcode API keys or tokens
- Use environment-specific credential sets
- Rotate credentials regularly
- Limit credential scope to minimum required permissions
## Testing
- Test each node independently with "Execute Node"
- Verify data structure at each step
- Mock external dependencies during development
- Log workflow execution for debugging

0
rules/languages/.gitkeep Normal file
View File

129
rules/languages/nix.md Normal file
View File

@@ -0,0 +1,129 @@
# Nix Code Conventions
## Formatting
- Use `alejandra` for formatting
- camelCase for variables, `PascalCase` for types
- 2 space indentation (alejandra default)
- No trailing whitespace
## Flake Structure
```nix
{
description = "Description here";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.default = pkgs.hello;
devShells.default = pkgs.mkShell {
buildInputs = [ pkgs.hello ];
};
}
);
}
```
## Module Patterns
Standard module function signature:
```nix
{ config, lib, pkgs, ... }:
{
options.myService.enable = lib.mkEnableOption "my service";
config = lib.mkIf config.myService.enable {
services.myService.enable = true;
};
}
```
## Conditionals and Merging
- Use `mkIf` for conditional config
- Use `mkMerge` to combine multiple config sets
- Use `mkOptionDefault` for defaults that can be overridden
```nix
config = lib.mkMerge [
(lib.mkIf cfg.enable { ... })
(lib.mkIf cfg.extraConfig { ... })
];
```
## Anti-Patterns (AVOID)
### `with pkgs;`
Bad: Pollutes namespace, hard to trace origins
```nix
{ pkgs, ... }:
{
packages = with pkgs; [ vim git ];
}
```
Good: Explicit references
```nix
{ pkgs, ... }:
{
packages = [ pkgs.vim pkgs.git ];
}
```
### `builtins.fetchTarball`
Use flake inputs instead. `fetchTarball` is non-reproducible.
### Impure operations
Avoid `import <nixpkgs>` in flakes. Always use inputs.
### `builtins.getAttr` / `builtins.hasAttr`
Use `lib.attrByPath` or `lib.optionalAttrs` instead.
## Home Manager Patterns
```nix
{ config, pkgs, lib, ... }:
{
home.packages = with pkgs; [ ripgrep fd ];
programs.zsh.enable = true;
xdg.configFile."myapp/config".text = "...";
}
```
## Overlays
```nix
{ config, lib, pkgs, ... }:
let
myOverlay = final: prev: {
myPackage = prev.myPackage.overrideAttrs (old: { ... });
};
in
{
nixpkgs.overlays = [ myOverlay ];
}
```
## Imports and References
- Use flake inputs for dependencies
- `lib` is always available in modules
- Reference packages via `pkgs.packageName`
- Use `callPackage` for complex package definitions
## File Organization
```
flake.nix # Entry point
modules/ # NixOS modules
services/
my-service.nix
overlays/ # Package overrides
default.nix
```

224
rules/languages/python.md Normal file
View File

@@ -0,0 +1,224 @@
# Python Language Rules
## Toolchain
### Package Management (uv)
```bash
uv init my-project --package
uv add numpy pandas
uv add --dev pytest ruff pyright hypothesis
uv run python -m pytest
uv lock --upgrade-package numpy
```
### Linting & Formatting (ruff)
```toml
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP"]
ignore = ["E501"]
[tool.ruff.format]
quote-style = "double"
```
### Type Checking (pyright)
```toml
[tool.pyright]
typeCheckingMode = "strict"
reportMissingTypeStubs = true
reportUnknownMemberType = true
```
### Testing (pytest + hypothesis)
```python
import pytest
from hypothesis import given, strategies as st
@given(st.integers(), st.integers())
def test_addition_commutative(a, b):
assert a + b == b + a
@pytest.fixture
def user_data():
return {"name": "Alice", "age": 30}
def test_user_creation(user_data):
user = User(**user_data)
assert user.name == "Alice"
```
### Data Validation (Pydantic)
```python
from pydantic import BaseModel, Field, validator
class User(BaseModel):
name: str = Field(min_length=1, max_length=100)
age: int = Field(ge=0, le=150)
email: str
@validator('email')
def email_must_contain_at(cls, v):
if '@' not in v:
raise ValueError('must contain @')
return v
```
## Idioms
### Comprehensions
```python
# List comprehension
squares = [x**2 for x in range(10) if x % 2 == 0]
# Dict comprehension
word_counts = {word: text.count(word) for word in unique_words}
# Set comprehension
unique_chars = {char for char in text if char.isalpha()}
```
### Context Managers
```python
# Built-in context managers
with open('file.txt', 'r') as f:
content = f.read()
# Custom context manager
from contextlib import contextmanager
@contextmanager
def timer():
start = time.time()
yield
print(f"Elapsed: {time.time() - start:.2f}s")
```
### Generators
```python
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
def read_lines(file_path):
with open(file_path) as f:
for line in f:
yield line.strip()
```
### F-strings
```python
name = "Alice"
age = 30
# Basic interpolation
msg = f"Name: {name}, Age: {age}"
# Expression evaluation
msg = f"Next year: {age + 1}"
# Format specs
msg = f"Price: ${price:.2f}"
msg = f"Hex: {0xFF:X}"
```
## Anti-Patterns
### Bare Except
```python
# AVOID: Catches all exceptions including SystemExit
try:
risky_operation()
except:
pass
# USE: Catch specific exceptions
try:
risky_operation()
except ValueError as e:
log_error(e)
except KeyError as e:
log_error(e)
```
### Mutable Defaults
```python
# AVOID: Default argument created once
def append_item(item, items=[]):
items.append(item)
return items
# USE: None as sentinel
def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
```
### Global State
```python
# AVOID: Global mutable state
counter = 0
def increment():
global counter
counter += 1
# USE: Class-based state
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
```
### Star Imports
```python
# AVOID: Pollutes namespace, unclear origins
from module import *
# USE: Explicit imports
from module import specific_function, MyClass
import module as m
```
## Project Setup
### pyproject.toml Structure
```toml
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"pydantic>=2.0",
"httpx>=0.25",
]
[project.optional-dependencies]
dev = ["pytest", "ruff", "pyright", "hypothesis"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
```
### src Layout
```
my-project/
├── pyproject.toml
└── src/
└── my_project/
├── __init__.py
├── main.py
└── utils/
├── __init__.py
└── helpers.py
```

100
rules/languages/shell.md Normal file
View File

@@ -0,0 +1,100 @@
# Shell Scripting Rules
## Shebang
Always use `#!/usr/bin/env bash` for portability. Never hardcode `/bin/bash`.
```bash
#!/usr/bin/env bash
```
## Strict Mode
Enable strict mode in every script.
```bash
#!/usr/bin/env bash
set -euo pipefail
```
- `-e`: Exit on error
- `-u`: Error on unset variables
- `-o pipefail`: Return exit status of last failed pipe command
## Shellcheck
Run shellcheck on all scripts before committing.
```bash
shellcheck script.sh
```
## Quoting
Quote all variable expansions and command substitutions. Use arrays instead of word-splitting strings.
```bash
# Good
"${var}"
files=("file1.txt" "file2.txt")
for f in "${files[@]}"; do
process "$f"
done
# Bad
$var
files="file1.txt file2.txt"
for f in $files; do
process $f
done
```
## Functions
Define with parentheses, use `local` for variables.
```bash
my_function() {
local result
result=$(some_command)
echo "$result"
}
```
## Command Substitution
Use `$()` not backticks. Nests cleanly.
```bash
# Good
output=$(ls "$dir")
# Bad
output=`ls $dir`
```
## POSIX Portability
Write POSIX-compliant scripts when targeting `/bin/sh`.
- Use `[[` only for bash scripts
- Use `printf` instead of `echo -e`
- Avoid `[[`, `((`, `&>` in sh scripts
## Error Handling
Use `trap` for cleanup.
```bash
cleanup() {
rm -f /tmp/lockfile
}
trap cleanup EXIT
```
## Readability
- Use 2-space indentation
- Limit lines to 80 characters
- Add comments for non-obvious logic
- Separate sections with blank lines

View File

@@ -0,0 +1,150 @@
# TypeScript Patterns
## Strict tsconfig
Always enable strict mode and key safety options:
```json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
```
## Discriminated Unions
Use discriminated unions for exhaustive type safety:
```ts
type Result =
| { success: true; data: string }
| { success: false; error: Error };
function handleResult(result: Result): string {
if (result.success) {
return result.data;
}
throw result.error;
}
```
## Branded Types
Prevent type confusion with nominal branding:
```ts
type UserId = string & { readonly __brand: unique symbol };
type Email = string & { readonly __brand: unique symbol };
function createUserId(id: string): UserId {
return id as UserId;
}
function sendEmail(email: Email, userId: UserId) {}
```
## satisfies Operator
Use `satisfies` for type-safe object literal inference:
```ts
const config = {
port: 3000,
host: "localhost",
} satisfies {
port: number;
host: string;
debug?: boolean;
};
config.port; // number
config.host; // string
```
## as const Assertions
Freeze literal types with `as const`:
```ts
const routes = {
home: "/",
about: "/about",
contact: "/contact",
} as const;
type Route = typeof routes[keyof typeof routes];
```
## Modern Features
```ts
// Promise.withResolvers()
const { promise, resolve, reject } = Promise.withResolvers<string>();
// Object.groupBy()
const users = [
{ name: "Alice", role: "admin" },
{ name: "Bob", role: "user" },
];
const grouped = Object.groupBy(users, u => u.role);
// using statement for disposables
class Resource implements Disposable {
async [Symbol.asyncDispose]() {
await this.cleanup();
}
}
async function withResource() {
using r = new Resource();
}
```
## Toolchain
Prefer modern tooling:
- Runtime: `bun` or `tsx` (no `tsc` for execution)
- Linting: `biome` (preferred) or `eslint`
- Formatting: `biome` (built-in) or `prettier`
## Anti-Patterns
Avoid these TypeScript patterns:
```ts
// NEVER use as any
const data = response as any;
// NEVER use @ts-ignore
// @ts-ignore
const value = unknownFunction();
// NEVER use ! assertion (non-null)
const element = document.querySelector("#foo")!;
// NEVER use enum (prefer union)
enum Status { Active, Inactive } // ❌
// Prefer const object or union
type Status = "Active" | "Inactive"; // ✅
const Status = { Active: "Active", Inactive: "Inactive" } as const; // ✅
```
## Indexed Access Safety
With `noUncheckedIndexedAccess`, handle undefined:
```ts
const arr: string[] = ["a", "b"];
const item = arr[0]; // string | undefined
const item2 = arr.at(0); // string | undefined
const map = new Map<string, number>();
const value = map.get("key"); // number | undefined
```