70 KiB
Harness-Agnostic Agent Migration
TL;DR
Quick Summary: Migrate AGENTS repo from OpenCode-specific agents.json to a tool-agnostic canonical format (agent.toml + system-prompt.md per agent). Build Nix rendering pipeline in m3ta-nixpkgs that generates tool-specific configs for OpenCode, Claude Code, and Pi. Support system-level (home-manager) and project-level (flake.nix + direnv).
Deliverables:
- 6 canonical agent definitions in AGENTS repo (TOML + Markdown)
- 3 tool renderers in m3ta-nixpkgs (OpenCode, Claude Code, Pi)
- Home-manager modules per tool replacing current opencode.nix
- Project-level lib functions for flake.nix + direnv usage
- Backward-compatible bridge during migration
Estimated Effort: Large Parallel Execution: YES — 4 waves Critical Path: TOML spike → canonical agents → lib/agents.nix → per-tool HM modules → golden file verification
Context
Original Request
Restructure AGENTS repo to be harness-agnostic so the same agent definitions, skills, prompts work across OpenCode, Claude Code, Codex, Pi, and future coding agents. Build corresponding Nix infrastructure in m3ta-nixpkgs for system-level and project-level consumption.
Interview Summary
Key Discussions:
- YAML rejected for canonical format — TOML chosen (native
builtins.fromTOML, no IFD) - Renderers belong in m3ta-nixpkgs, not AGENTS repo (AGENTS stays pure data)
- OpenCode + Claude Code + Pi renderers now; Codex/Aider later on demand
- Two-level permission model: simple intent + optional rules array for glob patterns
- mkOpencodeRules renamed to mkCodingRules (backward-compat alias)
- All 6 agents migrated to canonical TOML format
- opencode.nix replaced by new per-tool modules (but non-agent OpenCode config kept separate)
- Verification: nix flake check + rendered OpenCode output must match golden file
- Project-level: lib functions returning derivations, usable via shellHook in devShells
Research Findings:
- OpenCode: Now supports file-based agents (
.opencode/agent/*.mdwith YAML frontmatter) — modern path, avoids config.json embedding - Claude Code: Subagents require
name(kebab-case) +descriptionas mandatory frontmatter fields - Pi: No subagent concept. Uses AGENTS.md/CLAUDE.md for instructions, SYSTEM.md for prompt override, same SKILL.md format as OpenCode
- Codex: config.toml + AGENTS.md only, no agent definitions — single-agent tool
- Aider: .aider.conf.yml + read: lists, no agents/permissions/skills
- TOML in Nix:
builtins.fromTOMLsupports TOML 1.0.0 strict. No datetime fields, no multi-line inline tables.
Metis Review
Identified Gaps (addressed):
- oh-my-opencode.json ownership: Non-agent OpenCode config stays in slimmed opencode.nix (not in agents.nix)
- Pi has no subagents: Pi renderer produces AGENTS.md + SYSTEM.md from primary agent only. Subagents skipped.
- Claude Code name format: Renderer must slugify to
[a-z0-9-]+ - Model string formats differ: Need mapping table (canonical → tool-specific)
- OpenCode file-based agents: Modern path via
.opencode/agent/*.mdpreferred over config.json embedding - TOML feasibility risk: Must test Chiron-Forge's 15+ bash glob patterns FIRST
- Phase boundary enforced: agents only (no skills/rules/MCP migration in this plan)
- Backward-compat bridge:
lib.agentsJsonin AGENTS repo produces old JSON during transition - Partial migration hazard: Version check in nixpkgs to handle old AGENTS input gracefully
Work Objectives
Core Objective
Transform the AGENTS repository into a tool-agnostic data repository and build a Nix rendering pipeline that generates tool-specific configurations for multiple coding agents.
Concrete Deliverables
AGENTS/agents/{chiron,chiron-forge,hermes,athena,apollo,calliope}/agent.toml— 6 canonical agent definitionsAGENTS/agents/{name}/system-prompt.md— 6 system prompts (byte-identical to current .txt files)AGENTS/flake.nix— Updated withlib.loadAgentsand backward-compatlib.agentsJsonnixpkgs/lib/agents.nix—loadCanonical+ 3 renderer functionsnixpkgs/modules/home-manager/coding/agents/opencode.nix— OpenCode HM sub-modulenixpkgs/modules/home-manager/coding/agents/claude-code.nix— Claude Code HM sub-modulenixpkgs/modules/home-manager/coding/agents/pi.nix— Pi HM sub-modulenixpkgs/modules/home-manager/coding/opencode.nix— Slimmed (non-agent config only)nixpkgs/lib/coding-rules.nix— Renamed from opencode-rules.nix with backward-compat alias
Definition of Done
nix flake checkpasses on both repos- Rendered OpenCode agent output is semantically equivalent to current agents.json (golden file diff = 0)
- All 6 agents parse successfully via
builtins.fromTOML - Claude Code renderer produces valid MD files with required frontmatter
- Pi renderer produces valid AGENTS.md + optional settings.json
- System prompt content is byte-identical to current .txt files
nix fmt(alejandra) produces no changeslib.mkOpencodeSkillsstill works unchanged
Must Have
- All 6 agents in canonical TOML format with system-prompt.md
- OpenCode renderer producing
.opencode/agent/*.mdfile-based agents - Claude Code renderer producing
.claude/agents/*.mdwith valid YAML frontmatter - Pi renderer producing AGENTS.md + SYSTEM.md from primary agent
- Per-machine model overrides via home-manager
- Backward-compatible bridge (
lib.agentsJson) during transition - Project-level
renderForToollib function for flake.nix + direnv
Must NOT Have (Guardrails)
- No YAML files as canonical source (TOML only — no IFD)
- No renderer code in AGENTS repo (renderers live in nixpkgs)
- No Codex or Aider renderers (design for extensibility, implement only 3)
- No MCP configuration in agent.toml (MCP is tool-specific infrastructure)
- No prompt content changes during migration (byte-identical rename only)
- No skills/rules/context migration in this plan (separate concern)
- No
mkOpencodeSkillschanges (stays as-is) - No datetime fields in TOML schema (requires experimental Nix flag)
- No multi-line inline tables in TOML (not supported by Nix's TOML 1.0.0)
- No generic permission translation DSL (each renderer hard-codes its own mapping)
- No monolithic home-manager module (separate sub-module per tool)
Verification Strategy (MANDATORY)
ZERO HUMAN INTERVENTION — ALL verification is agent-executed. No exceptions.
Test Decision
- Infrastructure exists: YES — Nix evaluation + alejandra formatter
- Automated tests: Nix eval comparison (golden file diff)
- Framework:
nix eval,jq --sort-keys,diff,python3for YAML validation
QA Policy
Every task MUST include agent-executed QA scenarios.
Evidence saved to .sisyphus/evidence/task-{N}-{scenario-slug}.{ext}.
- Nix evaluation: Use Bash (nix eval) — Evaluate expressions, compare outputs
- File validation: Use Bash (python3/jq) — Parse YAML frontmatter, validate JSON
- Content comparison: Use Bash (diff) — Byte-identical prompt verification
- Formatting: Use Bash (alejandra --check) — No formatting drift
Execution Strategy
Parallel Execution Waves
Wave 1 (Start Immediately — foundation + spike):
├── Task 1: Capture golden file baseline [quick]
├── Task 2: TOML feasibility spike with Chiron-Forge [quick]
├── Task 3: Design canonical agent.toml schema [deep]
└── Task 4: Research OpenCode file-based agent frontmatter [quick]
Wave 2 (After Wave 1 — AGENTS repo migration):
├── Task 5: Create all 6 agent.toml + system-prompt.md files [unspecified-high]
├── Task 6: Update AGENTS flake.nix with loadAgents + agentsJson [deep]
├── Task 7: Create lib/agents.nix in nixpkgs with loadCanonical [deep]
└── Task 8: Verify backward-compat bridge produces golden file match [quick]
Wave 3 (After Wave 2 — renderers + HM modules, MAX PARALLEL):
├── Task 9: Implement OpenCode renderer in lib/agents.nix [deep]
├── Task 10: Implement Claude Code renderer in lib/agents.nix [deep]
├── Task 11: Implement Pi renderer in lib/agents.nix [unspecified-high]
├── Task 12: Create HM sub-module for OpenCode (agents/opencode.nix) [unspecified-high]
├── Task 13: Create HM sub-module for Claude Code (agents/claude-code.nix) [unspecified-high]
├── Task 14: Create HM sub-module for Pi (agents/pi.nix) [unspecified-high]
├── Task 15: Slim down existing opencode.nix to non-agent config only [quick]
└── Task 16: Rename mkOpencodeRules to mkCodingRules + backward-compat alias [quick]
Wave 4 (After Wave 3 — integration + project-level + cleanup):
├── Task 17: Add project-level renderForTool lib function [deep]
├── Task 18: Update nixpkgs flake.nix exports + aggregator imports [quick]
├── Task 19: Update AGENTS.md documentation [quick]
├── Task 20: Remove legacy agents.json + prompts/*.txt from AGENTS repo [quick]
└── Task 21: End-to-end integration test across both repos [unspecified-high]
Wave FINAL (After ALL tasks — 4 parallel reviews, then user okay):
├── 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)
-> Present results -> Get explicit user okay
Dependency Matrix
| Task | Depends On | Blocks | Wave |
|---|---|---|---|
| 1 | — | 8, 21 | 1 |
| 2 | — | 3, 5 | 1 |
| 3 | 2 | 5, 6, 7 | 1 |
| 4 | — | 9, 12 | 1 |
| 5 | 2, 3 | 6, 8, 9, 10, 11 | 2 |
| 6 | 3, 5 | 8, 17 | 2 |
| 7 | 3 | 9, 10, 11, 12, 13, 14, 17 | 2 |
| 8 | 1, 5, 6 | 20 | 2 |
| 9 | 4, 5, 7 | 12 | 3 |
| 10 | 5, 7 | 13 | 3 |
| 11 | 5, 7 | 14 | 3 |
| 12 | 9 | 18, 21 | 3 |
| 13 | 10 | 18, 21 | 3 |
| 14 | 11 | 18, 21 | 3 |
| 15 | — | 18 | 3 |
| 16 | — | 18 | 3 |
| 17 | 6, 7 | 21 | 4 |
| 18 | 12, 13, 14, 15, 16 | 21 | 4 |
| 19 | 5 | — | 4 |
| 20 | 8 | — | 4 |
| 21 | 1, 12, 13, 14, 17, 18 | F1-F4 | 4 |
Agent Dispatch Summary
- Wave 1: 4 — T1 →
quick, T2 →quick, T3 →deep, T4 →quick - Wave 2: 4 — T5 →
unspecified-high, T6 →deep, T7 →deep, T8 →quick - Wave 3: 8 — T9 →
deep, T10 →deep, T11 →unspecified-high, T12-T14 →unspecified-high, T15-T16 →quick - Wave 4: 5 — T17 →
deep, T18 →quick, T19 →quick, T20 →quick, T21 →unspecified-high - FINAL: 4 — F1 →
oracle, F2 →unspecified-high, F3 →unspecified-high, F4 →deep
TODOs
-
1. Capture Golden File Baseline
What to do:
- On the machine where home-manager is configured, capture the current rendered OpenCode agent config:
nix eval --json '.#homeConfigurations.sk.config.programs.opencode.settings.agent' | jq --sort-keys . > /tmp/agents-golden.json - Also capture the raw agents.json for direct comparison:
jq --sort-keys . /home/m3tam3re/p/AI/AGENTS/agents/agents.json > /tmp/agents-json-golden.json - Store both golden files in
.sisyphus/evidence/for later use by other tasks - Note: If home-manager eval isn't available, use direct file comparison as fallback
Must NOT do:
- Modify any source files
- Change agents.json content
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1 (with Tasks 2, 3, 4)
- Blocks: Tasks 8, 21
- Blocked By: None
References:
agents/agents.json— Current source of truth (173 lines, 6 agents)modules/home-manager/coding/opencode.nix:148-149in nixpkgs — Where agents.json gets embedded viabuiltins.fromJSON (builtins.readFile ...)
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Golden file captured and parseable Tool: Bash Preconditions: AGENTS repo at /home/m3tam3re/p/AI/AGENTS Steps: 1. Run: jq --sort-keys . /home/m3tam3re/p/AI/AGENTS/agents/agents.json > .sisyphus/evidence/agents-golden.json 2. Run: jq 'keys | length' .sisyphus/evidence/agents-golden.json 3. Assert output is exactly "6" (6 agents) 4. Run: jq 'keys' .sisyphus/evidence/agents-golden.json 5. Assert output contains "Chiron (Assistant)", "Chiron Forge (Builder)", "Hermes (Communication)", "Athena (Researcher)", "Apollo (Knowledge Management)", "Calliope (Writer)" Expected Result: Golden file exists, contains 6 agents, valid JSON Failure Indicators: jq parse error, agent count != 6, missing agent names Evidence: .sisyphus/evidence/agents-golden.jsonCommit: NO (evidence only, no source changes)
- On the machine where home-manager is configured, capture the current rendered OpenCode agent config:
-
2. TOML Feasibility Spike — Chiron-Forge Permission Matrix
What to do:
- Write a test
agent.tomlfor Chiron-Forge (the most complex agent — 2 primary modes, 15+ bash permission patterns with globs, wildcards, and special characters) - Test it parses correctly with
nix eval --expr 'builtins.fromTOML (builtins.readFile ./test.toml)' - Specifically verify these tricky patterns parse in TOML strings:
"rm -rf *"(glob with spaces)"git reset --hard*"(double-dash + glob)"git push --force*"(double-dash + glob)"git push -f *"(short flag + glob)"~/p/**"(home dir + double glob)"/run/agenix/**"(absolute path + double glob)
- Test the two-level permission schema: simple intent + rules array
- Write the test file to a temporary location, NOT in agents/ yet
- If parsing FAILS: document exactly what fails and propose schema workaround
Must NOT do:
- Create permanent files in agents/ directory (this is a spike)
- Modify flake.nix
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1 (with Tasks 1, 3, 4)
- Blocks: Tasks 3, 5
- Blocked By: None
References:
agents/agents.json:40-68— Chiron Forge's full permission matrix (the most complex agent)agents/agents.json:1-38— Chiron's permission matrix (read-only agent with extensive bash allowlist)- Nix TOML docs:
builtins.fromTOMLsupports TOML 1.0.0 strict (toml11 v4). No datetime, no multi-line inline tables.
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: TOML parses all permission patterns correctly Tool: Bash Preconditions: Nix available with builtins.fromTOML Steps: 1. Write test agent.toml with Chiron-Forge's full permission set to /tmp/test-agent.toml 2. Run: nix eval --expr 'builtins.fromTOML (builtins.readFile /tmp/test-agent.toml)' --json 3. Pipe output to jq and verify: - .name == "chiron-forge" - .permissions.bash.intent == "allow" - .permissions.bash.rules | length >= 4 (deny rules) - .permissions.edit.intent == "allow" - .permissions.external_directory.rules | length >= 4 4. Verify each deny pattern string is preserved exactly (no escaping issues) Expected Result: All fields parse, all glob patterns preserved, all special characters intact Failure Indicators: Nix eval error, missing fields, mangled glob patterns, escape issues Evidence: .sisyphus/evidence/task-2-toml-spike.json Scenario: TOML handles edge cases (empty rules, minimal agent) Tool: Bash Preconditions: Nix available Steps: 1. Write minimal agent.toml with only name + description to /tmp/test-minimal.toml 2. Run: nix eval --expr 'builtins.fromTOML (builtins.readFile /tmp/test-minimal.toml)' --json 3. Assert parse succeeds with only required fields Expected Result: Minimal TOML parses without error Failure Indicators: Nix eval error on missing optional fields Evidence: .sisyphus/evidence/task-2-toml-minimal.jsonCommit: NO (spike only, temporary files)
- Write a test
-
3. Design Canonical agent.toml Schema
What to do:
- Based on TOML spike results (Task 2) and research findings, define the final canonical schema
- Create
agents/SCHEMA.mddocumenting the canonical format with:- All required fields:
name(string, kebab-case),description(string) - All optional fields:
mode,tags,max_turns - Permission schema:
[permissions.TOOL]tables withintent(allow/deny/ask) +rules(array of "pattern:action" strings) - Skill references:
skillsarray of skill names - Context references:
contextarray of file paths - Rule references:
rulesarray of rule paths (e.g. "languages/nix") - NO
modelfield (model is per-machine via home-manager) - NO
promptfield (prompt lives in system-prompt.md, not in TOML) - NO MCP configuration (tool-specific)
- NO datetime fields (Nix limitation)
- All required fields:
- Schema must be a SUPERSET: renderers silently drop fields they can't map
- Document per-renderer field support matrix in SCHEMA.md
Must NOT do:
- Include model configuration (per-machine concern)
- Include MCP server config (tool-specific infrastructure)
- Include hooks (Claude Code exclusive, not canonical)
- Use datetime TOML types
- Use multi-line inline tables
Recommended Agent Profile:
- Category:
deep - Skills: []
Parallelization:
- Can Run In Parallel: YES (but should incorporate Task 2 results if available)
- Parallel Group: Wave 1 (with Tasks 1, 2, 4)
- Blocks: Tasks 5, 6, 7
- Blocked By: Task 2 (TOML feasibility must pass first)
References:
- Task 2's TOML spike results — Confirms which TOML patterns work
agents/agents.json— Current field set to preserve (all 6 agents)- Claude Code sub-agents docs — Required frontmatter fields:
name(kebab-case),description - OpenCode agent schema — Supports: name, description, mode, model, temperature, top_p, steps, permission[], color, hidden, disable
- Pi README — No agent schema. Uses AGENTS.md + SYSTEM.md + settings.json
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Schema document is complete and internally consistent Tool: Bash Preconditions: agents/SCHEMA.md created Steps: 1. Read agents/SCHEMA.md 2. Verify it documents: required fields, optional fields, permission schema, skill references, context references 3. Verify it explicitly lists: fields NOT included (model, prompt, mcp, hooks, datetime) 4. Verify it includes a per-renderer support matrix table 5. Write a sample agent.toml following the schema and parse it with builtins.fromTOML Expected Result: Schema is complete, sample TOML parses successfully Failure Indicators: Missing field documentation, sample TOML fails to parse Evidence: .sisyphus/evidence/task-3-schema-sample.tomlCommit: YES
- Message:
docs: add canonical agent.toml schema definition - Files:
agents/SCHEMA.md - Pre-commit:
nix eval --expr 'builtins.fromTOML (builtins.readFile ./evidence-sample.toml)' --json
-
4. Research OpenCode File-Based Agent Frontmatter
What to do:
- Verify OpenCode's
.opencode/agent/*.mdfile-based agent format by reading source code or docs - Document the exact YAML frontmatter fields supported:
- Which fields map from canonical agent.toml?
- What is the permission format in frontmatter?
- How does
mode: primary | subagent | allwork? - What is the default behavior for omitted fields?
- How does file-based agent discovery interact with config.json
agentkey?
- Confirm that file-based agents DON'T require
home-manager switchfor prompt changes (key advantage over config.json embedding) - Save findings to
.sisyphus/evidence/task-4-opencode-agent-format.md
Must NOT do:
- Modify any files
- Create agent files yet (that's Task 5)
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1 (with Tasks 1, 2, 3)
- Blocks: Tasks 9, 12
- Blocked By: None
References:
- OpenCode GitHub:
github.com/sst/opencode(oranomalyco/opencode) — search for agent loading logic - OpenCode docs on file-based agents:
.opencode/agent/*.mdwith YAML frontmatter - Current opencode.nix:148 in nixpkgs — Shows config.json embedding approach (what we're moving away from)
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: OpenCode file-based agent format documented Tool: Bash Preconditions: Research complete Steps: 1. Read .sisyphus/evidence/task-4-opencode-agent-format.md 2. Verify it documents: supported frontmatter fields, permission format, mode values, default behaviors 3. Verify it confirms or denies: file-based agents don't need home-manager switch Expected Result: Complete format documentation with concrete examples Failure Indicators: Missing field documentation, unresolved questions about discovery behavior Evidence: .sisyphus/evidence/task-4-opencode-agent-format.mdCommit: NO (research only)
- Verify OpenCode's
-
5. Create All 6 agent.toml + system-prompt.md Files
What to do:
- For each of the 6 agents, create
agents/{name}/agent.tomlfollowing the schema from Task 3 - For each agent, copy (byte-identical!) the system prompt from
prompts/{name}.txttoagents/{name}/system-prompt.md - Agent directories to create:
chiron,chiron-forge,hermes,athena,apollo,calliope - Translate current JSON fields to TOML:
"Chiron (Assistant)"→name = "chiron",display_name = "Chiron (Assistant)""mode": "primary"→mode = "primary""description": "..."→description = "..."- Permission objects → two-level
[permissions.TOOL]tables
- Translate OpenCode's nested bash permission objects:
Into TOML:
"bash": { "*": "ask", "git status*": "allow", ... }[permissions.bash] intent = "ask" rules = ["git status*:allow", "git log*:allow", ...] - Translate external_directory permissions similarly
- Skills, rules, context references per existing agent capabilities
- Verify EVERY toml file parses with
builtins.fromTOML
Must NOT do:
- Change prompt content (byte-identical copy only)
- Include
modelfield in agent.toml (per-machine concern) - Delete old agents.json or prompts/ yet (Task 20)
- Add MCP config to agent.toml
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
Parallelization:
- Can Run In Parallel: NO (depends on schema from Task 3)
- Parallel Group: Wave 2
- Blocks: Tasks 6, 8, 9, 10, 11, 19
- Blocked By: Tasks 2, 3
References:
agents/agents.json— Source data for all 6 agents (173 lines)prompts/chiron.txtthroughprompts/calliope.txt— System prompts to copyagents/SCHEMA.md(from Task 3) — Canonical schema to follow- Task 2 results — Confirmed TOML parsing patterns
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: All 6 agent.toml files parse without error Tool: Bash Preconditions: All agents/*/agent.toml created Steps: 1. for f in agents/*/agent.toml; do nix eval --expr "builtins.fromTOML (builtins.readFile ./$f)" --json > /dev/null && echo "OK: $f" || echo "FAIL: $f"; done 2. Assert all 6 print "OK" 3. Verify each has required fields: nix eval --expr '(builtins.fromTOML (builtins.readFile ./agents/chiron/agent.toml)).name' → "chiron" Expected Result: All 6 TOML files parse, all have name + description Failure Indicators: Any nix eval error, missing required fields Evidence: .sisyphus/evidence/task-5-toml-parse-all.txt Scenario: System prompts are byte-identical to originals Tool: Bash Preconditions: All agents/*/system-prompt.md created Steps: 1. diff prompts/chiron.txt agents/chiron/system-prompt.md 2. diff prompts/chiron-forge.txt agents/chiron-forge/system-prompt.md 3. diff prompts/hermes.txt agents/hermes/system-prompt.md 4. diff prompts/athena.txt agents/athena/system-prompt.md 5. diff prompts/apollo.txt agents/apollo/system-prompt.md 6. diff prompts/calliope.txt agents/calliope/system-prompt.md 7. All diffs must exit with code 0 (no differences) Expected Result: Zero differences across all 6 files Failure Indicators: Any diff showing changes Evidence: .sisyphus/evidence/task-5-prompt-diff.txt Scenario: Permission patterns preserved exactly Tool: Bash Preconditions: agents/chiron-forge/agent.toml exists Steps: 1. nix eval --expr '(builtins.fromTOML (builtins.readFile ./agents/chiron-forge/agent.toml)).permissions.bash.rules' --json 2. Assert result contains: "rm -rf *:ask", "git reset --hard*:ask", "git push --force*:deny", "git push -f *:deny" 3. nix eval --expr '(builtins.fromTOML (builtins.readFile ./agents/chiron/agent.toml)).permissions.bash.rules' --json 4. Assert result contains at least 12 allow rules (git status*, git log*, etc.) Expected Result: All glob patterns preserved with correct actions Failure Indicators: Missing patterns, wrong action types, escaping issues Evidence: .sisyphus/evidence/task-5-permissions.jsonCommit: YES
- Message:
feat: add canonical agent.toml definitions for all 6 agents - Files:
agents/*/agent.toml,agents/*/system-prompt.md - Pre-commit:
for f in agents/*/agent.toml; do nix eval --expr "builtins.fromTOML (builtins.readFile ./$f)" --json > /dev/null; done
- For each of the 6 agents, create
-
6. Update AGENTS flake.nix with loadAgents + agentsJson Bridge
What to do:
- Add
lib.loadAgentsfunction to AGENTS repo's flake.nix:- Reads all
agents/*/agent.tomlviabuiltins.fromTOML (builtins.readFile ...) - Reads corresponding
system-prompt.mdviabuiltins.readFile - Returns an attrset:
{ chiron = { name; description; mode; permissions; ...; systemPrompt = "..."; }; ... } - Discovery: reads
agents/directory, filters for subdirs containingagent.toml
- Reads all
- Add
lib.agentsJsonbackward-compat bridge function:- Calls
loadAgents, transforms back to current agents.json shape - Maps canonical permission format back to OpenCode's nested objects
- Maps
systemPromptback to"prompt": "{file:./prompts/chiron.txt}"format (or inline) - Adds
modelfield from a configurable default (since agent.toml has no model)
- Calls
- Keep ALL existing exports unchanged:
lib.mkOpencodeSkills,packages.skills-runtime,devShells.default libexport must be system-independent (noforAllSystemswrapper — pure functions)
Must NOT do:
- Change mkOpencodeSkills
- Remove any existing exports
- Add renderer logic (that goes in nixpkgs)
- Hardcode machine-specific model assignments
Recommended Agent Profile:
- Category:
deep - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Task 7)
- Parallel Group: Wave 2
- Blocks: Tasks 8, 17
- Blocked By: Tasks 3, 5
References:
flake.nix— Current AGENTS flake (188 lines). Keep structure, add tolibsection.flake.nix:52-123—lib.mkOpencodeSkillspattern (linkFarm approach)agents/agents.json— Target output shape for agentsJson bridge functionagents/SCHEMA.md(from Task 3) — Canonical schema definition
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: loadAgents returns all 6 agents with correct structure Tool: Bash Preconditions: Task 5 complete, flake.nix updated Steps: 1. nix eval --json '.#lib.loadAgents' | jq 'keys | length' 2. Assert output is 6 3. nix eval --json '.#lib.loadAgents' | jq '.chiron.name' 4. Assert output is "chiron" 5. nix eval --json '.#lib.loadAgents' | jq '.["chiron-forge"].permissions.bash.intent' 6. Assert output is "allow" Expected Result: 6 agents loaded, all fields present Failure Indicators: Eval error, wrong agent count, missing fields Evidence: .sisyphus/evidence/task-6-loadagents.json Scenario: agentsJson bridge matches golden file Tool: Bash Preconditions: Golden file from Task 1 available Steps: 1. nix eval --json '.#lib.agentsJson' | jq --sort-keys . > /tmp/agents-bridge-output.json 2. diff /tmp/agents-bridge-output.json .sisyphus/evidence/agents-golden.json 3. Exit code must be 0 Expected Result: Bridge output is semantically identical to original agents.json Failure Indicators: Any diff (key ordering differences are OK if using jq --sort-keys) Evidence: .sisyphus/evidence/task-6-bridge-diff.txtCommit: YES
- Message:
feat: export loadAgents and backward-compat agentsJson from flake - Files:
flake.nix - Pre-commit:
nix flake check && nix eval --json '.#lib.loadAgents' > /dev/null
- Add
-
7. Create lib/agents.nix in nixpkgs with loadCanonical
What to do:
- Create
/home/m3tam3re/p/NIX/nixpkgs/lib/agents.nixwith:loadCanonical { agentsInput }— reads canonical agents from the AGENTS flake input- Calls
agentsInput.lib.loadAgents(from Task 6) to get canonical attrset - Returns the canonical attrset (or wraps/validates it)
- Calls
- Stub functions for renderers (to be implemented in Tasks 9-11):
renderForOpencode { canonical; modelOverrides ? {}; }→ derivation placeholderrenderForClaudeCode { canonical; modelOverrides ? {}; }→ derivation placeholderrenderForPi { canonical; }→ derivation placeholderrenderForTool { agentsInput; tool; modelOverrides ? {}; }→ dispatcher
- Wire into
lib/default.nixalongside existingportsandopencode-rules - Follow existing lib patterns:
{lib}: { ... }function signature
Must NOT do:
- Implement actual renderers yet (stubs only — Tasks 9-11)
- Import pkgs at lib level (renderers need pkgs, but the interface should accept it as argument)
- Modify existing lib functions
Recommended Agent Profile:
- Category:
deep - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Task 6)
- Parallel Group: Wave 2
- Blocks: Tasks 9, 10, 11, 12, 13, 14, 17
- Blocked By: Task 3
References:
lib/default.nixin nixpkgs — Current lib exports (ports, opencode-rules). Add agents here.lib/opencode-rules.nixin nixpkgs — Pattern reference for lib function structure (116 lines)- Task 3 SCHEMA.md — Defines the canonical attrset shape
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: lib/agents.nix loads and stub functions exist Tool: Bash Preconditions: lib/agents.nix created, lib/default.nix updated Steps: 1. nix eval --expr '(import ./lib { lib = (import <nixpkgs> {}).lib; }).agents' --json 2. Assert result contains keys: loadCanonical, renderForOpencode, renderForClaudeCode, renderForPi, renderForTool 3. nix flake check /home/m3tam3re/p/NIX/nixpkgs 4. Assert exit code 0 Expected Result: All stub functions exist, flake check passes Failure Indicators: Import error, missing function names, flake check failure Evidence: .sisyphus/evidence/task-7-lib-agents.jsonCommit: YES
- Message:
feat(lib): add agents.nix with loadCanonical and renderer stubs - Files:
lib/agents.nix,lib/default.nix - Pre-commit:
nix flake check
- Create
-
8. Verify Backward-Compat Bridge Produces Golden File Match
What to do:
- With Tasks 1, 5, 6 complete, run the full backward-compat verification:
nix eval --json '.#lib.agentsJson' | jq --sort-keys . > /tmp/bridge-output.json diff /tmp/bridge-output.json .sisyphus/evidence/agents-golden.json - If diff shows differences, debug and fix in Task 6's
agentsJsonfunction - This is a GATE: do NOT proceed to Wave 3 until this passes
- Document any semantic differences that are acceptable (e.g., key ordering)
Must NOT do:
- Modify the golden file
- Accept content differences as "close enough"
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: NO (gate task)
- Parallel Group: Wave 2 (runs last in wave)
- Blocks: Task 20
- Blocked By: Tasks 1, 5, 6
References:
.sisyphus/evidence/agents-golden.json— Golden file from Task 1- Task 6's
lib.agentsJson— Bridge function to verify
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Bridge output matches golden file exactly Tool: Bash Preconditions: Tasks 1, 5, 6 complete Steps: 1. cd /home/m3tam3re/p/AI/AGENTS 2. nix eval --json '.#lib.agentsJson' | jq --sort-keys . > /tmp/bridge-verify.json 3. diff /tmp/bridge-verify.json .sisyphus/evidence/agents-golden.json 4. Assert exit code 0 (zero differences) Expected Result: Byte-identical output after jq normalization Failure Indicators: Any diff output, non-zero exit code Evidence: .sisyphus/evidence/task-8-bridge-verify.txtCommit: NO (verification only)
- With Tasks 1, 5, 6 complete, run the full backward-compat verification:
-
9. Implement OpenCode Renderer in lib/agents.nix
What to do:
- Replace the
renderForOpencodestub inlib/agents.nixwith full implementation - Renderer produces a derivation containing
.opencode/agent/*.mdfiles (file-based agents) - For each agent in canonical attrset, generate a markdown file with YAML frontmatter:
name: from canonicalnamedescription: from canonicaldescriptionmode: from canonicalmode(primary/subagent) — MUST set explicitly (OpenCode defaults to "all")model: frommodelOverrides.{name}if present, otherwise omit (let OpenCode use its default)permission: translate canonical two-level permissions to OpenCode's rule array format:permission: - permission: bash pattern: "git status*" action: allow - permission: bash pattern: "*" action: asksteps: from canonicalmax_turnsif present
- Body of markdown = content of
system-prompt.md - Use
pkgs.writeTextorpkgs.runCommandto generate each file, thenpkgs.linkFarmorpkgs.symlinkJointo combine - Handle edge case: agent with no permission rules (omit permission key entirely)
Must NOT do:
- Embed agents in config.json (use file-based agent path)
- Include oh-my-opencode.json or plugin config (that stays in opencode.nix)
- Hard-code model values
Recommended Agent Profile:
- Category:
deep - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Tasks 10, 11, 15, 16)
- Parallel Group: Wave 3
- Blocks: Task 12
- Blocked By: Tasks 4, 5, 7
References:
- Task 4 evidence — OpenCode file-based agent frontmatter format
agents/agents.json— Current permission format (for output comparison)lib/agents.nixstubs from Task 7 — Replace renderForOpencode- OpenCode source: agent file discovery logic
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Rendered OpenCode agents have correct frontmatter Tool: Bash Preconditions: Renderer implemented, AGENTS repo with canonical agents Steps: 1. Build rendered output: nix eval --raw '.#lib.x86_64-linux.agents.renderForOpencode { canonical = inputs.agents.lib.loadAgents; }' 2. List files in rendered output: expect 6 .md files 3. For chiron.md: extract YAML frontmatter, verify name="chiron", mode="primary", description present 4. For chiron-forge.md: verify permission rules contain bash deny patterns for "rm -rf *", "git push --force*" 5. For hermes.md: verify mode="subagent" Expected Result: 6 agent files, correct frontmatter, correct permissions Failure Indicators: Missing files, wrong mode, missing permissions Evidence: .sisyphus/evidence/task-9-opencode-render.txt Scenario: System prompts appear as markdown body Tool: Bash Preconditions: Rendered output available Steps: 1. Extract body (after frontmatter) from rendered chiron.md 2. Compare with agents/chiron/system-prompt.md 3. Assert byte-identical Expected Result: Prompt content unchanged through rendering Failure Indicators: Any content difference Evidence: .sisyphus/evidence/task-9-prompt-body.txtCommit: YES (groups with N1)
- Message:
feat(lib): implement OpenCode renderer in agents.nix - Files:
lib/agents.nix - Pre-commit:
nix flake check
- Replace the
-
10. Implement Claude Code Renderer in lib/agents.nix
What to do:
- Replace
renderForClaudeCodestub with full implementation - Renderer produces a derivation containing
.claude/agents/*.mdfiles AND.claude/settings.jsonfragment - For each agent, generate markdown with YAML frontmatter:
name: slugify canonical name to[a-z0-9-]+(e.g., "chiron-forge" stays, "Chiron" → "chiron")description: from canonicaldescription(REQUIRED by Claude Code)model: frommodelOverrides.{name}→ map to Claude Code alias (sonnet/opus/haiku) or full IDtools: from canonical permissions — collect tool names where intent=allow into allowlistdisallowedTools: from canonical permissions — collect tool names where intent=denypermissionMode: default to "default" unless canonical specifiesmaxTurns: from canonicalmax_turnsskills: from canonicalskillsarray
- Generate
.claude/settings.jsonwith permission rules translated to Claude Code DSL:- Canonical
bash: { rules: ["git push*:deny"] }→permissions.deny: ["Bash(git push*)"] - Canonical
edit: { intent: "allow" }→permissions.allow: ["Edit"]
- Canonical
- Body of markdown = content of
system-prompt.md - Handle subagent-only agents: Claude Code agents are always subagents (no "primary" mode)
Must NOT do:
- Include MCP server config in settings.json
- Include hooks (Claude Code exclusive concept, not in canonical)
- Use non-kebab-case names (Claude Code requires [a-z0-9-]+)
Recommended Agent Profile:
- Category:
deep - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Tasks 9, 11, 15, 16)
- Parallel Group: Wave 3
- Blocks: Task 13
- Blocked By: Tasks 5, 7
References:
- Claude Code sub-agents docs (indexed) — Frontmatter fields, tool names, permission syntax
- Claude Code settings docs (indexed) — Permission rule DSL:
"Bash(git diff *)","Read(./.env)" lib/agents.nixstubs from Task 7- Claude Code tool names:
Bash,Read,Edit,Write,Glob,Grep,WebFetch,Agent(type),MCP(server::tool)
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: All Claude Code agent files have valid YAML frontmatter Tool: Bash Preconditions: Renderer implemented Steps: 1. Build rendered output for claude-code 2. For each .md file in .claude/agents/: python3 -c " import yaml, sys content = open(sys.argv[1]).read() parts = content.split('---', 2) fm = yaml.safe_load(parts[1]) assert 'name' in fm, 'Missing name' assert 'description' in fm, 'Missing description' assert fm['name'].replace('-','').isalnum(), f'Invalid name: {fm[\"name\"]}' print(f'OK: {fm[\"name\"]}') " file.md 3. Assert all 6 files pass Expected Result: All frontmatter valid, names in kebab-case Failure Indicators: YAML parse error, missing required fields, invalid name format Evidence: .sisyphus/evidence/task-10-claude-frontmatter.txt Scenario: Permission DSL correctly translated Tool: Bash Preconditions: Rendered .claude/settings.json exists Steps: 1. Read rendered .claude/settings.json 2. Verify permissions.deny contains patterns like "Bash(rm -rf *)" for chiron-forge deny rules 3. Verify permissions.allow contains patterns like "Bash(git status*)" for chiron allow rules Expected Result: Permission rules correctly translated to Claude Code DSL Failure Indicators: Missing rules, wrong DSL format, lost patterns Evidence: .sisyphus/evidence/task-10-claude-permissions.jsonCommit: YES (groups with N1)
- Message:
feat(lib): implement Claude Code renderer in agents.nix - Files:
lib/agents.nix - Pre-commit:
nix flake check
- Replace
-
11. Implement Pi Renderer in lib/agents.nix
What to do:
- Replace
renderForPistub with full implementation - Pi has NO subagent concept — renderer produces DIFFERENT outputs than OpenCode/Claude Code:
AGENTS.md— Concatenation of all agent descriptions + primary agent's instructions~/.pi/agent/SYSTEM.mdor.pi/SYSTEM.md— Primary agent's system prompt (replaces Pi's default prompt).pi/settings.jsonfragment — Optional: tools list, model config- Skill symlinks — Pi uses same SKILL.md dirs at
~/.pi/agent/skills/or.agents/skills/
- Only PRIMARY agents render to SYSTEM.md. Subagent prompts get embedded as sections in AGENTS.md.
- Generate AGENTS.md with sections per agent:
# Agent Instructions ## Chiron (Assistant) Primary assistant for read-only analysis... ## Available Specialists - Hermes: Work communication (Basecamp, Outlook, Teams) - Athena: Work knowledge (Outline wiki) ... - Pi's tools config:
--tools read,bash,edit,writemaps from canonical permissions - Handle: Pi has no permission granularity — only tool enable/disable
Must NOT do:
- Create agent files (Pi doesn't have them)
- Try to render subagents as separate entities
- Include MCP config (Pi uses extensions instead)
- Create TS extensions (out of scope)
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Tasks 9, 10, 15, 16)
- Parallel Group: Wave 3
- Blocks: Task 14
- Blocked By: Tasks 5, 7
References:
- Pi README (indexed) — AGENTS.md loaded at startup, SYSTEM.md replaces default prompt, APPEND_SYSTEM.md appends
- Pi README skills section —
~/.pi/agent/skills/,.pi/skills/,~/.agents/skills/,.agents/skills/ - Pi README settings —
~/.pi/agent/settings.json(global),.pi/settings.json(project) - Pi README tools —
--tools read,bash,edit,write(default built-in tools)
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Pi renderer produces valid AGENTS.md Tool: Bash Preconditions: Renderer implemented Steps: 1. Build rendered output for pi 2. Assert AGENTS.md exists in output 3. Assert AGENTS.md contains "Chiron" and agent descriptions 4. Assert AGENTS.md contains specialist listing 5. Verify AGENTS.md is valid Markdown (no TOML/JSON artifacts) Expected Result: AGENTS.md exists with readable agent instructions Failure Indicators: File missing, contains raw TOML/JSON, empty content Evidence: .sisyphus/evidence/task-11-pi-agents-md.txt Scenario: Pi renderer produces valid SYSTEM.md from primary agent Tool: Bash Preconditions: Rendered output available Steps: 1. Assert SYSTEM.md or .pi/SYSTEM.md exists in output 2. Content should be the primary agent's system prompt 3. Verify it matches agents/chiron/system-prompt.md content Expected Result: SYSTEM.md exists with primary agent's prompt Failure Indicators: Missing file, wrong content, subagent prompt instead Evidence: .sisyphus/evidence/task-11-pi-system-md.txtCommit: YES (groups with N1)
- Message:
feat(lib): implement Pi renderer in agents.nix - Files:
lib/agents.nix - Pre-commit:
nix flake check
- Replace
-
12. Create HM Sub-Module for OpenCode (agents/opencode.nix)
What to do:
- Create
modules/home-manager/coding/agents/opencode.nixin nixpkgs - Options under
coding.agents.opencode:enable— mkEnableOptionagentsInput— flake input pointing to AGENTS repomodelOverrides— attrset mapping agent name → model string (e.g.,{ chiron = "anthropic/claude-sonnet-4"; })
- Config (mkIf enabled):
- Call
lib.agents.renderForOpencode { canonical; modelOverrides; }to get rendered derivation - Symlink rendered
.opencode/agent/dir viaxdg.configFileorhome.file - Symlink skills via existing
mkOpencodeSkills(if agentsInput set) - Symlink context/ and commands/ from AGENTS input
- Call
- Create
modules/home-manager/coding/agents/default.nixaggregator importing opencode.nix, claude-code.nix, pi.nix - Update
modules/home-manager/coding/default.nixto import./agentssubdir
Must NOT do:
- Handle oh-my-opencode.json, plugins, formatters (stays in slimmed opencode.nix)
- Embed agents in config.json (use file-based agents)
- Include MCP config
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
Parallelization:
- Can Run In Parallel: NO (depends on Task 9)
- Parallel Group: Wave 3 (after Task 9)
- Blocks: Tasks 18, 21
- Blocked By: Task 9
References:
modules/home-manager/coding/opencode.nixin nixpkgs — Current module to learn from (168 lines)- Task 9's renderer — Produces the derivation this module consumes
modules/home-manager/AGENTS.mdin nixpkgs — Module conventions doc
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Module options type-check Tool: Bash Preconditions: Module created Steps: 1. nix flake check /home/m3tam3re/p/NIX/nixpkgs 2. Assert exit code 0 (no type errors in module options) Expected Result: Flake check passes Failure Indicators: Type error in options, missing import Evidence: .sisyphus/evidence/task-12-flake-check.txtCommit: YES (groups with N2)
- Message:
feat(hm): add OpenCode agent sub-module - Files:
modules/home-manager/coding/agents/opencode.nix,modules/home-manager/coding/agents/default.nix - Pre-commit:
nix flake check
- Create
-
13. Create HM Sub-Module for Claude Code (agents/claude-code.nix)
What to do:
- Create
modules/home-manager/coding/agents/claude-code.nixin nixpkgs - Options under
coding.agents.claude-code:enable— mkEnableOptionagentsInput— flake input pointing to AGENTS repomodelOverrides— attrset mapping agent name → model alias or ID
- Config (mkIf enabled):
- Call
lib.agents.renderForClaudeCode { canonical; modelOverrides; }to get rendered derivation - Symlink rendered
.claude/agents/viahome.file - Generate
.claude/settings.jsonwith rendered permission rules - Symlink skills from AGENTS repo to
~/.claude/skills/(if skills exist)
- Call
- Handle: Claude Code's
CLAUDE.md— optionally generate from agent instructions
Must NOT do:
- Manage Claude Code's MCP config (.claude.json)
- Configure Claude Code API keys or auth
- Include hooks in settings.json
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
Parallelization:
- Can Run In Parallel: NO (depends on Task 10)
- Parallel Group: Wave 3 (after Task 10)
- Blocks: Tasks 18, 21
- Blocked By: Task 10
References:
- Claude Code settings docs (indexed) —
.claude/directory structure, settings.json scopes - Task 10's renderer — Produces the derivation this module consumes
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Module type-checks and creates expected file paths Tool: Bash Preconditions: Module created Steps: 1. nix flake check /home/m3tam3re/p/NIX/nixpkgs 2. Assert exit code 0 Expected Result: Flake check passes Failure Indicators: Type error, missing import Evidence: .sisyphus/evidence/task-13-flake-check.txtCommit: YES (groups with N2)
- Message:
feat(hm): add Claude Code agent sub-module - Files:
modules/home-manager/coding/agents/claude-code.nix - Pre-commit:
nix flake check
- Create
-
14. Create HM Sub-Module for Pi (agents/pi.nix)
What to do:
- Create
modules/home-manager/coding/agents/pi.nixin nixpkgs - Options under
coding.agents.pi:enable— mkEnableOptionagentsInput— flake input pointing to AGENTS repo
- Config (mkIf enabled):
- Call
lib.agents.renderForPi { canonical; }to get rendered derivation - Place AGENTS.md at
~/.pi/agent/AGENTS.mdviahome.file - Place SYSTEM.md at
~/.pi/agent/SYSTEM.mdviahome.file - Symlink skills from AGENTS repo to
~/.pi/agent/skills/ - Optionally symlink prompts from AGENTS repo to
~/.pi/agent/prompts/(Pi's prompt templates)
- Call
Must NOT do:
- Create fake agent files (Pi has no subagents)
- Configure Pi extensions (TypeScript, out of scope)
- Manage Pi's package system
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
Parallelization:
- Can Run In Parallel: NO (depends on Task 11)
- Parallel Group: Wave 3 (after Task 11)
- Blocks: Tasks 18, 21
- Blocked By: Task 11
References:
- Pi README (indexed) —
~/.pi/agent/directory structure, skill paths, prompt template paths - Task 11's renderer — Produces the derivation this module consumes
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Module type-checks Tool: Bash Preconditions: Module created Steps: 1. nix flake check /home/m3tam3re/p/NIX/nixpkgs 2. Assert exit code 0 Expected Result: Flake check passes Failure Indicators: Type error, missing import Evidence: .sisyphus/evidence/task-14-flake-check.txtCommit: YES (groups with N2)
- Message:
feat(hm): add Pi agent sub-module - Files:
modules/home-manager/coding/agents/pi.nix - Pre-commit:
nix flake check
- Create
-
15. Slim Down opencode.nix to Non-Agent Config Only
What to do:
- Edit existing
modules/home-manager/coding/opencode.nixin nixpkgs - REMOVE:
agentsInputoption (moved to agents/opencode.nix) - REMOVE:
externalSkillsoption (moved to agents/opencode.nix) - REMOVE: Skills linkFarm generation (moved to agents/opencode.nix)
- REMOVE: Context/commands/prompts symlinks (moved to agents/opencode.nix)
- REMOVE: agents.json embedding (
builtins.fromJSON (builtins.readFile ...)) (replaced by file-based agents) - KEEP:
programs.opencode.enable+enableMcpIntegration - KEEP:
programs.opencode.settingswith theme, formatter, plugin array - KEEP:
ohMyOpencodeSettings→oh-my-opencode.jsongeneration - KEEP:
extraSettingsfor provider/machine-specific config - KEEP:
extraPlugins - Result: opencode.nix handles ONLY tool-specific, non-agent config
Must NOT do:
- Delete opencode.nix entirely (it still handles non-agent concerns)
- Move oh-my-opencode.json to agents module
- Change option names that other configs depend on (check consumers first)
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Tasks 9-14, 16)
- Parallel Group: Wave 3
- Blocks: Task 18
- Blocked By: None (but coordinate with Task 12 for import order)
References:
modules/home-manager/coding/opencode.nixin nixpkgs — Current module (168 lines, will shrink to ~70)- Task 12 — New agents/opencode.nix takes over agent concerns
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Slimmed opencode.nix still manages non-agent config Tool: Bash Preconditions: opencode.nix edited Steps: 1. Verify opencode.nix still has: ohMyOpencodeSettings, extraSettings, extraPlugins options 2. Verify opencode.nix does NOT have: agentsInput, externalSkills options 3. nix flake check /home/m3tam3re/p/NIX/nixpkgs 4. Assert exit code 0 Expected Result: Module compiles, non-agent options preserved, agent options removed Failure Indicators: Missing options that should stay, leftover agent options Evidence: .sisyphus/evidence/task-15-opencode-slim.txtCommit: YES (groups with N3)
- Message:
refactor(hm): slim opencode.nix to non-agent config only - Files:
modules/home-manager/coding/opencode.nix - Pre-commit:
nix flake check
- Edit existing
-
16. Rename mkOpencodeRules to mkCodingRules with Backward-Compat Alias
What to do:
- In
lib/opencode-rules.nix: rename the main function tomkCodingRules - Add backward-compat alias:
mkOpencodeRules = builtins.trace "m3ta-nixpkgs: mkOpencodeRules is deprecated, use mkCodingRules" mkCodingRules; - Rename file:
lib/opencode-rules.nix→lib/coding-rules.nix - Update
lib/default.nix: expose bothcoding-rules.mkCodingRulesandopencode-rules.mkOpencodeRules(alias) - For now, the function body stays identical — tool-agnostic rule rendering is a future enhancement
Must NOT do:
- Change the function's behavior or output
- Remove the old name entirely (backward compat)
- Add multi-tool rendering logic yet
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Tasks 9-15)
- Parallel Group: Wave 3
- Blocks: Task 18
- Blocked By: None
References:
lib/opencode-rules.nixin nixpkgs — Current file (116 lines)lib/default.nixin nixpkgs — Current exports
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Both old and new names work Tool: Bash Preconditions: Rename complete Steps: 1. nix eval --expr '(import ./lib { lib = (import <nixpkgs> {}).lib; }).coding-rules.mkCodingRules' --json 2. Assert function exists (no error) 3. nix eval --expr '(import ./lib { lib = (import <nixpkgs> {}).lib; }).opencode-rules.mkOpencodeRules' --json 4. Assert function exists (backward compat, may show deprecation trace) Expected Result: Both names resolve to the same function Failure Indicators: Either name fails, function behavior changed Evidence: .sisyphus/evidence/task-16-rules-rename.txtCommit: YES (groups with N5)
- Message:
refactor(lib): rename mkOpencodeRules to mkCodingRules with compat alias - Files:
lib/coding-rules.nix,lib/default.nix - Pre-commit:
nix flake check
- In
-
17. Add Project-Level renderForTool Lib Function
What to do:
- Implement
renderForTooldispatcher inlib/agents.nix:renderForTool = { pkgs, agentsInput, tool, modelOverrides ? {} }: let canonical = agentsInput.lib.loadAgents; renderers = { opencode = renderForOpencode { inherit pkgs canonical modelOverrides; }; claude-code = renderForClaudeCode { inherit pkgs canonical modelOverrides; }; pi = renderForPi { inherit pkgs canonical; }; }; in renderers.${tool} or (throw "Unknown tool: ${tool}"); - Add
shellHookForToolhelper that generates a shellHook placing rendered files in project dir:- For OpenCode: symlinks
.opencode/agent/→ rendered derivation - For Claude Code: symlinks
.claude/agents/and.claude/settings.json→ rendered - For Pi: symlinks
.pi/SYSTEM.mdandAGENTS.md→ rendered - All shellHooks add appropriate entries to
.gitignoreif not already present
- For OpenCode: symlinks
- Export via
lib.agents.renderForToolandlib.agents.shellHookForTool - Usage in project flake.nix:
devShells.default = pkgs.mkShell { shellHook = m3taLib.agents.shellHookForTool { inherit pkgs; agentsInput = inputs.agents; tool = "opencode"; modelOverrides = { chiron = "anthropic/claude-sonnet-4"; }; }; };
Must NOT do:
- Write files imperatively (use symlinks to Nix store paths)
- Assume tool from environment (require explicit
toolargument)
Recommended Agent Profile:
- Category:
deep - Skills: []
Parallelization:
- Can Run In Parallel: NO
- Parallel Group: Wave 4
- Blocks: Task 21
- Blocked By: Tasks 6, 7 (and implicitly 9-11)
References:
lib/opencode-rules.nix:106-114in nixpkgs — shellHook pattern reference (ln -sfn + cat > file)- Task 9-11 renderers — Functions this dispatcher calls
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: renderForTool dispatches correctly Tool: Bash Preconditions: All renderers implemented Steps: 1. nix eval --raw '.#lib.x86_64-linux.agents.renderForTool { pkgs = import <nixpkgs> {}; agentsInput = inputs.agents; tool = "opencode"; }' 2. Assert output is a valid store path 3. List contents — expect .opencode/agent/*.md files 4. Repeat for tool = "claude-code" — expect .claude/agents/*.md 5. Repeat for tool = "pi" — expect AGENTS.md + SYSTEM.md Expected Result: Each tool produces correct output structure Failure Indicators: Eval error, wrong output structure, unknown tool error Evidence: .sisyphus/evidence/task-17-renderForTool.txtCommit: YES (groups with N4)
- Message:
feat(lib): add project-level renderForTool function - Files:
lib/agents.nix - Pre-commit:
nix flake check
- Implement
-
18. Update nixpkgs flake.nix Exports + Aggregator Imports
What to do:
- Update
modules/home-manager/coding/default.nixto import./agentssubdir:imports = [ ./editors.nix ./opencode.nix ./agents ]; - Update
flake.nixhomeManagerModules exports:- Keep:
default,ports,zellij-ps - Keep:
opencode(slimmed version) - Add:
agentspointing to./modules/home-manager/coding/agents - Remove or deprecate old
opencodeif fully replaced
- Keep:
- Update
lib/default.nixto export agents module:agents = import ./agents.nix { inherit lib; }; coding-rules = import ./coding-rules.nix { inherit lib; }; opencode-rules = import ./coding-rules.nix { inherit lib; }; # backward compat - Run
nix fmt(alejandra) on all changed files - Run
nix flake check
Must NOT do:
- Remove
opencodeexport without backward compat - Change export names that external configs depend on
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: NO (depends on all Wave 3 tasks)
- Parallel Group: Wave 4
- Blocks: Task 21
- Blocked By: Tasks 12, 13, 14, 15, 16
References:
flake.nixin nixpkgs — Current exports (lines 78-83)modules/home-manager/coding/default.nix— Current aggregatorlib/default.nix— Current lib exports
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: All exports resolve without error Tool: Bash Preconditions: All modules and lib functions created Steps: 1. nix flake check /home/m3tam3re/p/NIX/nixpkgs 2. nix eval '.#homeManagerModules' --json | jq 'keys' 3. Assert keys include: "default", "opencode", "agents", "ports", "zellij-ps" 4. nix fmt --check /home/m3tam3re/p/NIX/nixpkgs 5. Assert no formatting changes needed Expected Result: All exports work, formatting clean Failure Indicators: Missing export, eval error, formatting drift Evidence: .sisyphus/evidence/task-18-exports.txtCommit: YES (groups with N6)
- Message:
chore: update flake exports and aggregator imports - Files:
flake.nix,modules/home-manager/coding/default.nix,lib/default.nix - Pre-commit:
nix flake check && nix fmt --check
- Update
-
19. Update AGENTS.md Documentation
What to do:
- Update
/home/m3tam3re/p/AI/AGENTS/AGENTS.mdto reflect new directory structure - Document:
- New
agents/{name}/agent.toml+system-prompt.mdstructure - The canonical TOML schema (reference SCHEMA.md)
- How renderers work (live in nixpkgs, not here)
- How to add a new agent
- How project-level usage works (flake.nix + direnv)
- Backward-compat bridge (
lib.agentsJson) — note as temporary
- New
- Update directory tree diagram
- Remove references to
agents/agents.jsonas canonical source - Keep references to skills/, rules/, context/, commands/ unchanged
Must NOT do:
- Create README.md (update existing AGENTS.md)
- Document nixpkgs internals (that's nixpkgs's AGENTS.md responsibility)
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Tasks 17, 18, 20)
- Parallel Group: Wave 4
- Blocks: None
- Blocked By: Task 5
References:
/home/m3tam3re/p/AI/AGENTS/AGENTS.md— Current documentation- Task 3's SCHEMA.md — Schema to reference
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: AGENTS.md reflects new structure Tool: Bash Preconditions: AGENTS.md updated Steps: 1. grep "agent.toml" AGENTS.md — assert found 2. grep "system-prompt.md" AGENTS.md — assert found 3. grep "agents.json" AGENTS.md — should NOT appear as "canonical" or "source of truth" Expected Result: Documentation reflects canonical TOML format Failure Indicators: References to old agents.json as primary, missing new structure docs Evidence: .sisyphus/evidence/task-19-docs-check.txtCommit: YES (groups with A4)
- Message:
docs: update AGENTS.md for canonical agent format - Files:
AGENTS.md
- Update
-
20. Remove Legacy agents.json + prompts/*.txt from AGENTS Repo
What to do:
- ONLY after Task 8 confirms backward-compat bridge works
- ONLY after nixpkgs modules consume new canonical format (Tasks 12-14 complete)
- Delete
agents/agents.json - Delete
prompts/chiron.txt,prompts/chiron-forge.txt,prompts/hermes.txt,prompts/athena.txt,prompts/apollo.txt,prompts/calliope.txt - Delete
prompts/directory if empty - Remove
lib.agentsJsonbackward-compat function from flake.nix - Verify
nix flake checkstill passes after removal
Must NOT do:
- Remove before nixpkgs consumers are updated
- Remove system-prompt.md files (those are the NEW canonical prompts)
- Remove skills/, rules/, context/, commands/
Recommended Agent Profile:
- Category:
quick - Skills: []
Parallelization:
- Can Run In Parallel: YES (with Tasks 17, 18, 19)
- Parallel Group: Wave 4
- Blocks: None
- Blocked By: Task 8 (golden file match confirmed)
References:
agents/agents.json— File to deleteprompts/*.txt— Files to delete
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Legacy files removed, canonical files remain Tool: Bash Preconditions: Tasks 8, 12-14 confirmed complete Steps: 1. test ! -f agents/agents.json — assert file does NOT exist 2. test ! -d prompts/ — assert directory does NOT exist (or is empty) 3. for d in agents/chiron agents/chiron-forge agents/hermes agents/athena agents/apollo agents/calliope; do test -f "$d/agent.toml" && test -f "$d/system-prompt.md" && echo "OK: $d" done 4. Assert all 6 directories have both files 5. nix flake check — assert passes Expected Result: Legacy removed, canonical intact, flake passes Failure Indicators: Legacy files still present, canonical files missing, flake error Evidence: .sisyphus/evidence/task-20-cleanup.txtCommit: YES (groups with A3)
- Message:
chore: remove legacy agents.json and prompts/*.txt - Files:
agents/agents.json(deleted),prompts/*.txt(deleted),flake.nix(remove agentsJson)
-
21. End-to-End Integration Test Across Both Repos
What to do:
- Full cross-repo integration verification:
- In AGENTS repo:
nix eval --json '.#lib.loadAgents'→ verify 6 agents with all fields - In nixpkgs: simulate home-manager eval with agents input:
- OpenCode: rendered agents dir contains 6 .md files with correct frontmatter
- Claude Code: rendered .claude/agents/ contains 6 .md files with valid YAML + required fields
- Pi: rendered output contains AGENTS.md + SYSTEM.md
- Project-level: test
renderForToolfor each tool - Skills: verify
mkOpencodeSkillsstill produces correct output - Formatting:
nix fmt --checkon both repos - Flake checks:
nix flake checkon both repos
- In AGENTS repo:
- Document all results in evidence files
Must NOT do:
- Modify any source files (verification only)
- Skip any tool's verification
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
Parallelization:
- Can Run In Parallel: NO (integration gate)
- Parallel Group: Wave 4 (runs last)
- Blocks: F1-F4
- Blocked By: Tasks 1, 12, 13, 14, 17, 18
References:
- All previous task evidence files
- Both repo flake.nix files
Acceptance Criteria:
QA Scenarios (MANDATORY):
Scenario: Full pipeline works end-to-end Tool: Bash Preconditions: All tasks 1-20 complete Steps: 1. cd /home/m3tam3re/p/AI/AGENTS && nix flake check && echo "AGENTS: OK" 2. cd /home/m3tam3re/p/NIX/nixpkgs && nix flake check && echo "nixpkgs: OK" 3. nix eval --json '/home/m3tam3re/p/AI/AGENTS#lib.loadAgents' | jq 'keys | length' — assert 6 4. Test each renderer produces output without error 5. nix fmt --check /home/m3tam3re/p/AI/AGENTS — assert clean 6. nix fmt --check /home/m3tam3re/p/NIX/nixpkgs — assert clean Expected Result: Both repos pass all checks, all renderers produce output Failure Indicators: Any flake check failure, renderer error, format drift Evidence: .sisyphus/evidence/task-21-e2e.txt Scenario: Skills composition unchanged Tool: Bash Preconditions: mkOpencodeSkills not modified Steps: 1. nix eval --raw '/home/m3tam3re/p/AI/AGENTS#lib.mkOpencodeSkills { pkgs = import <nixpkgs> {}; customSkills = ./skills; }' 2. List contents of output directory 3. Assert contains all active skill directories Expected Result: Skills output identical to before migration Failure Indicators: Missing skills, broken linkFarm Evidence: .sisyphus/evidence/task-21-skills.txtCommit: NO (verification only)
- Full cross-repo integration verification:
Final Verification Wave (MANDATORY — after ALL implementation tasks)
4 review agents run in PARALLEL. ALL must APPROVE. Present consolidated results to user and get explicit "okay" before completing.
Do NOT auto-proceed after verification. Wait for user's explicit approval before marking work complete.
-
F1. Plan Compliance Audit —
oracleRead the plan end-to-end. For each "Must Have": verify implementation exists (read file, nix eval, diff). For each "Must NOT Have": search codebase for forbidden patterns — reject with file:line if found. Check evidence files exist in .sisyphus/evidence/. Compare deliverables against plan. Output:Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT -
F2. Code Quality Review —
unspecified-highRunnix flake checkon both repos. Runnix fmt --check(alejandra). Review all .nix files for: unused variables, hardcoded paths, missing mkIf guards, type errors. Check TOML files parse without error. Verify no AI slop: no excessive comments, no placeholder values, no TODO markers in production code. Output:Flake Check [PASS/FAIL] | Format [PASS/FAIL] | Nix Quality [N clean/N issues] | TOML Parse [N/N] | VERDICT -
F3. Real Manual QA —
unspecified-highExecute EVERY QA scenario from EVERY task. Capture evidence. Test cross-task integration: AGENTS repolib.loadAgents→ nixpkgsloadCanonical→ each renderer → home-manager module output. Test edge cases: agent with many permission rules, agent with minimal config, model override. Save to.sisyphus/evidence/final-qa/. Output:Scenarios [N/N pass] | Integration [N/N] | Edge Cases [N tested] | VERDICT -
F4. Scope Fidelity Check —
deepFor each task: read "What to do", read actual changes. Verify 1:1 — everything in spec was built (no missing), nothing beyond spec was built (no creep). Check "Must NOT do" compliance. Detect: skills/rules changes (forbidden), MCP in agent.toml (forbidden), Codex/Aider renderers (forbidden), prompt content changes (forbidden). Flag unaccounted changes. Output:Tasks [N/N compliant] | Scope [CLEAN/N issues] | Forbidden Patterns [CLEAN/N found] | VERDICT
Commit Strategy
AGENTS Repo
- Commit A1:
feat: add canonical agent.toml definitions for all 6 agents— agents/*/agent.toml + system-prompt.md - Commit A2:
feat: export loadAgents and backward-compat agentsJson from flake— flake.nix updates - Commit A3 (after nixpkgs consuming):
chore: remove legacy agents.json and prompts/*.txt - Commit A4:
docs: update AGENTS.md for canonical agent format
m3ta-nixpkgs
- Commit N1:
feat(lib): add agents.nix with loadCanonical and 3 tool renderers - Commit N2:
feat(hm): add per-tool agent HM sub-modules (opencode, claude-code, pi) - Commit N3:
refactor(hm): slim opencode.nix to non-agent config only - Commit N4:
feat(lib): add project-level renderForTool function - Commit N5:
refactor(lib): rename mkOpencodeRules to mkCodingRules with compat alias - Commit N6:
chore: update flake exports and aggregator imports
Success Criteria
Verification Commands
# AGENTS repo: all TOML files parse
for f in agents/*/agent.toml; do nix eval --expr "builtins.fromTOML (builtins.readFile ./$f)" --json > /dev/null; done
# AGENTS repo: backward compat bridge
diff <(nix eval --json '.#lib.x86_64-linux.agentsJson' | jq --sort-keys .) /tmp/agents-golden.json
# AGENTS repo: prompts unchanged
for agent in chiron chiron-forge hermes athena apollo calliope; do diff "prompts/$agent.txt" "agents/$agent/system-prompt.md"; done
# nixpkgs: flake check
nix flake check /home/m3tam3re/p/NIX/nixpkgs
# nixpkgs: formatting
nix fmt --check /home/m3tam3re/p/NIX/nixpkgs
# nixpkgs: OpenCode golden file match
diff <(nix eval --json '.#homeConfigurations.sk.config.xdg.configFile."opencode/agents"' | jq --sort-keys .) /tmp/opencode-agents-golden.json
Final Checklist
- All 6 agents have both
agent.tomlandsystem-prompt.md - All "Must Have" items present and verified
- All "Must NOT Have" items absent
nix flake checkpasses on both reposnix fmtproduces no changes on both repos- Golden file comparison passes (OpenCode output unchanged)
- Claude Code frontmatter valid (name + description present, kebab-case)
- Pi output valid (AGENTS.md exists, optional JSON valid)
lib.mkOpencodeSkillsunchanged and functional- Prompt content byte-identical to originals