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

RequirementVersionNotes
Node.js>= 20LTS recommended
pnpm>= 11corepack enable to install
PostgreSQL>= 15Web 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:

GoalStack
Contributing to the web frontend or API serverWeb
Deploying Zapvol as a multi-user serviceWeb
Running Zapvol as a personal agent on your machineDesktop
Working on Electron / SQLite / single-user featuresDesktop

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

  1. Open http://localhost:8000
  2. Register, or log in with the seeded demo account
  3. Create a task and send a message to the agent
  4. The agent should stream a reply and — if a tool is needed — start using tools

Troubleshooting

SymptomLikely cause
401 from the model on first messageAI_GATEWAY_API_KEY empty or invalid; or fall back to a direct provider key
Server crashes on bootDATABASE_URL wrong, or PostgreSQL not running
Login fails / redirect loopBASE_URL doesn’t match where the server is actually serving
Web page loads but API calls 404Server not running, or running on a port other than 8001
Agent replies but never uses toolsSANDBOX_TYPE unset, or sandbox initialization failed (check server logs)
Port 8000 / 8001 already in useStop 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:

  1. Gateway (above) — fill in AI_GATEWAY_API_KEY and the agent works on first launch
  2. 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:

OSPath
Windows%APPDATA%\zapvol\
macOS~/Library/Application Support/zapvol
Linux~/.config/zapvol

Verify

  1. The Electron window opens automatically
  2. (BYOK only) Open Settings → API Keys and add a provider key
  3. Create a task and send a message to the agent
  4. The agent should stream a reply and start using tools

Troubleshooting

SymptomLikely cause
Window opens, agent fails on sendNeither AI_GATEWAY_API_KEY nor a BYOK key is set; add one in Settings
Tools fail or don’t appearSandbox dependencies missing; check the main-process console (View → Toggle Developer Tools → Main Process)
White window / nothing rendersELECTRON_RENDERER_URL doesn’t match the dev port 8002
App launches but data is emptyFirst-launch state — create a task to bootstrap the SQLite schema
Want to reset local dataQuit 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.

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:

  1. Open chrome://extensions
  2. Enable Developer mode
  3. 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_connectable channel; 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 runAgentLoop turns, 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
Was this page helpful?