diff --git a/fly/DOMAIN_CUTOVER.md b/fly/DOMAIN_CUTOVER.md
new file mode 100644
index 0000000000..d65572d787
--- /dev/null
+++ b/fly/DOMAIN_CUTOVER.md
@@ -0,0 +1,184 @@
+# Domain cutover runbook — meshllm.cloud
+
+Goal: reshuffle the three public hostnames without breaking live inference or
+the public site.
+
+| Hostname | Today | Target |
+|---|---|---|
+| `meshllm.cloud` (apex) | Console (Fly) | **Marketing site** (GitHub Pages) |
+| `docs.meshllm.cloud` | Marketing + docs (GH Pages via Cloudflare) | **301 redirect → `meshllm.cloud/docs/`** |
+| `public.meshllm.cloud` | — | **Console** (Fly) ✅ done |
+
+Three control planes are involved:
+
+- **Fly** — runs the console app `mesh-llm-console` (`fly/console/fly.toml`).
+- **GitHub Pages** — builds/serves the static site from `website/` via
+ `.github/workflows/website-pages.yml`; custom domain driven by
+ `website/src/CNAME`. Pages origin host for this repo is `mesh-llm.github.io`.
+- **Cloudflare** — DNS + proxy for the `meshllm.cloud` zone.
+
+---
+
+## Status
+
+- [x] **Step 1 — Console on `public.meshllm.cloud`** (DONE)
+ - `fly certs add public.meshllm.cloud -a mesh-llm-console` — issued + verified.
+ - Cloudflare DNS: `CNAME public -> mesh-llm-console.fly.dev`, **DNS only (grey)**.
+ - `fly/console/fly.toml` + `fly/Dockerfile`: `VITE_API_URL=https://public.meshllm.cloud`.
+ - Console redeployed; `https://public.meshllm.cloud/api/status` + `/v1/models` verified.
+- [x] **Repo edits for apex** (DONE, committed on branch `console-public-domain`)
+ - `website/src/CNAME -> meshllm.cloud`
+ - `website/src/_data/site.js` canonical `url -> https://meshllm.cloud`
+ - `website/src/funding.json` + `.well-known/funding-manifest-urls -> apex`
+ - `fly/README.md` updated.
+- [ ] **Step 2 — Flip apex to GitHub Pages** (BELOW)
+- [ ] **Step 3 — `docs.` redirect** (BELOW)
+- [ ] **Step 4 — Decommission apex on Fly** (BELOW)
+- [ ] **Step 5 — Follow-up: UI anchor links** (BELOW, no urgency)
+
+---
+
+## Pre-flight
+
+Record current apex DNS so rollback is instant:
+
+```
+meshllm.cloud A 66.241.124.167 (Fly) <-- rollback target
+```
+
+Merge branch `console-public-domain` to `main` before triggering the Pages
+build (the build deploys from `main`). The console redeploy already shipped; the
+website CNAME change only takes effect once Pages rebuilds from `main`.
+
+---
+
+## Step 2 — Flip apex `meshllm.cloud` to the marketing site
+
+Order matters: set the Pages custom domain first, then DNS, then build.
+
+1. **GitHub → repo Settings → Pages**
+ - Set **Custom domain** to `meshllm.cloud`. Save.
+ - Leave **Enforce HTTPS** unchecked until the cert provisions (GitHub issues
+ it after DNS resolves to Pages), then enable it.
+
+2. **Cloudflare → DNS** for the `meshllm.cloud` zone — repoint the **apex**:
+ - Remove the existing apex `A 66.241.124.167` (Fly).
+ - Add the four GitHub Pages A records (Name = `@` / `meshllm.cloud`),
+ **Proxied (orange) is fine** with Cloudflare:
+ ```
+ A @ 185.199.108.153
+ A @ 185.199.109.153
+ A @ 185.199.110.153
+ A @ 185.199.111.153
+ ```
+ - (Optional IPv6) AAAA records:
+ ```
+ AAAA @ 2606:50c0:8000::153
+ AAAA @ 2606:50c0:8001::153
+ AAAA @ 2606:50c0:8002::153
+ AAAA @ 2606:50c0:8003::153
+ ```
+ - Alternative: a single Cloudflare CNAME-flattened `@ -> mesh-llm.github.io`
+ (Cloudflare flattens apex CNAMEs automatically). Pick A-records OR the
+ flattened CNAME, not both.
+
+3. **Trigger the Pages build** so `CNAME` = `meshllm.cloud` is published:
+ - Merge `console-public-domain` to `main` (touches `website/**`), or
+ - Run the **Public Website Deploy** workflow via `workflow_dispatch` on `main`.
+
+4. **Verify**
+ ```bash
+ dig +short meshllm.cloud # expect 185.199.108-111.153 (or CF proxy IPs)
+ curl -sI https://meshllm.cloud/ | grep -i 'server\|content-type' # GH Pages, text/html
+ curl -s https://meshllm.cloud/docs/ | grep -i '
' # Docs title
+ ```
+
+**Rollback:** in Cloudflare, restore apex `A 66.241.124.167`. Apex serves the
+console again within DNS TTL.
+
+---
+
+## Step 3 — `docs.meshllm.cloud` → 301 redirect to `meshllm.cloud/docs/`
+
+`docs.meshllm.cloud` is no longer a Pages custom domain (Pages allows one, now
+the apex). Keep the name alive as a redirect so old links never die.
+
+1. **Cloudflare → DNS** — make `docs` a **proxied** placeholder so the redirect
+ rule can run (must be **orange cloud**):
+ ```
+ CNAME docs meshllm.cloud (Proxied / orange)
+ ```
+ (If a `docs` record already exists pointing at GitHub Pages, just switch it to
+ this proxied CNAME.)
+
+2. **Cloudflare → Rules → Redirect Rules → Create rule**
+ - **When incoming requests match:** `Hostname equals docs.meshllm.cloud`
+ - **Then → Dynamic redirect:**
+ - Status code: **301 (Permanent)**
+ - Target expression:
+ ```
+ concat("https://meshllm.cloud/docs", http.request.uri.path)
+ ```
+ - **Preserve query string:** on
+
+3. **Verify** (path-preserving):
+ ```bash
+ curl -sI https://docs.meshllm.cloud/ # 301 -> https://meshllm.cloud/docs/
+ curl -sI https://docs.meshllm.cloud/install # 301 -> https://meshllm.cloud/docs/install
+ ```
+
+Note: `#fragment` anchors (e.g. `docs.meshllm.cloud/#install`) redirect to
+`meshllm.cloud/docs/#install`. The page loads; the anchor is wrong because
+`#install` lives on the marketing home (`meshllm.cloud/#install`). Step 5 fixes
+the source links.
+
+---
+
+## Step 4 — Decommission the apex on Fly
+
+Once apex serves Pages and is verified, stop Fly from claiming `meshllm.cloud`:
+
+```bash
+fly certs remove meshllm.cloud -a mesh-llm-console
+# Keep public.meshllm.cloud and *.fly.dev certs.
+```
+
+Verify the console is unaffected:
+```bash
+curl -s https://public.meshllm.cloud/api/status | head -c 120
+```
+
+---
+
+## Step 5 — Follow-up: fix in-console UI links (no urgency)
+
+These are baked into the console UI bundle and require a console rebuild +
+redeploy. Not blocking; covered by the Step 3 redirect in the meantime.
+
+In `crates/mesh-llm-ui/src/`:
+
+- Keep links meant for **docs** as `https://docs.meshllm.cloud/` (redirects to
+ `/docs/`) — or update to `https://meshllm.cloud/docs/` directly.
+- Fix **marketing-home anchors** to the apex:
+ - `https://docs.meshllm.cloud/#install` -> `https://meshllm.cloud/#install`
+ - `https://docs.meshllm.cloud/#blackboard` -> `https://meshllm.cloud/#blackboard`
+- Files with these refs: `features/app-tabs/data.ts`,
+ `features/shell/components/TopNav.tsx`, `features/app-shell/components/AppHeader.tsx`,
+ `features/chat/components/ChatPage.tsx`,
+ `features/configuration/pages/ConfigurationPage.tsx`,
+ `constants/default-system-prompt.md`, plus their `.test.tsx` expectations.
+
+After editing, rebuild + redeploy the console:
+```bash
+fly deploy --config fly/console/fly.toml --dockerfile fly/Dockerfile
+```
+
+---
+
+## Quick reference — final DNS state (Cloudflare)
+
+| Type | Name | Target | Proxy |
+|---|---|---|---|
+| A | `@` | 185.199.108–111.153 (GH Pages) | proxied or DNS-only |
+| CNAME | `public` | `mesh-llm-console.fly.dev` | **DNS only (grey)** |
+| CNAME | `docs` | `meshllm.cloud` | **Proxied (orange)** + redirect rule |
diff --git a/fly/Dockerfile b/fly/Dockerfile
index 44d1bea074..d7b81835ec 100644
--- a/fly/Dockerfile
+++ b/fly/Dockerfile
@@ -7,7 +7,7 @@
# syntax=docker/dockerfile:1.7
FROM node:24-alpine AS ui-builder
-ARG VITE_API_URL=https://meshllm.cloud
+ARG VITE_API_URL=https://public.meshllm.cloud
ARG VITE_APP_VERSION=
ARG VITE_STORAGE_NAMESPACE=mesh-llm-ui-production
ARG NODE_ENV=production
@@ -80,6 +80,15 @@ COPY crates/llama-spec-bench/ crates/llama-spec-bench/
COPY crates/skippy-bench/ crates/skippy-bench/
COPY crates/skippy-prompt/ crates/skippy-prompt/
COPY crates/mesh-mixture-of-agents/ crates/mesh-mixture-of-agents/
+COPY crates/mesh-llm-cli/ crates/mesh-llm-cli/
+COPY crates/mesh-llm-commands/ crates/mesh-llm-commands/
+COPY crates/mesh-llm-embedded-runtime/ crates/mesh-llm-embedded-runtime/
+COPY crates/mesh-llm-events/ crates/mesh-llm-events/
+COPY crates/mesh-llm-hardware-profile/ crates/mesh-llm-hardware-profile/
+COPY crates/mesh-llm-native-runtime/ crates/mesh-llm-native-runtime/
+COPY crates/mesh-llm-runtime-install/ crates/mesh-llm-runtime-install/
+COPY crates/mesh-llm-sdk/ crates/mesh-llm-sdk/
+COPY crates/mesh-llm-tui/ crates/mesh-llm-tui/
COPY tools/xtask/ tools/xtask/
COPY scripts/prepare-llama.sh scripts/build-llama.sh scripts/
COPY third_party/llama.cpp/upstream.txt third_party/llama.cpp/upstream.txt
diff --git a/fly/README.md b/fly/README.md
index 96753b9ce3..fbfac9a31b 100644
--- a/fly/README.md
+++ b/fly/README.md
@@ -6,7 +6,7 @@ Fly app running mesh-llm in `--client` mode — no GPU, just QUIC tunnels to mes
|---|---|---|
| **console** | [mesh-llm-console.fly.dev](https://mesh-llm-console.fly.dev) | `fly/console/fly.toml` |
-Also available at [www.mesh-llm.com](https://www.mesh-llm.com) and [meshllm.cloud](https://meshllm.cloud).
+Also available at [public.meshllm.cloud](https://public.meshllm.cloud).
## Architecture
diff --git a/fly/console/fly.toml b/fly/console/fly.toml
index 2aeb974558..becd444748 100644
--- a/fly/console/fly.toml
+++ b/fly/console/fly.toml
@@ -6,7 +6,7 @@ primary_region = "syd"
[build.args]
NODE_ENV = "production"
- VITE_API_URL = "https://meshllm.cloud"
+ VITE_API_URL = "https://public.meshllm.cloud"
VITE_STORAGE_NAMESPACE = "mesh-llm-ui-production"
[env]
diff --git a/website/src/.well-known/funding-manifest-urls b/website/src/.well-known/funding-manifest-urls
index abf31868c2..a4983a0764 100644
--- a/website/src/.well-known/funding-manifest-urls
+++ b/website/src/.well-known/funding-manifest-urls
@@ -1 +1 @@
-https://docs.meshllm.cloud/funding.json
+https://meshllm.cloud/funding.json
diff --git a/website/src/CNAME b/website/src/CNAME
index 1bcac675e5..155c22fb25 100644
--- a/website/src/CNAME
+++ b/website/src/CNAME
@@ -1 +1 @@
-docs.meshllm.cloud
+meshllm.cloud
diff --git a/website/src/_data/site.js b/website/src/_data/site.js
index 531aef969b..2a171e686c 100644
--- a/website/src/_data/site.js
+++ b/website/src/_data/site.js
@@ -1,7 +1,7 @@
const site = {
title: 'Mesh LLM',
description: 'Mesh serves large local models across multiple machines through one OpenAI-compatible endpoint.',
- url: 'https://docs.meshllm.cloud',
+ url: 'https://meshllm.cloud',
publicMeshUrl: 'https://public.meshllm.cloud',
githubUrl: 'https://github.com/Mesh-LLM/mesh-llm',
githubRepo: 'Mesh-LLM/mesh-llm',
diff --git a/website/src/funding.json b/website/src/funding.json
index 30212bfd7d..4a7833754c 100644
--- a/website/src/funding.json
+++ b/website/src/funding.json
@@ -21,7 +21,7 @@
},
"repositoryUrl": {
"url": "https://github.com/Mesh-LLM/mesh-llm",
- "wellKnown": "https://docs.meshllm.cloud/.well-known/funding-manifest-urls"
+ "wellKnown": "https://meshllm.cloud/.well-known/funding-manifest-urls"
},
"licenses": [
"spdx:Apache-2.0"