An AI data analyst that replicates the ChatGPT Containers pattern: a persistent sandbox where code execution state survives across conversation turns.
Built with E2B (cloud sandboxes), Durable Endpoints (with Inngest), and Claude.
Each LLM call and code execution is a durable step (step.run()). If anything fails, Inngest retries from the last successful checkpoint.
git clone https://github.com/inngest/e2b-durable-endpoints-chatgpt-containers.git
cd e2b-durable-endpoints-chatgpt-containers
npm install
Create a .env.local file:
ANTHROPIC_API_KEY=your-anthropic-key
E2B_API_KEY=your-e2b-key
# Optional: enables the web_search tool
EXA_API_KEY=your-exa-key
Run the application and Inngestdev server:
npx inngest-cli@latest dev
npm run dev
Open http://localhost:3000.
src/
app/
api/
chat/route.ts # Durable endpoint: LLM + E2B tool-calling loop
events/route.ts # Polling endpoint for progress events
page.tsx # Chat UI
components/
ChatMessage.tsx # Message rendering (code blocks, charts, search results)
ChatInput.tsx # Input field
CodeBlock.tsx # Collapsible code display
ChartImage.tsx # Base64 chart rendering
hooks/
useChat.ts # Chat state + event polling
inngest/
client.ts # Inngest client config
execute-code.ts # E2B code execution wrapper
mcp-client.ts # Sandbox creation + Exa search
event-store.ts # In-memory event store with dedup
types.ts # Shared types
Persistent sandbox: the E2B sandbox stays alive for 30 minutes. Ask “load this data”, then “filter by 2025”, then “chart it”. Each step builds on the previous state.
Durable execution: every LLM call and code execution is wrapped in step.run(). If the server crashes mid-conversation, Inngest replays from the last checkpoint.
Web search (optional): if EXA_API_KEY is set, Claude gets a web_search tool to find data sources before writing code.