Install
LatchAI is a TypeScript monorepo — packages/schema (the graph JSON and event types),
packages/engine (the daemon), packages/sdk (the code-first workflow builder), and
apps/ui (the workbench). The engine runs straight from source with tsx, so there is
no build step for it; only the UI bundle is built, and only when you want the desktop app.
There is no packaged download yet. You run LatchAI from a clone.
Prerequisites
Section titled “Prerequisites”Node and npm, and git. The repo uses npm workspaces, so a single npm install at the
root installs everything.
macOS gets three things for free: secrets in the login Keychain, the launchd integration
described in Run LatchAI as a service, and a native folder
picker when you add a mount. Elsewhere, secrets fall back to a
0600 JSON file in the home, the folder picker falls back to typing a path, and there is
no service integration — the engine itself is plain Node and has no macOS dependency.
Clone and install
Section titled “Clone and install”git clone <repository-url> latchai # TODO: public repository URLcd latchainpm installnpm install also runs a small postinstall script that brands the development Electron
shell; it is allowed to fail harmlessly on machines without it.
Nothing you create ends up in this directory. The repo is code only — every agent,
workflow, and transcript lands in the LatchAI home,
outside the clone, so you can git pull a new version without touching your work.
Start the engine and the workbench
Section titled “Start the engine and the workbench”The engine is the daemon; the UI is a Vite dev server that proxies /api and /events
to it. Run them in two terminals — the engine first.
npm run engine # daemon on :7777 (HTTP API + WebSocket event stream)npm run ui # workbench on :5173The engine’s first run creates and seeds the home, then tells you where it is listening and which provider it resolved:
[latchai] initialized home at /Users/you/LatchAI[latchai] engine on http://127.0.0.1:7777 (provider: mock)mock is the offline canned provider — that is what a fresh install with no
latchai.config.json resolves to, and it is what onboarding replaces in a moment. Open
http://localhost:5173 once Vite is up.
The engine binds 127.0.0.1 and rejects non-local Host/Origin headers on both HTTP
and WebSocket, so nothing on your network can reach it by default.
First boot
Section titled “First boot”Onboarding runs in two steps the first time the workbench loads.
Step one picks the LatchAI home — the directory that will hold your agents, workflows,
workspace, and run history. It defaults to ~/LatchAI. “Choose a different folder…” opens a
native picker and relocates the freshly seeded home; because relocating exits the engine
on purpose, the browser sits on “Moving…” until the engine answers again (in a terminal
setup, that means restarting npm run engine yourself — see
Moving the home).

Step one of onboarding: where the LatchAI home lives.
Step two picks a model, and the recommended path is ★ Run on this Mac: LatchAI
picks a starter model sized to the machine’s memory (Qwen3 4B with 16 GB or more,
Qwen3 1.7B below that), starts the download, and drops you into the app. Progress lives
in a status-bar chip, and until the model is ready, chat answers with a clearly-labeled
canned demo model. Running from a clone, local hosting also needs the llama-server
binary — see Running from a clone.
Prefer a model you already run elsewhere? Presets for OpenAI, Anthropic (Claude), Local
(Ollama), and Custom (OpenAI-compatible) fill in the fields. Test connection sends
one tiny completion and reports either ✓ Connected — <model> replied in <n>ms or a
specific failure (“could not reach …”, “authentication failed — check the API key”,
“endpoint reached, but model … was not found”). It never blocks you: Start using LatchAI
saves regardless. The API key you type is written to the
secret store, not into latchai.config.json.

Step two: run a model on this Mac, a provider preset, or demo mode.
Explore in demo mode dismisses this step and leaves LatchAI on the offline mock model — everything stays clickable, and chat shows a banner saying replies are canned examples. The 🤖 Models page connects a real one later.
After onboarding, ~/LatchAI holds a starter agents/assistant.md, a workflows/welcome.json
you can run immediately, the seeded widget catalog, and a dashboards/morning-briefing.md
brief.
Run it as a desktop app
Section titled “Run it as a desktop app”The engine serves the built UI as static files from a single origin, which is what makes the Electron shell possible:
npm run desktop # builds the UI bundle, then launches ElectronThe window is the workbench; closing it leaves the app running in the menu bar so triggers keep firing.
You can also skip Electron and use the engine’s own origin in a browser:
npm run build:ui # writes apps/ui/dist…then open http://127.0.0.1:7777 with the engine running. No Vite, no proxy.
Run a workflow headlessly
Section titled “Run a workflow headlessly”No UI required:
npm run run ~/LatchAI/workflows/welcome.jsonEvents stream to stdout — one line per event, with agent tokens printed as they arrive:
[19:04:11.281] run.started[19:04:11.283] node.started trigger[19:04:11.284] node.completed trigger (9 chars)[19:04:11.286] node.started helloHi — I'm LatchAI, a local-first AI automation workbench…[19:04:13.902] node.completed hello (214 chars)[19:04:13.903] run.completedTrailing arguments join into the optional run payload that a manual_trigger exposes as
{{trigger}}. This is a fresh process each time, so it always runs the engine code
currently on disk.
Troubleshooting
Section titled “Troubleshooting”Something else owns port 7777. LATCHAI_PORT moves the engine:
LATCHAI_PORT=7778 npm run engine. Note that only the engine reads it — npm run ui’s dev
proxy and the Electron shell both target 7777 — so with a moved port, use the engine’s
own origin (npm run build:ui, then http://127.0.0.1:7778) or the CLI.
- The LatchAI home — the directory layout you just created.
- Models — local models, connected providers, the OpenAI-compatible API, and embeddings.
- Your first project — mounting a repo you actually work in.