nexus-chat
A local-first terminal chat app for deep research and multi-agent work. Rust + ratatui, all state on your machine — SQLite per space, files and artifacts in space directories, model-created web apps served from localhost.
Install
This provides the nexus command. Requires Rust 1.91+ (edition 2024).
To run from a checkout instead:
CLI
nexus with no arguments launches the TUI. Subcommands work headless
from the shell — everything they write (sessions, usage, reports) lands in
the same local state the TUI reads, so you can mix both freely:
| |||
nexus ask/chat/research use your most recently used model (or
--model), run the same search/tool pipelines as the TUI, and save
conversations as normal sessions — tool status and token usage go to
stderr, answers to stdout. research without --approve parks at the
survey/plan checkpoints: interactive when stdin is a terminal, an error
otherwise (--approve runs unattended, like /research!). The read-only
commands (usage, sessions, spaces, export, status, doctor,
backup, memory, …) never touch the network.
Hosting
nexus host runs the same core on a loopback HTTP/SSE daemon. It exposes
/v1/snapshot, /v1/models, /v1/backends, /v1/events, /v1/command,
/v1/sync, hash-checked GET/PUT /v1/sync/blob, /v1/tools, and an
OpenAI-compatible /v1/chat/completions gateway. Sync clients POST metadata
first, then upload/download each manifest blob by space_id, name, and
hash. The host token is generated once and stored in
~/.config/nexus-chat/config.toml as [provider].host_token; provider API
keys remain on the machine and are never sent to clients.
CF_API_TOKEN=… # non-interactive setup can also set CF_ACCOUNT_ID, CF_ZONE_ID,
# CF_HOSTNAME, and CF_TUNNEL_NAME
The command prints an enrollment URI and an ASCII QR code. Public app links
use /apps/<uuid>/; the registry UUID is the app capability and the host
bearer token is never embedded in the URL or an app cookie. /v1/models
returns an OpenAI-compatible data list with backend-qualified ids such as
openrouter:anthropic/…. Codex's native Responses API is intentionally
excluded from this chat-completions gateway until a response-stream adapter is
available. Named tunnel setup is persisted and reused by later
nexus host --tunnel runs when its local cloudflared files still exist.
--no-sleep-guard disables caffeinate/systemd-inhibit if desired.
Requirements
- Rust 1.91+ (only needed to build/install — no runtime dependency)
- A modern terminal (truecolor recommended)
- Extra tooling, all optional:
tesseract— local OCRffmpeg— video transforms formediaollama— local embeddings/OCR
Configuration
Keys come from the config file or env (OPENROUTER_API_KEY,
OPENAI_API_KEY, OPENCODE_API_KEY), or /login in-app. On first launch a
key is enough; models are fetched from the catalogs.
| What | Where |
|---|---|
| credentials & settings | ~/.config/nexus-chat/config.toml |
| system prompt overrides | ~/.config/nexus-chat/system_prompt.md |
| custom banner | ~/.config/nexus-chat/banner.txt |
| spaces (db, files, scripts, apps, media) | ~/.local/share/nexus-chat/spaces/<space>/ |
Features
- Chat over any configured backend: OpenRouter, OpenAI, OpenCode Zen/Go, and Codex — one merged model list, per-model reasoning-effort control
- Deep research (
/research <topic>): a conversational scoping survey → a plan of questions with why/angles/sources briefs → parallel searcher agents → synthesis → critic → verifier → writer, with a live activity view and/steermid-run./research! <topic>runs ungated - Swarm (
/swarm): a moderator-conducted multi-persona roundtable that iterates toward consensus - Watches (
/watch): standing research jobs that re-run daily - Spaces: per-project context (instructions, memory, imported files, scripts, apps) with embeddings-backed semantic file search
- Skills: reusable instruction packs (SKILL.md) with sandboxed Python virtualenvs, installable from chat
- Tools for the model: nine consolidated tools —
search(web/academic/ discussion),fetch_url(with PDF/YouTube extraction),batch(multi-op calls),research_lookup,files,app(build & edit web apps served onhttp://localhost:8642;initscaffolds Astro+React / Vite+React starters,buildcompiles them with the framework's static build),scripts,skills, andmedia(image/video generation with ffmpeg transforms) - Usage analytics:
/usageshows token/cache/cost analytics by backend and model, priced from a synced catalog - Terminal ergonomics: markdown rendering, image display, @-file autocomplete, mouse selection → copy, context breakdown, compaction, incognito mode, per-session history
Commands
Type / in the composer for autocomplete. Aliases in parentheses.
| Command | What it does |
|---|---|
/new (chat, clear) |
start a new session |
/session (history, resume, switch) |
browse/switch sessions |
/space (project, workspace) |
switch spaces |
/model (llm) |
pick a model, set reasoning effort |
/login (key) |
log into a backend |
/research <topic> |
conversational deep research (see above) |
/research! <topic> |
same, no survey/approval gates |
/watch |
standing research, re-runs every 24h |
/swarm (panel) |
multi-persona roundtable |
/files (images, scripts, …) |
browse space files / images / scripts |
/apps (webapps) |
view model-created web apps |
/skills |
manage skills |
/usage (analytics, costs) |
token/cache/cost analytics by backend & model (←/→ for 24h/7d/30d/all windows) |
/compact (summarize) |
summarize old messages into a digest |
/config (settings, stats) |
settings, footer toggles, sampling params |
/web |
toggle search-first cited answering |
/export (save-report) |
write the research report + sources to a file |
/incognito |
toggle no-persistence mode |
/quit |
quit |
<skill-name> |
arm a skill for the next message |
Keybindings
| Keys | Action |
|---|---|
Enter |
send (Shift/Ctrl+Enter inserts a newline) |
Esc |
stop the streaming response / clear the composer |
Ctrl+C |
quit |
Ctrl+V |
paste (bracketed paste) |
Ctrl+Shift+C / Ctrl+X |
copy / cut composer selection |
Ctrl+A |
select all in composer |
Ctrl+Backspace |
delete previous word |
Ctrl+R |
expand/collapse reasoning traces |
Ctrl+T |
expand/collapse tool-call detail blocks |
Ctrl+G |
context breakdown (system/memory/skills/conversation) |
Ctrl+N |
start a new regular session |
Ctrl+Shift+N |
start a new incognito session |
Ctrl+O |
open a session-link message under the selection |
Ctrl+↑ |
live research activity view (Ctrl+X there stops the job) |
PageUp / PageDown |
scroll |
| mouse drag | select + copy |
While a research survey or plan approval is pending, Enter in that session answers the gate; a reply with edits is folded in once by the approval agent.
Architecture
Two-crate workspace: the engine and the terminal frontend.
crates/core/ nexus-chat-core (lib crate `nexus_core`) — domain only, zero TUI deps; drives TUI + CLI + the future host API
├── src/app/ the state machine (one module per feature)
│ ├── mod.rs App struct (domain fields only), gates, commands, boot, snapshot, event stream
│ ├── commands.rs AppCommand seam + the /-command catalog (COMMANDS, fuzzy_score)
│ ├── chat.rs request lifecycle: history build, streaming, tool loop
│ ├── research.rs the research pipeline: survey → plan → searchers → …
│ ├── swarm.rs multi-persona roundtable
│ ├── watches.rs standing research jobs
│ ├── usage.rs usage/cost analytics
│ ├── sessions.rs, spaces.rs, models.rs, backends.rs, memory.rs
│ ├── files.rs, images.rs, scripts.rs, apps.rs space artifacts
│ ├── skills_popup.rs, compaction.rs, export.rs, transcribe.rs
│ └── tests.rs app-level integration tests
├── src/provider/ message shapes, tool-call wire format, events
│ └── openrouter.rs one client for all OpenAI-wire backends (OR/OpenAI/…)
├── src/tools.rs the model's tools: search, fetch, python, video, apps…
├── src/skills.rs, extract.rs, citations.rs tool support
├── src/db.rs SQLite: sessions, messages, usage, citations, model prefs
├── src/appserver.rs localhost static server for model-created apps (8642)
├── src/host/ HTTP/SSE daemon, provider gateway, sync/worker routes,
│ Cloudflare setup, tunnel and sleep-guard lifecycle
├── src/markdown.rs pure to_plain copy path + the shared GFM table splitter
└── src/config.rs, space.rs credentials, spaces
crates/tui/ nexus-chat — the `nexus` binary
└── src/ main.rs bootstrap, cli.rs subcommands, events.rs loop,
app_view.rs (AppView: composer, popup chrome, render state —
wraps App via Deref), flows/ (popup flow methods), composer.rs,
theme.rs, selection.rs, filter_input.rs, history_cache.rs,
ui/ ratatui rendering (history, popups), ui/markdown.rs
Data lives under the XDG data dir: spaces/<space>/ holds the per-space
SQLite db, files, scripts, apps, and generated media.
Development
The pre-commit hook runs scripts/check.sh on every commit — a merge-ready
change passes it. See AGENTS.md for conventions and a deeper
module map.
Pushes to master release automatically: a workflow bumps the patch version,
tags vX.Y.Z, and runs the publish pipeline (crates.io + GitHub release with
the release binary). Release notes are generated from the conventional commits
since the last tag (scripts/release-notes.sh), so the GitHub release always
shows what changed. Manual v* tag pushes publish the same way. Details in
.github/workflows/.
Roadmap
Multi-device (web + mobile) via a sync mesh, no 24/7 backend — see
docs/roadmap.md.
Known limitations
- The research survey section is always visible, not collapsible.
- The survey's first-round questions are generated from the topic alone — the concurrent known-chunks/web-survey context arrives after round 1.
- A plan rework presented within the same second overwrites the plan file (same timestamped name).