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.
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),scripts,skills, andmedia(image/video generation with ffmpeg transforms) - Terminal ergonomics: markdown rendering, image display, @-file autocomplete, mouse selection → copy, context breakdown, compaction, incognito mode, per-session history
Build & run
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. Extra tooling (all
optional): tesseract for local OCR, ffmpeg for video transforms, an
ollama instance for local embeddings/OCR.
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 |
toggle incognito |
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; p / x pin / discard the cited source under the selection |
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
src/
├── main.rs bootstrap: config, space, db, App, event loop
├── app/ the state machine (one module per feature)
│ ├── mod.rs App struct, popups, settings, run_command, gate plumbing
│ ├── 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
│ ├── 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, copy.rs, transcribe.rs
│ └── tests.rs app-level integration tests
├── provider/
│ ├── mod.rs message shapes, tool-call wire format, events
│ └── openrouter.rs one client for all OpenAI-wire backends (OR/OpenAI/…)
├── tools.rs the model's tools: search, fetch, python, video, apps…
├── tools (cont.) skills.rs, extract.rs (PDF/OCR/text), citations.rs
├── db.rs SQLite: sessions, messages, citations, model prefs
├── appserver.rs localhost static server for model-created apps (port 8642)
├── ui/ ratatui rendering: history, popups, theme, markdown
├── input.rs composer, @-autocomplete, command catalog
├── events.rs key/mouse handling, clipboard
└── config.rs, space.rs credentials, spaces layout
Data lives under the XDG data dir: spaces/<space>/ holds the per-space
SQLite db, files, scripts, apps, and generated media.
Development
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).