Amplify is built as a single-package monorepo using Remix v2.15 + React 18 + Vercel AI SDK v7. This page covers every major subsystem and how they connect.
Architecture overview
Amplify has six core subsystems that work together:
Single-package monorepo
Amplify is NOT a multi-package monorepo. It uses a single package.json with pnpm 9.14.4. The app/ directory contains all UI components, stores, and services. The electron/ directory is a separate entry point for the desktop build.
Frontend (Remix + React 18)
The frontend is built with Remix v2.15 on top of React 18 and Vite for the build toolchain.
Key frontend components:
| Component | Purpose | Location |
| BaseChat | Main chat interface | app/components/chat/BaseChat.tsx |
| Chat.client | SSE stream handler + mutation signal parser | app/components/chat/Chat.client.tsx |
| Terminal | xterm.js terminal (3 shell types) | app/components/workbench/terminal/Terminal.tsx |
| Preview | iframe preview with device mode | app/components/workbench/Preview.tsx |
| ModelSelector | Fuzzy search model picker | app/components/chat/ModelSelector.tsx |
| StarterTemplates | Template icon grid | app/components/chat/StarterTemplates.tsx |
| Settings panel | 14 tab configuration UI | app/components/@settings/ |
State management uses two systems:
- Zustand : for complex state (workbench, files, terminal, previews, chat history, MCP settings)
- Nanostores : for atomic values (current chat ID, expo URL, theme, project ID)
AI layer (Vercel AI SDK v7)
The AI layer is the core of Amplify's intelligence. It uses Vercel AI SDK v7 for LLM communication with createUIMessageStream() for SSE streaming.
LLMManager (app/lib/modules/llm/manager.ts) is a singleton that:
- Registers all 22 providers from the registry
- Maintains a merged model list (static + dynamic)
- Handles API key resolution from cookies, localStorage, env vars, and config defaults
BaseProvider (app/lib/modules/llm/base-provider.ts) is the abstract class every provider extends:
- Required:
name,staticModels,config,getModelInstance() - Optional:
getDynamicModels()for runtime model fetching - Provides:
getProviderBaseUrlAndKey(),resolveDockerUrl(), caching helpers
How API keys are resolved
The priority chain for API key resolution:
providerSettings.baseUrl— from UI settings (cookieproviders)serverEnv[baseUrlKey]— Cloudflare environment bindingsprocess.env[baseUrlKey]— Node.js environment variablesLLMManager.env[baseUrlKey]— Vite-parsed env varsconfig.baseUrl— hardcoded default per provider
API keys are also stored in cookies (
apiKeysJSON cookie, 365-day expiry) and localStorage for cross-session persistence.
Sandbox (WebContainers)
Amplify runs code in WebContainers : a browser-native Node.js runtime powered by WebAssembly. This means no Docker, no remote servers, and no cloud dependencies.
The sandbox provides:
- File system: In-memory Node.js filesystem via
webcontainer.fs - Terminal: Three shell types (AI shell, init shell, user shell) via xterm.js +
/bin/jsh - Preview: Live preview in iframe with server-ready port detection
- Git:
isomorphic-gitfor repository operations
WebContainer boot configuration
WebContainer.boot({
coep: 'credentialless',
workdirName: 'project',
forwardPreviewErrors: true
})
The coep: 'credentialless' option is required for SharedArrayBuffer support. Without it, WebAssembly (and thus Node.js) cannot run in the browser.
Deep dive into the WebContainer sandbox
Planning engine
The planning engine handles complex, multi-step tasks by breaking them into sub-chat workers.
Sub-chat engine (app/lib/planning/sub-chat-engine.ts):
- Each PlanPoint executes as an independent sub-chat
- Context built by
ContextBuilderwith labeled sections: TASK / PROJECT / SKILLS / TOOL RESULTS / WORKSPACE / CONSTRAINTS / USER REQUEST - Checkpoints every N tool calls for resume-after-interruption
- FlowVerifier runs lint, type-check, and flow validation after each point completes
- Context extracted into
ProjectContextVectorStoreafter completion
Plan endpoint (/api/plan):
- Uses GLM-4.7-Flash (Z.ai provider) with
PLANNER_SYSTEM_PROMPT - Returns enriched Task Contracts as
{ ok: true, plan }
Read the full AI workflow documentation
Persistence (IndexedDB)
All Amplify data is stored in IndexedDB on the user's machine. No cloud storage, no external databases.
Database name: amplifyHistory (version 4)
| Object Store | KeyPath | Purpose |
chats | id | Chat messages with indexes on id and urlId |
snapshots | chatId | File state snapshots per chat |
project_files | projectId | Global per-project file state |
project_commits | id | Versioned file snapshots; indexes on projectId, createdAt |
project_screenshots | projectId | One PNG screenshot per project |
Vector store persistence uses a separate IDB database (amplify_vector_stores) with:
vector_store_user_profile— User preferences, tech stack, coding style (BM25 search)vector_store_project_{projectId}— Per-project context, decisions, errors, patterns
Read the vector database documentation
Native tools
Amplify provides 8 native Copilot-style tools that operate on the workspace file map shipped with each request.
Read-only tools (auto-execute, no user approval needed):
| Tool | Purpose | Limits |
read_file | Read file contents | 1-indexed line numbers, max 2000 lines |
list_dir | List directory contents | Entries from file map |
find_files | Glob pattern file search | Supports *, **, ?; max 200 results |
grep_search | Regex text search | Max 50 matches across workspace |
web_search | Web content fetch | DuckDuckGo API + /api/web-search |
Mutating tools (require user approval, return mutation signals):
| Tool | Purpose | Signal format |
create_file | Create new file | { op: 'create', filePath, content } |
replace_string_in_file | Single replacement | { op: 'replace', filePath, oldString, newString } |
multi_replace_string_in_file | Multiple edits | { op: 'multi_replace', filePath, edits: [...] } |
Mutation signal pattern
Mutating tools return JSON signals with { type: 'amplify_file_mutation', operations: [...] }. The browser-side Chat.client.tsx parses these signals and applies mutations to the workbench file store, which then writes to the WebContainer. The server never directly modifies files — only the client applies changes.