Skip to content

fly-apps/tanstack-sprite-agent

Repository files navigation

tanstack-sprite-agent

tanstack-sprite-agent

Claude with a real Linux sandbox — a Sprite (Fly.io) — in one chat() call.

MIT License TanStack AI Sprites Node >= 22


A chat app that gives Claude a real Linux sandbox — a Sprite (Fly.io) — through a single run_bash tool. Ask it to inspect the machine, write and run code, install packages, or drive a git repo, and it does the work inside an isolated, disposable Sprite and streams the results back.

  • Chat@tanstack/ai + @tanstack/ai-anthropic (anthropicText).
  • Execution@tanstack/ai-sandbox-sprites (SpritesClient): the run_bash tool runs commands inside a Sprite and streams stdout/stderr/exit back to the model.
  • UI — React + Vite + Tailwind v4 with shadcn (Base UI) chat components: MessageScroller (auto-scrolls the live edge), Message, Bubble, Marker (each run_bash step renders as an inline marker with a spinner + shimmer while it runs), plus markdown-rendered responses.

When the model needs to run something, chat()'s agent loop calls run_bash; the tool execs the command in a Sprite (created lazily on first use and reused) and the model reads the real output.

Screenshot 2026-07-01 at 13 06 00

Quick start

Prerequisites: Node.js ≥ 22 and pnpm (npm i -g pnpm), plus two credentials:

Credential Where to get it
ANTHROPIC_API_KEY console.anthropic.com — the chat model
SPRITES_API_KEY sprites.dev — the sandbox (org/projectNumber/tokenId/secret)

1. Clone & install

git clone https://github.com/fly-apps/tanstack-sprite-agent
cd tanstack-sprite-agent
pnpm install

2. Add your keys — copy the template and fill it in:

cp .env.example .env
# then edit .env and set ANTHROPIC_API_KEY and SPRITES_API_KEY

3. Run — builds the UI, then serves it + the API on port 8080:

pnpm serve

.env is loaded automatically (node --env-file-if-exists=.env). Open http://localhost:8080 and try:

  • "What OS, kernel, and node version is this sandbox?"
  • "Write fib.py that prints the first 10 Fibonacci numbers, then run it."
  • "Create a git repo, add a README, and show me the log."

The first request provisions a fresh Sprite and can take ~1–3 min; after that it's fast.

Development

Run the API and the Vite dev server side by side (the Vite dev server proxies /api:8081, giving you UI hot-reload):

PORT=8081 pnpm start   # API on :8081 (loads .env)
pnpm dev               # Vite UI with hot reload

How it fits together

server.mjs            Node http server: serves the built UI + POST /api/chat (SSE)
src/App.tsx           the chat UI (shadcn Base UI components + markdown)
src/lib/use-sandbox-chat.ts   streaming hook: parses the AG-UI SSE into messages + tool steps
src/components/ui/    shadcn Base UI components (message-scroller, message, bubble, marker, spinner, …)

The browser POSTs the conversation to /api/chat; the server runs chat() with the run_bash tool and streams AG-UI Server-Sent Events back (text deltas + TOOL_CALL_*), which the client renders as chat bubbles and tool markers.

Notes

  • Model. Defaults to claude-sonnet-5; set ANTHROPIC_MODEL to any Anthropic model id (e.g. claude-opus-4-8).
  • One shared sandbox. The demo creates a single Sprite on first tool use and reuses it. A production app would key a sandbox per session (see @tanstack/ai-sandbox's defineSandbox / withSandbox) and tear it down when done.
  • The Anthropic key stays on the server — nothing sensitive is written into the Sprite; the Sprite only ever runs the commands the model requests.
  • Cold start. The first run_bash in a fresh Sprite waits for it to provision (~1–3 min); after that calls are fast, and an idle Sprite resumes on the next exec.

Deploy on a Sprite

The app is a plain Node server, so it runs anywhere. To host it on a Sprite and expose it at the Sprite's public URL, run it as a service bound to the proxied HTTP port:

sprite-env services create tanstack-sprite-agent \
  --cmd /.sprite/bin/node --args server.mjs \
  --dir "$PWD" \
  --env "ANTHROPIC_API_KEY=…,SPRITES_API_KEY=…,PORT=8080" \
  --http-port 8080

License

MIT