# Todd
**A self-hosted, bring-your-own-model multi-agent operator.**
Describe an outcome. Todd designs the agents, gives them the right tools, runs them in parallel,
and asks you before it spends money or posts anything.
[](https://github.com/bobby-burns/todd/actions/workflows/ci.yml)
[](LICENSE)



[](https://m8ven.ai/mcp/bobby-burns-todd-1f9kxw)
[Quick start](#quick-start) · [Features](#features) · [Architecture](#architecture) ·
[Extending](#extending-todd) · [Contributing](#contributing) · [Security](#security)
---
Give Todd a goal like *"launch a waitlist site for dropin.hockey with Firebase auth"*. Its planner designs and
spawns the agents the job needs and gives each one the right toolsets: a code sandbox, a real signed-in
browser, infra APIs, your plugins and MCP servers. The agents run in parallel, and Todd pauses for you before
spending money or posting anything. Every agent gets its own live window in the dashboard, thinking included.
Open source and self-hosted: `docker compose up` and it's yours.
> [!WARNING]
> Todd has **no dashboard login yet**. It binds to `127.0.0.1` by default. Don't expose it to the internet.
> See [Status and known limits](#status-and-known-limits).
## Table of contents
- [Features](#features)
- [Quick start](#quick-start)
- [Configuration](#configuration)
- [Dashboard](#dashboard)
- [Architecture](#architecture)
- [Extending Todd](#extending-todd)
- [Development](#development)
- [Status and known limits](#status-and-known-limits)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
- [Security](#security)
- [License](#license)
## Features
- **Dynamic agents, working side by side without stepping on each other.** There's no hardcoded team. The planner
calls `spawn_agent(name, instructions, task, tasks, toolsets, model)` for each part of the work. Two agents never
work on the same code: one agent writes the code, and helpers run alongside it for what feeds it (a "Question
Bank" writing the questions file the site reads, research, images), while reviews and deploying wait until the
build is done. Todd refuses an edit to a file another running agent is working on. Up to 6 agents at once by
default (configurable); the planner waits on, messages or cancels them. It stays responsive while they work: message it any time and it acts
right away (for example, spawns another agent) while the others keep going.
- **Watch them think, pause them, steer them.** Each agent has its own window with its reasoning (narrated,
plus native model reasoning where supported), tool calls, browser steps, a **Pause/Resume** button and a
message box. Pause an agent (or the whole run) and send it a message: it picks up the change and resumes.
Pausing also freezes an agent's in-progress browser task. Finished agents fold into a compact tray (open one
to read its window again, or hide it).
- **Keep going after a run ends.** A finished (or stopped) run isn't a dead end: message its planner and it picks
its conversation back up with your follow-up, spawning new agents if needed. Runs can be renamed, run again or
deleted from the sidebar (**Edit** deletes several at once).
- **Every agent ends with a summary.** Done / Outputs / How / Left-needs-you, shown as a card in its window.
The planner's run summary adds a line per agent. If an agent is stopped or fails, Todd writes a fallback
summary from what it actually did.
- **Sign in once.** The setup wizard and the **Accounts** page cover about 70 services (dev and deploy,
domains, cloud, payments, Google, socials, launch communities, productivity, app stores, AI platforms). Todd
detects logins in the agents' browser and shows each session's status.
- **Asks for accounts up-front.** The moment you send a goal, Todd reads which accounts it needs ("an iPhone app on
TestFlight" → Expo, App Store Connect, Apple Developer, GitHub; plus any service you name) and skips the ones it
can already use. If any aren't signed in, the run pauses on one card with a **Sign in** button per service
(it opens the login page in the live browser) and **Later**. The card closes by itself once you're signed in, and
Todd sets up those CLIs and keys before any agent starts, so nothing stops for a login halfway through.
- **Sign in once: web and CLI.** When you sign in to GitHub, Vercel, Netlify, Railway, Cloudflare, Stripe,
Firebase or Expo, Todd signs in that service's CLI with the same session automatically. It approves the CLI's sign-in in
the browser itself; you only step in for a password or 2FA page, or for the one final Authorize/Allow click some
sites only accept from a person (Todd scrolls to it and highlights it), and only then, while you're there.
Credentials go straight into the encrypted vault; nobody copies tokens, and runs never stop for a login.
- **See what it made.** Each run has a **Files** view: everything its agents created or changed, live while they
work, read-only (code with line numbers, Markdown formatted, images shown, videos playable, `.env` values hidden
until you ask),
plus the vault keys that run saved. Settings → Vault groups every key by the run that saved it.
- **Shorts based on what's working now.** Todd scans recent TikToks in your niche (through Apify), finds the ones that
broke out of small accounts, studies their hooks and structure, and keeps what it learns as format cards to build
your videos from, never copying a video.
- **Short videos with a voiceover, timed from the voice.** Todd films the products it built in its own browser,
writes a script (2–3 hook variants and beats), voices it, and plans every cut, caption and clip length from the
voice's own timestamps, so nothing drifts. The first version is a free scaffold (a local voice, real captions, its
own recordings, AI shots as priced placeholders) for you to approve before anything costs money; the final voice is
ElevenLabs (`ELEVENLABS_API_KEY` in the vault). Plan for what comes next: [docs/video-step2-plan.md](docs/video-step2-plan.md).
- **Slideshow videos.** The `video` toolset turns a product into a short vertical slideshow video: a storyboard of
3–12 shots, each searched by meaning across stock photos and the run's own images (put app screenshots in
`video/library/`), ranked so every pick also matches the look of the shots already chosen, then a 1080×1920 MP4
(a slow zoom on each captioned slide, optional music you provide), the slides on their own for a TikTok photo
post, a contact sheet and photo credits, all in the run's `video//` folder; the video plays in the Files
view. Stock photos need a free [Pixabay API key](https://pixabay.com/api/docs/) in Settings → Vault as
`PIXABAY_API_KEY` (an existing `PEXELS_API_KEY` works too; Pexels has paused new keys); without one it uses only
the run's own images. Nothing is posted.
- **Built to launch, not just to demo.** When a goal makes a website, Todd asks at the start, on one card, where it
should live (your domain, a new one, or a free address for now), whether the code is private (the default) or
public, and whether to ask you before deploying. Agents keep building while you decide. Deploying (previews too),
connecting a domain and public repositories follow your answer, in code, and deploying is always the last step:
Todd refuses a deploy while an agent is still working on the project. Every site build ends with **launch
readiness**: titles and descriptions, a social preview image, icons, robots.txt, sitemap.xml, llms.txt, a 404
page, security headers, accessibility and a Lighthouse check. When the run ends, a **Ready for real visitors?**
checklist, read from the project's files, shows what's in place, and one tap asks Todd to add what's missing.
- **Questions you can tap.** When an agent needs you to choose (which domain, which option), you tap an answer
instead of typing; you can still write your own.
- **A recap anyone can read.** When a run finishes you get **In plain words** first, then what got done, what you
got (links you can click), what's next for you, and **Words to know**. Technical words in the recap explain
themselves when you hover or tap them.
- **Know what's happening and what it cost.** A live *Right now* card says what each agent is trying to do; the
Usage view and page show tokens, calls, tool calls, time and cost per run and per day. Finished runs suggest
next steps, starting with getting things production ready.
- **Secrets stay out of the models' context.** Keys are scrubbed from everything an agent reads, pages are
blurred before screenshots, and new keys go straight to the vault. See [SECURITY.md](SECURITY.md).
- **Your Claude plan, or your own keys.** By default every agent (planner included) runs as a headless
[Claude Code](https://code.claude.com) session signed in with your Claude account, so usage counts toward
your Pro/Max plan instead of API credits (Opus 5.5 by default). Or switch Settings → Engine to **API keys**
and use any LiteLLM model per tier: Anthropic, OpenAI, Gemini, OpenRouter, Groq, DeepSeek, or fully local via
Ollama.
- **APIs and MCP servers first, browser last.** Every agent calls `find_integrations` before touching a
service. It picks, in order: a ready toolset (Vercel, GitHub, your plugins, `mcp_*` servers), the service's
REST API via `api_request` with a vault key, a CLI in the sandbox, and only then the browser. `browse`
requires a `why_not_api` reason, which is shown in the agent's window. Settings suggests official MCP
servers (GitHub, Vercel, Stripe, Supabase, Neon, Linear, Notion, Sentry, Figma) with one-click add.
- **iPhone and Android apps.** Agents build Expo (React Native) apps and use the `eas` tool to run cloud builds
on Expo's servers (macOS included) and upload to TestFlight or Google Play. See
[iPhone and Android apps](#iphone-and-android-apps).
- **Agents check their own work.** Agents that build or deploy a site open it in the browser, look at the
screenshot, click through, and read JavaScript errors and failed requests with `browser_console`.
- **Spending rules the model can't override.** An auto-approve limit, per-run budgets and approval prompts,
with every charge in a ledger. Card payments always need your approval. Card details reach the browser only
as masked placeholders, only on the approved merchant's exact sites (a shared page like Stripe Checkout only
when opened from that merchant), only up to the approved total, with screenshots turned off. Clicking Buy,
Upgrade or Pay on a site with a saved card, and known purchase APIs and commands, wait for your approval too.
- **Public actions need approval, in code.** Posting, messaging or emailing from your accounts in the browser
waits until you OK that site; known posting APIs and publishing commands (npm publish, a public repo or release,
sending an app to the stores) show you the exact request first.
- **Extensible.** Each plugin file in `./plugins` becomes a toolset, each MCP server becomes a toolset, and
every system and harness prompt can be edited.
- **Survives restarts.** LangGraph + a Postgres checkpointer save every run, so a crashed run shows a
**Resume** button.
## Quick start
**Requirements:** Docker with Compose v2.24+. Optionally a Claude Pro/Max plan, or API keys for any
LiteLLM-supported provider.
```bash
git clone https://github.com/bobby-burns/todd.git
cd todd
cp .env.example .env # optional: change SANDBOX_TOKEN / POSTGRES_PASSWORD
docker compose up -d --build # the first build takes a few minutes
open http://localhost:3000
# sign in to Claude once (Anthropic's own sign-in; pick your Claude subscription)
docker compose exec -it api claude auth login
```
The **setup wizard** (Setup in the sidebar) walks you through the rest:
1. **Engine:** "Your Claude plan" (shows whether Claude Code is signed in, with a Test button) or "API keys"
(pick a provider, paste its key, test).
2. **Integrations:** a Vercel token and a GitHub token (fine-grained, repo administration + contents). Install
the Vercel GitHub app on your account so new repos can be connected.
3. **Spending:** auto-approve limit, default run budget, domain registrant contact.
4. **Sign in to accounts:** tick the services your agents should use. Todd opens each login page in the
agents' browser (embedded next to the list). You sign in, Todd detects it and moves to the next.
Manage sessions any time on **Accounts**: status and how it was detected (session cookie, verified by visit,
via Google…), sign in, verify, sign out, or add custom sites. A payment card for browser checkouts (use a
virtual card with a limit) goes in Settings.
### Fully local models
```bash
docker compose --profile local up -d
docker compose exec ollama ollama pull qwen3:14b
```
Then set a role to `ollama_chat/qwen3:14b` in Settings.
### iPhone and Android apps
Agents build mobile apps with [Expo](https://expo.dev) and the `eas` tool, which runs the EAS CLI in the sandbox.
Builds run on Expo's servers, so iOS works even though the sandbox is Linux. There's no iOS simulator: you test on
your phone with TestFlight (or Expo Go).
What you need: an [Expo account](https://expo.dev), and for iOS an
[Apple Developer Program](https://developer.apple.com/programs/) membership ($99/yr) where you're Account Holder or
Admin. For Android, a Google Play developer account ($25 once); Google requires the first upload of a new app to be
done by hand in the Play Console.
You only sign in, when the run's Sign in card asks (or on the Accounts page). Todd does the rest:
- **Expo:** Todd signs the EAS CLI in with your browser session, like GitHub or Vercel. No token to copy.
- **App Store Connect:** a short setup agent generates an API key (Team Keys, *App Manager*) in the browser and
saves the Issuer ID, Key ID and the `.p8` file straight into the vault (`browser_save_download`), without the model
seeing the key. If your team has never used the App Store Connect API, it asks you before accepting Apple's terms.
- The `eas` tool hands the key to EAS for one command at a time and removes it afterwards.
Adding them yourself still works: `EXPO_TOKEN`, `ASC_KEY_ID`, `ASC_ISSUER_ID`, `ASC_PRIVATE_KEY` (the whole `.p8`;
pasting it into the one-line field is fine) and optionally `APPLE_TEAM_ID` in **Settings → Vault**.
The first iOS build of a new app needs you once: EAS can't create the Apple distribution certificate without a
person, so Todd asks you to run `npx eas-cli build -p ios --profile production --auto-submit` in the app's repo on
your computer. That signs in to Apple, creates the certificate, profile and App Store Connect app, and uploads to
TestFlight. After that, Todd builds and uploads new versions on its own. It stops at TestFlight unless you ask it
to submit for App Store review, and asks you before it does.
Example goal: *"Build a simple Expo iPhone app that tracks my water intake with a daily goal and a reset button,
and put it on TestFlight."*
## Configuration
Everything in [`.env.example`](.env.example) is optional. Keys can also be added in the dashboard
(Settings → Models / Integrations), where they're stored encrypted in Postgres and take precedence over
environment variables.
| Variable | Purpose |
|------------------------------|--------------------------------------------------------------------------|
| `POSTGRES_PASSWORD` | Database password |
| `SANDBOX_TOKEN` | Shared secret between the API and the sandbox. **Change it.** |
| `TODD_SECRET_KEY` | Fernet key for the vault (auto-generated into the data volume if empty) |
| `VNC_PASSWORD` | Password for the live browser view (noVNC); random if empty |
| `TODD_ALLOWED_HOSTS` | Names besides `localhost` the dashboard answers to, e.g. a Tailscale name |
| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY` | Model keys for the **API keys** engine (never passed to Claude Code) |
| `VERCEL_TOKEN`, `GITHUB_TOKEN` | Integration tokens (fallbacks for the vault) |
| `TODD_PLANNER_MAX_TURNS`, `TODD_CODE_MAX_STEPS`, `TODD_BROWSER_MAX_STEPS` | Step limits |
## Dashboard
A glass-material interface (light, dark or follow-system) built with Next.js, Tailwind v4 and Motion. There's
one window per agent with live reasoning, paired tool calls (spinner → check), browser steps with screenshots,
chat-style messages, pause/resume and end-of-work summary cards. Approval and spend requests appear as sheets at
the top of the run. The live browser panel has **Take control**, which opens the agents' browser big and
interactive (sign-ins, captchas, 2FA, or helping an agent). It works on phones too, with a floating tab bar.
The design system lives in `services/web/app/globals.css` (color tokens + the `glass` material),
`components/ui.tsx` (status pills, segmented controls, switches, avatars) and `lib/motion.ts` (spring presets).
## Architecture
```
web (Next.js :3000) ──proxy/SSE + token──► api (FastAPI, internal)
├─ planner (LangGraph + Postgres checkpointer)
│ find_integrations / check_accounts / request_signins
│ spawn_agent(tasks=[…]) / wait_for_agents / message_agent / cancel_agent
│ │
│ ├─► agent "Store Listing" toolsets: web, browser, accounts
│ ├─► agent "Marketing Site & Domain" toolsets: sandbox, vercel, porkbun
│ └─► agent "Launch Assets" toolsets: sandbox, web (1–4 typical)
│
│ toolsets: sandbox ─► sandbox container (node/git/python)
│ browser ─► browser-use ─CDP─► Chromium + noVNC :6080
│ vercel, github, web, vault, accounts, plugins, mcp_*
└─ postgres: runs, agents, events, approvals, vault, ledger, checkpoints
```
| Service | Role | Exposed |
|------------|-----------------------------------------------------------------------------|------------------|
| `web` | Next.js dashboard; proxies `/api/*` (including SSE) to the API | `127.0.0.1:3000` |
| `api` | FastAPI + LangGraph orchestrator, tools, vault, spend policy | internal (token) |
| `postgres` | Runs, events, approvals, vault, ledger, settings, checkpoints | internal |
| `sandbox` | Node 22 / pnpm / git / Python / deploy CLIs (incl. EAS), with a small exec API | internal |
| `signedin` | Same image and workspace; runs only commands that use your sign-ins | internal |
| `browser` | Headful Chromium on Xvfb; CDP + noVNC live view | `127.0.0.1:6080` |
| `ollama` | Optional (`--profile local`) for local models | internal |
- **Parallelism:** background agents run at the same time (max 6 at once, 16 per run by default). Browser
tasks share one browser and queue.
- **Pause:** each agent (and the planner) has a pause gate checked before every model call and tool call. A
paused browser task is paused inside browser-use. Sending a message to a paused agent resumes it.
- **Responsive planner:** `spawn_agent` returns right away; `wait_for_agents` ends early when you send the planner a
message, so it can act on it while agents keep running. It can't finish while agents are still running.
- **Human in the loop:** `ask_human`, `request_approval` and the spend policy pause *in place* (no
`interrupt()` re-execution), so a 10-minute browser task isn't restarted when you answer.
- **Secrets:** stored encrypted, referenced by tools as `{{secret:NAME}}`, never placed in model context.
- **Isolation:** the sandbox (agent-run code) and the browser (untrusted pages) each share a network only with
the API, and every API call needs a token that only `api` and `web` hold.
See [ARCHITECTURE.md](ARCHITECTURE.md) for the module map, the lifecycle of a run, both engines and the full
security model.
## Extending Todd
### Custom tools (toolsets)
```python
# plugins/slack.py
from todd.sdk import todd_tool, get_secret
@todd_tool(toolset="slack") # agents spawned with toolsets=["slack"] get it
async def slack_post(channel: str, text: str) -> str:
"""Post a message to Slack.
Args:
channel: e.g. #launches
text: message
"""
...
```
Each plugin file becomes a toolset (named after the file unless you set `toolset=`), and the planner sees
every toolset's description when it designs agents. `planner=True` also gives a tool to the planner directly.
Reload from **Settings → Toolsets & plugins**. Plugins get `get_ctx()` (events, `ask_human`,
`request_approval`), `get_agent_id()`, `authorize_spend()` for anything that costs money, and vault access. Any
existing LangChain tool works too. See [`plugins/example_notify.py`](plugins/example_notify.py).
### MCP servers
MCP servers are configured in Settings as JSON (langchain-mcp-adapters format). Each one becomes a toolset
named `mcp_`.
### Prompts
Every prompt is a markdown file: `harness` (prepended to all agents), `planner`, `worker` (the template for
spawned agents; the planner's instructions are filled in) and `browser`. Override them in
`./prompts/.md` or in the dashboard. See [`prompts/README.md`](prompts/README.md).
## Development
```bash
# API tests (scripted fake models, no keys needed). With the sandbox server running they also cover spawned
# agents using the sandbox; with a browser reachable over CDP (BROWSER_CDP_HOST) they also test Accounts.
cd services/api && pip install -r requirements.txt pytest
TODD_DATA_DIR=$(mktemp -d) TODD_PLUGINS_DIR=tests/plugins pytest -q tests
# inside compose
docker compose exec api sh -c 'pip install pytest && TODD_DATA_DIR=$(mktemp -d) DATABASE_URL= TODD_API_TOKEN_FILE= TODD_PLUGINS_DIR=tests/plugins SANDBOX_WORKSPACE=/workspace pytest -q tests'
docker compose exec api python tests/browser_smoke.py # drives the real browser container
```
Dashboard: `cd services/web && npm install && API_URL=http://localhost:8000 npm run dev`.
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full setup, project layout and guidelines.
## Status and known limits
Todd is at **v0.4** and under active development.
- **No dashboard login yet.** The dashboard and live view bind to 127.0.0.1, the dashboard only answers its own
pages on `localhost`, and the live view has a password. Don't expose Todd publicly until auth is added.
(Internally, the API requires a generated token and the sandbox and browser are network-isolated; see
[ARCHITECTURE.md](ARCHITECTURE.md#security-model).)
- **Purchases and public actions are checked in code, by recognition.** Buy/Upgrade/Pay-style clicks, payment and
billing pages, posting sites and known purchase/posting APIs and commands wait for you. Something Todd doesn't
recognize as a purchase gets through, so keep the budget and auto-approve limit low and use a limited virtual card.
See [SECURITY.md](SECURITY.md#what-needs-a-person-enforced-in-code).
- **One shared browser.** Browser tasks run one at a time, across all runs; other agents keep working in parallel.
- **CLI sign-in with the browser session** covers GitHub, Vercel, Netlify, Railway, Cloudflare, Stripe and
Firebase. Supabase's CLI only signs in from a real terminal, so it needs a token in Settings. Approving uses
generic page rules (fill the code, click Continue/Authorize). Some final buttons, such as GitHub's Authorize and
Vercel's Allow Access, stay disabled until a person interacts with the page (clickjacking protection); Todd
doesn't work around that, so it asks you for that one click. If a provider's page changes, Todd leaves the tab
open in the live browser for you to finish.
- **Login detection is best-effort.** It's exact for services with a known session cookie. For others Todd
loads a dashboard page and looks for a login redirect or a visible password field, and you can mark a
service yourself.
- Background agents don't survive an API restart. Resume continues the planner, which can re-spawn them.
- **Vercel ↔ GitHub:** creating a Git-connected project requires the Vercel GitHub app to have access to
the repo.
- Screenshots are taken only for http(s) pages (a browser-use limitation).
- **Claude plan engine:** plan usage limits apply. Several Opus agents in parallel use them faster; when a limit
is hit, the run stops with a message and you can resume it after the reset. Todd never handles your Claude
credentials: the unmodified Claude Code CLI keeps its own sign-in in the `apidata` volume. Claude Code's own
tools (Bash, file edits, web) are switched off; agents only get Todd's toolsets. In this engine agents drive the
browser themselves step by step (`browser_start` … `browser_done`) instead of handing a task to browser-use's
LLM, so every model call goes through your plan. The engine is fixed per run; switching affects new runs.
- Pause takes effect at the agent's next step: a model call or tool call already in flight finishes first.
- `api_request` only sends `GITHUB_TOKEN` / `VERCEL_TOKEN` to their own API hosts; model provider keys are
never sent anywhere by tools, nor is the payment card. Other vault keys can go to any host the agent
chooses, so only store keys you're comfortable with agents using.
## Roadmap
Ideas under consideration. Feedback and PRs welcome.
- Recorded browser "recipes": the first run explores, later runs replay a saved script and fall back to the
model only when something changes
- Multiple browser instances (parallel browser agents)
- Agents that spawn sub-agents
- Saved agent templates
- Virtual-card issuing providers
- Dashboard auth and multi-user
- Per-run workspace download
- Scheduled runs
- More infra tools (Cloudflare, Supabase, Stripe)
## Contributing
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for the development setup and
guidelines, and follow the [Code of Conduct](CODE_OF_CONDUCT.md). For larger changes, open an issue first so we
can agree on the approach.
## Security
Todd can spend money and act from your accounts. If you find a vulnerability, **please report it privately**
as described in [SECURITY.md](SECURITY.md) rather than opening a public issue.
## License
Todd is released under the [MIT License](LICENSE).