Skip to content
3 min read · 633 words

Tutorial: Your First Agent

Goal: not just to create an agent, but to see everything the platform does when you use one. 15 minutes, both servers running (Installation).

1 · Design before you create

Three decisions matter (Agents):

  • System prompt — the only free-text the LLM sees. Be concrete about role and boundaries.
  • Tools — grant the minimum. We start with none to prove chat needs no tools.
  • Language/tone — enforced on every call; don't restate them in the prompt.

2 · Create it (two ways)

Open http://localhost:3000/create-agent. Fill: name Docs Helper, type Customer Support, system prompt below, language English, tone Friendly. Untick every tool. Watch the Live Preview mirror your input, then submit — the success banner shows the new ID.

Note the returned id (assume 2). Verify it appears at http://localhost:3000/agents — no deploy step; configuration is the agent.

3 · Chat, then autopsy the exchange

bash
curl -X POST http://localhost:8001/agents/2/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Can you check why my account is locked?"}'

The reply should respect your boundary ("I can't access accounts…") — that's your system prompt working inside the chat wrapper. Now the autopsy — three records were written (Request Lifecycle):

bash
curl "http://localhost:8001/agents/2/messages?limit=2" | jq   # user + assistant Message rows
curl http://localhost:8001/agents/2/runs | jq '.[0]'          # AgentRun: latency_ms, status

Or straight in SQLite:

bash
sqlite3 backend/app/agentops.db \
  "SELECT role, substr(content,1,40) FROM messages WHERE agent_id=2 ORDER BY id;"

4 · Prove statelessness

bash
curl -X POST http://localhost:8001/agents/2/chat \
  -H "Content-Type: application/json" -d '{"message": "What did I just ask you?"}'

The agent doesn't know — history is stored but never replayed into context (the platform's biggest chat limitation). You now understand it because you watched it.

5 · Prove tool gating

bash
curl -X POST http://localhost:8001/agents/2/email/analyze \
  -H "Content-Type: application/json" -d '{"email_text": "Please send the invoice by Friday."}'
json
{ "detail": "This agent does not have email_analyzer tool enabled" }

403 — the allow-list doing its job (Tools). Create a second agent with email_analyzer,task_creator and rerun to see the difference; then check GET /agents/{id}/tool-calls for the logged calls.

6 · Watch a failure get recorded

Temporarily rename OPENAI_API_KEY in backend/app/.env (uvicorn reloads), chat once, and observe graceful degradation:

  • Response: 200 with "Sorry, I could not generate a response right now."
  • GET /agents/2/runs → newest run has status: "failed" and the real ValueError in error_message.

Restore the key. You've now seen the chat error philosophy end to end — failures are polite to users and loud to operators.

What you learned

You didThe concept
created config, used it instantlyagents are rows, not deployments
read messages/runs after chattingthe observability contract
watched a boundary holdprompt wrapping (catalog)
got a 403tool gating
broke the key safelygraceful degradation

Next: Email Workflow Tutorial — where one request becomes a four-stage traced pipeline.