EmpryoEmpryo.beta
tools

Agents

Define specialized subagents as markdown files. Empryo reads them from project and global scopes, including your existing .claude and .opencode dirs.

An agent is a markdown file that defines a specialized worker: what it is for, which model runs it, which tools it may touch, and — in the body — the system prompt it thinks with. When the main agent dispatches parallel work, it can hand a task to one of your definitions instead of a generic explorer.

This is the same layout the rest of the ecosystem converged on in 2026, so Empryo reads the agent directories you already have. An existing .claude/agents/reviewer.md works here with no porting step.

Write one

Create a markdown file with name and description frontmatter. The body becomes the agent's system prompt.

---
name: perf-hunter
description: Finds hot paths and allocation churn. Use before optimizing anything.
mode: explore
tools: read, grep, genome_analyze
effort: low
---

You hunt for performance problems. Report the top 3 hot paths with `file:line`
and the measured or inferred cost of each. Never edit files.

Run /agents to see every definition Empryo found, grouped by scope, with the overrides each one carries. Press Enter on a row to read its full prompt, r to re-scan after an edit. On the desktop app the same view is a drawer, also on /agents.

Edits land within a few seconds — there is no restart step.

Scopes

Definitions resolve from project and global directories, with project winning any name collision:

.empryo/agents/                     project
.agents/agents/                     project
.claude/agents/                     project  (Claude Code compatible)
.opencode/agent/                    project  (opencode compatible)
.gemini/agents/                     project  (Gemini CLI compatible)

~/.empryo/agents/                   global
~/.agents/agents/                   global
~/.claude/agents/                   global
~/.config/opencode/agent/           global
~/.gemini/agents/                   global

Subdirectories are scanned too, so you can organize definitions into folders like agents/review/. Identity comes from the name field (or the filename when name is absent), never the path.

When two directories define the same name, the higher-precedence file wins silently at dispatch time — but the collision is tracked: agent_create warns which file it shadows (or is shadowed by), so a definition you just wrote never loses to a forgotten .claude/agents/ copy without telling you.

Frontmatter

Only name and description are required. Everything else narrows what the agent may do.

FieldMeaning
nameUnique id, lowercase and hyphenated. Falls back to the filename
descriptionWhen to delegate to this agent — the main agent routes on this text
modeexplore (read-only) or code (may edit). Omit to let the task decide
modelA full provider/model id, or an alias mapped onto Empryo's tiers
toolsAllowlist. Omit to inherit the role's full belt
disallowedToolsDenylist, applied on top of tools
effortReasoning effort for this agent's runs
maxTurnsHard cap on agentic steps
skillsSkills preloaded into the agent's context
temperatureSampling temperature override for this agent's runs
colorDisplay color for panels and transcripts

Unknown keys are ignored rather than fatal, so a permission: block written for another harness will not break a definition Empryo otherwise understands.

Modes

mode decides whether the agent can edit files. A definition that declares one always wins over what the dispatcher asked for — an explore agent stays read-only even when handed an editing task. Vocabulary from other tools is mapped onto the same two roles, so opencode's subagent and primary both work.

A tools list is a hard gate, not a hint: blocked tools stay visible to the model with their schema intact but refuse to run, naming the agent that restricted them.

Models

A full provider/model id is honored exactly. Bare aliases (sonnet, haiku, opus) map onto Empryo's cheap and capable tiers rather than being guessed into a provider — your configured provider may not be the one the definition's author had. inherit, or omitting the field, keeps whatever the dispatcher picked.

Run one

The main agent picks an agent on its own when a task matches a definition's description — that is what description is for, so write it as a routing instruction ("Use after writing or modifying code"), not as a title. Every definition appears in the dispatch tool's catalog, so the model can name it explicitly too:

  • dispatch(tasks:[{task: "…", agent: "perf-hunter"}]) — an in-turn parallel worker under that definition's prompt, model, and tool policy.
  • background_dispatch(task: "…", agent: "perf-hunter") — the same, detached: you get a bg-N handle and keep working while it runs.

A named agent decides its own role and model, with one hard rule: a definition can never grant edit power the session denied — read-only stays read-only.

Headless runs an entire session under a definition:

empryo --headless --agent perf-hunter "why is the boot path slow?"

An unknown name is an error listing what is available, rather than a silent fall back to the default agent.

Workers running under a definition are labeled with it: the desktop Subagents panel, the per-agent activity modal, and the TUI dispatch tree all badge the lane with the definition's name, so a custom agent is never mistaken for a generic explorer.

Let the agent write one

Forge can create definitions itself with the agent_create tool — name, description, and prompt land as a markdown file in .empryo/agents/ (or ~/.empryo/agents/ with scope: global), dispatchable in the same turn. Describe a repeatable role once ("a release-notes writer that reads CHANGELOG style") and it becomes part of the catalog.