What a working agent spec actually looks like
100-300 lines of markdown. The most consequential file in any agent system.
The format
Every agent in my fleet is a single markdown file at ~/.claude/agents/<name>.md. 100 to 300 lines. Frontmatter at the top, sections below.
Here's the skeleton:
---
name: <agent-name>
description: <one sentence — when to invoke this agent>
model: opus | sonnet | haiku
---
# <Agent Name>
## Role
What this agent IS. Two sentences.
## When to invoke
Bullets. Specific scenarios.
## Inputs
What this agent reads.
## Outputs
What this agent produces.
## Process
Steps. Numbered. Specific.
## Constraints
Hard rules the agent never violates.
## Examples
Real input/output pairs.
That's it. No frameworks. No SDKs. Just a markdown file the model reads before it runs.
What's load-bearing
The description in frontmatter is the highest-leverage line. It's what the router reads to decide whether to invoke this agent. Make it specific. Bad: "Helps with code review." Good: "Adversarial review for irreversible code changes (auth, payments, migrations) — invoke before merging."
The Constraints section is the second-highest. This is where you encode "never do X." If you don't write the constraint down, the agent will eventually do X.
The Examples section is the third. The model learns the format from examples better than from instructions.
What's not load-bearing
The Process section, despite being the longest. Models can figure out the steps from the role + examples. Over-specifying steps tends to make agents brittle.
I've cut 50%+ of the Process section in most of my agents over the last quarter and quality went UP. Fewer instructions, more freedom to apply judgment.
A real example
Here's the chief-of-staff agent (truncated):
---
name: chief-of-staff
description: Daily aggregator. Reads briefing inputs across all projects, writes one digest.
model: sonnet
---
# Chief of Staff
## Role
The reader of last resort. Synthesizes signal from every active project into one digest.
## When to invoke
- 6 AM cron (morning brief)
- 9 PM cron (evening digest)
- On-demand via /brief
## Inputs
- ~/Developer/lucface/business-ops/_memory/digests/yesterday.md
- ~/Developer/lucface/business-ops/PRIORITIES.md
- ~/Developer/lucface/business-ops/INBOX.md
- llm-wiki INDEX.md (last 7 days)
- Active project STATUS.md files
## Output
A markdown digest at ~/Developer/lucface/business-ops/_memory/digests/<date>.md.
Sections: WINS, ERRORS, OPEN, TOMORROW.
## Constraints
- Never include items older than 7 days unless flagged urgent
- Never include items already in yesterday's digest unless changed
- Never make up status for projects without input — list them as "no signal"
That's about a third of the actual file. The rest is examples and edge-case constraints.
What you can steal
If you're writing your first agent:
- Don't reach for a framework. Write a markdown file.
- Make the description specific to the routing decision.
- Constraints over Process. Tell the agent what NOT to do, more than what to do.
- Three examples minimum. Real ones from your domain.
The model is the universal substrate. The agent is the program. The markdown file IS the program.