Build with the API

Agent Link

Make Claude Code, Codex, or any MCP client the brain behind a persona: poll for hand-offs, do the work, reply.

How it works

A Theo Persona is a face and a voice people talk to. Agent Link lets an agentic tool you already run, such as Claude Code, Codex, Cursor, or any MCP client, be the brain behind it for real work. When the persona is asked for something that needs your files, systems, calendar, inbox, or codebases, it calls its ask_agent tool. That queues a request for your agent; your agent answers over MCP; the persona speaks the answer.

The transport is pull only. Your agent polls the OpenCharts MCP server with its own API key. Nothing connects inbound to your machine, no tunnel, no webhook receiver. If your agent is not polling, the persona says so honestly instead of guessing.

The hand-off
persona call  --ask_agent-------------->  request queued (per owner)
your agent    --await_persona_request--->  claims the oldest pending request
your agent    --reply_to_persona-------->  answer stored
persona       <--spoken live (within ~45s) or relayed into the call

Setup

  1. Connect the MCP server

    Your agent tool needs the OpenCharts MCP server with a key that has the write scope (default keys do). Set it up at Developers, MCP.

  2. Open the persona's Your agent step

    In the persona Studio, the Your agent step does the whole setup in place: it switches the capability on, mints a key, gives you the exact install command for Claude Code, Codex, Cursor, Warp, or any MCP client, and tests the connection. Publish afterwards. It is owner-only: it works on private personas, because the agent acts with your own tools and a stranger must never reach it.

  3. Start the loop, then test it

    Paste the loop prompt (from the Studio step or Developers, Agent Link) into your agent and leave it running. The first poll is what makes the persona report that an agent is connected; the step's Test the connection button then sends one small task through the real queue and shows the answer, no video call needed.

The MCP loop

Three tools, all on the regular OpenCharts MCP server. The two that move work need the write scope; the history read needs read.

Tools
await_persona_request
write
Long-polls up to 25s for the next hand-off and refreshes the listener heartbeat. Optional personaId (only that persona), timeoutSeconds, agentName (how the persona credits you). Returns { request } or { request: null }; on null, call it again.
reply_to_persona
write
Delivers your answer for a claimed requestId, with optional https links. Idempotent per requestId.
list_persona_requests
read
Recent hand-offs (task, answer, who answered, relayed or live) plus whether an agent is listening right now.
One pass through the loop
// 1. Long-poll for the next hand-off (returns within 25s)
await_persona_request { agentName: "Claude Code" }
→ { request: { requestId: "par_9f2c...", personaId: "...", personaName: "Ada",
               task: "Check my inbox for anything from Legal today and summarize it.",
               createdAt: "...", expiresAt: "..." } }

// 2. Do the work with your own tools (mail, files, code, the web, ...)

// 3. Send the answer, written to be spoken
reply_to_persona {
  requestId: "par_9f2c...",
  answer: "Two emails from Legal today. Maria sent the revised MSA and asked for a signature by Friday. Tom flagged one open clause on data retention, which he says is minor.",
  links: [{ title: "Revised MSA (PDF)", url: "https://..." }]
}
→ { delivered: true, requestId: "par_9f2c...", personaName: "Ada" }

// 4. Back to step 1. Only the user ends the loop.

Why write for polling

Claiming a request removes it from the queue, so a key that can take work must also be able to answer it. A read-only key cannot claim.

Writing answers

The persona reads your answer aloud, so write for the ear: lead with the result, keep it under about 150 words unless the task is a list, plain sentences, no markdown, no code. Numbers, names, dates, and decisions carry the value. Attach links only when the person can act on them; they render as cards in the call's activity panel and the persona offers them by voice.

If the task cannot be done, or needs something only the person can provide, say so in the answer. The persona never invents what you might have said.

Timing

Windows
live
~45s
Answer inside this window and the persona speaks it in the same turn.
relayed
up to 10 min
Slower answers still arrive: the persona says it is still working, then the call UI relays the answer into the live conversation when it lands.
connected
45s heartbeat
The persona reports that an agent is connected while your agent has polled within this window. A stalled loop reads as disconnected, on purpose.
expired
10 min
A request nobody answers expires and the persona tells the person its agent did not get back to it.

Limits and safety

  • Owner-only. ask_agent is refused on public and org personas, so a visitor can never reach your agent.
  • Your agent only sees the task text the persona wrote. It never sees the call audio, the visitor's identity, or the provider session.
  • The queue holds at most 20 pending requests per account; a full inbox makes the persona ask the person to try again in a moment.
  • Answers are capped at 6,000 characters and 5 links; the spoken summary is trimmed further, the full text stays in the activity panel.
  • The MCP endpoint allows 120 requests per minute per user. A polling loop at 25s uses roughly three.

Your agent acts with your tools

Give it the same care you would give any automation with access to your systems: the loop prompt tells it to avoid destructive actions unless the task explicitly asks, and never to put secrets in an answer.