内容
# Nexus
> A local MCP server that gives Claude a persistent memory, a private search index for your files and chats, encrypted secret storage, cost visibility across every LLM you use, and a bridge to every other MCP server on your machine.
Claude Desktop is powerful, but on its own it forgets everything between chats, can't see your files, can't hold API keys safely, can't tell you what you've spent this month, and only talks to one MCP server at a time. Nexus fixes all of that from a single local process.
**Status:** 1.0 — 342 tests green. All features are opt-in; existing users can enable them one at a time.
---
## 60-second tour
**Without Nexus:**
> You: *"Can you review the auth middleware in my project?"*
> Claude: *"Sure — please paste the code."*
> [You paste 400 lines.]
> Claude: *"I see a race condition in the token refresh… want me to explain?"*
> You: *"Yes."*
> [Answers.]
>
> — next day, new chat —
>
> You: *"What did we decide about that auth issue yesterday?"*
> Claude: *"I don't have access to previous conversations."*
**With Nexus:**
> You: *"Register `~/code/my-app` as workspace `app`."*
> Claude: [`workspace_register` → indexed 340 files in 4s]
>
> You: *"Review the auth middleware in workspace `app`."*
> Claude: [`workspace_search` → `workspace_read_file src/auth/middleware.ts` → returns the actual code and reviews it]
>
> — next day, new chat —
>
> You: *"Recall what we decided about the auth issue."*
> Claude: [`recall query="auth middleware review"` → surfaces yesterday's chat] *"We agreed to add a mutex around token refresh…"*
That's the whole product in three exchanges. Everything else is variations on the same theme: **make Claude aware of the stuff you already have**.
---
## Who is this for
- **Solo developers** who use Claude Desktop daily and are tired of pasting code.
- **AI/ML engineers** running local Ollama alongside cloud APIs and wanting one unified interface.
- **Privacy-conscious users** who don't want secrets or notes leaving their machine.
- **Anyone paying multiple LLM bills** and wanting one number for monthly spend.
- **MCP power users** who want to compose multiple upstream MCP servers under one roof.
It is **not** for:
- Teams that need multi-tenant SaaS features (auth, RBAC, sharing).
- Enterprises that need SOC-2 / GDPR audit tooling out of the box.
- Anyone who doesn't already use Claude Desktop (Nexus is an MCP server — Claude Desktop is its primary client).
---
## The problem
Anyone who uses Claude Desktop seriously runs into the same wall:
1. **No cross-conversation memory.** "*What did we decide about the migration last Tuesday?*" — Claude has no idea.
2. **Every prompt starts from zero.** You paste the same code, the same doc, the same context, chat after chat.
3. **Secrets end up in chat.** An API key pasted once for a quick test now lives in your Claude history, in your exports, in your logs.
4. **No spend visibility.** Claude Pro on one bill, Anthropic API on another, OpenAI API on a third — no single view of what you're actually spending on LLMs each month.
5. **One MCP server at a time.** Gmail MCP, Calendar MCP, browser MCP — each ships as its own subprocess, each competes for the "Nexus" slot.
6. **Screenshots and clipboards are dark data.** You have the answer somewhere, you just can't find it.
Nexus is one local process that solves all six.
---
## What ships in 1.0
**Core routing (from the original spec)**
- **Universal gateway** across Ollama, LM Studio, OpenAI, Anthropic, Groq, Together, Fireworks, DeepSeek, Gemini, OpenRouter, Mistral, Cohere.
- **Rules-based router** with fallback chains, cost + privacy constraints, and per-task-type overrides.
- **Speculative cascade** — try a cheap tier first, escalate only when confidence is low.
- **Two-layer cache** (exact hash + optional semantic similarity) with configurable TTL.
- **Guardrails pipeline** — PII detection (Presidio), prompt-injection filters, constitutional AI critique-revise.
- **Memory** — long-term facts with time-decay retrieval + episodic session store.
- **RAG** — hybrid BM25 + dense retrieval over PDFs, code, CSVs, images.
- **Sandboxed code executor**, web research, knowledge graph, personas, firewall for outbound content control.
- **Full observability dashboard** at `http://127.0.0.1:8765` with per-trace inputs, outputs, costs, and Prometheus metrics.
**Personal-productivity subsystems (Phase 1–4 additions)**
Each one is a self-contained opt-in subsystem. Enable it in `~/.nexus/config/nexus.yaml`, restart Claude Desktop, done.
| Subsystem | What it does | Problem it solves |
|---|---|---|
| **Workspaces** | Watches a folder, indexes every file, exposes `workspace_search` + `workspace_read_file` | Kills the "paste code every message" tax |
| **Inbox** | One place to save URLs, PDFs, text snippets, images; auto-OCR'd screenshots + clipboard captures | Unifies dark data across bookmarks / downloads / notes |
| **Chat recall** | Indexes your Claude Desktop + ChatGPT exports; `recall(query, days)` retrieves relevant snippets | Solves "what did we discuss last week?" |
| **Vault** | Encrypted secret storage via OS keyring; `{{vault.NAME}}` templating; auto-redaction from every log and trace | Keeps API keys out of chat history |
| **Reminders** | `remind("in 30 min", "check deploy")` → OS notification | Never lose a follow-up mid-conversation |
| **Voice** | `nexus voice` CLI records mic → local `faster-whisper` → transcript on stdout | Free, private, offline speech-to-text |
| **Cost ledger** | Imports Anthropic / OpenAI / Claude Pro spend + joins with internal calls | One monthly LLM burn number |
| **MCP bridges** | Spawns other MCP servers as subprocesses, proxies their tools as `bridge_<name>_<tool>` | Talk to Gmail, Calendar, Playwright — all through Nexus |
---
## How each subsystem works
### 1. Workspaces
Register a folder → Nexus walks the tree respecting `ignore_patterns` (`.git/`, `node_modules/`, `__pycache__/`, size caps), skips binary files via null-byte detection, and hands each file to the RAG parser dispatcher (PDF via PyMuPDF, code via tree-sitter, everything else via plain-text chunker). A `watchdog` observer debounces edits and re-indexes changed files in the background.
**MCP surface**: `workspace_register`, `workspace_list`, `workspace_search`, `workspace_read_file`, `workspace_reindex`, `workspace_unregister`.
**Safety**: `workspace_read_file` rejects `..` traversal, absolute paths, and any symlink escape. Only files under the registered root can be read.
### 2. Inbox
One reserved RAG collection (`_inbox`) with a metadata table (`inbox_items`). Every save is content-hash-deduplicated so re-saving the same URL or PDF is a cheap no-op.
- **URLs**: fetched via `PageFetcher`, main content extracted via `readability-lxml` (with a naïve tag-strip fallback if not installed), chunked into RAG.
- **PDFs**: dispatched through the existing RAG parser (fitz → pdfplumber fallback).
- **Text snippets**: direct RAG insert with a caller-supplied source tag.
- **Images**: routed through the existing OCR service (Tesseract → vision-LLM fallback).
**Watchers** (optional):
- `ScreenshotWatcher` — `watchdog` observer on `~/Downloads`, `~/Pictures/Screenshots`, and per-platform defaults. New image → OCR → save.
- `ClipboardWatcher` — asyncio polling loop over `pyperclip`. Content changes trigger a save; short (< 8 char) or duplicate content is skipped.
**MCP surface**: `inbox_save_url`, `inbox_save_text`, `inbox_save_file`, `inbox_search`, `inbox_list_recent`, `screenshot_search`, `clipboard_search`, `clipboard_history`.
### 3. Chat recall
Claude Desktop and ChatGPT both let you export your conversations as JSON. Drop those exports into `~/.nexus/chatlog-imports/` (or a configured directory). Nexus parses both formats (Claude's `chat_messages` array + ChatGPT's `mapping` DAG), joins each message with its role tag, and indexes the whole conversation as one document in the `_claude_chats` RAG collection.
State is tracked per conversation in the `chat_index_state` table so re-imports only touch what changed. The `recall(query, days=30, k=10)` tool queries the collection and post-filters by the original conversation's `created_at`.
**Why not scrape IndexedDB directly?** Claude Desktop stores chats in a LevelDB-backed IndexedDB whose schema is undocumented and changes between releases. The export path is stable, ships today, works for ChatGPT too.
**MCP surface**: `recall`, `chatlog_import`, `chatlog_stats`.
### 4. Vault
Two backends:
- **Keyring** (default): raw values live in the OS credential store — Windows Credential Manager, macOS Keychain, Linux Secret Service / kwallet. Never on disk.
- **File**: Fernet-encrypted blob under `<data_dir>/vault.enc`. Key derived from a per-install passphrase via PBKDF2-HMAC-SHA256 (200k iterations). Atomic writes.
Metadata (name, backend, timestamps) lives in the SQLite `secrets` table so listing doesn't touch the keyring. Names are validated to env-var style (`^[A-Z][A-Z0-9_]{0,63}$`).
**Redaction hook**: on startup, every stored secret's raw value is registered with the structlog redaction processor. Any log line or trace input/output containing the value is rewritten to `***REDACTED***` before it lands on disk. New secrets registered live via a change listener.
**Template resolution**: any string field passing through the router pipeline may reference `{{vault.NAME}}`. Unknown names raise a clear error instead of silently forwarding the placeholder to the provider.
**MCP surface**: `vault_set`, `vault_list_names`, `vault_delete`. **There is deliberately no `vault_get` tool** — reads only happen in-process.
### 5. Reminders
A thin adapter over the existing persistent scheduler. Registers a `notification` job kind at startup. `remind("in 30 minutes", "check deploy")` parses the time via `dateparser` (with ISO-8601 fallback), enqueues a `schedule_once` job. When the job fires, the handler dispatches via one of three channels:
- **Desktop** — `plyer.notification.notify` (Windows toast, macOS notification centre, Linux libnotify).
- **Log** — structured log entry. Useful in headless deploys.
- **Webhook** — POSTs `{title, message, timestamp}` to a configured URL.
Because reminders are just scheduler jobs, they survive restarts, show up in `scheduler_list`, and can be cancelled with `scheduler_cancel`.
**MCP surface**: `remind`.
### 6. Voice (local Whisper)
`nexus voice` CLI records N seconds from the default microphone via `sounddevice`, wraps the float32 PCM into a WAV buffer, and runs `faster-whisper` (CTranslate2 backend) in-process. Model is lazy-loaded once per process; subsequent runs skip the load. Transcript goes to stdout so it pipes cleanly:
```bash
nexus voice -s 8 -q | Set-Clipboard # Windows PowerShell
nexus voice -s 8 -q | pbcopy # macOS
nexus voice -s 8 -q | wl-copy # Linux (Wayland)
```
The MCP `transcribe_audio` tool also accepts `model="faster-whisper/base"` (or `small`, `medium`, `large-v3`, `distil-large-v3`) — same in-process engine, same cache, callable from inside Claude for file-based transcription.
**No cloud, no API key, no cost.** First run downloads the model (~145 MB for `base`, ~3 GB for `large-v3`).
### 7. Cost ledger
Three import paths land data in the `external_usage` table with a synthetic `unique_key` for dedup:
- **CSV** — the "download report" button on every provider dashboard. Parsers ship for Anthropic, OpenAI, Claude Pro, plus a generic fallback.
- **Anthropic API** — `GET /v1/organizations/usage_report/messages` using an admin key.
- **OpenAI API** — `GET /v1/organization/usage/completions` using an admin key.
Both API imports read the admin key from the vault (never from an env var directly), so the "one place for secrets" invariant holds.
`cost_summary(period)` joins external imports with Nexus-internal `backend_calls` and returns a single rollup. `cost_by_backend(period)` breaks it down per model. Periods: `day / week / month / year / all`.
**MCP surface**: `cost_summary`, `cost_by_backend`, `cost_import`.
### 8. MCP bridges
The `mcp` Python package supports both server and client roles. Nexus uses the client side to spawn each configured upstream MCP server as a stdio subprocess, performs the `initialize()` handshake, calls `list_tools()`, and — for every tool `T` on server `X` — registers a proxy tool named `bridge_<X>_<T>` on the local `FastMCP`.
**Signature synthesis**: FastMCP infers each tool's input schema from the registered function's Python signature. A bare `**kwargs` doesn't work. Nexus walks the upstream tool's `inputSchema.properties` and builds an async function with matching keyword-only parameters, so Claude sees the same shape end-to-end.
**Firewall gate**: every proxied call runs through `check_arbitrary` first. Denied calls return `{"error": "blocked by firewall", "rule": ...}` without touching the upstream.
**Lifecycle**: subprocesses start on server boot, run under an asyncio task each, and shut down cleanly on `NexusApp.shutdown`. `bridge_reload` reconciles against config without restarting Nexus; `bridge_disable` tears down one.
**MCP surface**: `bridge_list`, `bridge_reload`, `bridge_disable`, plus the dynamic `bridge_<X>_<T>` proxies.
---
## Example end-to-end workflows
Real multi-step scenarios that only work because subsystems compose.
### "I just joined a codebase — help me understand it"
```
You: Register C:\code\legacy-api as workspace "legacy".
Then read src/orders/processor.py and explain what it does.
You: Search the "legacy" workspace for "webhook signature".
You: Save https://legacy-api.internal/docs/webhooks to my inbox.
You: Ask again — this time using inbox_search + workspace_search
together: how does webhook verification work here?
You: Remind me tomorrow 10am: "review Alice's PR on webhook auth".
```
One workspace + one saved URL + one reminder — Claude now has the code, the docs, and a follow-up. Nothing left your laptop.
### "I use three LLM providers and have no idea what I'm spending"
```
You: vault_set name="ANTHROPIC_ADMIN_KEY" value="sk-admin-..."
You: vault_set name="OPENAI_ADMIN_KEY" value="sk-admin-..."
You: cost_import source="anthropic" days=30
You: cost_import source="openai" days=30
You: cost_import source="claude_pro_csv" path="C:\downloads\pro-jul.csv"
You: cost_summary period="month"
→ total_cost_usd: 47.30
by_source: { "anthropic": 22.10, "openai": 15.20, "claude_pro": 10.00 }
internal_cost_usd: 0.00 (nothing routed through local Nexus this month)
```
Three APIs, one number. Admin keys stayed in the OS keyring the whole time.
### "Bring back everything I've ever discussed with Claude about React hooks"
```
[Export past chats from Claude Desktop UI, drop into ~/.nexus/chatlog-imports/]
You: chatlog_import
→ files_scanned: 47, conversations_indexed: 47
You: recall query="React hooks useEffect dependency array" days=180 k=8
→ 8 snippets from 5 past conversations, each with title + created_at.
```
Nine months of context, one query.
### "I want to research a topic across the web without leaving Claude"
Requires the fetch MCP bridge:
```yaml
bridges:
enabled: true
upstream_servers:
- name: fetch
command: python
args: ["-m", "mcp_server_fetch"]
```
Then:
```
You: bridge_fetch_fetch url="https://news.ycombinator.com/item?id=..."
inbox_save_url url="https://news.ycombinator.com/item?id=..."
You: recall query="hacker news discussion I saved about rust async"
→ surfaces the saved page from the inbox.
```
Bridged fetch + inbox + recall — three subsystems, one workflow.
---
## How the whole thing connects
When you launch Claude Desktop:
1. Claude reads `claude_desktop_config.json`, sees the `nexus` MCP entry, spawns `nexus serve --transport stdio` as a subprocess.
2. Nexus's `NexusApp.startup()` runs in order:
- Configure logging → open the SQLite database → migrate schema to v14.
- Register backends (Ollama, OpenAI, Anthropic, …).
- Build the router pipeline + guardrails + cache.
- Boot the personal subsystems that have `enabled: true` in `nexus.yaml`.
- Start the dashboard as a background asyncio task on `127.0.0.1:8765`.
- Register every MCP tool on `FastMCP`.
3. Claude Desktop calls `initialize()` over stdin/stdout, then `list_tools()`. It now knows about ~126 tools including the personal ones.
4. Every user message that ends with a tool call flows Claude → stdio → Nexus → subsystem → storage → response → stdio → Claude.
5. Every tool call is traced. The dashboard reads the same SQLite database and renders `/traces`, `/subsystems`, `/metrics` live.
6. When you quit Claude Desktop, its subprocess dies → `NexusApp.shutdown()` fires → watchers stop → dashboard closes → DB commits are flushed.
**One process. One database. One dashboard. Every tool traced. Every secret redacted.**
## Install
### Prerequisites
- Python 3.11 or newer
- Claude Desktop (Windows / macOS)
- Optional: Ollama or another local LLM runtime if you want offline routing
### Install Nexus
```bash
git clone https://github.com/asmit557/nexus
cd nexus
# Core install
pip install -e .
# With personal-productivity extras (vault, watchers, whisper, dateparser, etc.)
pip install -e ".[personal]"
# Everything (also enables vectors, guardrails, RAG parsers, agents, multimodal, graph)
pip install -e ".[all]"
```
### Verify
```bash
nexus doctor --show-skips
```
Every check should be `PASS` except any optional extras you didn't install (they show as `SKIP`).
### First-time setup
```bash
# Creates ~/.nexus/config/nexus.yaml and ~/.nexus/.env from templates,
# migrates the SQLite database, and wires Nexus into Claude Desktop's config.
nexus init
```
`nexus init` finds Claude Desktop's config file automatically — including the Windows Store (MSIX) install path at `%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json`.
### Start
There's nothing to start manually. Once wired, **Claude Desktop launches Nexus as a subprocess** when it starts. Just launch Claude Desktop and open a new chat.
```bash
# Only run this if you want a dashboard-only instance (not required for Claude Desktop use):
nexus serve
```
### Verify integration
Open any Claude Desktop chat and try:
```
Use the ping tool from nexus.
```
You should see `{"pong": true, "server": "nexus", "version": "1.0.0"}`. If not, quit Claude Desktop from the system tray and reopen — that forces the subprocess to restart.
Open **http://127.0.0.1:8765/subsystems** in a browser to see the live dashboard.
---
## Configuration
All flags live in `~/.nexus/config/nexus.yaml`. Personal-productivity subsystems default to `enabled: false` so an install is a no-op until you opt in.
### Minimal example — everything enabled
```yaml
server:
transport: stdio # what Claude Desktop uses
observability:
dashboard:
enabled: true
port: 8765
# --- Personal-productivity subsystems ---
workspaces:
enabled: true
watch: true # incremental re-index on file save
max_file_size_kb: 512
# ignore_patterns has sensible defaults; override to add your own
inbox:
enabled: true
watch_screenshots: true # OCR new images in screenshot_dirs
watch_clipboard: true
clipboard_poll_seconds: 2.0
# screenshot_dirs: [] # empty → auto-detect Downloads / Pictures
chatlog:
enabled: true
# claude_data_path: null # null → ~/.nexus/chatlog-imports/
poll_interval_minutes: 15
retention_days: 365
vault:
enabled: true
backend: keyring # or "file" for a Fernet blob under data_dir
redact_from_traces: true
notifications:
enabled: true
channel: desktop # or "log" / "webhook"
webhook_url: null
costs:
enabled: true
anthropic_api_key_env: ANTHROPIC_ADMIN_KEY # vault name
openai_api_key_env: OPENAI_ADMIN_KEY
refresh_cron: "0 3 * * *" # 3 AM daily auto-refresh (via scheduler)
bridges:
enabled: false # flip on when you have upstream servers
upstream_servers:
- name: fetch
command: python
args: ["-m", "mcp_server_fetch"]
env: {}
```
### Environment variables
Any config field can be overridden with an env var following the `NEXUS_<SECTION>__<FIELD>` convention:
```bash
export NEXUS_WORKSPACES__ENABLED=true
export NEXUS_VAULT__BACKEND=file
```
### Backend API keys
Cloud-provider keys are **only** loaded from env vars, never from YAML. Each backend declares an `api_key_env` (e.g. `OPENAI_API_KEY`). Store them in `~/.nexus/.env`:
```
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GROQ_API_KEY=gsk_...
```
---
## Testing the setup
After enabling a subsystem, restart Claude Desktop and try these prompts:
**Workspaces**:
```
Register the folder C:\path\to\my-project as a workspace called "myproj" using workspace_register.
Search the "myproj" workspace for "database migration".
Read src/main.py from the "myproj" workspace.
```
**Inbox**:
```
Save https://en.wikipedia.org/wiki/Model_Context_Protocol to my inbox.
Search my inbox for "protocol servers".
```
**Chat recall** (after dropping exported JSONs into `~/.nexus/chatlog-imports/`):
```
Run chatlog_import.
Recall query="database migration decision" days=30.
```
**Vault**:
```
vault_set name="TEST_KEY" value="fake-value-for-testing"
vault_list_names
vault_delete "TEST_KEY"
```
**Reminders**:
```
remind when="in 60 seconds" message="test notification"
```
**Voice** (in your terminal, not Claude):
```
nexus voice -s 5 -m base
```
**Cost ledger**:
```
cost_import source="claude_pro_csv" path="C:\path\to\claude-billing.csv"
cost_summary period="month"
```
**Bridges** (after installing `mcp-server-fetch`):
```
bridge_list
bridge_fetch_fetch url="https://example.com"
```
The dashboard at `http://127.0.0.1:8765/subsystems` will show every enabled subsystem with a `wired` badge and live counts.
---
## Privacy & data handling
Nexus is **local-first by design**. Here's exactly what stays on your machine vs. what leaves it.
### Always local (never leaves your machine)
- **Workspaces** — file contents, embeddings, chunk indexes. Only ever read through `workspace_read_file`.
- **Inbox** — URL fetches happen from your machine; extracted text + embeddings stay in your local SQLite.
- **Chat recall** — imported chat JSONs, embeddings, per-conversation state.
- **Vault** — secret bytes live in the OS keyring (Credential Manager / Keychain / Secret Service) OR a Fernet-encrypted file. Never plaintext on disk.
- **Reminders** — jobs in your local scheduler table.
- **Voice transcription** — `faster-whisper` runs in-process; audio never leaves.
- **Cost ledger** — CSV imports read from disk; the rollup stays in SQLite.
- **All observability** — traces, metrics, logs live under `~/.nexus/`.
### Leaves your machine only when you explicitly invoke it
- **LLM calls** to cloud backends (OpenAI, Anthropic, Groq, …) go directly from Nexus → the provider you asked to route to.
- **Web fetches** (`inbox_save_url`, `web_research`) contact the site you specified.
- **Cost API imports** (`cost_import source="anthropic"`) hit the provider's admin usage endpoint.
- **MCP bridges** may spawn processes that themselves make network calls (a Gmail bridge does, obviously; a fetch bridge does when you invoke it).
### Redaction
- Every value stored in the vault is registered with the log redaction processor. Any log line, trace input, or trace output containing that value is rewritten to `***REDACTED***` before hitting disk.
- Well-known secret shapes (Bearer tokens, `sk-...`, `sk-ant-...`, AWS access keys, JWTs, SHA-1 signatures) are always redacted, even without registering them.
- Field-name substring matching redacts keys named `api_key`, `token`, `password`, `authorization`, and friends — but preserves `tokens_in` / `tokens_out` and similar accounting fields.
### Where the data lives on disk
```
~/.nexus/
├── config/
│ └── nexus.yaml ← your config
├── nexus.db ← SQLite: traces, workspaces, inbox, secrets metadata, cost rows, …
├── logs/
│ └── nexus.log ← structured logs (redacted)
├── vectors/ ← LanceDB embeddings when enabled
├── sandboxes/ ← code executor workdirs
├── chatlog-imports/ ← drop exported chat JSONs here
├── training/ ← reserved for future use
└── vault.enc, vault.key ← only present when vault.backend=file
```
You can back up the whole `~/.nexus/` directory as one unit. `nexus backup` does exactly this using `VACUUM INTO` for the database.
---
## Frequently asked questions
**Q: Do I have to install everything at once?**
No. Every subsystem is opt-in. The default `nexus init` gives you routing + memory + RAG + dashboard, nothing else. Enable subsystems one at a time in `nexus.yaml`.
**Q: Do I need Ollama to use Nexus?**
No. Nexus works with cloud providers alone (OpenAI, Anthropic, Groq, …). It also works with Ollama alone. Or any combination.
**Q: Does Nexus store my chats with Claude Desktop?**
Not automatically. Chats live in Claude Desktop's own storage. The chat-recall subsystem only sees conversations you **manually export** from Claude Desktop's UI and drop into `~/.nexus/chatlog-imports/`.
**Q: Where do vault secrets actually live on Windows?**
In the Windows Credential Manager under the service name `nexus`. Open `Control Panel → User Accounts → Credential Manager → Web Credentials` to see them. On macOS: Keychain Access, service `nexus`. On Linux: whatever your `libsecret` daemon uses (usually GNOME Keyring or KWallet).
**Q: What happens if I delete `~/.nexus/vault.key`?**
The file-backend vault becomes unreadable — this is by design. Rotate by re-setting every secret with `vault_set`. Keyring-backed secrets are unaffected.
**Q: Can multiple users share a Nexus install?**
Not intended. Nexus is per-user, per-machine. The SQLite database, keyring entries, and dashboard are all single-tenant.
**Q: How much disk does it use?**
Baseline: ~20 MB for the code + a few MB of SQLite. RAG collections grow linearly with content indexed (~1-2× the raw text size once embedded). Whisper models: 145 MB (base) to 3 GB (large-v3). Everything is under `~/.nexus/`.
**Q: How much CPU/RAM does it use?**
Idle: negligible (one Python process, some background asyncio tasks). During indexing / embedding / transcription: whatever those workloads normally cost.
**Q: Does the dashboard need to be open for anything to work?**
No. The dashboard is read-only. Nexus works exactly the same with or without a browser tab open on it.
**Q: What happens when Claude Desktop updates?**
Nothing — Nexus is a separate subprocess. Only the config file location matters, and `nexus init` handles that.
**Q: Can I run Nexus without Claude Desktop, just for the dashboard?**
Yes. `nexus serve` in a terminal boots everything. You lose the MCP surface (nobody's calling the tools) but the dashboard, doctor, backup, and CLI voice all work standalone.
**Q: How do I upgrade?**
```
git pull
pip install -e ".[personal]"
```
The SQLite schema migration runs automatically on next start. All migrations are additive (new tables only, no destructive ALTERs).
**Q: Is there a hosted version?**
No. Nexus is deliberately local-only.
---
## Troubleshooting
### "Could not attach mcp server nexus" in Claude Desktop
Claude spawned Nexus but the subprocess died before completing the MCP handshake. Common causes:
1. **Port 8765 already in use.** A previous Nexus or unrelated service is bound to it. Nexus pre-flights the port and skips the dashboard gracefully — but if you see repeated `dashboard.port_in_use` warnings, kill the offending process:
```
netstat -ano | findstr :8765
taskkill /F /PID <pid>
```
2. **You're running `nexus serve` manually AND letting Claude spawn its own.** Only one instance should own the port. Ctrl+C the manual one.
3. **A broken subsystem is crashing startup.** Check `~/.nexus/logs/nexus.log` for `<name>.startup_failed`. Set `enabled: false` for that subsystem and restart.
### "pip install fails: WinError 32 nexus.exe is being used"
Claude Desktop's Nexus subprocess is holding the executable open:
1. Quit Claude Desktop from the system tray (not just close the window).
2. `taskkill /F /IM nexus.exe`
3. Re-run pip install.
### `nexus doctor` shows a `FAIL` row
Match the check name against these fixes:
- `config` — YAML syntax error. Run `nexus config check` for a detailed line/column.
- `database` — corrupt SQLite. Restore with `nexus restore <backup>`.
- `backends` — API key env var missing. Add to `~/.nexus/.env` or set the env var directly.
- `claude_desktop` — config not registered. Run `nexus init --force`.
### The dashboard is unreachable
- Confirm the port: `netstat -ano | findstr :8765`.
- Confirm `observability.dashboard.enabled: true` in your config.
- Confirm you're browsing to `http://127.0.0.1:8765` (not `localhost:8765` — some corporate DNS blocks that).
### Watchers aren't firing (screenshots / clipboard / workspaces)
- Install the extras: `pip install "nexus-mcp[personal]"` (adds `watchdog`, `pyperclip`).
- Restart Claude Desktop to reboot the subsystem — hot reload is not supported for watchers.
- Check `~/.nexus/logs/nexus.log` for `watchdog_missing` or `pyperclip_missing` messages.
### "vault secret not found: XYZ"
The `{{vault.XYZ}}` placeholder was resolved against an empty vault. Options:
- Set the secret: `vault_set name="XYZ" value="..."`.
- Use `vault_list_names` to confirm what's stored.
- If you're the caller: verify the exact name (case-sensitive after upper-casing).
### Whisper transcription fails on first run
The `faster-whisper` model has to download from Hugging Face (~145 MB for `base`). Requires internet on first use per model. Subsequent runs use the cached weights.
---
## Architecture (in one screen)
```
+------------------------------------------------------------+
| Claude Desktop ─stdio→ NexusApp |
+------------------------------------------------------------+
│
▼
+-----------------------------------------------------+
| MCP tool surface (~126 tools, all traced) |
+-----------------------------------------------------+
| Router pipeline: rules → cache → backend |
+-----------------------------------------------------+
| Subsystems (each opt-in, each an attr on NexusApp) |
| |
| memory · sessions · rag · sql · sandbox · delegate |
| · scheduler · research · vision · transcription |
| · ocr · imagegen · kg · personas · firewall |
| |
| + workspaces · inbox · chatlog · vault |
| + notifications · costs · bridges |
+-----------------------------------------------------+
│
▼
+-----------------------------------------------------+
| Storage: SQLite (aiosqlite, WAL, schema v14) |
| + OS keyring / vault.enc + LanceDB (optional) |
+-----------------------------------------------------+
│
▼
+-----------------------------------------------------+
| Dashboard @ 127.0.0.1:8765 |
| /healthz /readyz /metrics /traces /subsystems |
+-----------------------------------------------------+
```
- Every subsystem lives on a package under `src/nexus/<name>/` and hangs off `NexusApp` as an attribute.
- Every MCP tool guards for a disabled subsystem and returns `{"error": "<name> disabled"}` rather than raising.
- Every startup block is wrapped in `try/except` — a broken subsystem logs `<name>.startup_failed` and continues.
- The dashboard runs in a background asyncio task alongside the MCP stdio loop; a busy port is detected before uvicorn is invoked so it never cascades into MCP.
---
## Rolling back a subsystem
Set its `enabled` flag to `false` in `nexus.yaml` and restart Claude Desktop. On-disk data (workspaces table, inbox items, secrets, imported cost rows) is preserved — the subsystem simply becomes invisible until re-enabled. Nothing is destructive.
---
## Non-goals
Nexus is deliberately opinionated about what it doesn't do:
- **No federation.** Peer-to-peer multi-instance sync isn't a solo-user problem.
- **No learned routing (bandit / semantic).** These need traffic volume solo users don't produce; rules are enough.
- **No training loop.** Fine-tuning is a separate tool.
- **No marketplace.** A shareable-artifact store needs users first.
- **No HITL approval subsystem.** Claude Desktop is already interactive.
These were previously in scope and were cut in the 1.0 trim to keep the surface honest.
---
## Development
```bash
# Full test suite (342 tests)
pytest tests/unit tests/integration tests/e2e -q
# Just the fast unit tests
pytest tests/unit -q
# One subsystem
pytest tests/integration/test_workspaces_service.py -v
```
Docs, tool inventory, config reference, and event catalog can be regenerated:
```bash
nexus docs generate --output docs/
```
Directory layout at a glance:
```
src/nexus/
├── server.py ← NexusApp: bootstraps + wires every subsystem
├── config/ ← Pydantic schemas + YAML/env loader
├── backends/ ← One adapter per LLM provider
├── router/ ← Rules router + cascade + estimator
├── cache/ ← Exact + semantic cache
├── rag/ ← Hybrid retrieval, parsers, vectorstores
├── memory/ ← Long-term + session store
├── agents/ ← Delegate, sandbox, SQL, web research
├── multimodal/ ← Vision, transcription (cloud + local), OCR, image gen
├── kg/ ← Knowledge graph service
├── personas/ ← Versioned prompt library
├── firewall/ ← Rule engine + audit log
├── observability/ ← Traces DB, tracing, redaction, conventions
├── scheduler/ ← Persistent async scheduler
├── dashboard/ ← FastAPI routes + Jinja templates
├── tools/ ← MCP tool registrations, one file per category
│
├── workspaces/ ← Phase 1: folder-scoped RAG collections
├── inbox/ ← Phase 1: URLs / PDFs / snippets + watchers
├── chatlog/ ← Phase 1: cross-conversation recall
├── vault/ ← Phase 2: encrypted secrets + redaction hook
├── notifications/ ← Phase 2: OS reminders on the scheduler
├── costs/ ← Phase 4: unified cost ledger
└── bridges/ ← Phase 4: upstream MCP-server proxying
```
Contributions welcome — the codebase is deliberately small and every subsystem follows the same pattern (service + tools + tests + dashboard card).
---
## Glossary
Non-obvious terms in this README, in the order you'd meet them:
- **MCP (Model Context Protocol)** — Anthropic's open protocol for connecting Claude (and other LLMs) to external tools and data. Every MCP server exposes named tools with JSON schemas; the client (Claude Desktop) discovers and calls them.
- **stdio transport** — one of the two MCP transports. The client spawns the server as a subprocess and talks to it via stdin/stdout. Nexus uses this.
- **FastMCP** — the Python framework Nexus uses to register MCP tools. Provides the `@mcp.tool()` decorator that turns a Python function into a callable MCP tool.
- **RAG (Retrieval-Augmented Generation)** — indexing documents so an LLM can search + read them at query time instead of stuffing everything into the prompt.
- **BM25** — a classical keyword-ranking algorithm. Cheap, no embeddings needed. Strong when the question uses vocabulary from the source.
- **Dense retrieval** — semantic search via embedding similarity. Strong on paraphrases + concept drift.
- **RRF (Reciprocal Rank Fusion)** — the scoring formula Nexus uses to combine BM25 and dense rankings without calibration.
- **Embedding** — a fixed-length vector representation of text. Similar meanings → nearby vectors.
- **Trace** — the record of one tool call: input, output, backend used, cost, latency, guardrail decisions. Persisted to SQLite.
- **Subsystem** — one self-contained package under `src/nexus/<name>/` that hangs off `NexusApp` as an attribute.
- **Guardrails** — input/output filters over a tool call: PII scrubbing, prompt-injection detection, refusal consistency.
- **Firewall** — a rule engine over outbound URLs, domains, and content patterns. Same idea as a network firewall, applied to LLM tool calls.
- **Scheduler** — the persistent job queue backing reminders and any future cron work. Restart-safe.
- **Vault** — encrypted secret storage. Backends: OS keyring or Fernet-encrypted file.
- **Fernet** — a symmetric-encryption format from the `cryptography` package. AES-128-CBC + HMAC-SHA256 in one authenticated envelope.
- **PBKDF2-HMAC-SHA256** — the key-derivation function used to turn the vault passphrase into an AES key. 200k iterations by default.
- **Watchdog** — a Python library that watches filesystem events (created, modified, deleted). Nexus uses it for workspace incremental reindex and screenshot capture.
- **Whisper / faster-whisper** — OpenAI's open-weights speech-to-text model. `faster-whisper` is a CTranslate2 port that runs 4× faster with the same accuracy.
- **`plyer`** — cross-platform library that Nexus uses to fire OS notifications (Windows toast, macOS notification centre, Linux libnotify).
- **`pyperclip`** — cross-platform clipboard access.
- **`dateparser`** — natural-language date parser ("tomorrow 9am", "in 2 hours").
- **CTranslate2** — the C++ inference runtime under `faster-whisper`.
---
## Contributing
Contributions are welcome. A few conventions to preserve:
1. **New subsystems are opt-in.** Add a config section with `enabled: bool = False`. Existing users must see zero behaviour change until they flip a flag.
2. **Startup is fault-tolerant.** Wrap subsystem init in `try/except`; log `<name>.startup_failed` and null out the attribute rather than aborting.
3. **Tools are defensive.** Every MCP tool checks `app.<subsystem> is None` and returns `{"error": "<name> disabled"}`.
4. **Schema is additive.** New tables only. No destructive `ALTER TABLE` migrations.
5. **Redaction is baked in.** Any log line, trace input, or trace output flows through the redaction processor before hitting disk.
6. **Tests come with the code.** New subsystem = new `tests/unit/test_<name>_*.py` + `tests/integration/test_<name>_service.py`.
Every subsystem in this codebase follows the same shape — service class + MCP tools + tests + dashboard card. Copy an existing one (`workspaces` is a good template) and adapt.
---
## Support & questions
- **Issues**: https://github.com/asmit557/nexus/issues
- **Logs**: `~/.nexus/logs/nexus.log` — always check here first; the structured events tell you what happened.
- **Doctor**: `nexus doctor --show-skips --json` — a single command that reports every runtime + config + integration check.
- **Traces**: `http://127.0.0.1:8765/traces` — every tool call is inspectable.
---
## License
Apache 2.0. See `LICENSE`.
连接信息
猜你喜欢
暂无推荐服务器