252 lines
11 KiB
Markdown
252 lines
11 KiB
Markdown
|
|
# 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)
|
||
|
|
1. Apollo (Knowledge Management) — subagent, private knowledge specialist
|
||
|
|
2. Athena (Researcher) — subagent, work knowledge specialist
|
||
|
|
3. Calliope (Writer) — subagent, writing specialist
|
||
|
|
4. Chiron (Assistant) — primary agent, plan mode
|
||
|
|
5. Chiron Forge (Builder) — primary agent, build mode
|
||
|
|
6. Hermes (Communication) — subagent, communication specialist
|
||
|
|
|
||
|
|
### Agent Object Structure
|
||
|
|
Every agent has 5 top-level keys:
|
||
|
|
- `description` (string) — agent purpose and capabilities
|
||
|
|
- `mode` (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 `rules` list
|
||
|
|
- 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.fromTOML` handles it perfectly with `--impure` flag
|
||
|
|
- **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 `name` field in frontmatter
|
||
|
|
- Example: `review.md` → agent named `review`
|
||
|
|
- 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., `reasoningEffort` for OpenAI)
|
||
|
|
|
||
|
|
### Permission Format in Markdown
|
||
|
|
```yaml
|
||
|
|
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 switching
|
||
|
|
- `subagent` — invoked via @mention or by other agents
|
||
|
|
- `all` — 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: `description` only ✅
|
||
|
|
- 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 `name` field: **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)
|
||
|
|
- `description` is the only REQUIRED frontmatter field
|
||
|
|
- Agent name is derived from filename (no `name` field in frontmatter)
|
||
|
|
- Supported tools: edit, bash, webfetch, question, websearch, external_directory, task
|
||
|
|
- `task` permission 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:
|
||
|
|
```yaml
|
||
|
|
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 → TOML `intent` field (straightforward)
|
||
|
|
- JSON non-`"*"` keys → TOML `rules` array as `"pattern:action"` strings
|
||
|
|
- Simple string permissions (e.g., `"question": "allow"`) → `intent` only, no rules array
|
||
|
|
- Description trailing periods stripped per SCHEMA.md constraint ("no trailing period")
|
||
|
|
- `td *` and `bd *` bash rules in chiron preserved (custom tool aliases)
|
||
|
|
- No model field, no prompt field per schema exclusion rules
|
||
|
|
|
||
|
|
## [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: a81e178 feat: export loadAgents and backward-compat agentsJson from flake
|