Knowledge transfer · Nov 2026
Welcome to KT of @ai
Intro
Objectives
- We launched @ai about 2 months ago, so a KT is overdue: how it was made, and why. - link
- I'm on leave 12–24 November, so someone needs to handle issues while I'm away. - link
Backstory
- @ai started as a tool for my team (web), as an extension of appbuilder.
- Around then, Pat/Gaurav were looking for a company agent and had set up the Razorpay meeting.
- @ai was nearly done for web, so we widened it to every team and added budgets and company skills.
Today it's a general purpose assistant for DB's tech and product teams: coding, PR reviews, debugging, design, PRDs and QA.
How @ai works
What is @ai?
A cloud agent built on the eve framework, which gives it a durable harness on Vercel's infrastructure.
Life of a request
Every message takes the same path through @ai's architecture. Click a step to see it on the diagram.
Ingress
Inside the Function:
- A message comes in from the web or Slack.
- We verify who you are and that you're approved.
- Voice notes are transcribed (Slack only).
- We resolve the agent.
- We pick a sandbox: home, fresh or named.
Turn setup
Inside the durable run:
- The run starts or resumes: one chat is one eve session is one workflow run.
- We check your budget and pick the model, with a fallback.
- We assemble the context: instructions, memories, connections, skills.
The agent loop
Until the model stops calling tools:
- The model is called through AI Gateway.
- Each tool call is checked for approval.
- We get your token for the service, or ask you to sign in.
- The tool runs, the step is saved, and the loop goes back to 9.
Finish
- The reply streams back to the web chat or Slack thread.
- After the turn: title, analytics, Slack thread index.
Is @ai just eve?
No. eve is a thin layer over Vercel's primitives: it gives you slots, and what goes in them is ours.
agent/plugs into eve's slots, one small file each (~8k lines).services/holds the implementations: auth, budgets, sandboxes, GitHub, connectors, memory, analytics (~32k lines).app/is the dashboard.
What we built on top of eve
Git integration
A token that can push can push to any branch, including main. We wanted pushes only to gluon/*, and only the commit asked for. So: the write token never goes anywhere the agent controls. Here's the path a commit takes:
- Clone and fetch are read-only:
git pushfrom the sandbox is rejected. - The agent asks to push one commit to a
gluon/*branch, throughpush_branch. - We bundle the commit and copy it out to a fresh push sandbox.
- The push sandbox verifies it with the network sealed.
- The network opens for two requests, with the push token added at the firewall.
- We open the pull request from our server, with a separate PR token.
- Merging needs the requester's approval; on db-digital a person merges.
Claude Code and Codex, on your own plan
@ai can hand coding to Claude Code, Codex or OpenCode in your sandbox, signed in with your own plan, so it doesn't spend @ai's budget. Here's how one task runs:
- Skills, not connectors. Each CLI is a skill over four tools:
shell__login,shell__run,shell__status,shell__cancel. - You sign in yourself through a private card. The sign-in stays in the sandbox, so your home sandbox keeps you signed in for the week.
- Tasks run in the background for up to 2 hours, one per chat. When one ends, @ai wakes up, reviews and replies.
- Follow-ups resume the exact session, by its saved ID.
Why you sign in yourself
Anthropic's terms don't let a third-party app store your subscription token or send requests through it, but do let you sign in to the unmodified Claude Code yourself. Codex follows the same pattern.
The catch: the sign-in lives in the sandbox
- Only the owner can use it. Others in a shared thread can't run the CLIs: their commands that mention one are blocked, unless Jev is sure it's just text.
- Signing out is real.
codex logoutrevokes the login on OpenAI's side.
Code: agent/skills/claude-code/SKILL.md, agent/skills/codex/SKILL.md, services/background-command/, services/cli-auth/
Automations: schedules and triggers
@ai can start on its own, on a timer or on a Slack message. Set it up in chat ("every weekday at 9, summarise yesterday's Sentry errors here") or on the Schedules and Triggers pages. Each run is a new chat, as you.
Schedules
A cron, a time zone and a task (how one runs).
- A Vercel cron ticks every minute and starts the schedules that are due, 25 at a time. A failed start retries in 5 minutes.
- The reply goes to the Slack thread it was set up in, or the dashboard.
- Running past its expected duration (10 min default, 15 max) sends a notice; the run continues.
maxRuns: 1makes a one-off.
Triggers
A run starts when a Slack message matches: up to 10 public channels, up to 10 allowed authors, and a regex. The match is queued, the next tick runs it, and @ai replies in its thread (from setup to run).
Guarding triggers
A trigger runs with your access on a message someone else wrote, so:
- Allowed authors only.
- A narrow task: Jev checks it's one specific job when you create it.
- A benign message: Jev checks each message before the run; a flagged one is skipped.
- Untrusted input: the message reaches the agent as data, not instructions.
- Limits: 20 runs per trigger per hour, 10 triggers per person.
Code: agent/schedules/dynamic.ts, agent/schedules/triggers.ts, services/triggers/server/trigger-safety.service.ts
Named sandboxes: your environment, kept
A new sandbox per chat would mean signing in to your CLIs every time. So a chat gets one of three:
- Home, the default: shared by your new chats for 7 days, with files and sign-ins. Then a new one.
- Named: "save this sandbox as cms-revamp" keeps a fresh sandbox for good; "use my cms-revamp sandbox" brings it back.
- Fresh: empty, when you ask for one.
How it works
- Jev picks on the first message, and the pick is fixed for the chat. Unsure means home.
- Sandboxes sleep when idle and resume from a snapshot: files survive, processes don't.
- Only the owner gets the keys to CLIs, the terminal and the editor.
- Chats can share a named sandbox, so keep parallel work on separate branches.
- Forgetting one deletes it, and chats using it lose access rather than get an empty one.
Code: services/sandbox/server/saved-sandbox.service.ts, services/sandbox/server/saved-sandbox-backend.ts, agent/sandbox.ts
CloudWatch proxy: estimate, then budget, then run
Logs Insights bills per GB scanned, and the AWS MCP's run_script will run any query. So our query tool:
- Estimates with a free
| estimaterun. - Checks your monthly budget ($20 by default).
- Runs the query and records the actual cost.
run_script is still there, but a log query in disguise is blocked and sent to our tool. The MCP gets you access; the harness gets you control.
Code: services/cloudwatch/server/query.service.ts, services/cloudwatch/server/script-guard.service.ts
Jev: a small classifier for judgment calls
Jev (typesafe-ai/jev) picks one of a few choices, with a probability for each. Every check has a 0.8–0.9 bar and a timeout; unsure, slow or failed means no. We use it for:
- Sandbox selection: home, fresh or named?
- Memory safety: is this fact safe to remember?
- Triggers: is the task narrow, and the message benign?
- Slack follow-ups: is this reply meant for @ai?
- Coding CLI guard: does this command run the owner's CLI?
- CloudWatch scripts: is this a log query in disguise?
Real story: the follow-up check acted on 51% "yes" answers, so @ai kept replying to colleagues. A 0.8 bar and an "uncertain" choice fixed it.
Multi-agent, built but disabled from the frontend
We built a full agent builder: agents with their own prompt, model, connections, skills and sandbox, and up to 5 specialists each. Then we asked why a web bot and a CMS bot need to differ if one bot can do it all. So it's still in the code, just hidden: everyone talks to @ai, and there's one place to debug.
Challenges
Connectors, and why MCPs aren't enough
@ai has 27 connectors: 17 MCP servers (Sentry, Linear, Slack, Axon…), 7 of our own tools (Coding, SolarWinds, Crashlytics, Drive, Artifacts…), and 3 hybrids (AWS, Vercel, Convex).
The catch with MCP
Every tool result goes straight into the model's context. An hour of logs is megabytes of text: the call fails, or you pay for it on every later step.
So our data connectors work like an engineer:
- Download, don't return. SolarWinds writes logs to a file in the sandbox and returns only the path.
- Then dig with
rg,jqandhead. Only what's printed reaches the context. - Same for big payloads: Crashlytics, Vercel billing, Drive files.
- Artifacts work in reverse: the agent writes the page to a file and passes the path.
MCP gets you access; the harness decides what reaches the model.
Sidenotes
- Axon was the surprise winner. Many questions turn out to be data questions, and Axon cost-checks the SQL, runs it read-only, and builds Metabase dashboards.
- @ai is an MCP server too, usable from Claude Code, Codex or Cursor: Gluon Platform (schedules, triggers, usage, bug reports) and Gluon Agent (start or continue an @ai chat, as you).
@ai KT