Skip to main content

One process

The server is a single Fastify app. It serves the JSON API under /api/*, the MCP endpoint at /mcp, the web app, better-auth login, and the connection gateway on loopback. A production install is one binary supervising itself.

The database is embedded

Postgres runs inside the app process as PGlite, against a directory under CRAFTSPACE_HOME. There is no separate database container, which is what makes an install one thing rather than two. Migrations run as one transaction, so a failed migration changes nothing and the previous version keeps serving. That is the property that makes rolling an image back safe, and it is also the constraint on every release: a release may only add what the previous one reads, never remove it.

The gateway is a module, not a service

Connection credentials are sealed at rest, and only the gateway can open them. It used to be a separate container, and it is not any more, because a second machine was the only thing that boundary actually bought. What survives is the shape: one module, importing nothing else in the app, holding the key.

Module layout

packages/app/server/src groups by subject rather than by layer: A group folder carries no code of its own, which npm run check:structure enforces. A module grows subfolders once it passes ten files.

Reading further

CONTEXT.md in the repository is the domain language: what a space, a page, a connection and an errand each mean here, in the words the code uses.