Local Development
Prerequisites
Section titled “Prerequisites”- Go — the version pinned in
go.mod(go 1.25.0). - Bun — no version is pinned; CI installs the latest via
oven-sh/setup-bun. Used forweb/,desktop/,sdk/, andautomations/.
Make targets
Section titled “Make targets”The root Makefile covers the Go binaries and the web build:
make build # build-server + build-runner + build-webmake build-server # ./dist/nexul-servermake build-runner # ./dist/nexul-runnermake build-web # bun run --cwd web buildmake build-single # single-binary server, web assets embedded via go:embedmake test # go test ./...make vet # go vet ./...make coverage # go test -race with the 80% gatemake sqlc # regenerate internal/platform/storage/sqlcgen from queries/*.sqlmake sqlc-check # sqlc vet + sqlc diff — fails if generated code is staleRunning the server and the web dev server
Section titled “Running the server and the web dev server”Outside the debug stack, run the server directly against Go:
go run ./server/cmdThe server generates its auth secret and reads its config from environment
variables (see .env.example — nothing is required for a local run; every
variable there is an override).
The web app has its own dev server:
bun installbun run --cwd web devThe debug compose stack
Section titled “The debug compose stack”docker-compose.debug.yml runs the server, web (Vite, not nginx), runner,
automations host, and an OpenObserve instance for logs together, with Delve
attached to the Go binaries (:2345 server, :2346 runner):
docker compose -f docker-compose.debug.yml upWeb (:5173), server HTTP/WS/MCP (:8080/:8081/:8082), and OpenObserve
(:5080) are all reachable on the host.
Named node_modules volumes. web-node-modules and
automations-node-modules are named Docker volumes, not bind mounts —
they exist so the container’s installed dependencies don’t get shadowed by
whatever (or nothing) is in your host checkout’s node_modules. That means
a host-side bun install doesn’t reach the container: after changing
package.json in web/ or automations/, install inside the running
container instead:
docker compose -f docker-compose.debug.yml exec web bun installdocker compose -f docker-compose.debug.yml exec automations bun installNever run docker compose -f docker-compose.debug.yml down -v to pick up a
dependency change — that also wipes the debug database and OpenObserve
volumes. exec ... bun install is the fix; down -v is not.
Running tests
Section titled “Running tests”go test ./... # Go, all packagesbun run --cwd web test # web, Vitestbun run --cwd desktop test # desktop, Vitestbun run --cwd sdk test # sdk, Vitestbun run --cwd automations test # automations, bun testThe coverage gate
Section titled “The coverage gate”make coverage is the enforced gate, not a suggestion:
make coverageIt runs go test -coverprofile=coverage.out -covermode=atomic ./..., drops
exempt paths from the denominator (cmd/*, testutil/, node_modules/,
generated code, sqlcgen/), computes the percentage over what’s left, and
fails below the threshold. It writes coverage.filtered.out and
coverage.html — the same artifacts CI uploads. See
Coding Standards for what the gate
expects beyond the number.