838860fdf0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
136 lines
12 KiB
Markdown
Executable File
136 lines
12 KiB
Markdown
Executable File
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## What is NexusOS
|
|
|
|
NexusOS is a local AI assistant platform. It runs a Python/FastAPI backend (Synapse) that interfaces with a locally bundled Ollama instance, a dedicated memory microservice, and a React/Vite frontend. All AI inference runs through Ollama on `localhost`; no external AI provider is configured or called.
|
|
|
|
## Running the Project
|
|
|
|
**Full stack (recommended):**
|
|
```bash
|
|
./launch_nexus.sh
|
|
```
|
|
This activates the `Promethean` venv, starts the memory service on port 8001, the Synapse backend on port 8000, and the Vite frontend (default port 5173).
|
|
|
|
**Individual services via CLI:**
|
|
```bash
|
|
# From nexus-core/ with Promethean venv active:
|
|
source Promethean/bin/activate
|
|
|
|
# Backend
|
|
uvicorn synapse.main:sio_app --host 0.0.0.0 --port 8000 --reload
|
|
|
|
# Memory service
|
|
uvicorn synapse.memory.service:app --host 0.0.0.0 --port 8001 --reload
|
|
|
|
# Frontend
|
|
cd interface/web && npm run dev
|
|
```
|
|
|
|
**Management CLI** (`ncp`) — start/stop services with PID tracking, plus terminal
|
|
access to the same features as the web UI (all via the REST API on `:8000`):
|
|
```bash
|
|
./management/nexus-cli.sh start # starts backend + frontend
|
|
./management/nexus-cli.sh stop
|
|
./management/nexus-cli.sh start --backend|-b / --frontend|-f / --memory|-m
|
|
|
|
# Feature commands (dispatch to management/nexus_api.py — httpx, no TUI):
|
|
ncp chat "<message>" # stream a reply (POST /chat/stream)
|
|
ncp memory list|add <text>|rm <id>
|
|
ncp playbook list|show <id> # first playbook (*) is the active system prompt
|
|
ncp history [query] # recent conversations
|
|
```
|
|
The old curses TUIs (`nexus-chat.py`, `nexus-playbook.py`) were removed in favor of
|
|
these API-backed subcommands. The CLI covers chat, memory, playbooks, and history;
|
|
the web UI and control panel expose the remaining management features.
|
|
`management/controlpanel.py` (tkinter GUI, wired into the XFCE panel via
|
|
`bin/panel/nexus-popup.py`) stays.
|
|
|
|
**Frontend lint:**
|
|
```bash
|
|
cd interface/web && npm run lint
|
|
```
|
|
|
|
**Frontend build:**
|
|
```bash
|
|
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, and a thin overlay pins the right PyTorch build for the target — `requirements-amd.txt` (ROCm), `requirements-nvidia.txt` (CUDA, generated by `bin/gen-nvidia-reqs.py`), or `requirements-wsl.txt` (CPU-only). `bin/install.sh` selects NVIDIA, AMD, or CPU/WSL requirements from the host.
|
|
|
|
### Synapse Backend (`synapse/`)
|
|
FastAPI app at `synapse/main.py`. Key responsibilities:
|
|
- `/chat/stream` — chat with Ollama; streaming uses SSE (the only chat endpoint — the non-stream `/chat` was removed). After each exchange the stream endpoint calls the Memory Service to auto-extract persistent facts.
|
|
- `/playbooks` — CRUD for playbooks stored as YAML files in `data/playbooks/` via `synapse/playbooks/store.py`.
|
|
- `/memory` — CRUD for persistent facts (proxies the same SQLite store as the memory service).
|
|
- `/models` — lists, pulls, and deletes Ollama models by proxying Ollama's HTTP API.
|
|
- `/settings` and `/ollama` — persist runtime settings and control Ollama lifecycle.
|
|
- `/conversations` — persists, retrieves, edits, deletes, and exports full chat history from SQLite.
|
|
- `/icons` — lists local application icons and applies NexusOS branding.
|
|
|
|
**System prompt assembly** (in `main.py` `chat_stream_endpoint`): the final system prompt is built by layering the active playbook instructions → reference playbook context → persistent memory facts → relevant past conversation snippets retrieved by `store.search_conversations`.
|
|
|
|
### Memory Service (`synapse/memory/`)
|
|
A separate FastAPI app on port 8001. `service.py` exposes `/memories/extract` which calls `extractor.py` — an Ollama prompt that decides whether to persist a new fact from a conversation exchange. The main Synapse backend calls this asynchronously after each streaming response. Both services share the same SQLite database (`synapse/memory/memory.db`).
|
|
|
|
### Playbook System (`synapse/playbooks/` + `synapse/playbook_manager.py`)
|
|
Playbooks are ordered records (title, goal, instructions, tags), each persisted as a `{id}.yaml` file in `data/playbooks/` by `PlaybookFileStore` (the dir is `PLAYBOOK_DIR` in `nexus_config.py`). The **first** playbook by order is the active system prompt; all subsequent playbooks are injected as reference context. `PlaybookManager` is the thin class the backend uses to retrieve them and assemble the system prompt.
|
|
|
|
### Ollama (`ollama/bin/ollama`)
|
|
A bundled Ollama binary lives at `ollama/bin/ollama`. `OllamaManager` in `synapse/ollama_manager.py` manages its lifecycle (start/stop/health-check) and selects the best available model. GPU detection uses Vulkan (`vulkaninfo`) to prefer discrete AMD/NVIDIA GPUs. The Ollama HTTP API is at `http://127.0.0.1:11434` (overridable via `OLLAMA_HOST` env var).
|
|
|
|
### Frontend (`interface/web/`)
|
|
React 19 + Vite. No routing library — `App.jsx` manages page state in a single `currentPage` useState. All API calls hit `http://localhost:8000` (configured in `src/config.js`). Pages: Chatbot, Playbook editor, Conversation History, Models, Memory, Settings.
|
|
|
|
### Persistent Storage
|
|
Most data lands in `synapse/memory/memory.db` (SQLite, WAL mode). Tables: memory facts, conversations, messages, app settings. `synapse/memory/store.py` (`PersistentMemoryStore`) owns the schema and all queries. Playbooks are the exception — they live as YAML files in `data/playbooks/` (see Playbook System). `nexus_config.py` defines all paths; it also ensures all required directories exist on import.
|
|
|
|
### Logs & Runtime State
|
|
- `runtime/backend.log`, `runtime/frontend.log`, `runtime/memory.log` — service stdout
|
|
- `runtime/logs/ollama.log`, `runtime/logs/chat.log`
|
|
- `runtime/pids/backend.pid`, `runtime/pids/frontend.pid` — used by the management CLI
|
|
|
|
## Key Config
|
|
|
|
| Concern | Location |
|
|
|---|---|
|
|
| Ollama host | `OLLAMA_HOST` env var (default `http://127.0.0.1:11434`) |
|
|
| All filesystem paths | `synapse/nexus_config.py` `Settings` class |
|
|
| Frontend API base URL | `interface/web/src/config.js` |
|
|
| Python dependencies (base) | `requirements-base.txt` |
|
|
| Python dependencies (AMD/ROCm) | `requirements-amd.txt` |
|
|
| Python dependencies (NVIDIA/CUDA) | `requirements-nvidia.txt` (generated by `bin/gen-nvidia-reqs.py`) |
|
|
| Python dependencies (WSL/CPU) | `requirements-wsl.txt` |
|
|
|
|
## Cross-Machine Notes
|
|
|
|
A shared scratch log so the two Claude Code instances (this NexusOS box and the WSL box) can hand off context. **Protocol for both instances:** only append under *your own* machine's heading — never edit the other's — and prefix every entry with an ISO date, e.g. `- [2026-06-11] …`. Owning-your-own-section keeps the two sides conflict-free, so the file can be merged by plain concatenation whenever it syncs. **Handoff ritual:** when you start a session after a sync, scan the *other* machine's section for items addressed to you (e.g. a bold `**WSL box:**` / `**NexusOS box:**` callout), act on them, and append the outcome — done or still blocked — under your *own* heading with the date.
|
|
|
|
> This file does **not** auto-sync between machines; it has to be carried across (see handoff below). The split-by-machine layout is what makes that merge painless.
|
|
|
|
### NexusOS box — native Linux · T2 Mac / AMD · XFCE
|
|
- [2026-06-11] Started this shared-notes log.
|
|
- [2026-06-12] Canonical backup folder is now `router:/tmp/mnt/Wingdrive2/nexus-core` (resolved the old nexus-core/nexus-backup cross-wiring). `bin/backup.sh` now targets `nexus-core` (was `nexus-backup`) so backup and restore use the same folder.
|
|
- [2026-06-12] Added `-c | --claude` check mode to `bin/backup.sh` + `bin/restore.sh`: a `--checksum` content-level dry-run that changes nothing and skips the rebuild — use it to decide whether a real backup/restore is actually needed.
|
|
- [2026-06-12] Added `--no-owner --no-group` to the real backup/restore rsyncs so they stop re-syncing group metadata on every file against the busybox router (quieter, faster).
|
|
- [2026-06-12] Fixed `management/nexus-cli.sh` `ensure_router_reachable` (~line 412): the `nmcli connection up wgs_client` WireGuard fallback dies under WSL (no NetworkManager → "permission denied"). It's now conditional on nmcli + the wgs_client connection existing. **WSL box:** you're a desktop with a direct LAN link to the server, so just make `ssh router` work (Host `router` → 192.168.50.1:9001, user jon, key `id_iWings`, in `~/.ssh/config` — which is NOT synced, set it up there) — then `ncp restore` passes the first check and never hits the VPN fallback.
|
|
- [2026-07-10] Over-engineering purge. Removed dead backend endpoints (`POST /chat`, `/memory/{id}/move[_to]`, `/playbook/run`, `/search`) + their orphaned store methods, and the sync chat wrappers. Deleted the two curses TUIs (`nexus-chat.py`, `nexus-playbook.py`, ~1280 lines) and replaced them with API-backed `ncp` subcommands (`chat`/`memory`/`playbook`/`history` → `management/nexus_api.py`). `controlpanel.py` kept (panel GUI). `/conversations/export` kept (ShareGPT export for future fine-tuning).
|
|
- [2026-07-10] Nuked the ML + scientific/GUI stack from THIS venv only: torch/transformers/accelerate/bitsandbytes/etc + numpy/scipy/pandas/matplotlib/PySide6 + 53 orphans total. **Promethean 16G → 108M.** Requirements files are UNCHANGED — `pip install -r requirements-amd.txt` restores the declared ML stack. Caveat: some installed extras (peft, datasets, mergekit, gguf, hf-xet) were NOT in any requirements file; if the desktop ML work needs them, add them to requirements first. Rollback freeze snapshot was taken pre-purge. **WSL box:** your venv is separate and untouched; run the same `pip uninstall` sweep if you want the space back (nothing in `synapse/` imports any of it — Ollama does inference over HTTP).
|
|
|
|
### WSL box — Windows 11 · WSL2 Ubuntu · DESKTOP-WINGX
|
|
- [2026-06-11] `install-windows.ps1` had a PowerShell syntax error at line 73 (`Unexpected token '}'`); fixed brace mismatch in the script.
|
|
- [2026-06-11] `$USER` env var unset error at line 103 — PowerShell doesn't inherit Linux env vars; fixed by reading user via `wsl -- bash -c "echo $USER"` with proper escaping.
|
|
- [2026-06-11] Promethean venv was not landing inside `nexus-core/` in WSL; root cause was the bootstrap path resolving to a Windows path instead of `\\wsl.localhost\Ubuntu\home\jon\nexus-core`. Fixed by rewriting `bin/wsl-bootstrap.sh` to resolve paths from within WSL.
|
|
- [2026-06-11] Added GPU detection script to auto-select `requirements-amd.txt` vs `requirements-nvidia.txt`.
|
|
- [2026-06-11] Added `ncp` as a `~/.bashrc` alias and wired a "Promethean Terminal" entry into the Windows right-click context menu.
|
|
- [2026-06-11] Python dependency install was failing; traced to pip resolving inside the wrong environment before venv was fully activated.
|
|
- [2026-06-11] Added `sudo apt install snapd` + `sudo snap install ollama` to `wsl-bootstrap.sh`; systemd must be enabled in `/etc/wsl.conf` for snap to work — added that check to bootstrap.
|
|
- [2026-06-11] `wsl-bootstrap.sh` requires `sudo`; wired `sudo ~/nexus-core/bin/wsl-bootstrap.sh` invocation into `install-windows.ps1`.
|
|
- [2026-06-11] Nuked WSL and re-provisioned a fresh Ubuntu instance to validate the full install path. WSL provisioned successfully (user `jon` created) but bootstrap did not fire — timing/invocation issue in the PS script.
|
|
- [2026-06-11] Session ended with `ncp restore` returning permission denied on `nexus-cli.sh:412` and WireGuard (`wgs_client`) unable to reach the router. Unresolved at session close.
|