Skip to main
maudeMDCC/00
The hub

Workspace mode

A hub that owns the project — autosave becomes append-only git history, media lives in object storage, and teammates sign in with an email instead of pasting a token. Self-hosted, one command, verified before it claims to work.

A plain hub relays documents between peers who each own their own copy of the project. A workspace goes further: the hub owns the project.

That changes three things:

  • Autosave becomes history. The workspace holds the authoritative checkout and turns saves into append-only git commits, attributed to whoever made the edit. Nothing is ever amended, rebased, or force-pushed.
  • Heavy media stops riding git. Images, video and audio go to an S3-compatible bucket. A 60 MB clip stops being 60 MB in every clone, forever.
  • People sign in. A teammate gets an address, an email and a password — not a token to paste, and not git.

Everything else is the hub you already know: same image, same admin console, same maude design link for peers who prefer it.

When you want this, and when you don't

Use a plain hub (Deploy a hub) when everyone involved has a clone and is comfortable with git. It is smaller, cheaper, and there is less to operate.

Use a workspace when someone on the team should never have to think about git at all, or when you want a single copy that is backed up, versioned, and reachable from anywhere without anybody's laptop being open.

One command

snippet
maude hub workspace-up --dry-run \
  --domain design.acme.com \
  --acme-email ops@acme.com \
  --admin-email alice@acme.com \
  --s3-endpoint https://<account>.r2.cloudflarestorage.com \
  --s3-bucket acme-design-assets \
  --s3-access-key-id <id> \
  --s3-secret-access-key <secret>

--dry-run shows exactly what it would write and what it would check. Every configuration problem is reported at once, so you fix them in one pass instead of one round-trip per typo.

Drop --dry-run and it writes docker-compose.yml, Caddyfile and .env (mode 0600 — it holds two secrets), brings the stack up, and then verifies it.

No object storage yet? Leave the --s3-* flags off and add them later; media stays in git in the meantime. --dev-minio stands up a throwaway MinIO for trying the whole thing locally — it is for testing, and the credentials are written into the directory, so don't point a real workspace at it.

Prefer a file? --config workspace.json accepts the same fields.

Try it on your laptop first

--local runs the whole stack on your own machine with no domain, no certificate and no account anywhere:

snippet
maude hub workspace-up --local --dev-minio \
  --domain ws.127.0.0.1.nip.io --admin-email you@example.com

That hostname resolves to 127.0.0.1 without touching /etc/hosts, so the stack comes up and the verification steps run against a real workspace — the same code a public deployment runs, minus TLS.

It is for testing only, and both the generated Caddyfile and .env say so: local mode serves plain HTTP, so a sign-in password would travel in the clear. Never point anyone else at a workspace started this way.

It verifies before it claims to work

This is the part that matters, and it is why the command takes longer than writing three files. Printing a URL without proving a round-trip tells you something the tool does not actually know.

CheckWhat it proves
The workspace answersTLS is up and the hub is serving
The operator credential worksHUB_SECRET in your .env really is admin
The first person can sign inThe account exists and the password works
A canvas survives a round tripIt syncs up and reads back byte-identical
Autosave produced a commitThe edit is in the workspace's git history
Media reaches the bucketObject storage is wired, not just configured
Nothing will expire the mediaNo lifecycle rule applies to assets/
A backup can be restoredmaude hub restore-drill passes

A check the current build cannot automate prints as skipped, never as passed. If you see one, it is unverified and needs a hand check — counting an unrun check as green is the fastest way to make a verification suite worthless.

Re-running is the upgrade path

Run workspace-up again to regenerate the deployment files. Secrets already in .env are reused, not re-minted: a fresh HUB_SECRET would lock out every peer that already has a token, and re-running is exactly what you do after a failed attempt.

What stays yours

The command scaffolds and verifies a workspace once. It does not operate it. On every successful run it prints the list, and it is worth reading rather than skimming:

  • Rotate HUB_SECRET when someone leaves. It is the operator credential. maude hub token rotate handles peer tokens.
  • Watch the restore drill, not the backup. Schedule maude hub restore-drill. A backup nobody has restored is a hypothesis — and a database that restores readable-but-empty looks exactly like a working one until the day you need it.
  • Pin the image tag. latest means an unplanned upgrade on the next restart.
  • Upgrades are yours. Re-running regenerates files; nothing here watches for releases.
  • The bill is yours. This runs on your infrastructure.
  • Never expire the assets/ prefix. A canvas in your git history can reference media no current canvas does, so "unreferenced" never means "unreachable". An expired object is a permanently broken canvas with no recovery path. maude hub asset-check proves nothing dangles.

Where "back" goes in a browser tab

Open a workspace project in a browser and the menubar names the project you are in. It shows no "← Dashboard" link, because a workspace is one hub serving one project — there is no list of projects to go back to. That is deliberate, not missing: the link used to default to Maude Cloud, which walked self-hosters off their own deployment onto an account most of them do not have.

If you run your own landing page and want the way back, set two optional variables in .env:

VariableWhat it does
HUB_DASHBOARD_URLThe address the "← Dashboard" link points at. Omit it and the link is not rendered at all.
MAUDE_REPORT_URLWhere the Report-a-Bug dialog sends its (consented, scrubbed) bundle. Omit it and reports go to Maude's own endpoint — nothing is ever sent without the preview and your click.

Your designs are never run on the server

A workspace stores and syncs canvases. It never renders one, never builds a bundle beyond the sandboxed canvas build, never runs a browser against your content — and it will refuse to start if any surface that could do so is reachable.

That is enforced by the process itself plus a CI gate, not by a convention someone has to remember.

"Never run on the server" does not mean "not visible in your browser." The two are easy to conflate and the first live deployment did: canvases do render in the browser studio — in your browser, on a segregated canvas origin the workspace serves. What the workspace never does is evaluate your canvas for its own purposes. If canvases come up as blank frames with ERR_CONNECTION_REFUSED in the console, that is not this policy at work — it is a missing canvas domain: the canvas origin needs its own public hostname (workspace-up --canvas-domain canvas.acme.com, plus a DNS record), or the iframe falls back to a container-internal port no remote browser can reach.

Exports split along the same line. PNG and SVG of the active artboard, and the PPTX deck, are captured by your browser — the same place the canvas already renders — so they work in every workspace, instantly, with no extra moving parts. Exports that need a server-side browser (video, PDF, multi-artboard scopes) run in Maude Desktop on your machine, or — if you deploy it — in the dedicated maude-render sidecar, a separate container that holds the browser and none of the workspace's secrets (Self-hosting → the render sidecar). Without either, the export dialog says so instead of failing; ZIP export always works, because zipping evaluates nothing.

Costs

Unchanged from Hub pricing — one small box plus object storage. A workspace adds the bucket (R2 is ~$0.015/GB with no egress charge) and nothing else. The self-host path is free forever and stays that way.

On this page