Files
AGENTS/.sisyphus/evidence/task-4-opencode-agent-format.md
2026-04-13 16:53:17 +02:00

530 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Task 4: OpenCode File-Based Agent Format Research
**Date**: 2026-04-10
**Status**: ✅ Complete
**Research Method**: WebFetch + Documentation Analysis
---
## Executive Summary
OpenCode supports **two agent configuration methods**:
1. **JSON** - Embedded in `opencode.json` (config.json)
2. **Markdown Files** - File-based in `.opencode/agents/` directory (per-project) or `~/.config/opencode/agents/` (global)
This research focuses on the **file-based markdown format**, which is the target for the harness-agnostic migration.
---
## File Location & Discovery
### Directory Structure
**Per-project agents** (takes precedence):
```
.opencode/agents/
├── agent-name.md
├── another-agent.md
└── ...
```
**Global agents** (fallback):
```
~/.config/opencode/agents/
├── agent-name.md
├── another-agent.md
└── ...
```
### Discovery Mechanism
- OpenCode **scans both directories** for `*.md` files
- The **filename (without .md extension)** becomes the **agent name**
- Per-project agents **override** global agents with the same name
- All agents are loaded at startup and available via `Tab` switching or `@mention`
### Key Finding
**The agent name is derived from the filename**, not from a `name` field in the frontmatter. Example:
- File: `review.md` → Agent name: `review`
- File: `code-reviewer.md` → Agent name: `code-reviewer`
---
## YAML Frontmatter Specification
All file-based agent markdown files must include YAML frontmatter with the following fields:
### Required Fields
| Field | Type | Description | Example |
|-------|------|-------------|---------|
| `description` | string | Brief description of agent purpose and when to use it. **REQUIRED**. | `"Reviews code for quality and best practices"` |
### Optional Fields
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `mode` | string | `all` | Agent mode: `primary`, `subagent`, or `all` |
| `model` | string | Model globally configured in config | Override LLM model for this agent |
| `temperature` | float | Model-specific (usually 0 or 0.55 for Qwen) | LLM response randomness (0.01.0) |
| `top_p` | float | — | Alternative to temperature for diversity control |
| `steps` | integer | No limit | Max agentic iterations before forced text-only response |
| `disable` | boolean | `false` | Set to `true` to disable the agent |
| `hidden` | boolean | `false` | Hide from `@` autocomplete (subagents only) |
| `color` | string | — | Hex color (e.g., `#FF5733`) or theme color (primary, secondary, accent, success, warning, error, info) |
| `permission` | object | — | Permission rules for edit, bash, webfetch, question, websearch, external_directory |
| `task` | object | — | Control which subagents this agent can invoke via Task tool |
### Provider-Specific Fields
Any additional fields are **passed through directly to the LLM provider**. Example for OpenAI reasoning models:
```yaml
---
description: Agent using high reasoning effort
model: openai/gpt-5
reasoningEffort: high
textVerbosity: low
---
```
---
## Permission Format (YAML)
Permissions control what actions an agent can perform. The format supports two styles:
### Simple Format (Single Action)
```yaml
permission:
edit: deny
bash: ask
webfetch: allow
```
### Granular Format (Rules Array)
For more control over specific patterns:
```yaml
permission:
edit:
"*": allow
"/run/agenix/**": deny
bash:
"*": ask
"git status*": allow
"git log*": allow
"git push": ask
"grep *": allow
webfetch: deny
question: allow
websearch: allow
external_directory:
"*": ask
"~/p/**": allow
"~/.config/opencode/**": allow
"/tmp/**": allow
```
### Permission Actions
| Value | Meaning |
|-------|---------|
| `allow` | Tool allowed without approval |
| `ask` | Prompt user for approval before running |
| `deny` | Tool disabled |
### Supported Permission Keys
| Key | Values | Notes |
|-----|--------|-------|
| `edit` | `allow\|ask\|deny` or nested rules | File write/patch operations |
| `bash` | `allow\|ask\|deny` or nested rules | Bash command execution; supports glob patterns |
| `webfetch` | `allow\|ask\|deny` | HTTP requests |
| `question` | `allow\|ask\|deny` | User questions/clarification |
| `websearch` | `allow\|ask\|deny` | Web search operations |
| `external_directory` | `allow\|ask\|deny` or nested rules | Access to external directories |
| `task` | nested rules | Subagent invocation control (glob patterns) |
### Glob Pattern Support
Patterns support wildcards and recursion:
- `*` — single-level wildcard
- `**` — recursive wildcard
- `git push*` — suffix matching
- `~/p/**` — home directory paths
- `/run/agenix/**` — absolute paths
### Rule Precedence
When multiple rules match, the **last matching rule wins**:
```yaml
bash:
"*": ask
"git status*": allow
"git push*": deny
```
In this example:
- `git status` matches both `*` and `git status*` → result: **allow** (last rule wins)
- `git push origin main` matches both `*` and `git push*` → result: **deny**
- `ls -la` matches only `*` → result: **ask**
---
## Mode Field Values
| Mode | Type | Description |
|------|------|-------------|
| `primary` | Primary agent | Agent available via `Tab` key switching; handles main conversation |
| `subagent` | Specialized agent | Invoked via `@mention` or automatically by other agents for specific tasks |
| `all` | Flexible | Can be used as both primary and subagent (default if omitted) |
---
## System Prompt Delivery
The markdown file body (after the YAML frontmatter) contains the **system prompt**:
```markdown
---
description: Code review without edits
mode: subagent
permission:
edit: deny
---
You are a code reviewer. Focus on:
- Code quality and best practices
- Potential bugs and edge cases
- Performance implications
- Security considerations
Provide constructive feedback without making direct changes.
```
The **markdown content is passed directly as the system prompt** to the LLM. It supports:
- Inline markdown formatting
- Lists and sections
- Structured instructions
- Code examples (fenced with backticks)
---
## Default Behavior for Omitted Fields
| Field | Default | Notes |
|-------|---------|-------|
| `description` | **ERROR** | Required; absence causes parse failure |
| `mode` | `all` | Agent can be used as primary or subagent |
| `model` | Global config model | Primary agents use global model; subagents use parent's model |
| `temperature` | Model-specific | Usually 0 for most models; 0.55 for Qwen models |
| `permission` | Full access | If omitted, all tools enabled (no restrictions) |
| `disable` | `false` | Agent is enabled by default |
| `hidden` | `false` | Agent visible in `@` autocomplete (if subagent) |
---
## Interaction with config.json (JSON Format)
### Current State (Task 1 Finding)
The current system embeds agents in **config.json** via JSON:
```json
{
"agent": {
"build": {
"description": "...",
"mode": "primary",
"permission": { ... }
}
}
}
```
### File-Based Agents Complement, Don't Replace
- **JSON agents** (in config.json) are loaded from embedded config
- **Markdown agents** (.opencode/agents/*.md files) are symlinked
- **Both are loaded** and available simultaneously
- **Markdown agents override** JSON agents with the same name
### Migration Path
The harness-agnostic migration will:
1. Move agent definitions from `agents.json``.opencode/agent/{name}.md` files
2. Update home-manager deployment to symlink `.opencode/agents/` instead of embedding `agents.json`
3. System prompt changes (markdown file edits) will **NOT require `home-manager switch`**
---
## Key Advantage: Prompt Changes Don't Require home-manager switch
### Current Limitation (JSON/Embedded)
```
agents.json → home-manager → embedded into config.json
Change required in nixpkgs module
home-manager switch (full system rebuild)
```
### New Capability (File-Based)
```
.opencode/agents/{name}.md → home-manager → symlinks to ~/.config/opencode/agents/
Change markdown file directly
OpenCode reloads on next startup (NO home-manager switch needed)
```
**This is the KEY ADVANTAGE** of file-based agents: faster iteration on prompts and agent configuration.
---
## Limitations & Gotchas
### No Name Field in Frontmatter
- Agent name comes from **filename only**
- No `name: foo` field in frontmatter
- Renaming file renames the agent
### Model References with {file:...}
In JSON config, you can reference external files:
```json
{
"prompt": "{file:./prompts/build.txt}"
}
```
In markdown files, the **body IS the prompt** — no `{file:...}` syntax. The entire markdown content after frontmatter is the system prompt.
### Subdirectories Not Scanned
- Only files directly in `.opencode/agents/` are loaded
- Subdirectories are ignored
- All agent definitions must be in one directory level
### Filename Validation
The filename should follow these conventions (not enforced, but recommended):
- Lowercase letters, numbers, hyphens: `[a-z0-9-]+`
- No spaces, no special characters
- Examples: `code-reviewer.md`, `security-auditor.md`, `docs-writer.md`
---
## Complete Example: File-Based Agent
### File: `.opencode/agents/code-reviewer.md`
```markdown
---
description: Performs comprehensive code review focusing on quality, security, and performance
mode: subagent
model: anthropic/claude-sonnet-4-20250514
temperature: 0.1
permission:
edit:
"*": deny
bash:
"*": allow
"grep *": allow
"git diff*": allow
webfetch: allow
question: allow
---
You are an expert code reviewer with deep knowledge of software architecture, security best practices, and performance optimization.
## Your Mission
Review code for:
1. **Correctness** - Logic errors, edge cases, off-by-one bugs
2. **Security** - Input validation, injection vulnerabilities, data exposure
3. **Performance** - Algorithmic efficiency, memory usage, unnecessary allocations
4. **Maintainability** - Code clarity, naming, documentation, SOLID principles
5. **Testing** - Coverage gaps, missing test cases, integration test concerns
## Process
1. Ask clarifying questions about context and constraints
2. Provide specific, actionable feedback with examples
3. Suggest refactorings with rationale
4. Never make changes directly (read-only mode)
5. Prioritize critical issues over style concerns
## Output Format
- **Critical Issues** (must fix before merge)
- **Important Improvements** (should fix)
- **Nice-to-Have Suggestions** (consider for future)
- **Questions** (for author clarification)
```
---
## Complete Example: JSON Config Format (For Reference)
For comparison, here's the equivalent in JSON config.json:
```json
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"code-reviewer": {
"description": "Performs comprehensive code review focusing on quality, security, and performance",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"permission": {
"edit": {
"*": "deny"
},
"bash": {
"*": "allow",
"grep *": "allow",
"git diff*": "allow"
},
"webfetch": "allow",
"question": "allow"
},
"prompt": "You are an expert code reviewer...\n\n## Your Mission\n..."
}
}
}
```
---
## Source Materials
### Documentation
- **Official**: https://opencode.ai/docs/agents
- **Agents Section**: Comprehensive spec for all agent config options
- **Markdown Example**: Review agent example provided in docs
- **Security Auditor Example**: Security-focused agent example
### Code References
- **GitHub**: https://github.com/anomalyco/opencode (dev branch)
- **Config Spec**: schema.json embedded in docs
- **Test Cases**: `.opencode/agents/` in opencode repo (example files)
### Current System Reference
- **Nix Module**: `/home/m3tam3re/p/NIX/nixpkgs/modules/home-manager/coding/opencode.nix`
- Line 149: `agent = builtins.fromJSON (builtins.readFile "${inputs.agents}/agents/agents.json");`
- Line 149: Shows current embedding pattern
- **AGENTS repo**: `/home/m3tam3re/p/AI/AGENTS/agents/agents.json`
- 6 agents: Chiron, Chiron Forge, Hermes, Athena, Apollo, Calliope
- Permission structure: nested objects with wildcard patterns
---
## Questions Addressed
### Q: Do file-based agents need `home-manager switch` for prompt changes?
**A: NO**
- File changes are immediately available
- `.opencode/agents/` is symlinked (not embedded)
- OpenCode reloads agent definitions at startup
- Prompt changes require only file edit + app restart
**This is the KEY ADVANTAGE** driving the migration.
### Q: What directory: `agent` or `agents`?
**A: `agents` (plural)** (both global and per-project)
- Global: `~/.config/opencode/agents/`
- Per-project: `.opencode/agents/`
### Q: Do agent names need a `name` field in frontmatter?
**A: NO**
- Agent name comes from **filename only**
- No `name: foo` field in frontmatter
- Example: `review.md` → agent name is `review`
### Q: What YAML frontmatter fields are required?
**A: Only `description`** is truly required
- All other fields have sensible defaults
- Missing fields use their defaults
- Frontmatter-less file will fail to parse
### Q: How are permissions specified in markdown?
**A: Same nested object format as JSON**
```yaml
permission:
edit:
"*": allow
"/sensitive/**": deny
bash:
"*": ask
"git push": deny
```
---
## Confirmation Summary
| Question | Finding |
|----------|---------|
| **Directory**: `agent` or `agents`? | `agents/` (both global and per-project) |
| **File naming**: How determined? | Filename (without .md) becomes agent name |
| **Required fields**: What's mandatory? | `description` only; others have defaults |
| **Permission format**: YAML or different? | Same nested object format as JSON |
| **Mode values**: Options? | `primary` \| `subagent` \| `all` |
| **Prompt format**: How specified? | Markdown body after frontmatter |
| **Requires HM switch for prompt changes?** | **NO** ✅ (major advantage) |
| **Does frontmatter need `name` field?** | **NO** (filename is the name) |
| **Can agents be in subdirectories?** | **NO** (only root level of `.opencode/agents/`) |
| **Can you override agents from JSON config?** | **YES** (markdown agents override JSON with same name) |
---
## Next Steps (Task 9: OpenCode Renderer)
The renderer will generate `.opencode/agents/{name}.md` files with:
1. **Frontmatter generation**:
- Convert agent.toml `[description]` → YAML `description:`
- Convert `[mode]` → YAML `mode:`
- Convert `[temperature]` → YAML `temperature:`
- Convert `[permission]` from two-level format → nested YAML objects
2. **Body generation**:
- Use agent.toml `system_prompt` field → markdown body
3. **File naming**:
- Filename: `{agent_name}.md` (from agent.toml `name` field)
- Agent name in OpenCode: derived from filename automatically
---
## Evidence Collection
- **Source 1**: https://opencode.ai/docs/agents (Official documentation)
- **Source 2**: `/home/m3tam3re/p/NIX/nixpkgs/modules/home-manager/coding/opencode.nix` (Current deployment)
- **Source 3**: `/home/m3tam3re/p/AI/AGENTS/agents/agents.json` (Current agent definitions)
- **Source 4**: `/home/m3tam3re/p/AI/AGENTS/AGENTS.md` (Repository documentation)
**Research Date**: 2026-04-10
**Researcher**: Sisyphus-Junior
**Task**: Task 4 of harness-agnostic-migration plan