Skip to content

Architecture

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:

ComponentPurposeLocation
BaseChatMain chat interfaceapp/components/chat/BaseChat.tsx
Chat.clientSSE stream handler + mutation signal parserapp/components/chat/Chat.client.tsx
Terminalxterm.js terminal (3 shell types)app/components/workbench/terminal/Terminal.tsx
Previewiframe preview with device modeapp/components/workbench/Preview.tsx
ModelSelectorFuzzy search model pickerapp/components/chat/ModelSelector.tsx
StarterTemplatesTemplate icon gridapp/components/chat/StarterTemplates.tsx
Settings panel14 tab configuration UIapp/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:

    1. providerSettings.baseUrl — from UI settings (cookie providers)
    2. serverEnv[baseUrlKey] — Cloudflare environment bindings
    3. process.env[baseUrlKey] — Node.js environment variables
    4. LLMManager.env[baseUrlKey] — Vite-parsed env vars
    5. config.baseUrl — hardcoded default per provider

    API keys are also stored in cookies (apiKeys JSON 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-git for repository operations
WebContainer boot configuration
typescript
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 ContextBuilder with 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 ProjectContextVectorStore after 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 StoreKeyPathPurpose
chatsidChat messages with indexes on id and urlId
snapshotschatIdFile state snapshots per chat
project_filesprojectIdGlobal per-project file state
project_commitsidVersioned file snapshots; indexes on projectId, createdAt
project_screenshotsprojectIdOne 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):

ToolPurposeLimits
read_fileRead file contents1-indexed line numbers, max 2000 lines
list_dirList directory contentsEntries from file map
find_filesGlob pattern file searchSupports *, **, ?; max 200 results
grep_searchRegex text searchMax 50 matches across workspace
web_searchWeb content fetchDuckDuckGo API + /api/web-search

Mutating tools (require user approval, return mutation signals):

ToolPurposeSignal format
create_fileCreate new file{ op: 'create', filePath, content }
replace_string_in_fileSingle replacement{ op: 'replace', filePath, oldString, newString }
multi_replace_string_in_fileMultiple 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.