From cd553b4031391bc7f6c0b5bd2c73474c35498c7a Mon Sep 17 00:00:00 2001 From: m3tm3re
Date: Fri, 10 Apr 2026 15:59:29 +0200 Subject: [PATCH] docs: add canonical agent.toml schema definition --- agents/SCHEMA.md | 275 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 agents/SCHEMA.md diff --git a/agents/SCHEMA.md b/agents/SCHEMA.md new file mode 100644 index 0000000..3e4aeeb --- /dev/null +++ b/agents/SCHEMA.md @@ -0,0 +1,275 @@ +# Canonical `agent.toml` Schema + +This document defines the canonical TOML schema for agent definitions in the AGENTS +repository. The format is **harness-agnostic**: every renderer (OpenCode, Claude Code, +Pi) consumes the same file and silently drops fields it cannot map. + +The schema is intentionally minimal. Fields that belong to the deployment environment +(model selection, MCP configuration) are excluded. Fields that belong to a specific +renderer (hooks, datetime) are excluded. The TOML file describes *what the agent is +and what it can do*, not *how it is deployed*. + +--- + +## Required Fields + +| Field | Type | Constraints | +|-------|------|-------------| +| `name` | string | kebab-case slug; pattern `[a-z0-9-]+`; must be unique across all agents | +| `description` | string | Human-readable purpose statement; single line; no trailing period | + +### Examples + +```toml +name = "chiron" +description = "Personal AI assistant (Plan Mode). Read-only analysis, planning, and guidance" +``` + +```toml +name = "chiron-forge" +description = "Personal AI assistant (Build Mode). Full execution and task completion capabilities with safety prompts" +``` + +**Constraint notes**: +- `name` must be kebab-case (lowercase, hyphens only). The OpenCode renderer uses it as + the agent identifier; Claude Code requires `[a-z0-9-]+` and will reject spaces. +- `description` is required by Claude Code. OpenCode uses it in the agent picker. + +--- + +## Optional Fields + +| Field | Type | Default | Notes | +|-------|------|---------|-------| +| `display_name` | string | — | Human-readable label (e.g. `"Chiron (Assistant)"`). Used by OpenCode in the agent picker. Ignored by Claude Code. | +| `mode` | string | `"all"` | One of: `"primary"`, `"subagent"`, `"all"` | +| `tags` | array of strings | `[]` | Freeform labels for grouping/filtering | +| `max_turns` | integer | — | Max agentic loop iterations. Maps to `steps` in OpenCode, `maxTurns` in Claude Code. Ignored by Pi. | +| `skills` | array of strings | `[]` | Skill names to load (e.g. `["systematic-debugging", "git-master"]`). Same `SKILL.md` format across all renderers. | +| `context` | array of strings | `[]` | Relative file paths to inject as context (e.g. `["../context/profile.md"]`) | +| `rules` | array of strings | `[]` | Rule references from the `rules/` directory (e.g. `["languages/nix", "concerns/testing"]`) | + +### `mode` semantics + +| Value | Meaning | +|-------|---------| +| `"primary"` | Agent is offered as a top-level choice to the user | +| `"subagent"` | Agent is invoked programmatically by other agents; not shown in primary picker | +| `"all"` | Both primary and subagent (default if omitted) | + +**Renderer note**: Claude Code has no distinction between primary and subagent — all +agents are effectively subagents. Pi only renders a `SYSTEM.md` for primary agents. + +--- + +## Permission Schema + +Permissions describe what each tool is allowed to do. The schema uses two-level TOML +tables: one section per tool. + +### Structure + +```toml +[permissions.TOOL_NAME] +intent = "allow" | "deny" | "ask" # required +rules = ["pattern:action", ...] # optional +``` + +- **`intent`** — the default action taken when no specific rule matches. + - `"allow"` — permit the operation without prompting + - `"deny"` — block the operation silently + - `"ask"` — prompt the user for confirmation +- **`rules`** — ordered list of override entries. Each entry is a string in the form + `"pattern:action"` where `action` is one of `allow`, `deny`, or `ask`. + Rules are evaluated first-match; the `intent` applies only when no rule matches. + +### Supported tool names + +| Tool | Description | +|------|-------------| +| `bash` | Shell command execution | +| `edit` | File creation and modification | +| `webfetch` | HTTP fetch to external URLs | +| `websearch` | Web search queries | +| `question` | Interactive user question prompts | +| `external_directory` | Access to filesystem paths outside the project | + +### Simple permission (no per-pattern overrides) + +```toml +[permissions.webfetch] +intent = "allow" + +[permissions.websearch] +intent = "deny" + +[permissions.question] +intent = "allow" +``` + +### Structured permission with rules + +```toml +[permissions.bash] +intent = "ask" +rules = [ + "git status*:allow", + "git log*:allow", + "git diff*:allow", + "git branch*:allow", + "rm -rf *:deny", + "git push --force*:deny", +] + +[permissions.edit] +intent = "allow" +rules = [ + "/run/agenix/**:deny", +] + +[permissions.external_directory] +intent = "ask" +rules = [ + "~/p/**:allow", + "~/.config/opencode/**:allow", + "/tmp/**:allow", + "/run/agenix/**:allow", +] +``` + +### Pattern syntax + +Patterns follow glob conventions: +- `*` — matches any characters within a single path segment or command token +- `**` — matches any characters including path separators +- Patterns are matched left-to-right; first match wins + +--- + +## Excluded Fields + +The following fields are intentionally absent from the canonical schema. + +| Field | Reason | +|-------|--------| +| `model` | Per-machine concern. Model selection is configured in `home-manager` (via `programs.opencode.settings`) and varies by host. Including it in `agent.toml` would couple the agent definition to deployment infrastructure. | +| `prompt` | System prompt content lives in a sibling `system-prompt.md` file alongside `agent.toml`. This allows renderers to consume it independently (e.g., Claude Code reads `prompt.md`, Pi generates `SYSTEM.md`). Embedding prompt paths in TOML adds indirection without benefit. | +| `mcp` | MCP server configuration is tool-specific infrastructure (e.g., `claude mcp add`). It belongs to the deployment layer, not the agent definition. | +| `hooks` | Claude Code-exclusive concept. Lifecycle hooks (pre-tool, post-tool, etc.) have no equivalent in OpenCode or Pi. Including them would leak renderer-specific concerns into the canonical schema. | +| Datetime types | `builtins.fromTOML` in Nix does not support TOML datetime values. This is a confirmed parser limitation (verified in Task 2 spike). All date/time data must be represented as strings if needed. | + +--- + +## Per-Renderer Support Matrix + +The table below shows how each field is consumed by each renderer. "✓" means full +support, "~" means partial/mapped support, "–" means ignored. + +| Field | OpenCode | Claude Code | Pi | +|-------|----------|-------------|----| +| `name` | ✓ agent identifier | ✓ must be `[a-z0-9-]+` | in `AGENTS.md` | +| `description` | ✓ agent picker | ✓ required | in `AGENTS.md` | +| `display_name` | ✓ picker label | – ignored | – ignored | +| `mode` | ✓ maps to `mode` | – all are subagents | primary only → `SYSTEM.md` | +| `tags` | ~ future use | – ignored | – ignored | +| `max_turns` | ✓ maps to `steps` | ✓ maps to `maxTurns` | – ignored | +| `skills` | ✓ SKILL.md loaded | ✓ SKILL.md loaded | ✓ SKILL.md loaded | +| `context` | ✓ injected | ✓ injected | ~ manual inclusion | +| `rules` | ✓ rule injection | ✓ rule injection | – ignored | +| `permissions.bash` | ✓ rule DSL | ✓ bash tool perms | – no granularity | +| `permissions.edit` | ✓ path rules | ✓ path rules | – no granularity | +| `permissions.webfetch` | ✓ intent only | ✓ intent only | – ignored | +| `permissions.websearch` | ✓ intent only | ✓ intent only | – ignored | +| `permissions.question` | ✓ intent only | – not a tool | – not a concept | +| `permissions.external_directory` | ✓ path rules | – not supported | – not supported | + +**Renderer summary**: +- **OpenCode** — full support; most fields have direct mappings +- **Claude Code** — strong support; drops `display_name`, `external_directory`, `mode` +- **Pi** — minimal support; reads `name`/`description` from `AGENTS.md`, skills via `SKILL.md`; permissions ignored + +--- + +## Sample `agent.toml` + +The following is a complete, valid example for the "chiron" agent. It demonstrates all +field categories and can be parsed with `builtins.fromTOML`. + +```toml +# agents/chiron/agent.toml +# Chiron — Personal AI Assistant (Plan Mode) + +name = "chiron" +display_name = "Chiron (Assistant)" +description = "Personal AI assistant (Plan Mode). Read-only analysis, planning, and guidance" +mode = "primary" +tags = ["assistant", "plan-mode", "read-only"] +max_turns = 50 + +skills = ["systematic-debugging", "git-master", "brainstorming"] +context = ["../../context/profile.md"] +rules = ["languages/nix", "languages/python", "concerns/testing"] + +[permissions.question] +intent = "allow" + +[permissions.webfetch] +intent = "allow" + +[permissions.websearch] +intent = "allow" + +[permissions.edit] +intent = "deny" + +[permissions.bash] +intent = "ask" +rules = [ + "git status*:allow", + "git log*:allow", + "git diff*:allow", + "git branch*:allow", + "git show*:allow", + "grep *:allow", + "ls *:allow", + "cat *:allow", + "head *:allow", + "tail *:allow", + "wc *:allow", + "which *:allow", + "echo *:allow", + "nix *:allow", +] + +[permissions.external_directory] +intent = "ask" +rules = [ + "~/p/**:allow", + "~/.config/opencode/**:allow", + "/tmp/**:allow", + "/run/agenix/**:allow", +] +``` + +### Parse verification + +This sample can be verified with: + +```bash +nix eval --impure \ + --expr 'builtins.fromTOML (builtins.readFile /path/to/agent.toml)' \ + --json | jq . +``` + +Expected top-level keys: `name`, `display_name`, `description`, `mode`, `tags`, +`max_turns`, `skills`, `context`, `rules`, `permissions`. + +Expected `permissions` keys: `question`, `webfetch`, `websearch`, `edit`, `bash`, +`external_directory`. + +--- + +## Schema Version + +This document describes schema version **1.0.0** (initial canonical definition). +Changes to field names, types, or semantics must be reflected here with a version bump.