Textcrew
2026Personal AI agent platform · Live
Textcrew is a messaging-first personal assistant, live on the web and Telegram. Each user texts Tex, their own AI agent. Tex splits the job into steps and calls in specialists when they fit: Byte writes code, Patch reviews pull requests and Scout searches the web. The crew works in the user's apps (Gmail, GitHub, Google Calendar, Google Docs and more), asks before anything risky, runs automations, and is billed in credits, or users bring their own Claude plan or API key. I did the system design and backend engineering: the architecture, the API contract, the backend (api + worker) and the Go service that manages every user's container.
- TypeScript
- Go
- gRPC
- MCP
- BullMQ
- gVisor
The problem
The idea is to text an assistant the way you would text a person, and have it do real work in your accounts. Building the backend for that means solving several problems at once:
- Running a separate agent for every user, with its own memory and files, without letting it reach anything it shouldn't.
- Taking messages from four channels with different rules, and never handling one user's messages out of order.
- Letting the agent act in Gmail or Slack without it sending or deleting anything the user didn't agree to.
- Charging for AI usage correctly, including refunds when the platform is at fault.
- Keeping costs down by waking containers only when there is work to do.
What I built
System design and backend engineering: the architecture, the API contract, the backend (api and worker) and the Go container manager. The agent inside each container is Hermes Agent; I wrote the Python Bridge that runs it and connects it to the platform.
I built it with Claude Code, splitting the design into build phases and running parallel agents on separate git branches.
Architecture
- Modular monolith
- One TypeScript codebase run as two processes: an api (Hono: REST, SSE, webhooks and an MCP server) that only adds jobs, and a worker (BullMQ) that only runs them. Nine modules, each owning its own tables; other modules call its functions, never its tables.
- vm-manager
- A separate Go service and the only thing with Docker access, which makes it a privilege boundary. It creates, wakes, stops and deletes each user's container. The backend talks to it over gRPC, with a server-streaming call for message delivery.
- Agent container
- One per user, running under gVisor: the Hermes agent plus a Python Bridge adapter I wrote. Its only way out is a Squid egress proxy with a per-user allowlist.
- Platform MCP server
- The agent's tools: send a message, run an app action, request approval, create an automation and so on. The user id always comes from the container's token, so an agent can never act as another user.
- Contract first
- OpenAPI 3.1 drives routing, auth and request validation, and tests check every response against the spec. The gRPC proto is shared by both services.
Engineering highlights
1.Webhooks never do work
Each webhook is verified, saved as a deduplicated event and turned into a job, then answered with 200. Four queues, retries with backoff, and a per-user Redis lock so one user's messages never run in parallel. Jobs are safe to re-run, and the system recovers if Redis is lost.
2.Credits without a stored balance
Credits are grants plus an append-only ledger; a database trigger rejects edits to ledger rows. The balance is always computed, never stored. Credits are spent in expiry order and every charge has an idempotency key. The AI budget is enforced live through LiteLLM virtual keys, and turns that fail because of the platform are refunded.
3.Approvals tied to the exact action
Risky actions (send, delete, pay) need a single-use approval bound to the exact action and arguments the user saw. Approvals never block the agent: it ends its turn, and the user's ✅ or ❌ arrives later as a new message that resumes the session.
4.Container lifecycle
Containers stop after 3 idle minutes but never mid-turn. An awake cap evicts the lowest-priority, longest-idle container first. Health checks restart broken containers, a reconciler fixes drift between Docker and the database, image rollouts keep the user's data, and stuck turns are force-stopped and refunded.
5.Routing before waking
A classifier (TypeSafe Jev) sorts each message as simple, a task, or spam. Simple messages get a cheap-model reply and no container wakes up. If the classifier is down or unsure, the message is treated as a task.
Also built
- Coupon codes stored only as hashes, with rate limits, one generic error for every failure, and an atomic redemption cap tested with 50 parallel redemptions on a real Postgres.
- Channel details: WhatsApp's 24-hour window and templates, Telegram inline buttons, iMessage yes/no replies, voice-to-text and media downloads.
- Dodo payments (subscriptions, top-ups, refunds, chargebacks) and plans.
- Automations on cron with timezones, app-event triggers, and auto-pause at zero credits.
- Bring-your-own AI key, a waitlist with abuse monitoring, backups, metrics and alerts.
In numbers
- backend tests on real Postgres and Redis, plus Go and Python suites
- 188backend tests on real Postgres and Redis, plus Go and Python suites
- API endpoints, all covered by contract tests
- 51API endpoints, all covered by contract tests
- database tables
- 25database tables
- gRPC calls
- 11gRPC calls
- agent tools
- 9agent tools
- job queues
- 4job queues
- chat channels
- 4chat channels
- app integrations
- 25app integrations
Tech stack
- Backend
- TypeScript (strict), Node 22, Hono, BullMQ, Redis, Postgres, Drizzle, Zod
- Contracts
- OpenAPI 3.1, Ajv, openapi-typescript, Redocly, gRPC, Connect-ES, grpc-go, buf
- Agent & AI
- MCP TypeScript SDK, Hermes Agent, Python, LiteLLM, Composio
- Sandbox & infra
- Go, Docker Engine SDK, gVisor, Squid, Caddy, GitHub Actions
- Services
- Clerk, Dodo Payments
- Tooling
- Vitest, pnpm
Status
Live. Textcrew runs on the web app and Telegram, with a free plan and paid plans. WhatsApp and iMessage are not live yet. See it at textcrew.in.
The repositories are private, so there is no source link.