operate / the operator's manual
One pod. Eight commands.
Everything you need to run, restart, update, pair, debug, and remove a
mazemaker pod. Every command on this page is verified against
installer/linux/install.sh — if the install script
changes, this page changes the same day. No aspirational
syntax. No "should work" handwaving.
01 / install.
1. Install.
One curl. Pre-flight checks run first — if rootless podman, systemd-user, or GPU prerequisites are missing, the installer tells you exactly what to fix before touching anything.
// the one-liner
curl -fsSL https://mazemaker.online/install.sh | bash
The installer is idempotent — re-running it is the standard "update" path (§4). It detects existing state and skips work that's already done. Your data is never overwritten.
// useful flags
--no-start # install but don't start the pod (configure first)
--refresh # re-sync compute.toml + runtime.env, skip image rebuild
--check # dry-run: print what would happen, install nothing
--reset-fingerprint # wipe local fingerprint+keypair+license, re-onboard fresh
--reconfigure # re-prompt for embedding + Hermes (backs up existing)
--uninstall # stop + remove units (keeps your data on disk)
--backend sqlite # opt out of Postgres/pgvector (CPU-only path)
--remote URL --key KEY # bind to a backend non-interactively (CI / scripts)
--help # print the full reference
// what runs after curl
- Pre-flight — verifies podman 4+, systemd-user, disk space, optional CUDA. Bails early with a fixable error if anything's missing.
- Fingerprint — derives a stable hardware fingerprint, generates an Ed25519 keypair in
~/.mazemaker/keys/(mode0600). This is the binding identity that pins your license. - Browser onboard — opens mazemaker.dev, you sign in (passkey or mzm-* key), the backend issues a license JWT bound to your fingerprint, the JWT lands at
~/.mazemaker/license.jwt. - Embedding choice — interactive prompt for the embedding provider (FastEmbed local / SentenceTransformers / Voyage / OpenAI / etc.). BYOK if not local.
- Quadlet install — copies
.containerunits into~/.config/containers/systemd/, runssystemctl --user daemon-reload. - Image build — rootless podman builds
localhost/mazemaker-v2-{mcp,embedding-worker,license-client,wonderland,dream-worker}. ~3–6 min on first install, ~30s on refresh. - Pod boot —
systemctl --user start mazemaker-pod.servicestarts the whole stack. Health checks confirm everything came up green. - Architect link — final message gives you the dashboard URL (architect.mazemaker.dev) which talks loopback to your fresh pod.
First install end-to-end: ~12 min on a warm machine. Re-installs (which is the update path): ~45s.
02 / start, stop, status.
2. Start, stop, status.
The pod is a standard rootless-systemd-user unit set. Everything
else flows from systemctl --user.
// two knobs, then the units
Day to day you touch exactly two knobs — the mazemaker CLI wraps the units so you never memorise them.
mazemaker on # knob 1: start the always-on memory layer
mazemaker off # knob 1: stop everything cleanly (pod + dream)
mazemaker dream on # knob 2: INTERNAL — engine consolidates in-process
mazemaker dream off # knob 2: EXTERNAL — hand off to the dedicated worker
mazemaker dream none # knob 2: stop all consolidation
mazemaker status # both knobs at a glance
// the unit set
Seven units underneath. Six form the always-on pod; mazemaker-dream-worker.service is on-demand (knob 2). mazemaker-pod.service is the parent.
mazemaker-pod.service # parent of the always-on pod
mazemaker-pgvector.service # Postgres + pgvector (Pro/Enterprise)
mazemaker-license-client.service # license refresh + tier-gate sidecar
mazemaker-embedding-worker.service # embedding model serving (CPU / GPU)
mazemaker-mcp.service # MCP server — what Claude Code talks to
mazemaker-wonderland.service # encrypted MCP proxy + federation (port 8765)
mazemaker-dream-worker.service # ON-DEMAND — dream cycles + DAE + Stage S (Pro+)
// start / stop / restart
Prefer mazemaker on|off. Under the hood, a clean stop needs
--job-mode=replace-irreversibly: the pod members carry Restart=on-failure,
so a plain stop mazemaker-pod.service gets cancelled by the restart policy and the
members revive. The CLI handles this for you.
mazemaker on # bring up the whole stack
mazemaker off # shut down cleanly (irreversible teardown)
# equivalent low-level calls:
systemctl --user start mazemaker-pod.service
systemctl --user --job-mode=replace-irreversibly stop 'mazemaker-*'
systemctl --user restart mazemaker-mcp.service # restart just the MCP server
// is it healthy?
systemctl --user is-active mazemaker-pod.service mazemaker-mcp.service \
mazemaker-wonderland.service mazemaker-embedding-worker.service \
mazemaker-license-client.service
# All five always-on units should print 'active' (dream-worker is on-demand —
# inactive unless knob 2 is on). If any say 'failed' → tail logs (§6).
# Wonderland (your pod's loopback API) health endpoint:
curl -s http://127.0.0.1:8765/health | jq
# License-client health (separate sidecar, port 8767 inside container):
podman exec systemd-mazemaker-license-client curl -s http://localhost:8767/health
// enable at boot
The installer enables the units at boot by default. If you opted out (or want to verify):
systemctl --user enable mazemaker-pod.service
loginctl enable-linger $USER # pod survives logout (one-time)
03 / logs.
3. Logs.
Every unit logs to the systemd-user journal. journalctl --user
is the front door.
# Tail the whole pod (everything multiplexed):
journalctl --user -u mazemaker-pod.service -f
# Tail just one unit:
journalctl --user -u mazemaker-mcp.service -f
journalctl --user -u mazemaker-license-client.service -f
journalctl --user -u mazemaker-wonderland.service -f
journalctl --user -u mazemaker-dream-worker.service -f
# Last hour of failures across all units:
journalctl --user --since "1 hour ago" -p err -u "mazemaker-*"
# Audit log (license-affecting events — issues, refreshes, bans, tripwires):
tail -f ~/mazemaker-v2-pod/data/audit.log | jq
04 / update.
4. Update.
Re-run the install one-liner. It's idempotent. Detects what's changed, rebuilds what needs rebuilding, restarts the affected units. Your data + license + fingerprint survive untouched.
// full update
curl -fsSL https://mazemaker.online/install.sh | bash
Pulls fresh source, rebuilds container images, copies new Quadlet
units, runs systemctl --user daemon-reload, restarts the
pod. ~45s on a warm machine.
// config-only refresh (no rebuild)
curl -fsSL https://mazemaker.online/install.sh | bash -s -- --refresh
Re-syncs compute.toml + runtime.env + Quadlet
units, skips image rebuild. Right call if you only changed a setting
in mazemaker.dev/#/pod-control.
// what the installer does on a re-run
- Pulls the latest pod source from
github.com/itsXactlY/mazemaker-v2-backendinto the cached install dir. - Rebuilds the five container images (unless
--refresh) — only layers that changed are rebuilt thanks to podman build cache. - Re-copies Quadlet
.container+.service+.pathunits into~/.config/containers/systemd/. systemctl --user daemon-reloadpicks up unit changes.systemctl --user restart mazemaker-pod.service+ all six container units. restart, not start — barestartis a no-op on already-active units, restart is the only way to pick up a freshly-built image.- Health check confirms everything came up green.
05 / pair a second pod.
5. Pair a second pod.
Federation = sovereign pods on different machines that opt in to cross-pod memory sync. Two-laptop, hub-and-spoke, or WWW-scale mesh — same paste-handshake model. Every relationship is a Bearer-key pair; nothing is auto-discovered.
// step 1 — get pod A's identity
# On pod A:
curl -s http://127.0.0.1:8765/peer/identity | jq
# Returns:
# {
# "fp_hash": "c0e550...",
# "peer_key": "fed-...", ← Bearer key for incoming /peer/sync calls
# "url": "http://A-host:8765",
# "issued_at": 1779730226
# }
Copy the entire JSON block. This is the invite. The
peer_key is a credential — treat it like an SSH key:
share it over a channel you trust.
// step 2 — paste into pod B
# On pod B (the inviter on the receiving end):
curl -s -X POST http://127.0.0.1:8765/peer/add \
-H 'Content-Type: application/json' \
-d '{
"name": "alca-7G",
"fp_hash": "c0e550...",
"peer_key": "fed-...",
"url": "http://A-host:8765"
}'
// step 3 — mirror, so it's mutual
Repeat steps 1–2 in the reverse direction (B's identity pasted into A's /peer/add). Federation is symmetric only when both sides have each other in ~/.mazemaker/peers.toml.
// step 4 — verify
# On BOTH pods:
curl -s http://127.0.0.1:8765/peer/list | jq
# → both pods should appear, with status: "healthy"
curl -s http://127.0.0.1:8765/federation/status | jq
# → last_sync_at, peers_count, sync_errors_24h, queue_depth
// the contract
Once paired:
- Periodic sync —
/peer/syncbackground task fans memory deltas to every peer inpeers.toml. Push-on-write semantics. Network-partition-tolerant (queues + retries). - On-demand recall —
POST /peer/recallfrom any pod fans a recall to every peer, merges + dedupes results, returns top-K. Faster than waiting for the next sync tick. - Trust boundary — the
peer_keyBearer authorises only/peer/sync+/peer/recall. It cannot trigger remembers, change settings, or read the license JWT. - Revocation —
POST /peer/editwith{"name": "...", "enabled": false}pauses sync without forgetting the peer. Delete the peers.toml entry to fully revoke.
For the architecture behind this — why every relationship is a key pair, why nothing's auto-discovered — see /federation/.
06 / troubleshooting.
6. Troubleshooting.
// "license refresh returns 403"
Tripwire fingerprint ban (usually triggered by multiple license-client restarts in a short window — the jti chain breaks). Check the
admin /#bans panel; if you're the operator, the ban can be lifted with one SQL.
Recovery path: clear last_issued_jti for your fp, delete the ban row, restart license-client. See the
admin /#bans panel for full context.
// "container won't start, immediately exits"
journalctl --user -u mazemaker-mcp.service --since "5 min ago"
podman logs systemd-mazemaker-mcp
9× out of 10 it's: missing env var, bind-mount path doesn't exist, or image needs a rebuild after a host-side bind-mount changed.
// "/#/pod-control shows old config after Save & restart"
Your local license-client hasn't refreshed yet. Force it:
curl -X POST http://127.0.0.1:8765/license/refresh-now
Should return {"status":"refreshed"}. If it 502s, see "license refresh returns 403" above.
// "lost my fingerprint / want a clean slate"
curl -fsSL https://mazemaker.online/install.sh | bash -s -- --reset-fingerprint
Wipes ~/.mazemaker/keys/ + license.jwt + the cached fingerprint, then re-runs the onboard flow. Memory data on disk is preserved — just the identity rotates.
// "podman build is slow / running out of disk"
podman system prune -a # frees old image layers
podman image ls | grep mazemaker # see what you've got
07 / uninstall.
7. Uninstall.
Two levels: stop + remove units (keeps data), or full wipe.
// stop + remove units, keep data
curl -fsSL https://mazemaker.online/install.sh | bash -s -- --uninstall
Stops all units, removes Quadlet files from ~/.config/containers/systemd/, removes container images.
Leaves ~/mazemaker-v2-pod/data/ + ~/.mazemaker/ in place — reinstall = exactly the same identity + memory.
// full wipe (destructive)
# Only run if you really want to lose your local identity + memory:
curl -fsSL https://mazemaker.online/install.sh | bash -s -- --uninstall
rm -rf ~/mazemaker-v2-pod/data/ # all memories, all backups
rm -rf ~/.mazemaker/ # keys, license, runtime.env, compute.toml
Re-installing after a full wipe = a brand new pod with a brand new fingerprint. Your peers will need to re-add you under the new identity.
08 / quick reference.
Quick reference.
install curl -fsSL https://mazemaker.online/install.sh | bash
update curl -fsSL https://mazemaker.online/install.sh | bash
config refresh curl -fsSL https://mazemaker.online/install.sh | bash -s -- --refresh
start systemctl --user start mazemaker-pod.service
stop systemctl --user stop mazemaker-pod.service
restart systemctl --user restart mazemaker-pod.service
status (all) systemctl --user is-active mazemaker-*.service
health curl http://127.0.0.1:8765/health
tail logs journalctl --user -u mazemaker-pod.service -f
force license curl -X POST http://127.0.0.1:8765/license/refresh-now
get peer ID curl http://127.0.0.1:8765/peer/identity
list peers curl http://127.0.0.1:8765/peer/list
fed status curl http://127.0.0.1:8765/federation/status
uninstall curl -fsSL https://mazemaker.online/install.sh | bash -s -- --uninstall
reset identity curl -fsSL https://mazemaker.online/install.sh | bash -s -- --reset-fingerprint