Quick Start
Pick a stack — Web or Desktop — and have the agent responding to a message in about ten minutes.
In ten minutes, the agent answers your first message
Follow this through and you’ll have a local Zapvol running — either a web app at localhost:8000 (Hono API server +
PostgreSQL) or a desktop app (Electron + local SQLite) — with the agent responding to your first message. The
optional BUA section at the end applies to both stacks.
Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Node.js | >= 20 | LTS recommended |
| pnpm | >= 11 | corepack enable to install |
| PostgreSQL | >= 15 | Web stack only (Desktop uses SQLite) |
Optional:
- Redis — Web stack only; needed for resumable SSE recovery (long agent runs that survive page reloads)
- Daytona / E2B API key — either stack; needed only to run tools in a cloud sandbox instead of locally
- Chrome / Chromium — needed only to develop the BUA extension
Get the Code
git clone https://github.com/zapvol/zapvol.git
cd zapvol
pnpm install
pnpm install is shared by both stacks — it bootstraps the entire monorepo.
Choose Your Stack
You don’t need both — pick the one that matches your goal:
| Goal | Stack |
|---|---|
| Contributing to the web frontend or API server | Web |
| Deploying Zapvol as a multi-user service | Web |
| Running Zapvol as a personal agent on your machine | Desktop |
| Working on Electron / SQLite / single-user features | Desktop |
The two stacks share the same agent engine, UI components, and tool set. They differ in storage, auth, transport, and configuration surface.
Web Stack
A two-process setup: Vite dev server for the frontend + tsx watcher for the API server. State lives in PostgreSQL; authentication goes through better-auth.
Configure the server .env
cp apps/server/.env.example apps/server/.env
Minimum required block:
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/zapvol
# Auth — generate a random string with at least 32 characters
BETTER_AUTH_SECRET=your-secret-key-at-least-32-chars
BASE_URL=http://localhost:8001
# AI — Gateway is the recommended path; all model calls flow through it
AI_GATEWAY_API_KEY=your-ai-gateway-key
# Sandbox — defaults to a local Node sandbox
SANDBOX_TYPE=node
On the AI key: Zapvol uses an AI Gateway by default to unify provider routing. If you don’t have a gateway key, you
can fall back to direct provider keys (ANTHROPIC_API_KEY=... or OPENAI_API_KEY=...). NODE_SANDBOX_WORKSPACE has a
sensible default; only set it if you want to pin the sandbox root explicitly.
Optional environment variables
# OAuth providers — enables social login
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
# MCP OAuth providers — enables MCP servers that require OAuth
LINEAR_CLIENT_ID=
LINEAR_CLIENT_SECRET=
# Web search tools
TAVILY_API_KEY=
EXA_API_KEY=
# Cloud sandboxes — pick one if you don't want the local Node sandbox
DAYTONA_API_URL=https://app.daytona.io/api
DAYTONA_API_KEY=
E2B_API_KEY=
# Object storage — enables context offloading and file uploads
R2_ACCOUNT_ID=
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_BUCKET_NAME=
R2_PUBLIC_URL=
# Skills — directory the agent loads skills from
SKILLS_DIR=./skills
Set up the database
createdb zapvol
pnpm --filter=@zapvol/server run db:reset
pnpm --filter=@zapvol/server run db:seed
For a first install, db:reset + db:seed is the standard “fresh start” — db:reset rebuilds the schema, db:seed
populates default models, agents, tier configs, and a demo account. Re-running db:reset later will drop your data,
so use it deliberately after that.
Run it
pnpm dev:app
This starts both processes — Web frontend on localhost:8000, API server on localhost:8001.
Verify
- Open http://localhost:8000
- Register, or log in with the seeded demo account
- Create a task and send a message to the agent
- The agent should stream a reply and — if a tool is needed — start using tools
Troubleshooting
| Symptom | Likely cause |
|---|---|
| 401 from the model on first message | AI_GATEWAY_API_KEY empty or invalid; or fall back to a direct provider key |
| Server crashes on boot | DATABASE_URL wrong, or PostgreSQL not running |
| Login fails / redirect loop | BASE_URL doesn’t match where the server is actually serving |
| Web page loads but API calls 404 | Server not running, or running on a port other than 8001 |
| Agent replies but never uses tools | SANDBOX_TYPE unset, or sandbox initialization failed (check server logs) |
| Port 8000 / 8001 already in use | Stop the conflicting process or change ports in the respective dev scripts |
Desktop Stack
A single Electron process with local SQLite storage. No PostgreSQL, no better-auth, no OAuth — the desktop app uses
a single hard-coded local-user and stores data in your OS’s per-user app data directory. Authentication-related env
vars are not used at all.
Configure the desktop .env
cp apps/desktop/.env.example apps/desktop/.env
The file is short:
ELECTRON_RENDERER_URL=http://localhost:8002
# AI Gateway key — required if you want the agent to work out-of-the-box
AI_GATEWAY_API_KEY=your-ai-gateway-key
Two paths for the AI key:
- Gateway (above) — fill in
AI_GATEWAY_API_KEYand the agent works on first launch - BYOK (Bring Your Own Key) — leave the env empty and add per-provider keys after first launch, in the app’s
Settings → API Keys page (Anthropic / OpenAI / etc., stored encrypted via Electron
safeStorage)
If both are set, BYOK takes precedence for the model’s provider.
Run it
pnpm dev:desktop
This launches Electron in dev mode with the renderer served from localhost:8002. The SQLite database is created
automatically on first launch, in the OS’s per-user app-data directory:
| OS | Path |
|---|---|
| Windows | %APPDATA%\zapvol\ |
| macOS | ~/Library/Application Support/zapvol |
| Linux | ~/.config/zapvol |
Verify
- The Electron window opens automatically
- (BYOK only) Open Settings → API Keys and add a provider key
- Create a task and send a message to the agent
- The agent should stream a reply and start using tools
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Window opens, agent fails on send | Neither AI_GATEWAY_API_KEY nor a BYOK key is set; add one in Settings |
| Tools fail or don’t appear | Sandbox dependencies missing; check the main-process console (View → Toggle Developer Tools → Main Process) |
| White window / nothing renders | ELECTRON_RENDERER_URL doesn’t match the dev port 8002 |
| App launches but data is empty | First-launch state — create a task to bootstrap the SQLite schema |
| Want to reset local data | Quit the app, delete the per-user app-data directory, relaunch |
(Optional) Set Up the BUA Browser Extension
The Browser Use Agent (BUA) is a Chrome extension that lets the agent act inside your already-logged-in browser, under per-domain consent. Compatible with either stack.
Dev mode (recommended)
pnpm dev:ext
WXT launches a fresh Chromium dev profile with the extension pre-loaded and HMR active. No manual
chrome://extensions load step needed — that flow is for the production build only.
Production build (install into your normal Chrome)
pnpm build:ext
Then in Chrome:
- Open
chrome://extensions - Enable Developer mode
- Click Load unpacked and select
apps/bua/.output/chrome-mv3/
Pairing
Pairing differs by stack:
- Web stack — the extension communicates with the web app via Chrome’s
externally_connectablechannel; trigger pairing from the web app’s BUA settings page - Desktop stack — Electron runs a loopback WebSocket server (
127.0.0.1:48123) and stores a per-machine pairing token; copy the token from Desktop Settings → Browser Extension into the extension’s Options page
Full guide: BUA Development.
Common Scripts
pnpm lint # ESLint across all packages
pnpm format # Format with Prettier
pnpm format:check # Check formatting without writing
Production builds: pnpm build, or scoped: pnpm build:web, pnpm build:server, pnpm build:desktop,
pnpm build:ext.
If you want every dev process at once (Web + Server + Desktop + Browser Extension), use pnpm dev. For day-to-day work,
prefer the stack-specific commands above — pnpm dev is heavier than most workflows need.
Where to Next
You’ve got it running — now go deeper into the same System tab:
- Agent Engine — the execution loop you just started: how
runAgentLoopturns, the state machine, how subsystems wire in - Repo Architecture — the monorepo you just cloned: package boundaries, the dependency graph, “adding a platform is writing an adapter”
- Operations — take this local setup to production: the observability stack, deployment, runtime health
- BUA Overview — optional: let the agent act in your logged-in browser, under per-domain consent