11 KiB
Learnings
[2026-04-10] Session Initialized
- Plan: harness-agnostic-migration (21 tasks + 4 final)
- AGENTS repo: /home/m3tam3re/p/AI/AGENTS
- nixpkgs repo: /home/m3tam3re/p/NIX/nixpkgs
- TOML chosen as canonical format (builtins.fromTOML, no IFD)
- Renderers belong in nixpkgs, not AGENTS repo
- 6 agents: chiron, chiron-forge, hermes, athena, apollo, calliope
- OpenCode: file-based agents (.opencode/agent/*.md) NOT config.json embedding
- Pi: no subagents — renders AGENTS.md + SYSTEM.md only
- Claude Code: name must be [a-z0-9-]+ (slugified)
- No model in agent.toml (per-machine via home-manager)
- No MCP in agent.toml (tool-specific infrastructure)
- No YAML files as canonical source
- Permission model: two-level — intent (allow/deny/ask) + rules array "pattern:action"
- mkOpencodeRules → mkCodingRules (backward-compat alias)
- lib.mkOpencodeSkills stays unchanged
[2026-04-10] Task 1: Capture Golden File Baseline
Golden File Created
- Path:
.sisyphus/evidence/agents-golden.json - Method:
jq --sort-keys . agents/agents.json - Status: ✓ Valid JSON, parseable, verified
Agent Count
- Total: 6 agents
- Verification:
jq 'keys | length'→ 6 ✓
Agent Names (Alphabetically Sorted)
- Apollo (Knowledge Management) — subagent, private knowledge specialist
- Athena (Researcher) — subagent, work knowledge specialist
- Calliope (Writer) — subagent, writing specialist
- Chiron (Assistant) — primary agent, plan mode
- Chiron Forge (Builder) — primary agent, build mode
- Hermes (Communication) — subagent, communication specialist
Agent Object Structure
Every agent has 5 top-level keys:
description(string) — agent purpose and capabilitiesmode(string) — "primary" or "subagent"model(string) — LLM model ID (all use "zai-coding-plan/glm-5")prompt(string) — reference to prompt file via{file:./prompts/...}permission(object) — capability matrix with granular controls
Permission Structure
All agents have 6 permission categories:
question→ "allow" | "deny" | "ask"webfetch→ "allow" | "deny" | "ask"websearch→ "allow" | "deny" | "ask" (not all agents)edit→ nested rules (allow/deny per path pattern)bash→ nested rules (allow/deny per command pattern)external_directory→ nested rules (allow/deny per path pattern)
Baseline Purpose
This golden file serves as the canonical reference for backward-compat verification in Task 8. It will be compared against output from the harness-agnostic bridge to ensure config integrity.
Next Steps
- Task 8 will generate a comparable JSON from the bridge
- Diff will be computed:
jq --sort-keys . bridge_output.json > bridge-output.json && diff agents-golden.json bridge-output.json - Any structural or content changes will be flagged
[2026-04-10] Task 2: TOML Feasibility Spike
Result: ✅ PASS
Test Execution
- Full Chiron-Forge TOML (16 lines, 5 permission sections, 15 bash rules, 4 external_directory rules): PARSED SUCCESSFULLY
- Minimal TOML (2 lines, name + description only): PARSED SUCCESSFULLY
- Parser:
nix eval --impure --expr 'builtins.fromTOML (builtins.readFile <path>)' --json
Glob Patterns Verified
All complex patterns preserved exactly:
rm -rf *→ intact (wildcard in rule)git reset --hard*→ intact (pattern suffix)git push*→ intact (pattern suffix)git push --force*→ intact (flag + pattern)git push -f *→ intact (short flag + wildcard)~/p/**→ intact (recursive glob)~/.config/opencode/**→ intact (home + recursive)/run/agenix/**→ intact (absolute + recursive)/tmp/**→ intact (absolute + recursive)
Special Handling
- TOML arrays of strings work perfectly for
ruleslist - Two-level structure (
intent+rules) maps cleanly from JSON nested objects - No datetime fields used (confirmed limitation is not a blocker for permissions schema)
- No multi-line inline tables needed (flat key-value structure only)
Conclusion
✅ TOML is suitable for agent permission config. The proposed two-level model (intent = "allow"|"deny"|"ask" + rules = [...] array) is:
- Parseable:
builtins.fromTOMLhandles it perfectly with--impureflag - Pattern-safe: All glob patterns (wildcards, recursion, flags) preserved exactly
- Backward-compatible: Maps cleanly from existing JSON nested object format
Evidence Files
/home/m3tam3re/p/AI/AGENTS/.sisyphus/evidence/task-2-toml-spike.json(full Chiron-Forge parsed result)/home/m3tam3re/p/AI/AGENTS/.sisyphus/evidence/task-2-toml-minimal.json(minimal test parsed result)
Next Steps
No workarounds needed. Ready to implement full harness with TOML permission loader.
[2026-04-10] Task 3: Canonical Schema Designed
- SCHEMA.md created at agents/SCHEMA.md
- Required fields: name, description
- Optional: display_name, mode, tags, max_turns, skills, context, rules
- Permissions: [permissions.TOOL] with intent + rules[]
- Supported tools: bash, edit, webfetch, websearch, question, external_directory
- Per-renderer matrix: documented
- Sample TOML parses: YES
- Evidence: .sisyphus/evidence/task-3-schema-sample.toml (TOML source)
- Evidence: .sisyphus/evidence/task-3-schema-sample-parsed.json (Nix parse result)
[2026-04-10] Task 4: OpenCode File-Based Agent Format
File Location
- Per-project:
.opencode/agents/ - Global:
~/.config/opencode/agents/ - Per-project agents override global agents with same name
Agent Naming
- Filename determines agent name — no
namefield in frontmatter - Example:
review.md→ agent namedreview - Naming convention:
[a-z0-9-]+(lowercase, hyphens)
YAML Frontmatter Structure
- Required:
description(string) - Optional:
mode(primary|subagent|all),model,temperature,top_p,steps,disable,hidden,color,permission,task - Provider-specific fields pass through to LLM (e.g.,
reasoningEffortfor OpenAI)
Permission Format in Markdown
permission:
edit:
"*": allow
"/sensitive/**": deny
bash:
"*": ask
"git push": deny
"git log*": allow
webfetch: allow
question: allow
websearch: allow
external_directory:
"*": ask
"~/p/**": allow
- Actions:
allow|ask|deny - Nested rules support glob patterns (
*,**, wildcards) - Last matching rule wins
Mode Field Values
primary— available via Tab switchingsubagent— invoked via @mention or by other agentsall— flexible, can be used both ways
System Prompt Delivery
- Markdown body (after frontmatter) IS the system prompt
- No
{file:...}syntax in markdown (unlike JSON config) - Direct markdown content → sent to LLM
Default Behaviors
mode→all(if omitted)model→ global config (primary agents) or parent's model (subagents)temperature→ model-specific default (0 for most, 0.55 for Qwen)permission→ full access (if omitted, all tools enabled)
Interaction with config.json
- Both JSON and markdown agents are loaded
- Markdown agents override JSON agents with same name
- No conflict; complementary
KEY ADVANTAGE: Prompt Changes Don't Require home-manager switch
- File changes → OpenCode reloads on next startup
- NO home-manager switch needed
- This is the primary motivation for file-based migration
Limitations
- No subdirectories: only root level of
.opencode/agents/scanned - No name field: filename is authoritative
- Filename must be valid: [a-z0-9-]+ convention
Evidence File
/home/m3tam3re/p/AI/AGENTS/.sisyphus/evidence/task-4-opencode-agent-format.md- Complete spec with examples, frontmatter reference, permission format, YAML/JSON comparison
Confirmed Answers
- Directory:
agents/(both global and per-project) ✅ - File naming: Filename determines agent name ✅
- Required fields:
descriptiononly ✅ - Permission format: Nested objects like JSON ✅
- Mode values:
primary|subagent|all✅ - System prompt: Markdown body after frontmatter ✅
- Requires HM switch for prompt changes: NO ✅
- Frontmatter needs
namefield: NO ✅
Sources
- https://opencode.ai/docs/agents (official documentation)
- /home/m3tam3re/p/NIX/nixpkgs/modules/home-manager/coding/opencode.nix (current deployment)
- /home/m3tam3re/p/AI/AGENTS/agents/agents.json (current 6 agents)
- /home/m3tam3re/p/AI/AGENTS/AGENTS.md (repo documentation)
[2026-04-10] Task 4: Key Finding — OpenCode Permission Rule Precedence
- OpenCode uses LAST-MATCHING-RULE-WINS (not first-match!)
- This matters for renderer: when translating
rules[]array, order must be preserved - The wildcard
"*"rule becomes the fallback (keep it first in YAML output, others after) - OpenCode directory is
.opencode/agents/(PLURAL), not.opencode/agent/ - Global agents:
~/.config/opencode/agents/(PLURAL too) descriptionis the only REQUIRED frontmatter field- Agent name is derived from filename (no
namefield in frontmatter) - Supported tools: edit, bash, webfetch, question, websearch, external_directory, task
taskpermission controls which subagents can be invoked (glob patterns)
[2026-04-10] Task 4: OpenCode Permission YAML Format
The granular format is nested YAML objects, NOT a rule array:
permission:
bash:
"*": ask # This is the intent/default
"git status*": allow # These are the rules
"git push*": deny
The renderer must convert from canonical intent + rules[] format to this nested YAML format.
The "*" key always goes FIRST (as the fallback), then specific rules after it.
[2026-04-10] Task 5: All 6 agent.toml Files Created
- Directories: agents/{chiron,chiron-forge,hermes,athena,apollo,calliope}/
- Each has: agent.toml + system-prompt.md
- All TOML parse: YES (6/6 verified via
nix eval --impure) - Prompt diffs: all zero (6/6 byte-identical)
- Chiron mode: primary
- Chiron-Forge mode: primary
- Other 4 mode: subagent
- Commit:
7a8dd52(12 files, 543 insertions) - Permission translation notes:
- JSON
"*"key → TOMLintentfield (straightforward) - JSON non-
"*"keys → TOMLrulesarray as"pattern:action"strings - Simple string permissions (e.g.,
"question": "allow") →intentonly, no rules array - Description trailing periods stripped per SCHEMA.md constraint ("no trailing period")
td *andbd *bash rules in chiron preserved (custom tool aliases)- No model field, no prompt field per schema exclusion rules
- JSON
[2026-04-10] Task 6: loadAgents + agentsJson Bridge Complete
- Fix applied: description = agent.description + "." (SCHEMA.md has no trailing period; golden file does)
- All 6 agents load correctly via lib.loadAgents
- agentsJson bridge matches golden file exactly (zero diff)
- nix flake check: PASS
- alejandra formatting: PASS
- Commit:
a81e178feat: export loadAgents and backward-compat agentsJson from flake