TL;DR
21st SDK and TerminalUse both solve the same fundamental problem: deploying production AI agents. But they take very different architectural paths to get there. 21st SDK is a TypeScript-first, component-driven platform built around the Claude Code runtime with a drop-in React chat UI. TerminalUse is a Python-first, Kubernetes-native platform designed as "Vercel for background agents" with a filesystem-centric model.
This article breaks down every architectural decision, feature, and trade-off between the two platforms.
Architecture Philosophy
The two platforms diverge fundamentally in how they think about what an "agent" is.
21st SDK: Relay + E2B Sandbox
21st SDK uses a Relay architecture. When a user sends a message:
- Your app calls the Chat API
- The Relay (runtime service) authenticates the request, resolves agent config
- Relay provisions an E2B sandbox (isolated Linux environment)
- The agent runtime (Claude Code / Codex) starts inside the sandbox
- User tools + MCP servers are loaded
- Response streams back via SSE (Server-Sent Events)
The Relay is the intermediary that handles auth, routing, sandbox provisioning, token counting, cost tracking, and session persistence. Developers never interact with the Relay directly - the SDK handles it.
TerminalUse: Kubernetes + Bubblewrap
TerminalUse uses a Kubernetes-native architecture with 11 foundational primitives:
- Namespace - top-level isolation (gets its own K8s namespace, GCS bucket, GCP service account)
- Project - collaboration boundary
- Filesystem - persistent files mounted at
/workspace - Agent - a deployed Python runtime
- Environment - deployment policies (production, preview)
- Branch - deployment slot tied to git branches
- Version - immutable build artifact
- Task - one running conversation
- Event - input to tasks
- Message - output from agents
- State - per-task persisted JSON
Two operational loops: Deploy Loop (code -> tu deploy -> version -> environment) and Run Loop (filesystem -> task -> event -> message -> filesystem).
Key Difference
21st SDK abstracts away infrastructure entirely - you don't think about containers, replicas, or orchestration. TerminalUse exposes infrastructure as first-class primitives - you manage namespaces, branches, versions, and replica counts directly.
Agent Definition & Languages
| 21st SDK | TerminalUse | |
|---|---|---|
| Primary language | TypeScript/JavaScript | Python |
| Additional languages | Go (full support), Python (server SDK only) | TypeScript (app SDK only) |
| Agent definition | agents/<slug>/index.ts with agent() config wrapper | src/agent.py with AgentServer() class + lifecycle hooks |
| Config format | Code-as-config (TypeScript) | config.yaml + Python code |
| Scaffolding | npx @21st-sdk/cli init scaffolds agent directory | tu init generates project structure |
21st SDK Agent Definition
import { agent, tool } from "@21st-sdk/agent"
import { z } from "zod"
export default agent({
model: "claude-sonnet-4-6",
runtime: "claude-code",
systemPrompt: "You are a helpful assistant.",
permissionMode: "bypassPermissions",
maxTurns: 30,
maxBudgetUsd: 2,
tools: {
search: tool({
description: "Search docs",
inputSchema: z.object({ query: z.string() }),
execute: async ({ query }) => ({
content: [{ type: "text", text: "results" }],
}),
}),
},
})TerminalUse Agent Definition
# src/agent.py
from terminaluse.lib import AgentServer, TaskContext
server = AgentServer()
@server.on_create
async def handle_create(ctx: TaskContext):
await ctx.state.create({"status": "started"})
await ctx.messages.send("Welcome!")
@server.on_event
async def handle_event(ctx: TaskContext, event):
state = await ctx.state.get() or {}
await ctx.state.update({"turns": state.get("turns", 0) + 1})
await ctx.messages.send("Processed your message")
@server.on_cancel
async def handle_cancel(ctx: TaskContext):
passKey Difference
21st SDK uses a declarative approach - you declare what the agent is (model, tools, prompt) and the platform handles the lifecycle. TerminalUse uses an imperative approach - you write lifecycle hooks (on_create, on_event, on_cancel) that control exactly what happens at each stage.
Runtime & Model Support
Both platforms support Claude and OpenAI models, but differ in how they expose the runtime and what comes out of the box.
| 21st SDK | TerminalUse | |
|---|---|---|
| Runtime approach | Managed - platform runs Claude Code / Codex runtime for you | BYO - you call Claude SDK or Codex SDK from your Python code |
| Supported models | Any model via OpenRouter (Claude, GPT, Gemini, GLM, etc.) | Any model - you import the SDK you need |
| Model switching | Runtime toggle for end users, per-request override | Developer-controlled in code |
| Built-in tools | Bash, Read, Write, Edit, Glob, Grep, WebSearch, WebFetch | No built-in tools (BYO) |
| Custom tools | Zod-schema typed tools in TypeScript | Python functions via ADK |
| MCP support | Full MCP protocol via .mcp.json | Not documented |
Built-in Tools Comparison
21st SDK ships with 8 built-in tool categories that are enabled by default when using the Claude Code runtime:
- Read-only: Read, Glob, Grep (file search and read)
- Edit: Edit, Write (create and modify files)
- Execution: Bash (run shell commands)
- Web: WebFetch, WebSearch (fetch URLs and web search)
TerminalUse does not include built-in tools - you bring your own via the Agent Development Kit (ADK) or connect external SDKs (Claude Agent SDK, Codex Agent SDK).
Sandbox & Execution Environment
| 21st SDK | TerminalUse | |
|---|---|---|
| Sandbox technology | E2B (dedicated microVMs) | Bubblewrap (Linux namespaces) |
| Isolation level | Full VM-level isolation | Process-level namespace isolation |
| Specs | Up to 8 CPU, 8 GB RAM | Not publicly documented |
| Pre-installed tools | Node 24, git, curl, ripgrep, GitHub CLI | Depends on Dockerfile |
| Persistence | Sandbox persists across messages, destroyed on idle | Filesystem persists independently of tasks |
| Filesystem model | Per-sandbox filesystem | Shared filesystem entity, mountable across tasks |
| Concurrent access | "Last user wins" semantics | Conditional writes with version-based concurrency |
| Network access | Full (web search, API calls, git clone) | Full (maintained for model APIs and external services) |
Filesystem Philosophy
This is one of the most significant architectural differences:
21st SDK: The sandbox IS the filesystem. Each sandbox has its own isolated filesystem that persists across messages within that sandbox. When the sandbox is destroyed, the filesystem is gone.
TerminalUse: Filesystems are independent entities that can be created, shared, mounted (writable, read-only, or tmpfs), and persisted across multiple tasks and agents. Multiple agents can share the same filesystem. Files are backed by Google Cloud Storage with checksums for change detection.
TerminalUse's filesystem model is more powerful for workflows where multiple agents need to collaborate on shared files, or where file state needs to survive across many task lifecycles.
Deployment
| 21st SDK | TerminalUse | |
|---|---|---|
| Deploy command | npx @21st-sdk/cli deploy | tu deploy |
| Build system | esbuild (JS/TS) or Go toolchain | Docker container build |
| Target | E2B sandbox template | Kubernetes deployment |
| Environments | Via --name flag (e.g. --name my-agent-staging) | Named environments in config.yaml (production, preview) |
| Branch mapping | Manual via --name | Automatic: main -> production, others -> preview |
| Versioning | Auto-incrementing versions with status tracking | Immutable versions with status tracking |
| Rollback | npx @21st-sdk/cli rollback to switch active version | tu rollback to restore version + secrets snapshot |
| Replicas | Managed by platform | Configurable 1-10 replicas per environment |
| Task stickiness | N/A | Configurable: tasks stay on old version or migrate |
Deploy Pipeline Comparison
21st SDK (4 steps):
- Bundle - CLI bundles with esbuild
- Upload - bundle + metadata uploaded
- Sandbox - platform prepares E2B sandbox template
- Live - deployment is immediately live
TerminalUse (5 steps):
- Build - CLI builds Docker container
- Push - image pushed to Google Artifact Registry
- Deploy - platform creates K8s deployment
- Register - container starts and registers itself
- Ready - CLI polls until READY or FAILED
Key Difference
21st SDK optimizes for speed - deploy in seconds with zero Docker knowledge, with built-in versioning and rollback. TerminalUse optimizes for control - you get replica management, branch-to-environment mapping, and task stickiness policies, but you need Docker and the deploy is slower.
Streaming & API
Both platforms use Server-Sent Events (SSE) for streaming and are compatible with the Vercel AI SDK.
| 21st SDK | TerminalUse | |
|---|---|---|
| Streaming protocol | SSE | SSE |
| AI SDK compat | Native (useChat, createAgentChat) | Via @terminaluse/vercel-ai-sdk-provider |
| Stream resumption | Dedicated GET /stream endpoint | Last-Event-ID header |
| Stream cancellation | DELETE /stream endpoint | POST /tasks/{id}/cancel |
| Auth | JWT token exchange (an_sk_ prefix) | Bearer token (tu_ prefix) |
| ID prefixes | sb_ (sandbox), th_ (thread) | No documented prefix convention |
SSE Event Types
Both platforms stream rich, granular events -- not just text tokens.
21st SDK events (11 types):
start,finish,errortext-start,text-delta,text-endtool-input-start,tool-input-delta(streaming tool input JSON)tool-input-available(complete tool call),tool-output-available(tool result)message-metadata(sessionId, totalCostUsd, tokens, duration)
TerminalUse events:
start,finish,errorstart-step,finish-step(per-step token usage)text-start,text-delta,text-endreasoning-start,reasoning-delta,reasoning-endtool-input-start/delta/end,tool-call,tool-resulthandler-complete
Both protocols are comparable in richness. 21st SDK streams tool inputs and outputs as first-class events. TerminalUse adds explicit reasoning events and step-level boundaries.
Frontend & UI
| 21st SDK | TerminalUse | |
|---|---|---|
| Drop-in chat UI | Yes (<AgentChat> React component) | No |
| Theming & customization | Yes (CSS variables, presets, Theme Builder) | No |
| Tool call visualizations | Yes (file edits, terminal, web searches) | No |
| Frontend SDK | @21st-sdk/react, @21st-sdk/nextjs | @terminaluse/sdk, @terminaluse/vercel-ai-sdk-provider |
Key Difference
This is the largest gap between the two platforms. 21st SDK includes a production-ready chat UI with extensive theming, tool visualizations, and customization options. TerminalUse provides only SDKs - you build the entire UI yourself.
If you need a chat interface, 21st SDK saves weeks of frontend development. If you're building a backend-only agent (CI/CD pipelines, background jobs, data processing), TerminalUse's approach may be more appropriate.
State Management
| 21st SDK | TerminalUse | |
|---|---|---|
| Conversation model | Sandbox -> Threads -> Messages | Task -> Events (in) / Messages (out) |
| State persistence | Messages stored per thread in database | Explicit per-task JSON state via ctx.state |
| Multi-conversation | Multiple threads within same sandbox | One task = one conversation |
| History management | Relay appends newest turn, SDK restores via client.threads.get() | ADK provides adk.state CRUD |
| Cross-turn state | Implicit (sandbox filesystem + thread history) | Explicit (developer manages ctx.state.create/get/update) |
Key Difference
21st SDK manages state implicitly - the sandbox filesystem and thread history persist automatically. TerminalUse requires explicit state management - you call ctx.state.create(), ctx.state.get(), and ctx.state.update() to persist data across turns.
Cost Controls & Observability
| 21st SDK | TerminalUse | |
|---|---|---|
| Budget cap | Yes (maxBudgetUsd per conversation) | No |
| Turn limit | Yes (maxTurns) | No |
| Token & cost tracking | Yes (per-turn tokens, total USD) | Per-step token usage in SSE events |
| Web dashboard | Yes (sessions, costs, errors, live monitoring) | Yes (app.terminaluse.com, details not publicly documented) |
| CLI logs | Yes (npx @21st-sdk/cli logs) | Yes (tu logs) |
Skills & Knowledge Management
| 21st SDK | TerminalUse | |
|---|---|---|
| Skills system | SKILL.md files, auto-discovered, on-demand context | No equivalent |
| System prompts | Max 4,000 chars, sent every turn, layerable | Not documented as a platform feature |
| Per-request overrides | systemPrompt, maxTurns, maxBudgetUsd, disallowedTools | Not documented |
21st SDK's Skills system is unique - it provides structured knowledge management through filesystem-backed markdown files that are automatically discovered by the runtime and referenced on demand. This separates general instructions (system prompt) from detailed domain knowledge (skills).
Security & Access Control
| 21st SDK | TerminalUse | |
|---|---|---|
| Sandbox isolation | E2B microVM (full VM-level) | Bubblewrap (namespace-level) |
| Permission modes | Default, Accept Edits, Bypass All | Not documented |
| Env var handling | Encrypted, injected into sandbox runtime (not agent process) | Managed via tu env, secrets snapshot on deploy |
| Auth mechanism | API key -> JWT token exchange | API key + Webhook keys |
| Multi-tenant isolation | Per-sandbox | Per-namespace (K8s + GCS + GCP SA) |
| Access control | Team-scoped API keys | Role-based (discoverer/viewer/editor/owner/admin/executor) |
| Webhook verification | N/A | Dedicated webhook key system (internal, external, GitHub, Slack) |
Key Difference
21st SDK uses VM-level isolation (E2B microVMs) which provides stronger security boundaries. TerminalUse uses process-level isolation (bubblewrap with Linux namespaces) which is lighter but has a smaller isolation boundary.
TerminalUse has a more granular access control system with role-based permissions, dual-parent authorization, and multiple authentication mechanisms. 21st SDK keeps it simpler with team-scoped API keys and permission modes.
CLI Comparison
| Command | 21st SDK (npx @21st-sdk/cli, or 21st if installed globally) | TerminalUse (tu) |
|---|---|---|
| Install | npx @21st-sdk/cli | uv tool install terminaluse |
| Auth | login | login, logout, whoami |
| Scaffold | init | init |
| Deploy | deploy | deploy |
| Rollback | rollback | rollback |
| Env vars | env list/set/remove | env add/ls/get/rm/pull/import |
| Logs | logs with filters | logs with filters |
| Tasks | - | tasks create/send/list/pull/delete |
| Filesystem | - | fs create/push/pull/list |
| Projects | - | projects list/get/create/update/delete |
| Agents | agents, agents get/delete | agents ls/get/delete |
| Versions | versions / deployments | ls (list versions) |
TerminalUse has a richer CLI with full CRUD operations for tasks, filesystems, and projects. 21st SDK's CLI is focused on the agent lifecycle: scaffold, deploy, rollback, manage agents, and inspect versions.
API Surface Area
| 21st SDK | TerminalUse | |
|---|---|---|
| Sandboxes/Tasks | Create, Get, Delete sandbox | Create, List, Get, Update, Cancel, Migrate tasks |
| Sandbox Operations | Exec command, Write files, Read file, Git clone | - |
| Threads/Events | List, Create, Get, Delete threads | Send events, list events |
| Chat/Messages | Send message (SSE), Resume stream, Cancel stream | Send event, stream SSE, list messages |
| Files | Write/Read via sandbox API | Create filesystem, Upload/Download, Presigned URLs |
| State | Implicit (sandbox + thread) | Full CRUD on per-task JSON state |
| Agents | List, Get, Delete agents | - |
| Deploy | Via CLI, versioned | Via CLI + API endpoint |
| Versions | List deployments, Rollback | Redeploy, Rollback |
TerminalUse has a larger API surface with more fine-grained control over every entity. 21st SDK's API covers the full agent lifecycle (deploy, version, rollback, manage) while abstracting away lower-level infrastructure.
When to Choose 21st SDK
- You want a chat UI out of the box with theming and tool visualizations
- Your agents are conversational (chatbots, assistants, support agents)
- You prefer TypeScript/JavaScript for agent code
- You want zero infrastructure management (no Docker, no K8s)
- You need built-in Claude Code tools (Bash, file operations, web search)
- You want fast deploys (seconds, not minutes)
- You need cost controls (budget caps, turn limits) as platform features
- You want per-request runtime overrides without redeploying
- You need a rich observability dashboard with live monitoring
- You need stronger security isolation (VM-level sandboxing, encrypted environment variables)
When to Choose TerminalUse
- You need shared filesystems across multiple agents
- You want full infrastructure control (replicas, branch mapping, task stickiness)
- You need granular access control with roles and permissions
- You need task migration between versions
- You want conditional file writes with version-based concurrency
- Your workflow requires the Deploy Loop + Run Loop model
- You need explicit state management with per-task JSON state
Summary Table
| Dimension | 21st SDK | TerminalUse |
|---|---|---|
| Philosophy | Abstraction-first, code-as-config | Control-first, infrastructure-as-primitives |
| Language | TypeScript (+ Go) | Python |
| Sandbox | E2B microVMs | Bubblewrap (Linux namespaces) |
| Deployment | esbuild -> E2B template (seconds), versioned with rollback | Docker -> Kubernetes (minutes) |
| Chat UI | Drop-in <AgentChat> with 70+ theme vars | BYO |
| Built-in tools | 8 tool categories | None |
| Filesystem | Per-sandbox, ephemeral | Independent entity, persistent, shareable |
| State | Implicit (sandbox + threads) | Explicit (per-task JSON CRUD) |
| Cost controls | maxBudgetUsd, maxTurns | Not documented |
| Observability | Dashboard + CLI logs | CLI logs |
| Access control | Team-scoped API keys | Role-based with dual-parent auth |
| CLI richness | 8 command groups | 15+ command groups |
| API surface | ~15 endpoints | ~50+ endpoints |
| Skills system | SKILL.md auto-discovery | No equivalent |
| Streaming | SSE (11 event types, tool streaming) | SSE (reasoning + step boundaries) |
| Best for | Conversational agents with UI | Background agents with file workflows |



