Skip to main content
This page is for working in this repository. If you are consuming the published packages instead, Quickstart is the page you want. The root Makefile is the task runner. Running make with no target prints the same index this page documents:
Every script in every workspace package.json has a root target, so the whole monorepo is drivable from the repo root. The Makefile is a thin wrapper — nothing is reachable only through make.
Targets are named in an area:thing form, but each is an alias over a plain-named rule: build:ui and build-ui are the same target. Both spellings work on the command line. The distinction matters only when editing the Makefile, because GNU make accepts an escaped colon in a target name but silently ignores one in a prerequisite list — so dependencies between rules are always expressed with the plain names.

Setup

setup is install plus the example app’s doctor check, which is the one to run on a fresh clone.

Running the examples

make tauri forwards arguments through the ARGS variable:
These targets are not standalone — they build their prerequisites first, and that ordering is load-bearing.Both example apps consume @exegia/use-auth, which imports the bindings package; that resolves to guest-js/dist through the workspace link, so the bindings must exist before either dev server can start. The web example goes one step further: its tsconfig maps @exegia/use-auth to react/dist, and bun honours tsconfig paths, so its bundle comes from the built package rather than from source. A stale react/dist is a stale app.That is why dev:web and start:web depend on build:ui while dev:tauri and dev:mcp only need build:bindings.

Building

make build chains the three publishable artifacts in dependency order: bindings, then the hooks package, then the crate package check.
build:plugin and pack only verify that a release would work. Neither publishes anything — releases happen when a release/vX.Y.Z PR merges into main, via the publish:* targets.pack exists because bun pm pack does not apply publishConfig field overrides, so packing @exegia/use-auth naively yields a tarball still pointing at ./src/index.ts. scripts/pack.sh mirrors the rewrite that the release workflow performs.
The Docker targets reproduce the Linux CI toolchain (Rust, webkit2gtk, bun, node, the Supabase CLI) so the Linux build is reachable from macOS. The image is for local use; CI itself runs on runs-on, not inside it.

Testing

Narrower runs go through the underlying tools directly:
The UI suite resolves @exegia/plugin-supabase-auth through the built bindings, so a fresh checkout fails until they exist. make test:ui handles that ordering; a raw vitest invocation does not.
The E2E lifecycle test is #[ignore]d and needs credentials. make test:e2e reads them from supabase status, so start the stack with make supabase-up first.

Quality gates

lint and fmt cover two Cargo workspaces: the plugin at the repo root, and the example’s src-tauri/, which has its own lockfile and is not reached by root cargo commands.

Release pipeline

Every step in .github/workflows/*.yml is one of these targets, so anything CI does can be run locally. The branch flow they implement is described in .github/WORKFLOW.md.
One version number covers all three artifacts. version:set writes guest-js/package.json, react/package.json and Cargo.toml, then regenerates bun.lock — a plain bun install does not re-resolve a workspace member’s pinned version, and a stale pin ships the hooks package depending on an old copy of the bindings.
publish:* is for CI. Each target writes a registry-scoped $HOME/.npmrc for the duration of one publish and restores whatever was there before, but it still needs a real token in NODE_AUTH_TOKEN and publishes for real. Use make pack to inspect what a release would ship.

Local Supabase stack

The Supabase config lives at the repo root, not in the example app.

Cleaning

make clean at the repo root removes both Cargo target directories and every node_modules — on the order of 10 GB. It prompts before doing so, and make clean:dry shows the list first.The example app’s own clean is a different, narrower target that keeps dependencies. make clean:build is the root equivalent.
Tooling changes are worth verifying against a clean tree:
Ordering defects — a missing build prerequisite — pass on a warm tree and only fail on a fresh checkout.

The example app’s own targets

examples/tauri-app/ has a second Makefile. The root targets above delegate to it rather than duplicating it, and it carries the app-specific work that has no root equivalent:
The mcp-* targets drive the running app through the tauri-mcp CLI — screenshotting the webview, querying the DOM, evaluating JS — which is how UI changes get verified against the real app. supabase-restart is needed after editing supabase/config.toml, and supabase-reset destroys all local auth users.
The example app is multi-window, so every tauri-mcp CLI call needs --window-id. main is the method picker; each method opens its own auth-<id> window. Without the flag you drive whichever window is default and silently assert against the wrong DOM.