One command. Twelve minutes. Your own engine.

curl -fsSL https://mazemaker.online/install.sh | bash is the whole surface. Behind it: ten idempotent stages, one browser handoff, a license JWT signed against your device fingerprint, and a customer pod that boots on systemd --user and stays out of root. This page is the map of what happens between the one-liner and your first recall. No surprises, no telemetry, no "make an account first."

What the one-liner actually does.

Four moving parts, in this order. Every part is recoverable, every part re-runnable, every part inspectable in the script itself (install.sh, ~1500 lines, source-available).

// 1. host preparation

Detects your distro, verifies podman >= 4.4, ensures rootless networking is configured (uidmap, slirp4netns), and installs minimum host Python deps in an isolated venv at ~/.local/share/mazemaker/.host-venv. Your system Python is never touched. Nothing is sudo'd that doesn't need to be.

// 2. fingerprint + handshake

Generates a device fingerprint (HMAC over hardware salts + a generated keypair), opens https://mazemaker.dev/onboard?fp=… in your browser, and polls the backend every 30s for up to 15 minutes. You complete email verification + plan choice in the browser; the installer waits, patient, on the CLI. No keys ever ride the curl pipe.

// 3. license + embedding choice

Once the browser hands off, the installer signs a fingerprint-install proof, requests a license JWT from api.mazemaker.dev, writes it to ~/.local/share/mazemaker/license.jwt, and prompts you for an embedding provider: FastEmbed CPU (offline default), Cloudflare Workers AI (managed, your license unlocks it), or a self-hosted GPU embedding worker for Pro/Enterprise.

// 4. pod install + boot

Renders Quadlet units (.container, .network, .volume) into ~/.config/containers/systemd/, systemctl --user daemon-reload, starts the pod, and probes http://127.0.0.1:8765/healthz until green. Total elapsed: ~12 minutes on first run (mostly embedding model download). Subsequent install.sh --refresh runs are sub-30s.

The ten stages, in order.

Each stage is gated on the previous one's success. Each stage logs to stdout with a [mazemaker] prefix — success is green, warnings yellow, fatal red with a runbook pointer. Failures stop the installer; nothing half-installs.

# Stage What it does Idempotent?
01 Pre-flight Distro detection, podman ≥ 4.4, systemd --user reachable, curl + python3 ≥ 3.11. yes
02 Rootless env uidmap / slirp4netns sanity. Writes ~/.config/containers/containers.conf if missing. yes
03 Host venv Creates ~/.local/share/mazemaker/.host-venv, installs cryptography + pyjwt for fingerprint signing. yes
04 Fingerprint init One-shot HMAC over hardware salts + ed25519 keypair. Stored at ~/.local/share/mazemaker/.fingerprint/. Never leaves disk. yes (skip if present)
05 Browser onboard Opens mazemaker.dev/onboard?fp=…, polls /api/onboard/install-session/<fp> every 30s for up to 15 min. yes
06 License issue Signs fingerprint-install proof, POSTs to /api/license/issue, receives JWT, writes to license.jwt. yes (skip if present)
07 Embedding choice Interactive prompt: FastEmbed CPU (default) / Cloudflare Workers AI / GPU worker. Writes embedding.toml. yes (skip if config present)
08 Quadlet render Renders mazemaker-pgvector.container, -wonderland.container, -embedding-worker.container, -dream-worker.container, -mcp.container, plus .network + .volume siblings. yes (re-renders idempotently)
09 Pod boot systemctl --user daemon-reload, then start each unit in dependency order. ~10 min first run (model download). yes
10 Health check Polls 127.0.0.1:8765/healthz + 127.0.0.1:5432 until green. Prints the next-steps banner. yes

The installer never asks for sudo unless step 01 fails — in which case it prints the exact pacman / apt / dnf / zypper / apk / xbps / emerge line for your distro and exits. You re-run after installing podman.

The browser handoff, step by step.

This is the one stage that leaves the terminal. It's also the one stage where most installers get cute — we don't. The CLI waits silently while you read, click, and verify. No countdown, no "press any key", no telemetry beacon.

05a

Browser opens

The installer prints URL: https://mazemaker.dev/onboard?fp=<fp> and tries to open it via xdg-open. On a headless box it just prints the URL — copy it to a desktop browser.

05b

Email + plan

You enter your email, solve a Cloudflare Turnstile captcha, pick Community (free, AGPL) or Pro (paid, PolyForm-NC). Stripe checkout is optional — Community runs forever without it.

05c

Verification mail

One signed magic-link in your inbox. Click it; the browser tab confirms the install-session and writes a ready flag against your fingerprint.

05d

CLI resumes

The next 30s poll on the CLI sees the ready flag, signs the fingerprint-install proof, requests the license JWT, writes it to disk, and moves to stage 06. You can close the browser tab.

After the green check — three doors.

The installer's final banner gives you three URLs. Each one is a different way to use the same pod.

door 1

Your MCP client

~/.config/mazemaker/mcp.json is already wired. Add it to your Claude Code / Cursor / Cline / Continue config; you get mcp__mazemaker__recall, remember, graph, think, dream, stats, prune, quota. This is the daily-driver path.

how the MCP wiring works →

door 2

The Architect cockpit

Point your browser at https://architect.mazemaker.dev/ — the 12-monitor SPA pulls everything from your local pod over loopback. Watch recalls land in real time, replay dream cycles, scrub the chrono-timeline, index Hermes skills as memories.

behind the door →

door 3

The dev console

https://mazemaker.dev/ with passkey login. Issue mzm-* API keys, manage device fingerprints, view billing, rotate the license JWT, check quota usage. This is the only door that talks to the hosted backend — everything memory-shaped stays in your pod.

the four-domain split →

Guarantees the installer actually upholds.

Half of these are claims any installer can make. The other half are claims almost no installer keeps. We tested every one in CI.

Guarantee How it's enforced
No root Every container, every unit, every socket runs under systemd --user. The installer refuses if invoked as root (EUID 0) unless --allow-root is set.
No data exfiltration The only outbound calls during install are: (a) api.mazemaker.dev/api/onboard/install-session poll, (b) api.mazemaker.dev/api/license/issue one-shot, (c) Quay/Docker Hub for container images. All three are documented in the script.
No data loss on re-run Volumes are external (mazemaker-pgdata.volume, mazemaker-models.volume). --refresh only re-renders Quadlet; --uninstall stops + removes units but leaves volumes.
Resumable Every stage is gated on a sentinel file. A killed install at stage 07 resumes at stage 07. Network failures during stage 05 are auto-retried for the full 15-min window.
Inspectable install.sh is a single Bash file. Pipe to less instead of bash if you want to audit before running. Every command is plain Bash; no obfuscated curl-to-eval chains.
Reversible install.sh --uninstall stops units, removes ~/.config/containers/systemd/mazemaker-*, and prints a single command for hard wipe (rm -rf ~/.local/share/mazemaker).
Offline-capable Once installed, the pod runs without internet. FastEmbed ships ONNX models locally. License JWT is verified offline against an embedded public key for up to 30 days before phoning home for renewal.

What if it breaks?

The installer is opinionated about failure: stop loudly, point at the runbook, never auto-fix a hard problem. The most common failure modes:

// podman version too old

Distros pin old podman in their stable repos. The installer needs >= 4.4 for Quadlet + rootless networking. Fix: upgrade podman (the installer prints the exact pacman -S / apt install line for your distro and exits cleanly).

// browser handoff times out

15-minute window, then stage 05 fails. Re-run install.sh — the fingerprint is preserved, the browser link is re-issued, polling resumes. Headless boxes can paste the URL into a desktop browser; the fingerprint travels with the URL.

// pgvector boot loop

Almost always a uid/gid mismatch on the data volume from a prior install. journalctl --user -u mazemaker-pgvector.service tells you. Fix: podman volume rm mazemaker-pgdata (destructive) or podman unshare chown -R 999:999 ~/.local/share/containers/storage/volumes/mazemaker-pgdata/ (non-destructive).

// embedding-worker GPU not detected

Requires CDI-style passthrough (nvidia-ctk cdi generate) plus AddDevice=nvidia.com/gpu=all in the Quadlet (already there). If nvidia-smi works on host but not in the container, the host libnvidia-container stack needs updating. Falls back to CPU FastEmbed gracefully if GPU init fails.

For anything weirder: install.sh --check-only runs every pre-flight check without touching state and prints a single pass/fail per stage. Then installer/linux/debug.sh bundles journalctl + state files into a single tarball you can paste into a GitHub issue.

Twelve minutes.
Your engine, your data, your machine.

The install one-liner is on the homepage. The script is on GitHub. The pod is yours the moment health-check goes green.