- {/* Header */}
-
-
-
- Experimental. Pool GPUs with others
- for decentralized LLM inference — no API keys, no cloud. Start a private mesh, join one
- with an invite token, or discover public meshes.{' '}
-
- docs.anarchai.org
-
-
-
-
-
- {error &&
{error}
}
-
-
- {/* Not installed — non-macOS only; on macOS start-mesh handles the download */}
- {status === 'not-installed' && (
-
-
Get started
-
- mesh-llm is not installed. Follow the install guide to set it up, or connect to a mesh
- already running on this machine.
-
-
-
- )}
-
- {/* Downloading */}
- {status === 'downloading' && (
-
-
Downloading latest mesh-llm...
-
- Fetching the latest version to ~/.mesh-llm/. This should only take a moment.
-
-
- )}
-
- {/* Setup panel — shown when stopped and installed */}
- {(status === 'stopped' || status === 'unknown') && (
-
- {/* Mode selector */}
-
-
- setMode('auto')}
- />
-
-
- Auto-discover a public mesh
-
-
- Find and join the best available mesh automatically.
-
-
- Public meshes are run by volunteers. Your prompts are sent to their hardware — no
- privacy guarantees.
-
-
-
-
-
- setMode('join')}
- />
-
-
- Join with invite token
-
-
- Join a private mesh someone shared with you.
-
-
-
-
-
- setMode('new')}
- />
-
-
- Start a new private mesh
-
-
- Create your own mesh. Share the invite token with others to pool GPUs.
-
-
-
-
-
- {/* Mode-specific options */}
- {mode === 'new' && (
-
-
Model to serve
-
setSelectedModel(e.target.value)}
- className="text-sm bg-background-default border border-border-subtle rounded px-2 py-1.5 text-text-default w-full max-w-sm"
- >
- {MODEL_CATALOG.map((m) => (
-
- {m.name} ({m.size})
-
- ))}
-
-
- Downloads automatically if not already cached. Larger models need more VRAM.
-
-
- )}
-
- {mode === 'join' && (
-
- Invite token
- setJoinToken(e.target.value)}
- placeholder="Paste invite token here"
- className="max-w-md"
- />
-
- )}
-
- {(mode === 'auto' || mode === 'join') && (
-
- setContributeGpu(e.target.checked)}
- />
-
- Contribute GPU
- (serve models for others too)
-
-
- )}
-
-
-
- Start Mesh
-
-
-
- When you start the mesh, keep goose running to stay connected.
-
-
- )}
-
- {/* Starting indicator */}
- {status === 'starting' && (
-
-
Starting mesh-llm...
-
- Connecting to the mesh and loading models. This may take a minute on first run.
-
-
- )}
-
- {/* Running state */}
- {status === 'running' && (
- <>
- {/* Invite token */}
- {statusInfo.token && (
-
-
-
-
Invite token
-
- Share this with others so they can join your mesh.
-
-
-
- {copiedToken ? (
- <>
-
- Copied
- >
- ) : (
- <>
-
- Copy
- >
- )}
-
-
-
- {statusInfo.token}
-
-
- )}
-
- {/* Model list */}
- {statusInfo.models.length > 0 && (
-
-
Available Models
-
- Select a model to use it as your Goose provider.
-
-
- {statusInfo.models.map((modelId) => {
- const isActive = activeModel === modelId;
- return (
-
!saving && activateModel(modelId)}
- >
-
-
- {modelId}
- live
-
- {isActive ? (
-
Active
- ) : (
-
{
- e.stopPropagation();
- activateModel(modelId);
- }}
- disabled={saving}
- >
-
- Use
-
- )}
-
-
- );
- })}
-
-
- )}
-
- {statusInfo.models.length === 0 && (
-
- Mesh is running but no models are available yet. A model may still be loading.
-
- )}
-
-
- Keep goose running to stay connected to the mesh.
-
-
- {/* Actions row */}
-
- >
- )}
-
- {/* Advanced settings */}
-
-
setShowAdvanced(!showAdvanced)}
- className="flex items-center gap-1 text-sm text-text-muted hover:text-text-default transition-colors"
- >
- {showAdvanced ? (
-
- ) : (
-
- )}
- Advanced
-
-
- {showAdvanced && (
-
- {statusInfo.binaryPath && (
-
- Binary
- {statusInfo.binaryPath}
-
- )}
-
- API endpoint
- http://localhost:{MESH_API_PORT}/v1
-
-
- Console
-
- http://localhost:{MESH_CONSOLE_PORT}
-
-
-
- )}
-
-
- {/* Refresh */}
-
-
-
- Refresh
-
-
-
- );
-};
diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts
index cd8b69ac3..fc06dbb69 100644
--- a/ui/desktop/src/main.ts
+++ b/ui/desktop/src/main.ts
@@ -50,7 +50,6 @@ import { UPDATES_ENABLED } from './updates';
import './utils/recipeHash';
import { Client } from './api/client';
import { GooseApp } from './api';
-import * as mesh from './mesh';
import installExtension, { REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer';
import { BLOCKED_PROTOCOLS, WEB_PROTOCOLS } from './utils/urlSecurity';
import { buildCSP } from './utils/csp';
@@ -1093,19 +1092,6 @@ const createChat = async (app: App, options: CreateChatOptions = {}) => {
stopErrorLogCollection();
errorLog.length = 0;
- // Nudge the user if mesh is their provider but isn't running.
- // Delay to let the renderer mount before sending the IPC event.
- setTimeout(() => {
- mesh
- .checkProviderRunning(goosedClient)
- .then((ok) => {
- if (!ok && !mainWindow.isDestroyed()) {
- mainWindow.webContents.send('mesh-not-running');
- }
- })
- .catch(() => {});
- }, 5000);
-
// Let windowStateKeeper manage the window
mainWindowState.manage(mainWindow);
@@ -2037,12 +2023,6 @@ ipcMain.handle('select-import-session-file', async () => {
}
});
-// ── Mesh-LLM lifecycle (see mesh.ts) ────────────────────────────────
-
-ipcMain.handle('check-mesh', () => mesh.check());
-ipcMain.handle('start-mesh', (_event, args: string[]) => mesh.start(args));
-ipcMain.handle('stop-mesh', () => mesh.stop());
-
ipcMain.handle('check-ollama', async () => {
try {
return new Promise((resolve) => {
@@ -2925,9 +2905,6 @@ async function getAllowList(): Promise