Build your first agent
By the end of this tutorial you will have built a working agent from an empty directory: run it offline with no API key, give it a sandboxed tool, serve it over HTTP, and add a deterministic check. It takes about ten minutes.
Prerequisites
Section titled “Prerequisites”- A Rust toolchain (to build the
maidenbinary). - The maiden repository checked out.
Build the binary once:
cargo build --release -p maidenThat produces target/release/maiden. The examples below call it as maiden;
either add target/release to your PATH or substitute the full path.
Step 1 — Create the folder
Section titled “Step 1 — Create the folder”An agent is a directory. Make one with the two files every agent needs:
mkdir -p my-agentCreate my-agent/agent.toml:
[agent]model = "openai/gpt-4o-mini"instructions_file = "instructions.md"max_turns = 6temperature = 0.2Create my-agent/instructions.md:
You are a concise assistant. When a tool is available, prefer using it overguessing, and quote what it returns.Step 2 — Run it offline
Section titled “Step 2 — Run it offline”You don’t need an API key to see the loop work. The --mock flag swaps in a
scripted provider that behaves deterministically:
maiden run my-agent "say hello" --mockNo tools available.The agent ran end to end — loaded the (empty) thread, drove one turn, and answered. It has nothing to do yet because it has no tools. Let’s fix that.
Step 3 — Give it a tool
Section titled “Step 3 — Give it a tool”A tool is a WASI-P2 WebAssembly component in tools/. Authoring one is its own
topic (Add a sandboxed tool); for now, borrow the
structured-echo tool that ships with the examples:
mkdir -p my-agent/toolscp examples/echo-agent/tools/structured-echo.wasm my-agent/tools/The tool name comes from the file: structured-echo.wasm is the tool
structured-echo. Run again:
maiden run my-agent "echo the phrase hello" --mockTool returned: {"echoed":"from-mock","nested":{"ok":true},"timestamp":1700000000}The mock provider called the tool and quoted its output. The tool ran inside the WASM sandbox with a timeout and a memory ceiling — you didn’t have to configure any of that.
Step 4 — Use a real model
Section titled “Step 4 — Use a real model”Drop --mock to run against the model in agent.toml. That model is an OpenAI
model, so set your key:
export OPENAI_API_KEY="sk-..."maiden run my-agent "echo the phrase hello, then explain what you did"Now the real model decides when to call structured-echo and writes the answer
in its own words. To use Anthropic instead, change model in agent.toml — see
Choose a provider.
Step 5 — Serve it
Section titled “Step 5 — Serve it”Instead of one-shot runs, serve the agent over HTTP. Each thread is checkpointed after every turn, so conversations survive restarts.
maiden serve my-agent --port 8080In another terminal:
curl -s localhost:8080 -d '{"thread":"t1","message":"echo hello"}'Send a second message on the same thread and it continues the conversation.
Kill the server, start it again, and thread t1 resumes from disk. To stream
the answer token by token, see Serve over HTTP and
stream.
Step 6 — Add an eval
Section titled “Step 6 — Add an eval”Evals are the deterministic smoke test that your agent still boots, calls its
tools, and answers. Create my-agent/evals/echo.toml:
prompt = "echo the phrase hello"expect = ["echoed"]Run it:
maiden eval my-agent --mock ok echo[maiden] 1/1 eval(s) passedmaiden eval exits non-zero if any case fails, so this line drops straight into
CI. See Write and run evals for more.
Where to go next
Section titled “Where to go next”You’ve touched every core piece. To go deeper:
- Author your own tool → Add a sandboxed tool
- Reach external services → Connect an MCP server
- Compose agents → Subagents
- Understand the loop → Execution model and durability