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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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).
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.
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).
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.