Build with the API

Agent Link

Make Codex, Claude Code, or any MCP client the brain behind a persona: pair the bridge, or 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 Codex, Claude Code, 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.

For Codex and Claude Code the recommended way to run that loop is the Agent Link Bridge (@hitheo/agent-link), a small process on your computer that pairs with your account, waits for hand-offs, runs your agent in the folder you choose, and posts the answer. The persona becomes the front end of the coding agent you already have; no prompt to keep alive, no key to paste.

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 with the bridge (Codex, Claude Code)

The short way is one paste. Pick your agent under Connect this computer (in the Personas tab, the persona Studio's Your agent step, or the Agent Link dashboard) and it issues a code and shows one command. Paste that command in a terminal: it pairs this computer, checks your plan, installs the bridge as a background service in a folder of its own (~/OpenCharts unless you choose another), and opens your persona in the browser. The code is good for 5 minutes and is used once; you never see or paste a key.

Connect this computer
# The one paste. "Connect this computer" in the Personas tab (or here on the dashboard) issues the code.
npx -y @hitheo/agent-link@latest connect --code <code> --runner codex

# No Node.js? The same, through the installer (downloads the bridge as a single binary first)
curl -fsSL https://www.opencharts.com/agent-link/install.sh | sh -s -- --code <code> --runner codex

The persona opens as a small floating window you can drag, resize, expand to fullscreen or shrink to a face bubble, and it keeps talking while you work elsewhere in OpenCharts. If Codex runs the setup for you, it needs full permissions for these commands: they write outside the workspace and use the network, and a permission error inside the sandbox means run it outside the sandbox, never chown or sudo.

The long way, step by step, does the same thing:

  1. Pair this computer

    Run the login command. It prints a link and opens Developers, Agent Link, where you confirm the computer by name. That click mints a key for this computer only and hands it to the bridge, which stores it privately. You never see or paste the key. The link is good for 5 minutes.

  2. Install the bridge

    Install it with the runner you use and the folder your agent should work in. It runs as a background service that starts with your computer and restarts itself; status, restart and uninstall manage it later. The first heartbeat is what makes the persona report that an agent is connected; the dashboard shows which runner, which computer and which folder.

  3. Send a test task, then turn it on

    Send a test task on the dashboard (or Test the connection in the persona Studio) pushes one small task through the real queue and shows the answer, no video call needed. Then switch Your agent on for the persona in the Studio and publish. It is owner-only and works on private personas, because the agent acts with your own tools and a stranger must never reach it.

The three commands
# 1. Pair this computer (prints a link, opens the dashboard, waits for your click)
npx -y @hitheo/agent-link@latest login

# 2. Install the bridge as a background service, in the folder you want the agent to work in
npx -y @hitheo/agent-link@latest install --runner codex --cwd ~/Developer/my-app
#    ...or drive Claude Code instead:
npx -y @hitheo/agent-link@latest install --runner claude-code --cwd ~/Developer/my-app
#    (`start` instead of `install` runs it in this terminal only)

# 3. Anything unclear? The doctor explains what would stop a link from working
npx -y @hitheo/agent-link@latest doctor

Easier still: in the Personas tab, Start agent then Open in Codex hands Codex a prompt that runs these steps for you. Codex users can also install the OpenCharts plugin, which signs Codex in to your account and carries the same setup as a skill:

The Codex plugin
# Codex: install the OpenCharts plugin once (signs you in with OAuth, no key anywhere)
codex plugin marketplace add hitheoai/codex-plugins
codex plugin add opencharts@opencharts
# then, in any Codex chat: "Connect this computer as the brain behind my OpenCharts personas"
Without Node.js
# No Node.js? One line installs the bridge as a single binary, then prints the same steps
curl -fsSL https://www.opencharts.com/agent-link/install.sh | sh
# use ~/.opencharts/agent-link/bin/opencharts-agent-link in place of npx -y @hitheo/agent-link@latest

Why a bridge

Coding agents are built to answer a person, not to poll forever, and desktop apps do not read the environment variables your shell has. The bridge owns the polling, hands each task to your agent as a fresh turn in a thread it keeps per persona, and holds the key itself, so the loop never stalls and a stale key can never silently fail.

Setup without the bridge (Cursor, Warp, any MCP client)

  1. Connect the MCP server

    Your agent tool needs the OpenCharts MCP server with a key that has the write scope (default keys do). The dashboard and the Studio's Your agent step mint one in place and show the exact config for your tool; the general recipes live at Developers, MCP.

  2. Paste the loop prompt

    Paste the loop prompt (from the Studio step or the dashboard) into your agent and leave it running. The first poll is what makes the persona report that an agent is connected.

  3. Test the connection

    The Test the connection button sends one small task through the real queue and shows the answer. Then switch the capability on and publish.

The MCP loop

Four tools, all on the regular OpenCharts MCP server. The bridge calls them for you; a hand-run loop calls them itself. The three 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), and client (bridge version, runner, host, workspace: what the dashboard shows as connected). Returns { request } or { request: null }; on null, call it again.
report_persona_progress
write
Optional. Appends one short note (kind: status, command, file, tool or message; up to 200 characters, the newest 30 kept) to the request you are working on. The dashboard shows it live; it also counts as a heartbeat.
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, ...)
//    Optionally narrate what you are doing — it shows live on the dashboard
report_persona_progress { requestId: "par_9f2c...", kind: "status", note: "Reading today's mail from Legal" }

// 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.