chore: update flake, agents lib, and clean up tracked dotfiles
Some checks failed
Update Nix Packages with nix-update / nix-update (push) Failing after 3m59s

- Remove .pi* and .td-root files from git index (now in .gitignore)
- Update flake.lock and flake.nix
- Add shells/coding.nix, remove shells/opencode.nix
- Update lib/agents.nix, lib/coding-rules.nix
- Update modules/home-manager/coding/agents/pi.nix
- Update tests for agents and coding-rules
- Update .gitignore
This commit is contained in:
sascha.koenig
2026-04-21 20:24:38 +02:00
parent 300ef0c28f
commit 69b736e302
21 changed files with 452 additions and 202 deletions

2
.gitignore vendored
View File

@@ -43,5 +43,5 @@ flake.lock.bak
.sidecar-start.sh
.sidecar-base
.td-root
.pi-lens
.cache
.pi*

View File

@@ -1,7 +0,0 @@
{
"success": true,
"clones": [],
"duplicatedLines": 0,
"totalLines": 0,
"percentage": 0
}

View File

@@ -1,3 +0,0 @@
{
"timestamp": "2026-04-11T04:17:20.531Z"
}

View File

@@ -1,9 +0,0 @@
{
"success": false,
"issues": [],
"unusedExports": [],
"unusedFiles": [],
"unusedDeps": [],
"unlistedDeps": [],
"summary": "Failed to parse output"
}

View File

@@ -1,3 +0,0 @@
{
"timestamp": "2026-04-11T04:17:21.374Z"
}

View File

@@ -1 +0,0 @@
null

View File

@@ -1,3 +0,0 @@
{
"timestamp": "2026-04-19T15:52:39.989Z"
}

View File

@@ -1,3 +0,0 @@
{
"items": []
}

View File

@@ -1,3 +0,0 @@
{
"timestamp": "2026-04-19T15:42:10.963Z"
}

View File

@@ -1,6 +0,0 @@
{
"files": {},
"turnCycles": 0,
"maxCycles": 3,
"lastUpdated": "2026-04-11T04:17:22.397Z"
}

View File

@@ -1 +0,0 @@
/home/sascha.koenig/p/NIX/nixpkgs

17
flake.lock generated
View File

@@ -1,5 +1,21 @@
{
"nodes": {
"agents": {
"flake": false,
"locked": {
"lastModified": 1776092721,
"narHash": "sha256-avV4Snqp0K57I9s8D61+GHlg9DYZFSIvjaS4d4RYpG8=",
"ref": "refs/heads/master",
"rev": "0ad41acb03eee0e22cba611b2171a3d3ee30cb10",
"revCount": 72,
"type": "git",
"url": "https://code.m3ta.dev/m3tam3re/AGENTS"
},
"original": {
"type": "git",
"url": "https://code.m3ta.dev/m3tam3re/AGENTS"
}
},
"basecamp": {
"inputs": {
"nixpkgs": [
@@ -96,6 +112,7 @@
},
"root": {
"inputs": {
"agents": "agents",
"basecamp": "basecamp",
"nixpkgs": "nixpkgs",
"nixpkgs-master": "nixpkgs-master",

View File

@@ -21,6 +21,12 @@
url = "github:Fission-AI/OpenSpec";
inputs.nixpkgs.follows = "nixpkgs";
};
# Agent definitions and coding rules
agents = {
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
flake = false;
};
};
outputs = {
@@ -81,11 +87,11 @@
# Development shells for various programming environments
# Usage: nix develop .#<shell-name>
# Available shells: default, python, devops, opencode
# Available shells: default, python, devops, coding
devShells = forAllSystems (system: let
pkgs = pkgsFor system;
in
import ./shells {inherit pkgs inputs;});
import ./shells {inherit pkgs inputs; agents = inputs.agents;});
# Formatter for 'nix fmt'
formatter = forAllSystems (system: (pkgsFor system).alejandra);

View File

@@ -223,7 +223,10 @@
canonical,
modelOverrides ? {},
primaryAgent ? null,
codingRules ? null,
}: let
# Import coding-rules lib for concatRulesMd when codingRules is provided
codingRulesLib = (import ./coding-rules.nix {inherit lib;});
# Find the primary agent (there should be exactly one).
primaryAgents = lib.filterAttrs (_: a: a.mode == "primary") canonical;
primaryNames = lib.attrNames primaryAgents;
@@ -306,6 +309,17 @@
"- **" + dn + "**: " + agent.description;
in
lib.mapAttrsToList mkEntry subagents;
# ── Coding rules section (optional) ────────────────────────
# When codingRules is provided, append selected rules to AGENTS.md.
# codingRules attrset: { agents, languages, concerns, frameworks }
codingRulesSection =
if codingRules != null
then let
section = codingRulesLib.mkRulesMdSection codingRules;
in
if section != "" then "\n" + section else ""
else "";
agentsMd =
"# Agent Instructions\n"
+ "\n"
@@ -320,7 +334,8 @@
if subagents == {}
then ""
else "## Available Specialists\n\n" + lib.concatStringsSep "\n" specialistEntries + "\n"
);
)
+ codingRulesSection;
agentsMdFile = pkgs.writeText "AGENTS.md" agentsMd;
systemMdFile = pkgs.writeText "SYSTEM.md" primary.systemPrompt;
@@ -346,6 +361,7 @@
agentsInput,
tool,
modelOverrides ? {},
codingRules ? null,
}: let
canonical = agentsInput.lib.loadAgents;
in
@@ -362,7 +378,7 @@
else if tool == "pi"
then
agentsLib.renderForPi {
inherit pkgs canonical modelOverrides;
inherit pkgs canonical modelOverrides codingRules;
}
else throw "lib.agents.renderForTool: unknown tool '${tool}'. Must be opencode, claude-code, or pi.";
@@ -386,9 +402,10 @@
agentsInput,
tool,
modelOverrides ? {},
codingRules ? null,
}: let
rendered = agentsLib.renderForTool {
inherit pkgs agentsInput tool modelOverrides;
inherit pkgs agentsInput tool modelOverrides codingRules;
};
in
if tool == "opencode"

View File

@@ -27,6 +27,7 @@
# The shellHook creates:
# - A `.opencode-rules/` symlink pointing to the AGENTS repository rules directory
# - A `coding-rules.json` file with a $schema reference and instructions list
# - (Optional) Appends coding rules to `AGENTS.md` for Pi agent discovery
#
# The instructions list contains paths relative to the project root, all prefixed
# with `.opencode-rules/`, making them portable across different project locations.
@@ -43,6 +44,9 @@
# (e.g., [ "react" "fastapi" "django" ])
# extraInstructions: Optional list of additional instruction paths
# (for custom rules outside standard locations)
# forPi: Whether to also append rules to AGENTS.md for Pi agent (default: true)
# Pi discovers AGENTS.md files by walking parent dirs + cwd and concatenates them.
# When enabled, a delimited block is appended to (or created in) AGENTS.md.
#
# Returns:
# An attribute set containing:
@@ -83,6 +87,7 @@
frameworks ? [],
extraInstructions ? [],
rulesDir ? ".opencode-rules",
forPi ? false,
}: let
# Build instructions list by mapping concerns, languages, frameworks to their file paths
# All paths are relative to project root via the rulesDir symlink
@@ -97,11 +102,46 @@
"$schema" = "https://opencode.ai/config.json";
inherit instructions;
};
# Pi rules content (concatenated markdown) — only computed when forPi is true
piRulesSection =
if forPi
then mkRulesMdSection {inherit agents languages concerns frameworks;}
else "";
# Bash snippet to append rules to AGENTS.md for Pi discovery.
# Uses HTML comment markers for idempotent updates:
# - Removes any existing CODING-RULES block
# - Appends the new block
# - Creates AGENTS.md if it doesn't exist
# Note: Uses plain if-then-else instead of lib.optionalString to avoid
# forcing the `lib` argument (which may come from import <nixpkgs/lib>)
# when forPi is false.
piShellHook =
if forPi && piRulesSection != ""
then ''
# Pi agent: append coding rules to AGENTS.md
if [ -f AGENTS.md ]; then
# Remove existing coding-rules block (if any)
sed -i '/<!-- CODING-RULES:START -->/,/<!-- CODING-RULES:END -->/d' AGENTS.md
# Append new coding-rules block
cat >> AGENTS.md <<'PIRULES_EOF'
${piRulesSection}
PIRULES_EOF
else
# Create AGENTS.md with just the coding rules
cat > AGENTS.md <<'PIRULES_EOF'
${piRulesSection}
PIRULES_EOF
fi
''
else "";
in {
inherit instructions;
# Shell hook to set up rules in the project
# Creates a symlink to the AGENTS rules directory and generates coding-rules.json
# Optionally appends rules to AGENTS.md for Pi agent discovery
shellHook = ''
# Create/update symlink to AGENTS rules directory
ln -sfn ${agents}/rules ${rulesDir}
@@ -110,8 +150,73 @@
cat > coding-rules.json <<'RULES_EOF'
${builtins.toJSON rulesConfig}
RULES_EOF
${piShellHook}
'';
};
# Concatenate selected rule files from the AGENTS repository into a single
# markdown string. Used by Pi (append to AGENTS.md) and could be used by
# other tools that don't support an instructions list.
#
# Args:
# agents: Path to the AGENTS repository (non-flake input)
# languages: Optional list of language-specific rules to include
# concerns: Optional list of concern rules to include
# Default: [ "coding-style" "naming" "documentation" "testing" "git-workflow" "project-structure" ]
# frameworks: Optional list of framework-specific rules to include
#
# Returns: A single concatenated markdown string with all selected rules.
#
# Example:
# concatRulesMd {
# agents = inputs.agents;
# languages = [ "python" ];
# concerns = [ "coding-style" ];
# }
# # Returns: "\n# Coding Style\n\n...python rules...\n"
concatRulesMd = {
agents,
languages ? [],
concerns ? [
"coding-style"
"naming"
"documentation"
"testing"
"git-workflow"
"project-structure"
],
frameworks ? [],
}: let
rulePaths =
(map (c: {kind = "concerns"; name = c;}) concerns)
++ (map (l: {kind = "languages"; name = l;}) languages)
++ (map (f: {kind = "frameworks"; name = f;}) frameworks);
readRule = rule: builtins.readFile "${agents}/rules/${rule.kind}/${rule.name}.md";
ruleContents = map readRule rulePaths;
in
lib.concatStringsSep "\n\n" ruleContents;
# Build a coding rules section suitable for appending to AGENTS.md.
# Wraps concatRulesMd output with a header and HTML comment markers
# for idempotent updates in project-level shellHooks.
#
# Args: Same as concatRulesMd
#
# Returns: A markdown string with start/end markers and a header.
mkRulesMdSection = args: let
content = concatRulesMd args;
in
if builtins.stringLength content == 0
then ""
else ''
<!-- CODING-RULES:START -->
# Coding Rules
${content}
<!-- CODING-RULES:END -->
'';
in {
inherit mkCodingRules;
inherit mkCodingRules concatRulesMd mkRulesMdSection;
}

View File

@@ -44,6 +44,60 @@ in
'';
};
codingRules = mkOption {
type = types.nullOr (types.submodule {
options = {
languages = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Language-specific coding rules to include
(e.g. [ "python" "typescript" "nix" ]).
Rule files are read from the AGENTS repo's rules/languages/ directory.
'';
};
concerns = mkOption {
type = types.listOf types.str;
default = [
"coding-style"
"naming"
"documentation"
"testing"
"git-workflow"
"project-structure"
];
description = ''
Concern rules to include from the AGENTS repo's rules/concerns/ directory.
'';
};
frameworks = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Framework-specific coding rules to include
(e.g. [ "react" "fastapi" ]).
Rule files are read from the AGENTS repo's rules/frameworks/ directory.
'';
};
};
});
default = null;
description = ''
Coding rules to inject into ~/.pi/agent/AGENTS.md.
Rules are read from the AGENTS repository and appended as markdown sections.
Requires agentsInput to be set.
'';
example = literalExpression ''
{
languages = [ "python" "typescript" ];
concerns = [ "coding-style" "testing" ];
frameworks = [ "fastapi" ];
}
'';
};
settings = mkOption {
type = types.submodule {
freeformType = types.attrsOf types.anything;
@@ -166,6 +220,12 @@ in
piSettings = filterNulls cfg.settings;
# Coding rules config for renderForPi (only when both agentsInput and codingRules are set)
piCodingRules =
if cfg.agentsInput != null && cfg.codingRules != null
then cfg.codingRules // { agents = cfg.agentsInput; }
else null;
# Rendered agents (only computed when agentsInput is set)
rendered =
if cfg.agentsInput != null
@@ -175,6 +235,7 @@ in
canonical = cfg.agentsInput.lib.loadAgents;
modelOverrides = cfg.modelOverrides;
primaryAgent = cfg.primaryAgent;
codingRules = piCodingRules;
}
else null;

111
shells/coding.nix Normal file
View File

@@ -0,0 +1,111 @@
# AI coding agent development environment with coding rules
# Sets up coding rules for OpenCode and Pi, plus useful companion tools.
# Usage: nix develop .#coding
#
# To enable coding rules, add the agents input to your flake:
# agents = {
# url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
# flake = false;
# };
{
pkgs,
lib ? pkgs.lib,
inputs ? null,
agents ? null,
}: let
# Import the coding-rules library
m3taLib = import ../lib {lib = pkgs.lib;};
# Import custom packages
customPackages = import ../pkgs {inherit pkgs inputs;};
# Create rules configuration only if agents input is provided
rulesConfig = lib.optionalAttrs (agents != null) {
rules = m3taLib.coding-rules.mkCodingRules {
inherit agents;
# Languages relevant to this repository
languages = ["nix" "python" "shell"];
# Frameworks used in this repo
frameworks = ["n8n"];
# Standard concerns for development
concerns = [
"coding-style"
"naming"
"documentation"
"testing"
"git-workflow"
"project-structure"
];
# Also append rules to AGENTS.md for Pi agent discovery
forPi = true;
};
};
in
pkgs.mkShell {
name = "coding";
# Development tools
buildInputs = with pkgs;
[
# Task management for AI coding sessions
customPackages.td
# Companion tool for CLI agents (diffs, file trees, task management)
customPackages.sidecar
# Code analysis tools
customPackages.code2prompt
# Nix development tools (for this repo)
nil
alejandra
statix
deadnix
];
shellHook = ''
echo "🤖 AI Coding Environment"
echo ""
${
if (agents != null)
then ''
# Set up coding rules for OpenCode + Pi
${rulesConfig.rules.shellHook}
echo " Coding rules configured (OpenCode + Pi)"
echo " Languages: nix, python, shell"
echo " Frameworks: n8n"
echo " Concerns: coding-style, naming, documentation, testing, git-workflow, project-structure"
''
else ''
echo " Coding rules not configured"
echo ""
echo "To enable, add the agents input to your flake.nix:"
echo ""
echo " agents = {"
echo " url = \"git+https://code.m3ta.dev/m3tam3re/AGENTS\";"
echo " flake = false;"
echo " };"
''
}
echo ""
echo "Available tools:"
echo " opencode - AI coding agent"
echo " td usage --new-session - View current tasks"
echo " sidecar - Companion tool (diffs, file trees, tasks)"
echo " code2prompt - Convert code to prompts"
echo ""
echo "Nix development tools:"
echo " nix flake check - Check flake validity"
echo " nix fmt . - Format Nix files"
echo " statix check . - Lint Nix files"
echo " deadnix . - Find dead code"
echo ""
'';
}

View File

@@ -4,6 +4,7 @@
{
pkgs,
inputs,
agents ? null,
}: {
# Default shell for working on this repository
default = pkgs.mkShell {
@@ -32,5 +33,5 @@
# Import all individual shell environments
python = import ./python.nix {inherit pkgs inputs;};
devops = import ./devops.nix {inherit pkgs inputs;};
opencode = import ./opencode.nix {inherit pkgs inputs;};
coding = import ./coding.nix {inherit pkgs inputs agents;};
}

View File

@@ -1,155 +0,0 @@
# OpenCode development environment with AI coding rules
# This shell demonstrates the mkCodingRules library provided by this repository
# Usage: nix develop .#opencode
#
# To enable OpenCode rules, add the agents input to your flake:
# agents = {
# url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
# flake = false;
# };
{
pkgs,
lib ? pkgs.lib,
inputs ? null,
agents ? null,
}: let
# Import the coding-rules library
m3taLib = import ../lib {lib = pkgs.lib;};
# Import custom packages
customPackages = import ../pkgs {inherit pkgs inputs;};
# Create rules configuration only if agents input is provided
# This demonstrates how to use mkCodingRules in a real project
rulesConfig = lib.optionalAttrs (agents != null) {
rules = m3taLib.coding-rules.mkCodingRules {
# Pass the AGENTS repository path
inherit agents;
# Languages relevant to this repository
languages = ["python" "typescript" "nix"];
# Frameworks used in this repo
frameworks = ["n8n"];
# Standard concerns for development
concerns = [
"coding-style"
"naming"
"documentation"
"testing"
"git-workflow"
"project-structure"
];
};
};
in
pkgs.mkShell {
name = "opencode-dev";
# Development tools
buildInputs = with pkgs;
[
# OpenCode AI coding agent (if inputs are available)
]
++ lib.optionals (inputs != null)
[inputs.opencode.packages.${pkgs.stdenv.hostPlatform.system}.opencode]
++ [
# Task management for AI coding sessions
customPackages.td
# Companion tool for CLI agents (diffs, file trees, task management)
customPackages.sidecar
# Code analysis tools
customPackages.code2prompt
# Nix development tools (for this repo)
nil
alejandra
statix
deadnix
];
# Shell hook that sets up OpenCode rules
shellHook = ''
echo "🤖 OpenCode Development Environment"
echo ""
echo "This environment demonstrates the mkCodingRules library"
echo "provided by the m3ta-nixpkgs repository."
echo ""
${
if (agents != null)
then ''
# Execute the OpenCode rules shellHook
${rulesConfig.rules.shellHook}
echo " OpenCode rules configured!"
''
else ''
echo " OpenCode rules not configured"
echo ""
echo "To enable OpenCode rules, add the agents input to your flake.nix:"
echo ""
echo " inputs = {"
echo " m3ta-nixpkgs.url = \"git+https://code.m3ta.dev/m3tam3re/nixpkgs\";"
echo " agents = {"
echo " url = \"git+https://code.m3ta.dev/m3tam3re/AGENTS\";"
echo " flake = false;"
echo " };"
echo " };"
echo ""
echo "Then pass agents to the shell:"
echo " opencode = import ./opencode.nix { inherit pkgs inputs agents; };"
''
}
echo ""
echo "Available tools:"
echo " opencode - AI coding agent"
echo " td usage --new-session - View current tasks"
echo " sidecar - Companion tool (diffs, file trees, tasks)"
echo " code2prompt - Convert code to prompts"
echo ""
echo "Nix development tools:"
echo " nix flake check - Check flake validity"
echo " nix fmt . - Format Nix files"
echo " statix check . - Lint Nix files"
echo " deadnix . - Find dead code"
echo ""
${
if (agents == null)
then ''
echo "💡 Using mkCodingRules in your project:"
echo ""
echo "Add to your flake.nix:"
echo " inputs = {"
echo " m3ta-nixpkgs.url = \"git+https://code.m3ta.dev/m3tam3re/nixpkgs\";"
echo " agents = {"
echo " url = \"git+https://code.m3ta.dev/m3tam3re/AGENTS\";"
echo " flake = false;"
echo " };"
echo " };"
echo ""
echo " outputs = {self, nixpkgs, m3ta-nixpkgs, agents, ...}:"
echo " let"
echo " system = \"x86_64-linux\";"
echo " pkgs = nixpkgs.legacyPackages.''${system};"
echo " m3taLib = m3ta-nixpkgs.lib.''${system};"
echo " rules = m3taLib.coding-rules.mkCodingRules {
echo " inherit agents;"
echo " languages = [\"python\" \"typescript\"];"
echo " frameworks = [\"n8n\"];"
echo " };"
echo " in {"
echo " devShells.''${system}.default = pkgs.mkShell {"
echo " shellHook = rules.shellHook;"
echo " };"
echo " };"
''
else ""
}
echo ""
'';
}

View File

@@ -20,7 +20,67 @@ let
result = agentsLib.loadCanonical {agentsInput = fakeInput;};
in
assert result == {test = {description = "test";};}; {result = "pass";};
# Test 3: renderForPi accepts codingRules parameter without error (null case)
# Verifies that passing codingRules = null produces the same result as omitting it.
# Uses a minimal fake canonical set instead of a real agents repo.
testPiNullCodingRules = let
pkgs = import <nixpkgs> {};
canonical = {
chiron = {
mode = "primary";
description = "Test primary agent";
display_name = "Chiron";
systemPrompt = "You are a test agent.";
permissions = {};
};
};
result = agentsLib.renderForPi {
inherit pkgs canonical;
codingRules = null;
};
agentsMd = builtins.readFile "${result}/AGENTS.md";
hasMarkers = builtins.match ".*CODING-RULES:START.*" agentsMd != null;
in
assert hasMarkers == false; {result = "pass";};
# Test 4: renderForPi with codingRules includes rules in AGENTS.md
# Uses the real AGENTS repo to read rule files (requires --impure or local path)
testPiWithCodingRules = let
agentsPath = /home/sascha.koenig/p/AI/AGENTS;
pkgs = import <nixpkgs> {};
canonical = {
chiron = {
mode = "primary";
description = "Test primary agent";
display_name = "Chiron";
systemPrompt = "You are a test agent.";
permissions = {};
};
};
result = agentsLib.renderForPi {
inherit pkgs canonical;
codingRules = {
agents = agentsPath;
concerns = ["coding-style"];
languages = [];
frameworks = [];
};
};
agentsMd = builtins.readFile "${result}/AGENTS.md";
hasStartMarker = builtins.match ".*CODING-RULES:START.*" agentsMd != null;
hasEndMarker = builtins.match ".*CODING-RULES:END.*" agentsMd != null;
hasCodingStyle = builtins.match ".*Coding Style.*" agentsMd != null;
# Also verify agent descriptions are still present
hasAgentInstructions = builtins.match ".*Agent Instructions.*" agentsMd != null;
in
assert hasStartMarker == true;
assert hasEndMarker == true;
assert hasCodingStyle == true;
assert hasAgentInstructions == true; {result = "pass";};
in {
unknown-tool-throws = testUnknownTool;
load-canonical = testLoadCanonical;
pi-null-coding-rules = testPiNullCodingRules;
pi-with-coding-rules = testPiWithCodingRules;
}

View File

@@ -37,8 +37,74 @@ let
in
assert hasSymlink;
assert hasConfigGen; {result = "pass";};
# Test 4: forPi=false does not include AGENTS.md logic in shellHook
testForPiDisabled = let
rules = codingRulesLib.mkCodingRules {
agents = "/tmp/fake-agents";
forPi = false;
};
hook = rules.shellHook;
hasPiBlock = builtins.match ".*CODING-RULES:START.*" hook != null;
in
assert hasPiBlock == false; {result = "pass";};
# Test 5: forPi=true adds CODING-RULES markers to shellHook (when agents path has rules)
# Note: This test uses the real AGENTS repo at /home/sascha.koenig/p/AI/AGENTS
# It is only run when the path exists.
testForPiEnabled = let
agentsPath = /home/sascha.koenig/p/AI/AGENTS;
rules = codingRulesLib.mkCodingRules {
agents = agentsPath;
forPi = true;
concerns = ["coding-style"];
languages = [];
frameworks = [];
};
hook = rules.shellHook;
hasPiBlock = builtins.match ".*CODING-RULES:START.*" hook != null;
hasCodingStyle = builtins.match ".*Coding Style.*" hook != null;
in
assert hasPiBlock == true;
assert hasCodingStyle == true; {result = "pass";};
# Test 6: concatRulesMd produces concatenated markdown (with real agents path)
testConcatRulesMd = let
agentsPath = /home/sascha.koenig/p/AI/AGENTS;
md = codingRulesLib.concatRulesMd {
agents = agentsPath;
concerns = ["coding-style"];
languages = [];
frameworks = [];
};
hasHeader = builtins.match ".*Coding Style.*" md != null;
hasCritical = builtins.match ".*Critical Rules.*" md != null;
in
assert hasHeader == true;
assert hasCritical == true; {result = "pass";};
# Test 7: mkRulesMdSection wraps content with markers
testRulesMdSection = let
agentsPath = /home/sascha.koenig/p/AI/AGENTS;
section = codingRulesLib.mkRulesMdSection {
agents = agentsPath;
concerns = ["coding-style"];
languages = [];
frameworks = [];
};
hasStartMarker = builtins.match ".*CODING-RULES:START.*" section != null;
hasEndMarker = builtins.match ".*CODING-RULES:END.*" section != null;
hasHeader = builtins.match ".*# Coding Rules.*" section != null;
in
assert hasStartMarker == true;
assert hasEndMarker == true;
assert hasHeader == true; {result = "pass";};
in {
instructions-correct = testInstructions;
default-rules-dir = testDefaultRulesDir;
shell-hook = testShellHook;
forpi-disabled = testForPiDisabled;
forpi-enabled = testForPiEnabled;
concat-rules-md = testConcatRulesMd;
rules-md-section = testRulesMdSection;
}