Deploy via Playground
Five minutes from “I have a Claude agent” to “it's running on Theseus.”
In one paragraph
agent.rs from your markdown, compiles in the browser via WASM, and submits the SCALE bytes to the chain. No Rust to write. The other 16 templates work the same way; this guide picks the simplest path.This is the hands-on counterpart to /docs/agents (which covers the conceptual model: lifecycle, registration, fees, inter-agent interaction). If you'd rather build the chain from source and deploy via CLI, see /docs/quickstart instead.
Pick the right starter template
The “+ New workspace” picker has 17 templates. Three matter when porting an existing tool-using agent:
| Template | When to pick it |
|---|---|
| BYO Markdown Agent | You have a Claude/OpenAI tool-loop agent and want to ship without touching Rust. Tools declared in YAML frontmatter;agent.rs is synthesised at compile. Default recommendation. |
| BYO Typed Agent | You want explicit control over the SHIP IR — custom node graphs, HITL pauses, parallel sub-agent calls. Each tool is a hand-written ToolSpec in agent.rs. |
| BYO Agent | Lightest path: every tool call goes through one generic fetch_url(url, body) surface. Lowest registration cost, lowest tool-selection quality. Good for prototyping. |
The 13 demo templates (vellum, aave-spot, aviation, governance, etc.) are full working agents — read their code to see what's possible, or fork one for ideas.
The 5-step deploy
1Open the playground
Visit play.theseus.network. Click your workspace name (top left) → + New workspace → pick BYO Markdown Agent — frontmatter only, no Rust from the dropdown → name it → Create.
You'll see two files in the file tree:
THESEUS.md
skills/
my-tools/
SKILL.mdThat's the whole agent. No agent.rs.
2Edit THESEUS.md
The template ships as a working “Weather Assistant” you can deploy as-is. To make it yours:
---
name: My Agent # display name on chain
id: my-agent-v1 # stable on-chain handle (don't change after deploy)
model: deepseek-chat # which registered model to use
native-tools: none # opt out of the built-in tokens.*, chain.*, bridge.* surface
tools:
- name: get_weather # MUST match a proxy_tools entry on the tool-executor
description: Get the current temperature (Celsius) for a city.
args:
city: string
return: string
- name: lookup_user
description: Read a user record by id.
args:
user_id: string
return: string
---
You are a helpful assistant.
When the user asks about weather, call `get_weather` with the city.
When the user asks about a user account, call `lookup_user` with the
user id. Otherwise just answer directly.The body below the frontmatter is the system prompt — same shape and conventions as a Claude or OpenAI system prompt. Be specific about when to call each tool.
Supported arg types: string | number | bigint | boolean.
3Edit skills/my-tools/SKILL.md
The skill is how the model discovers which tools to consider for a task. List each tool's purpose:
--- name: my-tools description: Catalog of weather + user-lookup tools. allowed-tools: get_weather lookup_user --- # Tools ## `get_weather` Use when the user asks about weather. One argument: `city`. Returns JSON with `temperature` and `conditions`. ## `lookup_user` Use when the user asks about a user account. One argument: `user_id`. Returns `name`, `email`, `preferences`.
The allowed-tools: line must list every tool you want the model to have access to via this skill (space-separated).
4Set up your tools as HTTP endpoints
Your existing tool code keeps running wherever it lives today — you just need to expose each one as a POST endpoint:
POST https://your-server/get_weather
Content-Type: application/json
{"city": "Tokyo"}…returning the tool's result as the response body. FastAPI, Express, Cloudflare Workers, ngrok during dev — all fine.
Then the operator running the tool-executor needs a proxy_tools: entry per tool in their config:
proxy_tools:
- name: get_weather
endpoint: https://your-server/get_weather
- name: lookup_user
endpoint: https://your-server/lookup_userNames must match exactly
tools: in your frontmatter, allowed-tools: in your skill, and proxy_tools: on the tool-executor — must match exactly. A typo on any side surfaces as Unknown tool: <name> at runtime.5Deploy
Click Deploy this workspace in the bottom-right. The playground:
- Reads your
THESEUS.mdfrontmatter - Synthesises an
agent.rsfrom thetools:list (you don't see this) - Compiles the whole thing via WASM into SCALE bytes
- Signs with your connected wallet (today:
//Alicein dev; wallet integration coming) and submits theregister_agentextrinsic
You'll see “Agent registered” with your agent's SS58 and a link to the chain explorer. The agent is live; you can prompt it from the panel right underneath.
What you get on chain
- A deterministic content hash for the deployed agent (hash of the SCALE bytes). Anyone can re-derive it from your published THESEUS.md + skills.
- An on-chain account for the agent (the SS58 above). It has its own keypair, can hold THE, can spend on its own operations.
- Every model invocation queued as a chain event; every tool dispatch recorded with
content_sha256of the response. - Skills with their
allowed-toolsfield declared — forward-compatible with the active-allowed-tools filter when it ships.
When to drop into Rust
The synthesised agent.rs covers ~95% of agents (a tool-loop with init → think → act → loop → done). You add your own agent.rs to the workspace when you need:
- A different control-flow graph (parallel sub-agents, HITL pauses, scheduled triggers between loops)
- Custom state fields beyond
messages+model_out - Output schemas / structured
ModelInvokeresults - Native tool calls mixed with external HTTP
Add an agent.rs to the workspace; the playground uses yours instead of synthesising one. Start with BYO Typed Agent for a worked example.
When something breaks
| You see | What it means | Fix |
|---|---|---|
Unknown tool: <name> at runtime | The model called a tool the tool-executor doesn't have | Add the proxy_tools: entry with the matching name |
| Agent stalls without committing | Model narrating instead of calling tools | Tighten the system prompt — “Do not narrate. Call the tool ONCE.” |
405 Method Not Allowed on a tool | Your endpoint doesn't accept POST | Make sure your handler is POST, not GET |
| Compile error on the WASM side | agent.rs (yours or synthesised) doesn't satisfy the walker | Drop the custom agent.rs to let the synth run; report the synth bug if it persists |
model not registered | The model: in your frontmatter isn't on chain | Pick one of the registered tags (deepseek-chat, gpt-5.1, claude-sonnet-4-5) |