Skip to content

About

Mai Tai Agent Development Platform

Resources

Contributing

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Repository files navigation

Mai-Tai

Async human-agent collaboration. Spin up AI agents, step away, check in from your phone.

Mai-Tai is a self-hosted platform that lets you launch AI coding agents as Docker containers, communicate with them via a mobile-first web UI, and stay in the loop from anywhere — no IDE required.

What It Does

  • Spin up agents — create a workspace, pick a template (research, coding, assistant), and Mai-Tai spawns a Docker container running Claude Code connected to your workspace
  • Talk to your agents — real-time WebSocket messaging from any device, including mobile
  • Step away — agents run autonomously in Docker, sending you updates and asking questions via Mai-Tai when they need you
  • Persistent memory — agents remember lessons learned across restarts via a per-workspace mounted volume
  • Stash — save and organize links with AI enrichment and #NNNN issue numbers

Quick Start

Prerequisites: Docker, Docker Compose, Git, Python 3.11+, and uv (curl -LsSf https://astral.sh/uv/install.sh | sh).

git clone https://github.com/jmcdice/mai-tai-dev.git && cd mai-tai-dev
uv tool install ./cli
mai-tai init

Run init from inside the clone — it locates the repo by walking up from your working directory. pipx install ./cli works too; a bare pip install usually does not, because most distributions now ship Python as externally managed and refuse to install into it.

init walks the whole path from a bare clone to an agent that talks back: it starts the stack, builds the agent image, creates your admin account, wires up the API key the backend needs to spawn containers, and launches a first Supervisor workspace. It's idempotent — every step it finds already done, it skips — so it's safe to re-run on a half-finished install.

Then visit http://localhost:3000, log in with the account you just made, and say hi to the Supervisor.

Don't run cp .env.example .env yourself. dev.sh only generates secrets when .env is missing; hand-copying the example leaves POSTGRES_PASSWORD empty and the stack refuses to start.

On Vertex AI? Pass --vertex-project <gcp-project> and agents authenticate off the host's gcloud ADC instead of an API key. Add --model if your project only has some models enabled — the default is the runtime's, and an agent whose model is not enabled will connect and greet you before failing its first real turn. See cli/README.md.

Doing it by hand instead
./dev.sh local up                       # generates .env secrets, migrates the DB
docker build -t mai-tai-agent:latest -f agents/claude-code/Dockerfile .

Then, in the web UI, register an account and copy the API key shown once at registration. The backend reads that key off the host to authenticate the agent containers it spawns, so it has to land here:

mkdir -p ~/.config/mai-tai
cat > ~/.config/mai-tai/config <<EOF
MAI_TAI_API_KEY=mt_your_key_here
MAI_TAI_API_URL=http://localhost:8000
EOF
chmod 600 ~/.config/mai-tai/config

Miss this step and every Start Agent click fails with "No Mai-Tai API key available." Create the directory before ./dev.sh local up — compose bind-mounts it, and Docker will otherwise create it for you as root.

Finally, give the agents a model credential: either set ANTHROPIC_API_KEY in Settings → AI, or run on Vertex (CLAUDE_CODE_USE_VERTEX=1), in which case containers fall back to the host's gcloud ADC automatically.

Agent Workspaces

The core feature. Create an agent workspace, pick a template, and Mai-Tai launches a Docker container running Claude Code connected to your workspace via MCP.

Templates

Template Description
Research Searches the web, compiles findings, sends reports
Coding Agent Clones a GitHub repo, writes code, opens PRs
Personal Assistant General tasks, daily questions, follow-ups
Monitor Periodic checks, alerts on changes
Custom Your own system prompt and behavior

How It Works

You (mobile/browser)
    │
    ▼
Mai-Tai Web UI  ──WebSocket──▶  Backend (FastAPI)  ──▶  PostgreSQL
                                       │
                               Docker Socket
                                       │
                                       ▼
                          ┌─────────────────────┐
                          │  Agent Container     │
                          │  (Claude Code + MCP) │
                          │  /home/agent/memory/ │  ← persistent volume
                          └─────────────────────┘

Each agent container:

  • Runs Claude Code in headless mai-tai mode
  • Connects to your workspace via the MCP server
  • Has a persistent volume at /home/agent/memory/ for lessons and task notes
  • Gets template-specific CLAUDE.md with working principles baked in

Coding Agent Setup

  1. Create a workspace → select Coding Agent template
  2. Enter your GitHub repo URL
  3. Add a GitHub PAT in Settings → AI tab
  4. Start the agent — it clones the repo and gets to work

MCP Config (host-based sessions)

For Claude Code sessions running directly on a machine (not in a Docker container):

# Global credentials (~/.config/mai-tai/config)
MAI_TAI_API_URL=http://localhost:8000
MAI_TAI_API_KEY=mt_your_key_here

# Per-project workspace (.env.mai-tai in project root)
MAI_TAI_WORKSPACE_ID=your-workspace-uuid

Features

  • Docker-per-agent — each workspace gets its own isolated container
  • Persistent memory — agents learn from corrections, lessons survive restarts
  • Mobile-first — designed for checking in from your phone
  • Real-time — WebSocket-powered live updates
  • Multi-workspace — separate workspaces per project/agent
  • Auth — email/password + optional OAuth (GitHub, Google)
  • Admin panel — user management, registration toggle, impersonation
  • Stash — save links with AI enrichment and #NNNN issue tracking
  • Self-hosted — runs entirely on your machine, no data leaves your network

Architecture

┌─────────────────────────────────────────────────┐
│                  Mai-Tai Platform                │
│                                                  │
│  Frontend (Next.js)  ◀──▶  Backend (FastAPI)     │
│         │                        │               │
│         │ WebSocket         PostgreSQL           │
│         │                        │               │
│         │                  Docker Socket         │
│         │                        │               │
│         │               Agent Containers         │
│         │               (Claude Code + MCP)      │
└─────────────────────────────────────────────────┘
         ▲
         │
   You (anywhere)

Development

./dev.sh local up          # Start everything
./dev.sh local logs        # View logs
./dev.sh local rebuild     # Rebuild after code changes
./dev.sh local migrate     # Run database migrations
./dev.sh local down        # Stop everything
./dev.sh local nuke-db     # Wipe database and start fresh

Configuration

See .env.example for all options. Key settings:

Variable Description
SECRET_KEY JWT signing key (required, change in production)
NEXTAUTH_SECRET NextAuth session encryption
CORS_ORIGINS JSON array of allowed origins
REGISTRATION_ENABLED Set false to disable new signups (also toggleable in admin UI)
AGENT_IMAGE Docker image for agent containers (default: mai-tai-agent:latest)
AGENT_MODEL Model agents run (default: sonnet)
CLAUDE_CODE_USE_VERTEX Set 1 to auth agents via Google Vertex AI instead of an Anthropic key
ANTHROPIC_VERTEX_PROJECT_ID GCP project for Vertex (required when Vertex is on)
CLOUD_ML_REGION Vertex region (default: global)
GITHUB_CLIENT_ID/SECRET GitHub OAuth (optional)
GOOGLE_CLIENT_ID/SECRET Google OAuth (optional)

With Vertex enabled, the backend reads the host's Application Default Credentials (~/.config/gcloud, mounted read-only) and passes them to each agent container — no per-user Anthropic key needed. Run gcloud auth application-default login on the host first.

Building the Agent Image

Build from the repo root, not agents/ — the images copy mcp-server/ into the container, so it has to be inside the build context.

# Claude Code runtime (required for agent workspaces)
docker build -t mai-tai-agent:latest -f agents/claude-code/Dockerfile .

# OpenAI Codex runtime (optional — for workspaces using the codex runtime)
docker build -t mai-tai-agent-codex:latest -f agents/codex/Dockerfile .

Rebuild after changes to agents/.

Agent containers run a driver loop: each user message triggers one CLI turn (claude -p --resume), so there is no long-lived agent process to babysit. Persistent memory lives on the per-workspace volume: MEMORY.md (curated, size-capped, loaded every session), journal/ (daily notes), and tasks/lessons.md — plus a search_history tool backed by Postgres full-text search over the workspace's entire message history.

Tools the agent installs for itself land there too. uv tool install is redirected to memory/tools/, so a CLI an agent needed once is still there after a restart — which matters most for scheduled tasks, since a job that depended on a vanished install fails silently at 5am. The container is otherwise immutable: the agent is not root, there is no sudo, and apt-get will not work. memory/tools/bin is appended to PATH rather than prepended, so a self-installed binary can't shadow python3 or git and survive a restart doing it.

Migrating to Another Host

mai-tai config (the admin CLI) moves a whole deployment — users, workspaces, agents, and full message history — to another machine.

# On the source host
mai-tai config export mai-tai-backup.tar.gz
mai-tai config inspect mai-tai-backup.tar.gz   # peek without restoring

# On the target host
mai-tai config check-env                       # what's missing from .env
mai-tai config import mai-tai-backup.tar.gz    # prompts before wiping

⚠️ Treat the bundle as a secret

By default the dump is byte-for-byte complete, so the credentials in users.settings (Anthropic/OpenAI keys, GitHub token, LLM keys) travel with it. That's deliberate — the target comes up as a working copy with nothing to re-enter. The tradeoff is that the tarball is credential material. It's written mode 0600, mai-tai-export-*.tar.gz is gitignored, and you should delete it once the move is done.

Those settings are Fernet-encrypted at rest, but the key comes from ENCRYPTION_KEY — or, when that's unset, from SECRET_KEY — so the target needs the same values or the restored credentials decrypt to nothing. Import fingerprints both ends and warns on a mismatch before it touches the database.

Flag Effect
(none) Full fidelity — credentials included, nothing to re-enter on the target
--scrub Strip credentials from users.settings; you re-enter keys in Settings → AI
--with-env Also bundle .env. Import writes it to .env.imported for review rather than overwriting

--scrub is not the same as "safe to share." It strips users.settings and nothing else. Message history is not scrubbed — agents paste keys into chat and operators paste them back — so every export scans the dump for credential-shaped strings and tells you what it found. Take that count seriously; on this repo's own database it found three.

Password hashes and mt_ API-key hashes are always included, so logins and existing agent configs keep working on the target.

A restored clone is live. Schedules come across enabled, so on the next tick the target starts waking agents and doing real work — sending messages, reaching the LAN — from a host that was only ever meant to be a copy. Import warns when the bundle carries enabled schedules; mai-tai config import --disable-schedules turns them all off as part of the restore.

Either way, copy ~/.config/mai-tai/config across so existing mt_ API keys still authenticate — and fix its MAI_TAI_API_URL to point at the target.

What the bundle doesn't carry

The bundle is the database plus (optionally) .env. Everything below is source-host specific and has to be handled on the target by hand:

  • The host's address, baked into .env. NEXT_PUBLIC_API_URL, NEXT_PUBLIC_WS_URL, and NEXTAUTH_URL are compiled into the frontend bundle. Left alone, the target's UI loads fine and then quietly talks to the source host. Rewrite them before ./dev.sh local up.
  • The agent image. mai-tai-agent:latest is built locally, so a fresh clone has none — agent workspaces fail to start until you build it (see Building the Agent Image).
  • TLS and LAN DNS. caddy/certs/ is untracked and infra/dnsmasq.conf hardcodes the source host's IP, so both services crash-loop on a new host. Unless you're serving the same domain from the target, leave them stopped: docker compose stop caddy dnsmasq.

Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines.

License

MIT — see LICENSE for details.

About

Mai Tai Agent Development Platform

Resources

Contributing

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages