This open-source project and video are by Code With Antonio,
and are featured here with their permission. The code lives in their GitHub repository.
Overview
Grok AI Teammates is an open-source, fullstack app where each bot has a name, a job and a persistent cloud computer of its own. A bot works in its sandbox through shell, file, mouse and keyboard tools, and you can watch its desktop live in the chat. Every chat turn runs as a durable chat agent on Trigger.dev, so a long desktop task survives page refreshes, redeploys and closed tabs. Tech stack:- Trigger.dev AI chat for the durable chat agent, and a scheduled task that meters running sandboxes
- Next.js with
useTriggerChatTransportand the AI SDKuseChathook - Daytona for one cloud sandbox per bot: a shell, a filesystem and a desktop the bot controls
- Clerk for authentication, plus Billing for plans and feature gates
- Neon for serverless Postgres (with Drizzle ORM) and the AI gateway the model is called through
- Sentry for errors, traces and logs from the app and every task run
- A computer per teammate: each bot gets a persistent Linux sandbox. Files it leaves there are still there next time.
- Live desktop view: watch a bot move the mouse and type, streamed into the chat over noVNC.
- Group chats with handoffs: a
handofftool passes the rest of a turn to the teammate whose job it is. A request can’t bounce back to a bot that already held it. - Memory across chats:
rememberandrecalltools read and write a notes file in the bot’s sandbox, shared by every conversation the bot is in. - Durable turns: the turn loop, streaming and transcript storage all run in a
chat.agent()task on Trigger.dev. - Plans and usage limits: model spend is recorded per turn in
onTurnComplete; sandbox time is metered every 5 minutes by a scheduled task that stops sandboxes once an owner runs out.
GitHub repo
View the AI Teammates repo
Click here to view the full code for this project on GitHub. It’s maintained by Code With Antonio,
and you can fork it and use it as a starting point for your own project.
How it works
The chat agent
Onechat.agent() answers every chat, direct or group. The browser sends the botId a message is addressed to as typed client data, and the agent loads that bot’s job and instructions from the database on every turn, so edits to a bot apply to the next message.
Tools are built per chat in the tools callback: every bot gets its sandbox tools, and group chats also get the handoff tool. Declaring them on the agent config keeps screenshot tool results as images when earlier turns are replayed. The run function returns the managed streamText with 2 stop conditions: a 50-step cap for desktop work, and the user’s remaining model budget.
trigger/chat.ts
idempotencyKey on each usage record is built from the run ID and turn number, so a retried onTurnComplete can’t charge the same turn twice.
Metering sandboxes with a scheduled task
Daytona stops idle sandboxes on its own and doesn’t report running time, so the app measures it by looking. A scheduled task runs every 5 minutes, charges each running sandbox’s owner for the interval, and stops the sandboxes of owners with no hours left:trigger/usage.ts
The Next.js chat UI
The browser talks to the agent directly throughuseTriggerChatTransport. Server actions check that the signed-in user owns the chat and has a plan with the bots feature before they start a session or mint a session-scoped access token. Previous messages load with useLoadTranscript from the agent’s default transcript storage:
components/chat.tsx
actions/chat.ts
Running it
You need accounts with Clerk, Neon, Trigger.dev and Daytona (Sentry is optional). Set the variables listed in the repo’s README in.env.local, including TRIGGER_SECRET_KEY and TRIGGER_PROJECT_REF, then push the schema and run the app and the tasks in 2 terminals:
npx trigger.dev@latest deploy and add the tasks’ variables (DATABASE_URL, CLERK_SECRET_KEY, DAYTONA_API_KEY and the Neon AI gateway settings) on the Environment Variables page of your production environment. The repo’s README covers the Clerk Billing setup and hosting the Next.js app.
Relevant code
- Chat agent: trigger/chat.ts: the
chat.agent()definition, per-chat tools, handoffs, instructions, and per-turn usage recording - Sandbox metering: trigger/usage.ts: the scheduled task that charges and stops running sandboxes
- Global hooks: trigger/init.ts: Sentry setup with
tasks.onFailure,tasks.onWaitandtasks.onCompletehooks that flush logs before a run freezes - Sandbox tools: lib/sandbox-tools.ts: shell, file, mouse, keyboard, screenshot and memory tools on the bot’s Daytona sandbox
- Handoff tool: lib/handoff-tool.ts: passes a group chat turn to another bot
- Server actions: actions/chat.ts: session start, token minting and transcript loading, each behind an ownership and plan check
- Chat UI: components/chat.tsx:
useTriggerChatTransport,useLoadTranscriptanduseChat - Trigger.dev config: trigger.config.ts: retries, max duration and the Sentry source map build extension
Learn more
AI chat overview
How chat agents, sessions, and the turn loop work.
Frontend
The chat transport, session tokens, and reconnection.
Tools
Declaring tools on your agent and how they persist across turns.
Scheduled tasks
Run tasks on a cron schedule.

