Architecture
TinyFat is built on open-source components with a transparent architecture.
The stack
Section titled “The stack”| Component | Technology | Purpose |
|---|---|---|
| Agent runtime | troublemaker | Claude-powered agent framework (open source) |
| Container | Cloudflare Sandbox SDK | Secure container execution |
| Storage | Cloudflare R2 | Per-agent persistent storage (S3-compatible) |
| Platform | Astro on Cloudflare Pages | Dashboard, landing page |
| Queue | Cloudflare Queues | Webhook delivery, dedup, retry |
| Resend | Inbound/outbound email | |
| Database | Supabase | User accounts, agent config, secrets |
| Skills | fat-skills | Platform skills (browser, PDF, etc.) |
The key insight
Section titled “The key insight”Agent identity lives entirely in R2 storage, not the container.
All agents share the same stateless container image. Each agent gets R2 credentials scoped to their storage prefix (agents/{id}/). The container mounts that prefix at /data. Your agent sees only its files.
┌─────────────────────────────────────────────┐│ Shared Sandbox Container ││ (stateless - same code for all agents) │├─────────────────────────────────────────────┤│ Agent A: r2:bucket/agents/a/ → /data ││ Agent B: r2:bucket/agents/b/ → /data │└─────────────────────────────────────────────┘Four channels, one brain
Section titled “Four channels, one brain”Your agent runs on all channels simultaneously:
| Channel | How it works |
|---|---|
| Send an email, get a reply. Async, one turn per email | |
| Telegram | Chat with your bot. Instant ack, then reply |
| Slack | @mention in your workspace. 👀 ack, then reply |
| Web Chat | Real-time streaming (coming soon to dashboard) |
All channels share the same agent storage, memory, and sessions.
Request flow
Section titled “Request flow”1. You email yourname@tinyfat.com2. Resend receives it, sends webhook to platform3. Platform verifies signature, resolves agent, validates sender4. Message queued for async delivery5. Sandbox container wakes, R2 mounted at /data6. troublemaker processes your message7. Agent writes response to /data/outbox/email/8. Platform sends the reply via Resend9. You receive the responseTelegram / Slack
Section titled “Telegram / Slack”1. You message the bot2. Platform receives webhook, sends instant ack3. Message queued for async delivery4. Sandbox container wakes, troublemaker processes5. Agent replies on the same channelWeb Chat
Section titled “Web Chat”1. You type a message in the dashboard2. Platform opens SSE stream, wakes sandbox3. troublemaker streams response in real timeComponents
Section titled “Components”troublemaker (Agent Runtime)
Section titled “troublemaker (Agent Runtime)”Open-source TypeScript agent runtime running inside the container:
- Unified HTTP gateway on port 3002 with path-based routing
- Adapters for email, Telegram, Slack, and web chat
- Readiness gate (503 until adapters initialize)
- Context sanitization (strips orphaned tool_results)
- Event scheduling (cron-like scheduled tasks)
- Session and memory management
- Auto-detects available adapters from environment variables
fat-skills (Platform Skills)
Section titled “fat-skills (Platform Skills)”Skills cloned into the container image at /opt/fat-skills/:
- browser-tools — Headless Chrome CLI (screenshot, navigate, eval)
- gh-login — GitHub CLI authentication
- pdf-gen — PDF generation with headless Chrome
Platform Orchestrator
Section titled “Platform Orchestrator”A Cloudflare Worker that handles:
- Webhook routing for all four channels
- Signature verification per-adapter
- Async delivery via CF Queue (dedup, retry, DLQ)
- Sandbox lifecycle (wake, mount R2, start troublemaker)
- Agent provisioning
- Scheduled wake via Durable Object alarms
Webhook queue
Section titled “Webhook queue”External webhooks are queued for reliability:
- Immediate ack — Platform returns 200 to Telegram/Slack instantly
- CF Queue — Messages enqueued with dedup IDs (5-min TTL via KV)
- Retry — Queue retries failed deliveries with DLQ fallback
- Secrets re-fetched — Consumer re-reads secrets from DB at delivery time
This prevents webhook timeout cascades under load.
Scheduled wake
Section titled “Scheduled wake”Your agent can schedule future events (cron-like). The platform acts as a process supervisor:
- After every interaction, the platform reads the wake manifest from troublemaker
- All event timestamps are stored in a Durable Object’s SQLite table
- DO alarms fire at each registered time, waking the container
- Events are processed, manifest re-synced
Even when your container is asleep, the platform wakes it at the right time.
Storage layout
Section titled “Storage layout”Per-agent prefix in R2: agents/{agent_id}/
agents/{agent_id}/├── MEMORY.md # Agent's persistent memory├── config.json # Agent preferences (model, etc.)├── sessions/│ └── {id}.jsonl # Conversation history files├── outbox/│ ├── email/ # Pending emails (written by agent)│ ├── sent/ # Successfully sent│ └── failed/ # Failed to send└── events/ └── {name}/ # Scheduled event filesSecurity model
Section titled “Security model”API keys
Section titled “API keys”Your Anthropic API key is encrypted at rest using AES-256-GCM. It’s only decrypted when starting your container, injected as an environment variable, and never logged.
Allowed senders
Section titled “Allowed senders”Only whitelisted emails can trigger your agent. This prevents spam triggering expensive API calls. Your signup email is automatically added.
Container isolation
Section titled “Container isolation”Each agent run is isolated:
- Scoped R2 credentials (can’t access other agents’ data)
- Container sleeps after inactivity timeout
- Webhook signatures verified per-adapter
Provisioning
Section titled “Provisioning”New agents are provisioned when you email start@tinyfat.com:
- Platform creates a user account (if new)
- Generates a unique name (
swiftpebble,calmflint, etc.) - Creates agent record, email alias, allowed senders
- Seeds
MEMORY.mdand outbox directories in R2 - Sends welcome email + agent hello email
The outbox pattern
Section titled “The outbox pattern”Agents don’t send emails directly. They write JSON files to /data/outbox/email/. The platform reads these and sends via Resend. See The Outbox Pattern.
Open source
Section titled “Open source”The agent runtime is fully open source:
- troublemaker: github.com/tinyfatco/crawdad
- fat-skills: github.com/tinyfatco/fat-skills
Next steps
Section titled “Next steps”- The outbox pattern — How email sending works
- Memory & persistence — How data survives restarts