feat(macos): add native Homebrew install path #14
@@ -37,6 +37,17 @@ desktop shortcut runs and still works directly.
|
||||
```
|
||||
This activates the `Promethean` venv and starts the Synapse backend on port 8000 (which also serves the built UI). It additionally starts a **Vite dev server** for frontend hot-reload — a Linux-dev convenience, unlike the single-process Windows/production path where the backend serves `dist/` alone. It does **not** start Ollama.
|
||||
|
||||
**macOS (community-supported):**
|
||||
```bash
|
||||
./install-macos.sh # one-time: Homebrew packages + venv + web build, via bin/sync.py
|
||||
./launch_nexus.sh # same script as Linux - it's plain bash, no Linux-only calls
|
||||
```
|
||||
No bundled Ollama binary (Linux x86-64 only) and no XFCE desktop branding — both
|
||||
already no-op on macOS via `bin/sync.py`'s `linux_stage()`. Ollama is instead the
|
||||
Homebrew-installed native binary, picked up automatically because
|
||||
`OllamaManager` falls back to `ollama` on PATH when the bundled binary is
|
||||
absent; that gets full Metal GPU acceleration with no extra config.
|
||||
|
||||
**Individual services via CLI:**
|
||||
```bash
|
||||
# From nexus-core/ with Promethean venv active:
|
||||
@@ -92,7 +103,7 @@ cd interface/web && npm run build
|
||||
## Architecture
|
||||
|
||||
### Python venv
|
||||
All Python code runs inside `Promethean/` (a local venv). Always activate it before running backend commands: `source Promethean/bin/activate`. Dependencies are layered: `requirements-base.txt` holds the GPU-agnostic core (nothing in it needs a GPU or imports torch), and a thin overlay per platform sets the right PyTorch package index — `requirements-amd.txt` (ROCm), `requirements-nvidia.txt` (CUDA, generated by `bin/gen-nvidia-reqs.py`), or `requirements-windows.txt` (CPU-only, standalone). `bin/sync.py` (`requirements()`) selects NVIDIA, AMD, or CPU/Windows requirements from the host and installs that alone by default — fast, no multi-GB downloads.
|
||||
All Python code runs inside `Promethean/` (a local venv). Always activate it before running backend commands: `source Promethean/bin/activate`. Dependencies are layered: `requirements-base.txt` holds the GPU-agnostic core (nothing in it needs a GPU or imports torch), and a thin overlay per platform sets the right PyTorch package index — `requirements-amd.txt` (ROCm), `requirements-nvidia.txt` (CUDA, generated by `bin/gen-nvidia-reqs.py`), or `requirements-windows.txt` (CPU-only, standalone). macOS uses `requirements-base.txt` without an overlay because Ollama handles inference outside the venv. `bin/sync.py` (`requirements()`) selects the appropriate requirements for the host and installs that alone by default — fast, no multi-GB downloads.
|
||||
|
||||
`requirements-ml.txt` is a separate, **opt-in** overlay for local ML inference (transformers/accelerate/bitsandbytes + torch/torchaudio/torchvision) — nothing in `synapse/` imports any of it; Ollama does all inference over HTTP. Only pull it in for local model work outside Ollama: `pip install -r requirements-amd.txt -r requirements-ml.txt` (or `-nvidia`, or alone for CPU-only torch). Not installed by `bin/sync.py`/the installers.
|
||||
|
||||
|
||||
@@ -134,7 +134,8 @@ ncp web
|
||||
Python deps are layered: `requirements-base.txt` (GPU-agnostic core) plus one
|
||||
GPU overlay — `requirements-amd.txt` (ROCm) or `requirements-nvidia.txt` (CUDA).
|
||||
`requirements-windows.txt` is the standalone CPU-only runtime (no base overlay).
|
||||
`bin/sync.py` picks the right one for the host.
|
||||
macOS uses `requirements-base.txt` directly, no overlay — see the macOS section
|
||||
below. `bin/sync.py` picks the right one for the host.
|
||||
|
||||
`./install.sh` is also the update path — re-run it any time to pull the latest
|
||||
and rebuild. `--check` dry-runs it; `--no-desktop` skips the XFCE panel/theme
|
||||
@@ -172,10 +173,38 @@ The app opens at `:8000`; click **Start AI** to launch Ollama. The installer
|
||||
uses `requirements-windows.txt` (CPU-only, pure-Python — no ML stack, since Ollama
|
||||
does all inference over HTTP).
|
||||
|
||||
### macOS
|
||||
|
||||
Community-supported — no bundled Ollama binary or XFCE desktop branding (that
|
||||
stage is Linux/XFCE-only and already skips itself here), but the
|
||||
backend/frontend/Ollama stack itself runs natively, no VM or container needed.
|
||||
|
||||
```bash
|
||||
# 1. Install Homebrew first if you don't have it: https://brew.sh
|
||||
|
||||
# 2. Build everything: Homebrew packages (Python, Node, git, Ollama), venv,
|
||||
# web UI, memory DB.
|
||||
./install-macos.sh
|
||||
|
||||
# 3. Launch (memory :8001, backend :8000 — backend also serves the built UI)
|
||||
./launch_nexus.sh
|
||||
```
|
||||
|
||||
Ollama here is the Homebrew-installed native binary, not the Linux-only bundled
|
||||
one — `OllamaManager` already falls back to `ollama` on PATH when
|
||||
`ollama/bin/ollama` doesn't exist, so **Start AI** in the sidebar (or `ollama
|
||||
serve` in a terminal) uses it with full Metal GPU acceleration automatically,
|
||||
no configuration needed.
|
||||
|
||||
`./install-macos.sh` is also the update path, same idea as Linux — re-run it
|
||||
any time to pull the latest and rebuild; `--check` dry-runs it. It's a thin
|
||||
wrapper over `bin/sync.py restore`, the same code Linux and `ncp restore`
|
||||
(any platform) run.
|
||||
|
||||
### Individual services
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
# Linux / macOS
|
||||
source Promethean/bin/activate
|
||||
|
||||
uvicorn synapse.main:sio_app --host 127.0.0.1 --port 8000 --reload # backend (serves the UI too)
|
||||
@@ -199,7 +228,7 @@ Nexus's dependencies out of the system Python. To add a package, activate it
|
||||
and `pip install` as usual:
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
# Linux / macOS
|
||||
source Promethean/bin/activate
|
||||
pip install <package>
|
||||
```
|
||||
@@ -274,7 +303,9 @@ are the exception (YAML files in `data/playbooks/`). All paths are defined in
|
||||
- **Filesystem paths** — `synapse/nexus_config.py`
|
||||
- **Frontend API base URL** — `interface/web/src/config.js`
|
||||
- **Python deps** — `requirements-base.txt` + amd/nvidia GPU overlay;
|
||||
`requirements-windows.txt` = standalone CPU runtime
|
||||
`requirements-windows.txt` = standalone CPU runtime; macOS uses
|
||||
`requirements-base.txt` with no overlay (Ollama, not this venv, does
|
||||
inference — natively, with Metal)
|
||||
|
||||
## Issues and feature requests
|
||||
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ else
|
||||
fi
|
||||
|
||||
echo "== shell parse =="
|
||||
for f in scripts/install-termux.sh launch_nexus.sh management/nexus-cli.sh; do
|
||||
for f in scripts/install-termux.sh install-macos.sh launch_nexus.sh management/nexus-cli.sh; do
|
||||
[ -f "$f" ] && { bash -n "$f" || fail=1; }
|
||||
done
|
||||
|
||||
|
||||
+12
-3
@@ -66,9 +66,11 @@ def ensure_exec_bits() -> None:
|
||||
|
||||
|
||||
def linux_stage(script: str, *args) -> None:
|
||||
"""Run one of the Linux-only bash stages. A no-op on Windows, where apt,
|
||||
xfconf, plank and the rest have nothing to act on."""
|
||||
if os.name == "nt":
|
||||
"""Run one of the Linux-only bash stages. A no-op on Windows and macOS,
|
||||
where apt, xfconf, plank and the rest have nothing to act on. os.name is
|
||||
'posix' on both Linux and macOS, so the Windows-only os.name check alone
|
||||
doesn't exclude macOS - needs the explicit darwin check too."""
|
||||
if os.name == "nt" or sys.platform == "darwin":
|
||||
return
|
||||
path = ROOT / "bin" / script
|
||||
bash = shutil.which("bash")
|
||||
@@ -109,6 +111,13 @@ def requirements() -> str:
|
||||
"""Pick the PyTorch overlay for this host."""
|
||||
if os.name == "nt":
|
||||
return "requirements-windows.txt" # CPU / pure-Python, right for native Windows
|
||||
if sys.platform == "darwin":
|
||||
# No ROCm/CUDA overlay applies here, and none is needed: Ollama does
|
||||
# all inference over HTTP (see requirements-ml.txt), and on macOS
|
||||
# that's a natively-installed, Metal-accelerated Ollama binary
|
||||
# (OllamaManager falls back to it on PATH - see synapse/ollama_manager.py),
|
||||
# entirely outside this venv.
|
||||
return "requirements-base.txt"
|
||||
if shutil.which("nvidia-smi"):
|
||||
return "requirements-nvidia.txt"
|
||||
lspci = shutil.which("lspci")
|
||||
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# NexusOS installer, macOS. One painless command:
|
||||
#
|
||||
# git clone <repo> nexus-core && cd nexus-core && ./install-macos.sh
|
||||
#
|
||||
# Mirrors install.sh's philosophy: every portable step - git pull, venv, pip
|
||||
# with the right overlay, npm build - lives in bin/sync.py, shared with Linux
|
||||
# and Windows. This script only does what sync.py can't do for itself on a
|
||||
# bare Mac: install the Homebrew packages needed before Python even exists to
|
||||
# run sync.py with. Re-run any time to update; --check dry-runs it.
|
||||
#
|
||||
# Ollama itself is *not* fetched here - bin/fetch-ollama.sh only ships a Linux
|
||||
# x86-64 binary, and linux_stage() in bin/sync.py already no-ops on macOS, so
|
||||
# that stage is skipped entirely. The Homebrew `ollama` installed below is
|
||||
# picked up automatically instead: synapse/ollama_manager.py prefers the
|
||||
# bundled Linux binary and falls back to whatever `ollama` it finds on PATH,
|
||||
# which on macOS is this one - with full Metal GPU acceleration, no flags
|
||||
# needed. The XFCE desktop branding (theme/panel/splash) is Linux-only and
|
||||
# already gated off macOS the same way; nothing to install for it here.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if ! command -v brew >/dev/null; then
|
||||
echo "Homebrew is required (it installs Python/Node/git/Ollama)." >&2
|
||||
echo "Install it, then re-run this script: https://brew.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installing/checking system packages (python@3.12, node, git, ollama)..."
|
||||
brew install python@3.12 node git ollama
|
||||
|
||||
py="$(brew --prefix python@3.12)/bin/python3.12"
|
||||
if [ ! -x "$py" ]; then
|
||||
echo "python3.12 not found at $py after brew install - check 'brew doctor'." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prefer the venv interpreter once it exists, same as install.sh; the brewed
|
||||
# interpreter above is only the bootstrap case on a fresh clone. sync.py is
|
||||
# stdlib-only either way.
|
||||
[ -x "Promethean/bin/python" ] && py="Promethean/bin/python"
|
||||
|
||||
exec "$py" bin/sync.py restore "$@"
|
||||
Reference in New Issue
Block a user