Skip to content

Local setup ​

Prerequisites ​

  • Node.js 22.12 or later. That is the engines range in the root package.json; the Docker image and the maintainers use Node 24.
  • pnpm 10, through Corepack. The root package.json pins pnpm@10.20.0 in packageManager, and Corepack fetches that version for you.
  • Git. On Windows, Git Bash and PowerShell both work; see the Windows notes.

Wireface Core, the face engine, is already in the repo (vendor/wireface-core). You only need its own repo, next to this one as ../core, to update that copy (see Wireface Core).

sh
corepack enable
pnpm install

The first build ​

Build everything once before you start the dev servers:

sh
pnpm build

This runs build in every package under packages/ and apps/ that has one: the widget (loader, frame and manifest.json), the npm package, the admin panel and the server. pnpm dev rebuilds the widget's loader and frame as you work, but not its manifest.json (the version and SRI hash the admin panel shows for the pinned snippet), and the server's own /admin/ needs apps/admin/dist. For the docs at /docs/ on the server, also run pnpm docs:build.

A widget build also copies the loader into packages/widget/releases/. In development it replaces the copy there (with a warning) when the loader changed, so check git status before you commit: that change belongs in a release only. See Released loaders.

pnpm dev ​

sh
pnpm dev

The root dev script runs three packages' dev scripts in parallel:

PackageScriptWhat it does
@wireface/servernode --watch --watch-preserve-output --import tsx src/main.tsRuns the server from source on port 8800. Node restarts it when any file it imports changes, workspace packages included.
@wireface/widgetvite build --watch for the loader and for the frameRebuilds packages/widget/dist on every change. The server serves the new files straight away: reload the page.
@wireface/adminviteThe admin panel with hot reload at http://127.0.0.1:5180/admin/. It proxies /api and /v1 (WebSockets included), /core, /frame, /embed, /widget, /docs and /healthz to the server on 127.0.0.1:8800, so cookies, the widget and the face are same-origin, as in production.

Open http://127.0.0.1:5180/admin/ to work on the admin panel. http://localhost:8800/admin/ serves the last built copy (pnpm --filter @wireface/admin build; the server picks up a rebuild on the next page load).

To work on the docs, run pnpm docs:dev. It regenerates the reference pages, then starts VitePress (on port 5173, or the next free one) with the docs under /docs/.

Configuration ​

The server reads .env from its working directory (apps/server when pnpm runs it), then from the repo root. Neither replaces a variable that is already set in the environment, and an empty value counts as not set. Copy the example to the repo root and fill in what you need:

sh
cp .env.example .env

Nothing in it is required for development. Every variable is listed in Environment variables; the ones that matter in development are these:

VariableIn development
NODE_ENVDefaults to development: readable logs (pino-pretty), every request logged, the widget socket accepted from localhost pages, http:// webhook URLs allowed, source maps served. Tests use test. See Production mode.
DATA_DIRDefaults to ./data, relative to the server's working directory: apps/server/data. It holds wireface.db, files/ and master.key. Stop the server and delete the folder to start again from nothing.
WIREFACE_MASTER_KEYLeave it empty: the first start generates DATA_DIR/master.key and logs a warning saying so. The database's sealed keys can't be read without that file, so keep the two together.
SETUP_TOKENLeave it empty to get a random one (see below), or set your own (8 characters or more).
PORT, HOST8800 and 0.0.0.0. The admin dev server's proxy expects 8800.

On the first start the log shows the setup token:

text
First run: open http://localhost:8800/admin/setup and enter this setup token: ...

The token is kept in the database until setup is done, so a restart prints the same one. Setup creates the owner account and the workspace; the quick start walks through it.

Provider keys and the mock providers ​

When setup creates the workspace, the server connects every key it finds in ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY and ELEVENLABS_API_KEY. That happens once. After it, add or change keys in the admin panel under Providers.

To work offline, or without spending anything, run the mock providers and point the server at them:

sh
pnpm --filter @wireface/mock-providers start

They listen on 127.0.0.1:8899 (set MOCK_PORT for another port) and print the PROVIDER_BASE_URL_* and PROVIDER_WS_URL_* lines to add to .env. Restart pnpm dev after adding them. Any API key then works, except one containing bad (rejected) or broke (out of credit). What the mock models answer is described in Testing.

Blank your real keys for the server before setup, or setup imports them into this workspace: they would be stored in your development database and used against the real APIs once the PROVIDER_* lines are gone. Since .env never overrides the environment, OPENAI_API_KEY= in .env is not enough if your shell sets the key. Blank them for the command instead:

sh
# Git Bash
ANTHROPIC_API_KEY= OPENAI_API_KEY= GEMINI_API_KEY= ELEVENLABS_API_KEY= pnpm dev
powershell
# PowerShell, for this session
$env:ANTHROPIC_API_KEY = ''; $env:OPENAI_API_KEY = ''; $env:GEMINI_API_KEY = ''; $env:ELEVENLABS_API_KEY = ''
pnpm dev

Trying the chat on a page ​

The bot editor's preview in the admin panel shows the unpublished draft. To see a published bot on a page of its own, serve one of the examples:

sh
node examples/serve.mjs plain-html --host http://localhost:8800 --bot pk_your_bot_id

It serves the page at http://localhost:5500 (--port to change it). Add that origin to the bot's allowed origins first (Security in the bot editor). examples/README.md lists the examples.

Windows notes ​

  • tsx watch hangs. The server's dev script is node --watch --watch-preserve-output --import tsx rather than tsx watch, because tsx watch freezes at startup when stdin is a pipe, which is what pnpm --parallel gives each process (tsx's watcher reads stdin). Keep it that way.

  • Port 5173 is avoided. It is Vite's default, and other local apps use it (Wireface Core's demo, the simulator), so the admin dev server uses 5180. It sets strictPort: if 5180 is taken, it stops with an error instead of moving to another port, which the proxy setup and these docs would not expect.

  • Use 127.0.0.1, not localhost, with curl. In Git Bash localhost can resolve to the IPv6 address ::1 first, and the admin dev server only listens on 127.0.0.1:

    sh
    curl http://127.0.0.1:8800/healthz
  • Line endings. Biome formats with LF. With core.autocrlf=true (the Git for Windows default) a checkout gets CRLF files and biome check reports every one of them. Set git config core.autocrlf input in this repo, and make scripts that write files use \n.

  • Stalled connections. On some Windows machines connections to 127.0.0.1 stall for a few seconds now and then. A test that fails with a timeout may pass when run again: see Flaky runs.

A production build ​

sh
pnpm build
pnpm docs:build     # optional: the docs at /docs/
NODE_ENV=production pnpm start

pnpm start runs node dist/main.js in apps/server: the tsdown bundle, with npm dependencies left external (the native ones, better-sqlite3 and sharp, must be) and the migrations read from apps/server/drizzle. It finds the built widget, admin panel, docs and face engine in the repo. Without NODE_ENV=production it runs in development mode. Running it for real is covered in Docker.

Wireface Chat 0.1.0. These docs are served by your own server.