Skip to content

Skills and the format

The format

The document shape

An agent.3md file is a 3md document: a frontmatter header (the manifest) followed by a series of @plane slices. Exactly one plane is the agent's identity; every other plane is a skill.

---
3md: 1.0
axis: skill
agent: dev
tools: rg, fd
---
Prose intro (optional). The model and host are the runner's choice.

@plane z=0 label="dev" kind=identity
# dev
Operating rules go here.

@plane z=1 label="search" kind=skill triggers="find, search, grep" inputs="pattern:string, path:string" tool="rg --line-number {pattern} {path}"
# Skill: search
Find code by regex. For filenames, see [[z=2|files]].

Frontmatter: the manifest

The frontmatter is lean. The only required keys are 3md and a name. Everything else, model included, is an optional hint.

KeyRequired?Meaning
3mdRequiredBase 3md format version. Use 1.0.
title or agentRequiredThe agent's name. title is a display name; agent is a short id. At least one must be present.
modelOptionalA suggested default model the agent was built against. A hint only: the host may override it, and the agent should work on any capable model. Omit it to stay model-agnostic.
axisRecommendedskill (the Z axis enumerates skills).
toolsOptionalComma-separated names of the real binaries the agent's skills run, e.g. rg, jq, git. When present, each command-backed skill's binary should be one of them.
personaOptionalA one-line behavioral summary.
versionOptionalAgent version, distinct from the format version.
entryOptionalThe z of the plane to start from. Defaults to the identity plane.

Any other key is preserved as agent metadata and is implementation-defined. A conforming loader ignores unknown frontmatter keys and unknown plane attributes rather than failing, so the format can grow additively.

model is just a hint

model is deliberately optional. An agent that omits it stays portable across hosts, and a host is free to override whatever an agent suggests. Do not treat a model line as a hard requirement.

Identity plane vs skill planes

Each @plane carries a z (its position), an optional label (its name), optional attributes, and a Markdown body.

  • Exactly one identity plane. It carries kind=identity and is conventionally z=0. Its body is the agent's system prompt and operating rules. If no plane declares kind=identity, the first plane (lowest z) is treated as the identity by a fallback rule.
  • Every other plane is a skill (kind=skill). Its label is the skill name and its body is the skill's instructions, the prompt the agent loads when that skill is selected.

Skill attributes

A skill plane is @plane z=N label="<name>" kind=skill plus these optional attributes:

AttributeMeaning
triggersComma-separated trigger phrases used by route(). A phrase matches a request when every word in the phrase appears in the request (case-insensitive). So look up matches only when both look and up are present, never on up alone.
inputsComma-separated typed inputs the skill expects (see below).
toolOptional. A runnable command this skill drives, written as a template, e.g. rg --line-number {pattern} {path}.
costOptional tag for a side-effect or resource class, e.g. net, db.

Triggers and routing

route(text) ranks skills by the number of distinct trigger phrases the request satisfies, best first, ties broken by lower z. Tokens are maximal runs of Unicode letters and digits, lowercased. A skill with no triggers can only be reached by name or z, never by routing, so writing distinct triggers is what makes routing accurate.

Typed inputs grammar

Each item in inputs is one of:

FormMeaning
nameA required input of type string.
name:typeA required input of the given type.
name:type?An optional input (trailing ?) of the given type.

type must be one of a closed set: string, number, boolean, object, array. The bare comma-separated form (inputs="question, schema") is still valid: every name becomes a required string, so older untyped agents keep working unchanged.

inputs="pattern:string, count:number, recurse:boolean?, schema:object"

That declares pattern and count and schema as required, and recurse as an optional boolean. The same name must not be declared twice in one skill.

Tool command templates

When tool is set, it is a command template. Its first token is the binary; its {placeholder} slots name the skill's inputs.

@plane z=1 label="search" kind=skill triggers="search, find, grep" inputs="pattern:string, path:string" tool="rg --line-number {pattern} {path}"

The contract that ties placeholders to inputs:

  • Every {placeholder} in the command must be a declared input. A placeholder with no matching input is an error (tool-input).
  • A declared input the command never references is a likely mistake, so loaders warn (unused-input).
  • The command's binary should appear in the agent's frontmatter tools list, so the manifest does not lie about what the agent runs.

A loader fills the template from concrete values, shell-quoting each one:

agent.command("search", { pattern: "TODO", path: "src" });
// -> rg --line-number 'TODO' 'src'

A tool with no placeholders (a bare binary, or an opaque id) is still valid; it just is not parameterized. This is the route then fill then run loop: route a request to a skill, fill its inputs, run its command.

cost

cost is a free-form tag for the side-effect or resource class of a skill, such as net for a network call or db for a database write. Loaders surface it in the manifest and the per-skill listing so a host can gate or warn on it; the format does not assign it any built-in meaning.

A skill can depend on another skill by linking to its plane in the body, in either 3md cross-plane form:

  • [[z=N]]
  • [[z=N|label]] (the label is a display alias)

Both declare that this skill depends on the skill at plane N. A loader resolves these transitively via resolve(), so a skill arrives with everything it needs, each dependency included once.

@plane z=5 label="pr" kind=skill triggers="pr, pull request, review" inputs="state:string" tool="gh pr list --state {state}"
# Skill: pr
List pull requests by {state}. To review one, read its commits with [[z=4|commits]].

Links must point at a real plane (a dangling target is a dead-link error), and the dependency graph must not contain a cycle (cycle error).

Guidance-only skills (no tool)

tool is optional, and not every skill is a CLI command. A skill with no tool is guidance only: its body is a playbook the agent follows using whatever capabilities the host already gives it. Web search, a judgment call, an action routed to a host or MCP tool, none of these need a binary. For such a skill, command() returns null.

@plane z=7 label="research" kind=skill triggers="research, web, online, docs, look up"
# Skill: research
Guidance only, no bound command. When a question needs the open web rather than
this repo, use the host's own web-search tool: issue two or three focused
queries, read the most authoritative sources, and cite them.

A real agent is usually a mix: some skills run a command, some are a playbook.

See also