Authoring

Write the agent in markdown.

A Theseus agent is four files. You write the prompt, the tools, and any skills as markdown and yaml. The runtime signs every output the agent produces.

In one paragraph

A Theseus agent is a directory. THESEUS.md holds the system prompt and a small YAML frontmatter. tools.yaml lists which tools the agent can call. skills/<name>/SKILL.md files are activatable procedures in the same format Claude Skills uses. agent.rs is a 133-line generic adapter that you don’t edit. The runtime compiles the workspace to a SCALE blob, registers it on chain, and runs it. Every output is signed by the agent’s own key.

The four files

Every deployed agent ships in this shape. Here’s the file tree for the Aave Spot Oracle (one of the 14 reference agents):

aave-spot/
aave-spot/
├── THESEUS.md
├── tools.yaml
├── agent.rs
└── skills/
    └── three-venue-reconciliation/
        └── SKILL.md

THESEUS.md

YAML frontmatter (name, id, model) and a markdown body that’s the system prompt. The compiler reads the frontmatter at deploy time; the body is what the model sees on every run.

tools.yaml

Three optional blocks. native-tools is the allowlist of built-in on-chain ops the agent can call. common-tools opts into the curated catalog (web_search, fetch_url). byo-tools declares your own tools inline with JSON Schema.

skills/<name>/SKILL.md

Activatable procedures, in the same Claude Skills format Anthropic ships. The frontmatter names the skill and describes when to activate it. The body is the procedure the agent runs once the skill is in scope.

agent.rs

A generic adapter. It does include_str!("THESEUS.md") and globs the skills/ directory; the compiler does the rest. All 14 reference agents ship a byte-identical copy of this file.

THESEUS.md

Here’s the Aave Spot Oracle’s prompt in full. That’s the entire agent definition. No Python, no decorators, no chain code:

THESEUS.md
---
name: Aave Spot Oracle
id: aave-spot-v1
model: claude-sonnet-4-6
---

You are the Aave Oracle agent. Your job: produce one PRICED or
REFUSED line for ETH/USD by reading three independent venues and
checking that they agree within tolerance. Do not narrate. Do not
call any tool more than once. The refusal IS the product. Mango
Markets lost $116M when an oracle averaged a single manipulated
venue.

## Three venues (call each once, no exceptions)

1. Coinbase spot: https://api.coinbase.com/v2/prices/ETH-USD/spot
2. Binance spot:  https://api.binance.com/api/v3/ticker/price?symbol=ETHUSDT
3. Kraken spot:   https://api.kraken.com/0/public/Ticker?pair=ETHUSD

## Disagreement check

spread_bps = (max - min) / median * 10000

- spread_bps ≤ 50  → PRICED using median across venues
- spread_bps > 50  → REFUSED with the spread and divergent venues

## Output format (strictly one of)

PRICED · $<median> (median of cb=$<x>, bn=$<y>, kr=$<z>; spread=<n>bps)
REFUSED · spread=<n>bps · <venueA>=$<a> vs <venueB>=$<b>

The prompt does the work. Frontmatter on top, the body underneath. Once the agent is deployed, that body is what the model reads on every run.

tools.yaml

The Aave Spot Oracle calls one tool, so its tools.yaml is short:

tools.yaml
native-tools: []

byo-tools:
  fetch_url:
    description: GET an HTTP(S) URL and return the response body as text.
    parameters:
      type: object
      properties:
        url:
          type: string
      required: [url]
    auto-activate: true

Agents that need no tools (the Luna Failsafe runs purely on vault state) ship an empty tools.yaml. Agents using the curated catalog drop names under common-tools:. Custom tools go under byo-tools: inline, with a JSON Schema for the parameters.

SKILL.md

One skill per directory under skills/. The frontmatter matches Anthropic’s Claude Skills exactly: name, description, allowed-tools. The body is the procedure the skill runs.

skills/three-venue-reconciliation/SKILL.md
---
name: three-venue-reconciliation
description: Three fetches, one verdict. Fetch Coinbase, Binance, Kraken; reconcile within 50bps or REFUSE. The refusal is the product.
allowed-tools: fetch_url
---

# Three-venue reconciliation

The Aave Oracle exists to refuse manipulated prices. Single-venue
oracles are not oracles, they are price publishers. Mango Markets,
October 2022: a single AMM price was manipulated by 15x over 30
minutes, $116M of borrows opened against the inflated collateral,
attacker walked. The Mango oracle was reading one venue.

## Procedure

1. Call fetch_url once on Coinbase. Read data.amount.
2. Call fetch_url once on Binance. Read price.
3. Call fetch_url once on Kraken. Read result.XETHZUSD.c[0].
4. Compute spread_bps = (max − min) / median × 10000.
5. If any read failed, emit REFUSED · venue=<which>.
6. If spread_bps ≤ 50, emit PRICED with median.
7. If spread_bps > 50, emit REFUSED with the divergent venues.

## Rule

Exactly three fetch_url calls per run. No fourth attempt to
"resolve" a disagreement with a fourth venue. The 50bps spread IS
the resolution. The contract halts every operation on the asset
the moment REFUSED lands.

Skills activate when the model picks them up from their description, or always if auto-activate: true is set. Activation injects the skill body into the agent’s working context and restricts tool calls to the allowed-tools list. Same activation model as Claude Code.

Why markdown, not Python

Code-based agent frameworks (LangChain, AutoGen, CrewAI, the OpenAI Assistants SDK) push the definition through a Python class hierarchy. You subclass Agent, override six methods, register tools as decorators, wire a memory store, ship a Dockerfile, deploy a server. That’s a lot of code to describe what’s usually a prompt plus a tool list.

With the markdown shape, the agent is the prompt. The tools are one yaml file. The skills are one file each. There’s no class hierarchy and no build step:

  • A teammate reading THESEUS.md sees the whole agent. Nothing is hidden in a helper module or decorator that the prompt is competing with.
  • A security reviewer or program operator reads the four files and knows what the agent will do. No translation between the description and the behavior.
  • Tightening a refusal rule is editing a paragraph. Adding a tool is editing yaml. Adding a skill is dropping a folder under skills/. No build, no dependency bump.

Compatible with Claude Skills

If you already write skills for Claude Code or the Anthropic API, the skills/<name>/SKILL.md file inside a Theseus agent looks exactly the same: name, description, allowed-tools, markdown body. Theseus runs that file unchanged. You don’t migrate to Theseus, you wrap your existing skills in a Theseus agent.

Once those skills run inside a Theseus agent instead of inside a Claude session, four things change:

  • The agent has its own key. Every output is signed against the registered agent, not against your session. Anyone consuming the output can verify which agent produced it.
  • State carries between runs. The agent’s memory and context live on chain instead of in your local config or a database you set up.
  • Receipts are public and permanent. Every signed decision lands at /poa/<agentId>. You don’t build an audit trail; you have one.
  • Sub-agent calls are first-class. Calling another agent works the same way as calling a tool, and the response comes back signed by the agent you called.

Fourteen reference agents to read or fork

Every reference agent ships as a markdown workspace. The source viewer at /poa shows the four files for each one inline. The tutorials at /docs/build walk through the design decisions behind each agent.

Comparison with what you probably use today

If you write skills for Claude Code or you run agents in an OpenClaw-style workspace, your existing files will run inside a Theseus agent. The comparison pages explain what carries over and what you get on top.

Write a workspace and deploy it

The hosted playground compiles the four files in your browser and submits the registration transaction from your custodial wallet. No local toolchain. Five-minute walkthrough at /docs/playground.

Self-hosted path

Same workspace, same compiler. Build the agent-compiler crate from the chain repository and call theseus agent deploy <workspace> from the CLI. See /docs/quickstart Path B for the local flow.
Documentation