Nova is a local personal AI agent assistant for CLI and desktop workflows.
It combines streamed LLM chat, tool calling, persistent sessions, runtime skills, long-term memory, and local model/provider configuration into one assistant runtime. The CLI is the most complete surface today. The desktop surface is built around a React frontend, a FastAPI backend, and a PyWebView host that reuse the same agent core.
Todo list:
- Textual CLI chat app
- shared async agent runtime
- streamed tool-calling loop
- SQLite-backed sessions, messages, agents, and memories
- user/project/session memory tools
- runtime skill catalog with
list_skills,load_skill, andinstall_skill - Ollama and OpenAI-compatible provider support
- FastAPI backend for frontend and desktop integration
- AI SDK UI compatible SSE stream for
assistant-ui - React + Vite desktop-facing frontend
- PyWebView desktop launcher
- PyInstaller build scripts and platform specs
- packaged Python release metadata such as
pyproject.toml - hardened desktop distribution workflow
Nova should be read as a personal agent assistant tool, not just a chat demo.
Core capabilities:
- Chat with a local or OpenAI-compatible model through CLI, server, or desktop.
- Let the model use tools for files, shell commands, code execution, search, browser automation, image reading, todo tracking, follow-up questions, and dependency installation.
- Load and install reusable runtime skills from local skill folders or ClawHub.
- Save, search, list, and delete structured memories across user, project, and session scopes.
- Persist local sessions and replay user-visible conversation history.
- Run multiple configured model providers from
~/.nova/config.json. - Use the same runtime from CLI, HTTP backend, and desktop shell.
The server exists mainly to support the frontend and desktop app. It can also be run directly for development and integration tests, but it is not the main product surface.
frontend/ React + Vite UI built on assistant-ui
nova/
app/ shared runtime assembly
agent/ agent loop, events, tool execution, and compaction
cli/ Textual CLI app, commands, screens, widgets, and stream handling
config/ config and agent CRUD services
db/ async SQLite persistence
desktop/ PyWebView host and backend server thread
llm/ provider abstraction plus Ollama and OpenAI-compatible providers
memory/ structured memory models, repository, service, and tools
prompt/ system prompt builder
server/ FastAPI app, chat service, schemas, and SSE adapters
session/ session lifecycle and user-visible history projection
skills/ runtime skill scanning, loading, installing, and catalog logic
tools/ built-in tool implementations and registry
build.py cross-platform desktop build script
nova.py thin local launcher for `nova.__main__`
requirements.txt
Install Python dependencies:
pip install -r requirements.txtCurrent runtime dependencies include:
aiohttpaiosqlitefastapihttpxprompt_toolkitrichtextualuvicorntiktokenplaywrightmarkdownifypywebview
Browser automation tools require Playwright browser assets:
playwright install chromiumDesktop packaging uses PyInstaller. Install it in the build environment before
running build.py.
The default mode is CLI:
python -m nova
python -m nova cliWith a configured provider alias and model:
python -m nova cli --provider ollama --model gemma4:26b
python -m nova cli --provider openai --model gpt-5.4Run with a DB-backed agent key:
python -m nova cli --agent mainCLI behavior highlights:
- Textual chat interface with a persistent message viewport and bottom composer.
- Streamed assistant output, reasoning blocks, tool calls, and tool results.
- Escape can interrupt an in-flight run.
- Successful
editandwritetool results show file mutation diffs. /modelsswitches between configured models./sessionsbrowses and loads persisted sessions.ask_usercan render inline text or option prompts.- Runtime skills are summarized in the system prompt so the model can decide
when to call
list_skillsorload_skill.
Inside CLI mode:
- type normal text to chat with Nova
/newstarts a new session/sessionsbrowses and loads sessions/clearclears the screen/modelsopens model selection/install-skill <slug-or-url> [--force]installs one runtime skill/quit,/q,exit, orquitexits the app
Server mode starts the FastAPI backend used by the frontend and desktop shell:
python -m nova serveWith explicit runtime overrides:
python -m nova serve --provider ollama --model gemma4:26b
python -m nova serve --provider openai --model gpt-5.4Default bind address:
http://127.0.0.1:8765
Start the backend first:
python -m nova serveThen run the Vite frontend:
cd frontend
npm install
npm run devDev-time API behavior:
- Vite proxies
/api/*and/healthtohttp://127.0.0.1:8765by default. - Override the proxy target with
NOVA_FRONTEND_PROXY_TARGET. - Override the browser API base URL with
VITE_NOVA_API_BASE_URL.
Build static frontend assets:
cd frontend
npm run buildDesktop mode starts the FastAPI backend in a background thread and opens a PyWebView window.
During frontend development:
python -m nova desktop --devThis loads the Vite dev server at http://localhost:5173 while the backend
runs on the configured Nova backend port.
To run against a built frontend from the source tree:
cd frontend
npm run build
cd ..
NOVA_FRONTEND_DIST=frontend/dist python -m nova desktopTo package the desktop app:
python build.py --cleanOn this repo, build.py builds frontend/dist first, then invokes PyInstaller
with the platform-specific spec file.
Nova keeps framework-side skill code in nova/skills/.
Runtime skill content is loaded from the local Nova home:
~/.nova/skills/
some-skill/
SKILL.md
references/
scripts/
assets/
Current runtime skill behavior:
- Skill folders are scanned into an in-memory catalog during runtime setup.
SKILL.mdfrontmatter is parsed without adding a YAML dependency.- The prompt includes summaries of the currently available skills.
- The model can call
list_skillsto inspect the runtime catalog. - The model can call
load_skillto load the fullSKILL.mdfor a known skill. - The model can call
install_skillonly when the user explicitly asks to install a ClawHub skill. - The CLI exposes
/install-skill <slug-or-url> [--force]. - A successful skill install refreshes the catalog immediately.
Nova has structured memory support under nova/memory/.
Memory records are stored in SQLite and include:
keyscope:user,project, orsessionmemory_type:fact,preference,decision, orcontextcontentsummary- optional tags
- optional
session_idfor session-scoped memory
Memory tools exposed to the agent:
save_memorysearch_memorylist_memoriesdelete_memory
The memory system is tool-driven: the agent decides when to search or update memory based on the task and the prompt. Nova does not do a separate agent-side keyword prefetch before every turn.
Agent workspace files can also contribute prompt context when present:
~/.nova/agents/<agent-key>/
IDENTITY.md
SOUL.md
USER.md
MEMORY.md
Nova currently ships with these built-in tools:
readwriteeditshellcode_runglobgrepweb_searchweb_fetchbrowser_useread_imageask_usertodo_writeinstall_python_packagesave_memorysearch_memorylist_memoriesdelete_memorylist_skillsload_skillinstall_skill
ask_user uses a single-question JSON payload.
Normalized payload shape:
{
"question": {
"header": "Current City",
"question": "Please tell me which city you want the weather for.",
"input_type": "text",
"options": []
}
}Rules:
input_type="text"means free-form input.input_type="select"means choose fromoptions.optionsmust be empty for text input.- The CLI expects this JSON protocol.
Nova loads settings through nova/settings.py.
Default runtime home:
~/.nova/
Derived paths:
- config:
~/.nova/config.json - database:
~/.nova/nova.db - logs:
~/.nova/logs/nova.log - skills:
~/.nova/skills/ - workspace:
~/.nova/workspace/ - agents:
~/.nova/agents/
Override the home directory:
export NOVA_HOME=/path/to/custom/homePrimary config shape:
{
"model": "gpt-5.4",
"model_provider": "openai",
"providers": {
"openai": {
"type": "openai-compatible",
"name": "OpenAI Compatible",
"options": {
"base_url": "https://api.openai.com/v1",
"api_key": "sk-example"
},
"models": {
"gpt-5.4": {
"name": "gpt-5.4",
"tools": true
}
}
},
"ollama": {
"type": "ollama",
"name": "Ollama (local)",
"options": {
"base_url": "http://localhost:11434"
},
"models": {
"gemma4:26b": {
"name": "gemma4:26b",
"tools": true
}
}
}
}
}Config rules:
model_provideris the selected provider alias.providers.<alias>.typecontrols runtime dispatch.- Supported provider types are
ollamaandopenai-compatible. providers.<alias>.models.<model-key>.nameis used as the configured model label in model selection surfaces.providers.<alias>.options.api_keystores the provider secret in the local user config file.--providerand--modeloverride the config defaults for the current process only.
Relevant environment variables:
NOVA_HOMENOVA_HOSTNOVA_BACKEND_PORTNOVA_UI_PORTNOVA_LOG_LEVELNOVA_FRONTEND_DISTNOVA_OLLAMA_BASE_URLNOVA_OPENAI_BASE_URLNOVA_OPENAI_API_KEYOPENAI_API_KEYOPENAI_BASE_URLOLLAMA_BASE_URL
Implemented endpoints:
GET /healthGET /api/modelsGET /api/providersPOST /api/config/providersPOST /api/config/modelsGET /api/sessionsGET /api/sessions/{session_id}/messagesPOST /api/chatPOST /api/chat/streamPOST /api/chat/interruptGET /api/agentsGET /api/agents/{key}POST /api/agentsDELETE /api/agents/{key}
Request body:
{
"session_id": "existing-session-id",
"message": "Hello",
"provider": "ollama",
"model": "gemma4:26b",
"agent_key": "main",
"metadata": {},
"attachments": []
}Rules:
messageis required.session_idis optional; omit it to create a new session.providerandmodelare optional per-request overrides.agent_keydefaults tomain.metadatais accepted by the schema but is not currently interpreted.attachmentscan carry image and document data for the agent stream.
Response shape:
{
"session_id": "sess_xxx",
"status": "completed",
"message": "Hello from Nova"
}Current status values:
completedcancelledinput_requirederror
Request body shape is the same as POST /api/chat.
Response:
- HTTP 200
Content-Type: text/event-streamx-vercel-ai-ui-message-stream: v1- AI SDK UI compatible message parts generated by
nova/server/ai_sdk_stream.py
Example:
data: {"type":"data-nova-session","data":{"sessionId":"sess_xxx"}}
data: {"type":"start","messageId":"msg_xxx"}
data: {"type":"start-step"}
data: {"type":"text-start","id":"text_xxx"}
data: {"type":"text-delta","id":"text_xxx","delta":"hello"}
data: {"type":"text-end","id":"text_xxx"}
data: {"type":"finish-step"}
data: {"type":"finish"}
data: [DONE]
Current stream part types include:
data-nova-sessionstartstart-steptext-starttext-deltatext-endreasoning-startreasoning-deltareasoning-endtool-input-starttool-input-availabletool-output-availabledata-nova-tool-errordata-nova-input-requiredfinish-stepabortfinisherror
Response shape:
{
"items": [
{
"id": "openai:gpt-5.4",
"provider": "openai",
"provider_name": "OpenAI Compatible",
"model": "gpt-5.4",
"label": "gpt-5.4",
"tools": true
}
]
}Response shape:
{
"items": [
{
"key": "openai",
"name": "OpenAI Compatible",
"type": "openai-compatible"
}
]
}Optional query parameter:
agent_key
Response shape:
{
"items": [
{
"id": "sess_xxx",
"title": "Optional title",
"updated_at": 1713510000000,
"agent_key": "main"
}
]
}Response shape:
{
"items": [
{
"id": "msg_xxx",
"session_id": "sess_xxx",
"role": "user",
"content": "Hello",
"tool_call_id": null,
"tool_calls": [],
"time_created": 1713510000000,
"images": null,
"reasoning_content": null,
"group_id": null
}
]
}The history endpoint returns user-visible history. Tool artifacts are projected so only selected tool calls and results are shown to frontend consumers.
Request body:
{
"session_id": "sess_xxx"
}Response shape:
{
"session_id": "sess_xxx",
"interrupted": true
}Logging is file-only by default.
Current log file:
~/.nova/logs/nova.log
Rotation policy:
- daily rotation at midnight
- 30-day retention
Run tests from the repository root:
PYTHONPATH=. pytestUseful subsets:
PYTHONPATH=. pytest tests/test_cli.py -q
PYTHONPATH=. pytest tests/test_runtime.py -q
PYTHONPATH=. pytest tests/test_memory.py -q
PYTHONPATH=. pytest tests/test_server.py -qLive server + Ollama e2e tests are opt-in:
RUN_LIVE_OLLAMA_SERVER_E2E=1 \
NOVA_SERVER_BASE_URL=http://127.0.0.1:8765 \
NOVA_OLLAMA_BASE_URL=http://127.0.0.1:11434 \
NOVA_OLLAMA_E2E_MODEL=gemma4:26b \
PYTHONPATH=. pytest tests/e2e/test_server_ollama_live_e2e.py -qNova is a working personal agent assistant with a complete CLI surface, a desktop-oriented frontend and PyWebView shell, and a shared runtime designed to keep agent behavior consistent across surfaces.
When changing this repository, preserve the shared core boundary: agent logic, tools, memory, sessions, skills, and provider handling should stay reusable by CLI, server, and desktop instead of being forked into one UI surface.