Docs · Getting started

Install on a Mac

On a Mac, Nodeau runs models directly on the GPU through Metal. No Kubernetes, no Docker, no NVIDIA tooling, and nothing that needs your password.

What a Mac does#

A Mac makes a lovely private AI endpoint. Nodeau serves chat, embedding, reranking and vision models on the Mac's own GPU, several at once, and the whole install needs no password. Nodeau on Apple Silicon is qualified, and this is its scope:

On a Mac
Chat, with streaming, on the GPU behind a local OpenAI-compatible endpointYes, through Metal
Embeddings, reranking and image input (vision)Yes, through Metal
Several models serving at once, each on its own portYes, as unified memory allows
The curated catalog, downloads and SHA-256 verificationYes
The fit check before anything startsYes, against unified memory
run, ps, stop, logs, doctor and uninstallYes
Fleets, batch inference and bringing your own modelOn your Linux machines with NVIDIA GPUs. A Mac runs standalone
Structured output and tool callingOn your Linux machines with NVIDIA GPUs
Several GPUs, scheduling modes, power limits, health, limits and policiesPart of a Linux fleet. A Mac has one integrated GPU

Requirements#

  • An Apple Silicon (M-series) Mac. Metal execution needs an M-series chip, so on an Intel Mac the installer stops and names that as the reason.
  • About 20 GB free disk. A Mac needs no container images, so it's the binaries plus your models.
  • Outbound HTTPS, to install and to download a model.
  • No password. Nothing on this path uses sudo.

Nodeau has been run on M3 Pro Macs under macOS 26.5 and macOS 27. It checks no macOS version number anywhere, so if you're on another release you're welcome to try it: untested isn't the same as unsupported, and we'd love to hear how it goes.

Step 1: get the CLI#

Terminal
curl -fsSL https://get.nodeau.ai/install.sh | bash

Or read it first:

Terminal
curl -fsSL https://get.nodeau.ai/install.sh -o install-nodeau.sh
less install-nodeau.sh
bash install-nodeau.sh

This downloads nodeau-darwin-arm64.tar.gz, checks its SHA-256 against the published manifest, and puts nodeau into ~/.local/bin. It runs as you and calls no sudo.

The macOS archive also carries a Metal model runtime, which the script places beside the binary so nodeau install can find it. There's nothing for you to build or supply.

Step 2: look at the machine#

Terminal
nodeau doctor

This only looks. It reports the chip, the Metal accelerator, memory, the state directory, whether a model runtime is installed and verified, and what's running.

Step 3: set it up#

Terminal
nodeau install --dry-run     # what would change
nodeau install               # the same, then it asks

It checks four things, then gets to work:

CheckWhat it looks for
Apple SiliconThe machine reports arm64
Metal acceleratorA usable GPU is present
Model runtimeA prepared runtime is available, bundled or named with --runtime
Storage safetyThe state directory lands on a writable, native filesystem

All four need to pass. Then Nodeau creates its directories, installs the model runtime, copies the nodeau binary into its own directory, warms the Metal shader cache ahead of your first model run, and offers to add one line to your login profile.

Everything lives in your own Library folder. There's no Kubernetes, no container runtime, no virtual machine and no privileged step.

Options#

FlagWhat it does
--dry-runShow what would change and stop
--yes, -yAnswer yes to every question
--runtime <path>Install a prepared model runtime from a directory or a .tar.gz. A path you give always wins over the bundled runtime
--skip-pathLeave your shell PATH as it is
--skip-binaryLeave the Nodeau binary where the bootstrap put it
--state <path>Path to the install ledger
--jsonMachine-readable output. A pipeline still says yes with --yes

The PATH line#

macOS has no user-writable directory on the default PATH, so one line has to go into your login profile. Nodeau shows you the exact text and asks before appending it. If you'd rather not, the line is printed for you, and nodeau still works by its full path.

It goes in ~/.zprofile rather than ~/.zshrc. Terminal.app runs login shells, so a PATH line in .zshrc works by hand and then goes missing in a script, an ssh command or a LaunchAgent.

It takes effect in a new terminal window.

Step 4: run a model#

Terminal
nodeau model list                # what you can run
nodeau run qwen3.5-4b-q4km       # download it, check the fit, serve it
nodeau ps                        # what's running

nodeau run resolves the model from the catalog, asks before downloading anything, checks that it fits, starts it on the Mac's GPU and brings up the loopback endpoint. When it's ready you'll see:

Output
──────────────────────────────────────
Nodeau is ready.
──────────────────────────────────────

Model
  qwen3.5-4b-q4km

Local API
  http://127.0.0.1:8080/v1

  Only this computer can reach it. It is not on your network.

Below that it prints a curl command you can paste as it is. From here, call it exactly as you would on Linux: see the OpenAI-compatible API.

The endpoint runs as a launchd user agent in ~/Library/LaunchAgents, so it keeps serving after you close the terminal.

Several models at once#

Each nodeau run starts its own endpoint, so give each model a port of its own:

Terminal
nodeau run qwen3.5-4b-q4km                          # chat on 8080
nodeau run qwen3-embedding-0.6b-q8_0 --port 8081    # embeddings
nodeau run bge-reranker-v2-m3-q8_0 --port 8082      # reranking
nodeau ps

Every endpoint answers as its own model, and stopping one leaves the others serving. Before nodeau run gives you an address, it checks that the model answering there is the one it started: if another program already holds the port you asked for, it tells you what holds it and prints no address, so you never get a working-looking endpoint for the wrong model.

Vision models, such as gemma-4-e4b-qat-q4-0, bring a second file with them (the image projector). Nodeau downloads and verifies both, and the request shape is the one in image input.

Unified memory#

This is the one thing about a Mac that surprises people, and it's worth a minute to understand.

On Apple Silicon the system, your applications and the GPU share one pool of memory. So "will this model fit?" isn't a fixed property of the machine. It depends on what else is open.

Nodeau reads two separate numbers:

  • a static ceiling, the most the GPU is allowed to hold. It's a property of the device, and it stays put even when free memory swings by gigabytes.
  • a live figure for what's actually free right now.

The fit check uses the smaller of the two, minus a system reserve. That has a real, correct consequence:

A model that started yesterday can be turned away today, because you now have a browser and a video call open. Close something and try again.

That's Nodeau reading the machine honestly. It keeps its safety margin whole, because an out-of-memory kill on a machine whose display runs on the same GPU is much worse than a clear "not right now".

If you want to accept that risk for one workload, nodeau run takes --accept-estimate-risk and --spend-safety-reserve. Both are explicit, both apply to one workload, and both are recorded. See accepting the risk yourself.

Where things live#

PathWhat
~/.local/bin/nodeauThe CLI, as the bootstrap installed it
~/Library/Application Support/Nodeau/Nodeau's own directory
~/Library/Application Support/Nodeau/state/models/Model cache
~/Library/Application Support/Nodeau/state/runtimes/The Metal model runtime
~/Library/Application Support/Nodeau/api-keyYour local API key, mode 0600
~/Library/LaunchAgents/The endpoint's user agent

XDG_CONFIG_HOME and XDG_STATE_HOME are honoured when you set them explicitly.

The model runtime#

On Linux a runtime is a container image with a digest, which vouches for itself. A directory can't do that, so on macOS the runtime carries a manifest (version, engine, backend, OS and architecture, a SHA-256 for every file, and the upstream commit) and fails closed if it doesn't verify.

Installing one is verify-then-promote: if a new runtime fails its checks, the previous one keeps serving. nodeau doctor reports RUNTIME_MISSING, RUNTIME_CORRUPT, RUNTIME_UNVERIFIED and RUNTIME_UNMANAGED separately, because each needs a different answer.

Upgrading#

Terminal
curl -fsSL https://get.nodeau.ai/install.sh | bash
nodeau install

nodeau update checks whether there's something newer first. See updates and release channels.

Uninstalling#

Terminal
nodeau uninstall --dry-run
nodeau uninstall

It removes what nodeau install put here and leaves everything else. A model runtime you assembled yourself, a PATH line you wrote, or a copy of nodeau you manage all stay, and the plan says so.

FlagWhat it does
--dry-runShow what would be removed and stop
--yes, -yAnswer yes to every question
--modelsAlso delete downloaded model weights
--keep-pathLeave the PATH line in your login profile
--state <path>Path to the install ledger

Your downloaded models are kept unless you pass --models. Removing the software and throwing away gigabytes of downloads are different decisions, so they're different flags.

If something went wrong#

Troubleshooting has a section for Macs.

These docs describe the current release, the beta channel. Spotted something wrong or missing? Tell us. A report from a machine we have never seen is the most useful thing we get.