exo splits a language model across several computers on the same network so they act as one. Devices running it find each other automatically, and exo decides how to shard the model from each machine's memory and the speed of the links between them, with tensor parallelism the README measures at up to 1.8 times faster on two devices and 3.2 times on four. Each node serves a dashboard and an API on port 52415, reachable from the local network, that speaks the OpenAI Chat Completions, OpenAI Responses, Claude Messages and Ollama formats, so existing clients connect without changes.
It is built on Apple's MLX and is at its best on Apple Silicon. With macOS 26.2 and Thunderbolt 5 cables it uses RDMA between Macs, which is how four 512 GB Mac Studios ran DeepSeek V3.1 671B and Kimi K2 Thinking in Jeff Geerling's benchmarks. On Linux it currently runs on the CPU, with GPU support still in development.
exo is made by exo labs, licensed Apache-2.0, and has about 47,700 stars. Its clips of stacked Mac Minis running large models spread widely on X, and those demos are a fair picture of what it is for: pooling memory you already own instead of buying one very large GPU.
- Repository: github.com/exo-explore/exo
- Licence: Apache-2.0 (Apache License 2.0)
- Language: Python. Stars: 47.7K. Forks: 3,539. Last push: Oct 2, 2026.
- Scan: safe, Aug 25, 2026, commit 21a54c5
Who it is for
People with two or more Apple Silicon Macs, or a Mac plus other machines, who want to run models larger than any one of them can hold, and labs testing distributed inference on consumer hardware.
Getting started
1. macOS app, with Homebrew (requires macOS Tahoe 26.2 or later)
brew install --cask exo2. Or run from source: clone and build the dashboard (needs Xcode, uv, Node and nightly Rust)
git clone https://github.com/exo-explore/exo && cd exo/dashboard && npm install && npm run build && cd ..3. Install the MLX backend and start the node (Linux: --extra mlx-cpu)
uv sync --extra mlx && uv run exo4. Open the dashboard and API on any device in the cluster
open http://localhost:52415The macOS app asks for permission to change system settings and installs a network profile and a LaunchDaemon; uninstall it from the app's own menu to remove those cleanly. RDMA needs every Mac on exactly the same macOS version, each connected to all the others by Thunderbolt 5 cables, and a one-time rdma_ctl enable run from Recovery mode. The API has no login and listens on every network interface, so run exo on a network you trust.
Safety scan
We cloned exo-explore/exo at commit 21a54c5 on Aug 25, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.
- No secrets, no suspicious code patterns and no bare-IP URLs across 888 files and about 99,000 lines of Python, Svelte, Swift and Rust. The one npm hook is the dashboard's prepare step, svelte-kit sync, which only generates type files.
- The API server binds to 0.0.0.0:52415 with no authentication. That is how nodes reach each other, but it also means any device on the same network can load models and send prompts. Run it on a network you trust, and set EXO_LIBP2P_NAMESPACE if other exo machines nearby should not join your cluster.
- Three shell scripts were listed as installers. app/EXO/uninstall-exo.sh needs sudo because it removes what the macOS app set up as root: the io.exo.networksetup LaunchDaemon, its network script and logs, and an exo network location, and it switches Thunderbolt Bridge back on. The two in tmp/ are developer helpers that deploy a pushed commit to other machines over SSH with Nix.
- 182 known advisories (4 critical, 72 high) across three lockfiles. uv.lock holds 117: the criticals are anyio 4.11.0, a runtime dependency, over TLS name checks for internationalised domain names, and three in NLTK, which arrives only through the lm-eval benchmarking package and concerns its Stanford wrappers and pickle loaders. dashboard/package-lock.json (45) is build tooling for a dashboard compiled to static files, and Cargo.lock (20, none critical) covers the Rust networking bindings.
- Two workflows, none using pull_request_target; the 5 third-party actions are pinned to tags, not commits. Licence and contributing guide present; no security policy, Dependabot or CodeQL. The scanned main branch is from August 25, 2026, while the latest tagged release, 1.0.71, which the Homebrew cask installs, dates from April.
What the scanner counted
| Check | Result |
|---|---|
| Secrets | None found. |
| Suspicious code | None found. |
| Install-time code | 1 npm lifecycle script. 3 installer scripts (one can call sudo) |
| Committed binaries | None. |
| CI workflows | 2 workflows. None use pull_request_target. 5 of 5 third-party actions pinned to a tag rather than a commit. |
| Network hosts | 14 distinct hosts referenced from source; most often huggingface.co, ui.perfetto.dev, github.com, pyo3.rs. No URLs to bare IP addresses. |
| Known vulnerabilities | 182 advisories across 975 pinned packages: 4 critical, 72 high, 70 moderate, 24 low, 12 unrated. Cargo.lock: 559 packages, 20 advisories; dashboard/package-lock.json: 233 packages, 45 advisories; uv.lock: 186 packages, 117 advisories. |
| Project hygiene | Has licence file, contributing guide. Missing security policy, automated dependency updates, CodeQL. |
| OpenSSF Scorecard | Not scored: the project is not in Scorecard's weekly index. |
The raw findings
Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.
npm lifecycle scripts (1)
dashboard/package.jsonprepare:svelte-kit sync || echo ''
Installer scripts (3)
- app/EXO/uninstall-exo.sh, 210 lines, uses sudo
- tmp/run_exo_on.sh, 54 lines
- tmp/run_llm.sh, 25 lines
Worst known vulnerabilities (24 of 182)
| Advisory | Severity | Package | Summary |
|---|---|---|---|
| GHSA-82r6-8w77-94w6 | critical | anyio@4.11.0 | AnyIO: TLSStream IDNA 2003 host name encoding enables potential TLS certificate spoofing |
| GHSA-m4rf-3fr8-xwx3 | critical | nltk@3.9.3 | NLTK: JVM argument injection bypass via per-call options in the NLTK Stanford wrappers (incomplete fix of CVE-2026-12841… |
| GHSA-rhp5-r9x4-f5g2 | critical | nltk@3.9.3 | NLTK: Unsafe Pickle Deserialization in TransitionParser Allows Remote Code Execution |
| GHSA-x99w-6fgc-pmfw | critical | nltk@3.9.3 | NLTK: Allowlisted pickle loaders still permit code execution in current source |
| GHSA-vvp9-7p8x-rfvv | high | lz4_flex@0.10.0 | lz4_flex's decompression can leak information from uninitialized memory or reused output buffer |
| GHSA-36hh-v3qg-5jq4 | high | pyo3@0.28.3 | PyO3 has an Out-of-bounds Read in `nth` / `nth_back` for `PyList` and `PyTuple` iterators |
| GHSA-4w2j-m93h-cj5j | high | quinn-proto@0.11.14 | Quinn: Remote memory exhaustion in quinn-proto from unbounded out-of-order stream reassembly |
| GHSA-2crg-3p73-43xp | high | @sveltejs/kit@2.49.0 | @sveltejs/adapter-node has a BODY_SIZE_LIMIT bypass |
| GHSA-j2f3-wq62-6q46 | high | @sveltejs/kit@2.49.0 | @sveltejs/kit has memory amplification DoS vulnerability in Remote Functions binary form deserializer (application/x-sve… |
| GHSA-j62c-4x62-9r35 | high | @sveltejs/kit@2.49.0 | SvelteKit is vulnerable to denial of service and possible SSRF when using prerendering |
| GHSA-j22f-vq7h-c4qm | high | devalue@5.6.2 | devalue: `stringify`/`uneval` serialize shared memory |
| GHSA-mcm9-63f2-9j32 | high | devalue@5.6.2 | devalue: Repeated primitive strings cause quadratic expansion in uneval |
| GHSA-r9w8-h9r3-54w4 | high | devalue@5.6.2 | devalue: Custom ArrayBuffer revivers can bypass typed-array allocation validation |
| GHSA-28wg-ghj8-5hjv | high | nanoid@3.3.11 | nanoid: non-secure generators can loop indefinitely with negative size |
| GHSA-2v37-7h3g-55p8 | high | nanoid@3.3.11 | nanoid: custom generators can loop indefinitely when size is zero |
| GHSA-xwg4-73v4-xw9w | high | nanoid@3.3.11 | nanoid: Integer Overflow or Wraparound |
| GHSA-hq66-cqwq-w95j | high | pdfjs-dist@5.6.205 | PDF.js: Arbitrary JavaScript execution upon opening a malicious PDF |
| GHSA-c2c7-rcm5-vvqj | high | picomatch@4.0.3 | Picomatch has a ReDoS vulnerability via extglob quantifiers |
| GHSA-6g55-p6wh-862q | high | postcss@8.5.6 | PostCSS: Arbitrary file read and information disclosure via attacker-controlled sourceMappingURL in CSS comments |
| GHSA-r28c-9q8g-f849 | high | postcss@8.5.6 | PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) leads to Arbitrary .map File Disclosure |
| GHSA-mw96-cpmx-2vgc | high | rollup@4.53.3 | Rollup 4 has Arbitrary File Write via Path Traversal |
| GHSA-fx2h-pf6j-xcff | high | vite@6.4.1 | vite: `server.fs.deny` bypass on Windows alternate paths |
| GHSA-p9ff-h696-f583 | high | vite@6.4.1 | Vite Vulnerable to Arbitrary File Read via Vite Dev Server WebSocket |
| GHSA-cq5v-8q36-5273 | high | aiohttp@3.13.3 | AIOHTTP: Out-of-bounds heap read in C HTTP response parser error path (malformed chunked response) |
By the numbers
| Stars | 47.7K |
|---|---|
| Forks | 3,539 |
| Contributors | 107 |
| Commits | 2,354 |
| Open issues | 211 |
| Open pull requests | 228 |
| Releases | 16 |
| Latest release | v1.0.71 |
| Licence | Apache-2.0 |
| Main language | Python |
| Project age | 2 years |
| Last push | Oct 2, 2026 |
| Tracked files | 888 |
| Lines of code | 98.7K |
| Checkout size | 8 MB |
Lines by language: Python 56.4K, Svelte 20.1K, Swift 6,284, TOML 5,499, TypeScript 4,541, Markdown 2,125.
Questions
Is exo free?
Yes. exo is Apache-2.0 and free, including the macOS app, with no account or paid tier. Models download from Hugging Face under their own licences. The real cost is hardware: the large-model results in its benchmarks used Mac Studios with 512 GB of memory each.
What hardware does exo need?
Any machines that can reach each other on a network; exo pools their memory. It runs best on Apple Silicon Macs through MLX, and RDMA over Thunderbolt 5 (M4 Pro Mac Mini, M4 Max Mac Studio or MacBook Pro, M3 Ultra Mac Studio) cuts latency between them sharply. Linux nodes currently run on the CPU only.
Can I use exo with my existing chat apps?
Yes. Every node exposes an API on port 52415 that is compatible with OpenAI Chat Completions, OpenAI Responses, Claude Messages and the Ollama API, so Open WebUI or anything that accepts a custom OpenAI base URL can point at the cluster.
This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.
