nova ❯man nova
A coding agent that verifies its own work.
NovaCode is an open-source, terminal-based AI coding assistant built on
LangGraph and the deepagents framework. It runs entirely in your terminal
with a Textual TUI, a headless non-interactive mode for scripting and CI, and remote
bridges for Discord and Telegram.
Version 1.0.23 · MIT licensed · Python 3.11+. Runs locally, brings your own model. NovaCode does not retrain your model. What changes are prompts, skills, and thresholds on disk, readable and deletable.
- ~30 core tools · ~85 total
- 12 async background agents
- 8 model providers
- 20 MCP presets
- 7 sandbox providers
- 50+ built-in skills
Core flow
User Input → CLI Entry (main.py) → Agent Loop (core/agent_loop.py) → UI Renderer
CLI Entry
main.pytocli_main(): parses args, initializesSessionState, runs optional onboarding, then enters the TUI or the headless runner.Agent Loop
core/agent_loop.pytoiterate_agent_events(): the single canonical async generator driving the LangGraph agent stream.UI Events
ui_events.py: dataclass instances decoupled from rendering. The TUI, headless runner, and remote bridges all consume the same event types.Middleware
Wraps every model call: retry, vision, learning, security, bootstrap, steering, file tracking, loop guard, rubric, context editing, shell, memory, task discipline.
Key design principles
One canonical agent loop
iterate_agent_events() drives a LangGraph agent stream and yields
ui_events dataclasses. Bug fixes and features belong here so every
renderer benefits.
SessionState is a composite
Six state slices (UISettings, AgentRuntimeState,
RemoteBridgeState, BackgroundTaskState,
NotificationState, WikiState) with properties that delegate to
slices. Zero callers change when a slice is added.
Deepagents is monkey-patched
Three patches at import time: validate_path (Windows path
normalization), perform_string_replacement (UTF-8 BOM tolerance), and
create_sub_agent (graph compile caching).
Heavy imports are blocked
A meta-path finder makes import transformers/torch raise
ImportError (305 MB / ~13 s to 145 MB / ~2.4 s). Set
NOVA_ALLOW_TRANSFORMERS=1 to opt out.
What ships in the box
| Component | Count | Description |
|---|---|---|
| Core tools | ~30 | Bound to the model on every call; the rest are deferred behind search_tools |
| Total tools | ~85 | Full roster (~117k chars of schemas), loaded on demand |
| In-process subagents | 5 | general-purpose, code-explorer, refactoring-specialist, bug-fix, browser-automation |
| Research personas | 7 | Dispatched by /research, loaded on demand |
| Async agents | 12 | Background LangGraph graphs: docs, review, tests, audits, research |
| Model providers | 8 | OpenAI, Anthropic, Google, NVIDIA, OpenRouter, OpenCode, OpenCode Zen, Ollama |
| MCP presets | 20 | Playwright, Serena, Context7, Apify, CUA Driver, and more |
| Sandbox providers | 7 | os, docker, modal, runloop, daytona, langsmith, none |
| Built-in skills | 50+ | Progressive disclosure, loaded on demand |
| Slash commands | 80+ | In-TUI commands for every feature |
nova ❯cat INSTALL.md
Two commands and you are running.
Python 3.11 or newer. Nothing is installed globally.
git clone https://github.com/Babitdor/NovaCode.gitcd NovaCode && uv syncuv run novagit clone https://github.com/Babitdor/NovaCode.gitcd NovaCode; uv syncuv run novauv tool install "novacode-cli @ git+https://github.com/Babitdor/NovaCode.git"novaPrerequisites
| Requirement | Minimum | Notes |
|---|---|---|
| Python | 3.11+ | Required. python --version to check. |
| uv | latest | Package manager. Install from astral.sh/uv if missing. |
| Git | any | For cloning the repository and for nova skills add. |
| API key | 1 | At least one model provider key, or a local Ollama host. |
| Node.js | optional | Only for installing skills from GitHub via the Skills CLI. |
Verify installation
nova --version nova doctor # validate config + connections nova # start the TUI
nova doctor runs six checks: configuration file, secrets,
LLM provider connection, Tavily connection, file permissions, and the voice stack. It
returns exit code 0 when everything passes.
Update Nova
nova update --check # check without installing nova update # update the running installation
The TUI checks in the background at startup and hourly. Installation
detection covers source checkout, uv-tool, git, and package installs. On Windows,
uv-managed updates run in a separate detached process because nova.exe locks
the package directory. Set NOVA_DISABLE_UPDATE_CHECK=1 to disable background
checks.
Onboarding
First-run setup checks what you enter before saving it: an API key is tested against the provider, and an Ollama host must answer with a model installed. Keys go to the OS keychain. A typo shows up on the setup screen, not on your first prompt.
nova ❯nova --help
CLI reference.
Every subcommand, flag, and environment variable, with defaults.
Entry point chain
| Layer | Responsibility |
|---|---|
| pyproject.toml | Registers nova = "novacode_cli.entrypoint:cli_main" |
| entrypoint.py | Thin forwarder (--version, update, skills install), then calls main.py:cli_main() |
| main.py:main() | Path approval, keychain hydration, Vixie server, SQLite store/checkpointer, model creation, agent build, TUI launch |
| os._exit() | Exits with session_state.headless_exit_code |
Subcommands
| Command | Description |
|---|---|
| nova init | Initialize project or global configuration |
| nova list | List all available agents |
| nova help | Show help information |
| nova reset | Reset an agent's memory/store (--agent <name>) |
| nova skills | Manage agent skills (list, create, add, remove, find, update, info) |
| nova mcp | Manage MCP servers (add, remove, list, install) |
| nova config | View or edit configuration (show, set, get) |
| nova secrets | Manage API keys securely (set, list, delete) |
| nova doctor | Validate configuration and connections |
| nova paths | Manage approved file system paths (list, revoke, clear) |
| nova migrate | Migrate to the new directory structure |
| nova update | Update Nova or check for new code (--check) |
Flags
| Flag | Default | Description |
|---|---|---|
| --agent | "nova-agent" | Agent identifier for separate memory stores |
| --auto-approve | off | Auto-approve tool usage (disables HITL) |
| --sandbox | os / none | Sandbox provider: none, os, modal, daytona, runloop, docker, langsmith |
| --no-sandbox | off | Run shell commands unconfined on the host |
| --sandbox-id | None | Reuse an existing sandbox |
| --sandbox-setup | None | Path to a setup script for the sandbox |
| --sandbox-vcpus | None | Virtual CPUs (LangSmith only) |
| --sandbox-mem-bytes | None | Memory in bytes (LangSmith only) |
| --sandbox-fs-capacity-bytes | None | Filesystem capacity (LangSmith only) |
| --sandbox-snapshot | None | Snapshot name (LangSmith only) |
| --sandbox-snapshot-id | None | Snapshot ID (LangSmith only) |
| --ports | None | Port forwarding for the Docker sandbox |
| --no-splash | off | Disable the startup splash screen |
| --continue / -c | off | Continue last session (optionally a session ID) |
| --resume / -r | off | Interactively select and resume a session |
| --print / -p | off | Run a single prompt non-interactively and exit |
| --output-format | text | Headless output: text, json, or stream-json |
| --max-turns | None | Headless only: cap agent turns |
| --deny-tools | off | Headless only: auto-reject tool approvals (fail-closed) |
| --safe-ui | off | Start with the default UI, skipping saved customizations |
| --import | — | Import a conversation (codex, claude, nova, or adapter) |
| --latest | off | Import the selected provider's latest session |
| --import-session | — | Source session ID or transcript file path |
| --import-mode | compact | Import mode: compact, full, relevant |
| --no-agent-server | off | Do not launch a local LangGraph server for async subagents |
| --agent-server-port | None | Port for the local agent server |
| --version | — | Show version number and exit |
Environment variables
| Variable | Purpose |
|---|---|
| OPENAI_API_KEY | OpenAI API key |
| ANTHROPIC_API_KEY | Anthropic API key |
| GOOGLE_API_KEY | Google Gemini API key |
| NVIDIA_API_KEY | NVIDIA API key |
| OPENROUTER_API_KEY | OpenRouter API key |
| OPENCODE_API_KEY | OpenCode Go gateway key |
| OPENCODE_ZEN_API_KEY | OpenCode Zen key |
| TAVILY_API_KEY | Tavily web search key |
| NOVA_ALLOW_TRANSFORMERS | Set to 1 to allow transformers/torch import |
| NOVA_DISABLE_UPDATE_CHECK | Set to 1 to disable background update checks |
| NOVA_ASYNC_AGENT_ROOT | Directory for an external async agent server |
| ASYNC_AGENT_PROVIDER | Provider for async agents |
| ASYNC_AGENT_MODEL | Model for async agents |
| PLAN_SCOUT_MODEL | Per-agent override for plan-scout |
| TYPESAFE_API_KEY | TypeSafe API key for System One compaction |
| SYSTEM_ONE_API_KEY | Custom System One endpoint API key |
| LANGSMITH_TRACING | Enable LangSmith tracing |
| LANGSMITH_API_KEY | LangSmith API key |
Credential storage
Keys go to the OS keychain (via the keyring library) with a
permission-restricted JSON fallback. The endpoint and project are paired with the key as
non-secret metadata in Nova.config.json. Enumeration and deletion are
supported, and secrets are never logged or interpolated into exception messages.
nova secrets set openai_api_key nova secrets set anthropic_api_key nova secrets list nova secrets delete openai_api_key
get_provider_auth_status() resolves credential readiness
into a ProviderAuthStatus with states: CONFIGURED,
MISSING, NOT_REQUIRED, MANAGED,
UNKNOWN.
nova ❯nova config show
Config file.
Configuration lives in ~/.nova/Nova.config.json, with project config under .nova/.
nova config show # view all settings nova config get <key> # get one setting nova config set <key> <val> # set a setting
Configuration modules
config/ holds 14 modules:
| Module | Responsibility |
|---|---|
| config.py | Settings hub, color scheme, model factory, console init |
| nova_config.py | Persistent JSON config at ~/.nova/Nova.config.json |
| model_create.py | Model instantiation for all providers |
| model_manager.py | Model provider management |
| model_catalog.py | Model lineup per provider |
| model_capabilities.py | Static capability registry (which models accept images) |
| provider_auth.py | Provider credential readiness |
| credentials.py | Credential storage (keychain + JSON fallback) |
| role_models.py | Per-role model selection (main, subagent, async, dynamic) |
| google_oauth_auth.py | Google OAuth authentication |
| openai_chatgpt_auth.py | OpenAI ChatGPT plan sign-in |
| opencode_gateway.py | OpenCode Go gateway integration |
Key directories
| Path | Contents |
|---|---|
| ~/.nova/ | Global config, agents, skills, hooks, daemons, plans, plugins, trash |
| ~/.nova/store.db | Durable LangGraph key/value store |
| ~/.nova/Nova.config.json | Persistent configuration |
| ~/.nova/logs/ | Application log, freeze log |
| ~/.nova/ui/ | Saved UI layouts, per workspace |
| .nova/ | Project context, config, hooks, skills, wiki, plans, council |
| .nova/NOVA.md | Project-specific context and conventions |
Model providers
| Provider | Key variable | Notes |
|---|---|---|
| OpenAI | OPENAI_API_KEY | Default; also supports ChatGPT plan sign-in |
| Anthropic | ANTHROPIC_API_KEY | Claude models |
| GOOGLE_API_KEY | Gemini models; also supports OAuth | |
| NVIDIA | NVIDIA_API_KEY | NVIDIA AI endpoints |
| OpenRouter | OPENROUTER_API_KEY | OpenAI-compatible, routed through ChatOpenAI |
| OpenCode | OPENCODE_API_KEY | OpenCode Go gateway |
| OpenCode Zen | OPENCODE_ZEN_API_KEY | OpenCode Zen gateway |
| Ollama | — | Local models; live list from ollama list |
The model catalog draws from two sources: provider profile data
(LangChain packages ship auto-generated _profiles.py listing every model with
capability flags) for OpenAI, Anthropic, Google, and NVIDIA; and a live list for Ollama and
OpenCode Go. The curated MODEL_PRESETS list is unioned into every result and
ordered first.
Per-role model selection
/model covers four roles:
| Role | Covers | Takes effect |
|---|---|---|
| Main agent | The agent you talk to | Immediately (hot-swapped) |
| Subagents | In-process delegation via task | On the next dispatch |
| Async agents | Graphs on the LangGraph server | On the next dispatch |
| Dynamic agents | Agents discovered in agent directories | On the next dispatch |
Any role left unset inherits the main agent's model. Reasoning effort
changes without a restart via /effort low|medium|high|off.
nova ❯nova
The TUI.
The only interactive UI. Chat messages, modals, animations, and keyboard shortcuts.
The Textual TUI provides a scrollable transcript, multi-line input that
grows with content (shift+enter for a newline), modal dialogs with entrance
animations, keyboard shortcuts, condensed tool groups, syntax-highlighted diffs,
click-to-copy, parallel session panes, a docked todo checklist, a status bar with shimmer
animation, and pulsing borders on active elements.
Screens
| Screen | Purpose |
|---|---|
| Chat | Main conversation view |
| Model picker | Switch models for main agent, subagents, async agents, dynamic agents |
| Auth | Manage API keys and provider credentials |
| Wiki | Browse the project wiki vault |
| Settings/Configuration | Adjust settings |
| Artifacts viewer | Browse and open artifacts |
| Tasks panel | Background task monitoring |
| Subagents panel | Running subagent tasks with model and elapsed time |
| Notifications | Review and manage notifications |
Key bindings
| Key | Action |
|---|---|
| shift+enter | Insert a newline in the input |
| ctrl+n | New parallel session |
| alt+<n> | Switch to session n |
| ctrl+g | Push-to-talk (voice) |
| ctrl+l | Hands-free listening (voice) |
| ctrl+shift+backspace | Reset UI to default |
| alt+s | Collapse/expand the subagents panel |
| F6–F12 | Custom panel shortcuts |
Performance features
- status ticks repaint in place
- rendered Markdown cached per width
- static data stays out of checkpoints
- subagent graphs compile on first use
- skill listing cached across restarts
- garbage collection tuned to run while idle
- a watchdog logs any UI freeze over 1s
UI panels
Optional notes, workspace files, and activity panels are customizable via
/ui patch with a JSON object, then /ui preview and
/ui commit. Panel order follows the panels list. Layouts are saved
per workspace under ~/.nova/ui/. /ui rollback restores the saved
layout.
nova ❯/help
Slash commands.
All slash commands are registered via CommandRegistry and invoked through a single dispatch. Plugin commands are registered last, so built-ins always win on collision.
| Command | Description |
|---|---|
| /help | Show interactive help |
| /exit / /quit / /q | Exit the CLI |
| /clear | Clear conversation history and reset session |
| /tokens | Display token usage for the session |
| /context | Display current context window status |
| /cost | Show session token spend |
| /verbose | Toggle verbose mode |
| /steer | Set persistent steering instructions |
| /goal | Set a persistent goal (rubric, status, clear) |
| /btw | Ask a side question on an ephemeral thread |
| /save | Save current session |
| /compact | Compact conversation history with optional focus |
| /sessions | List, select, or delete saved sessions |
| /ui | Inspect UI panels (patch, preview, commit, rollback, reset) |
| /session | Parallel sessions: new / list / close |
| /resume | Resume a saved session (/resume <id>) |
| /restore | Restore a previous file version from snapshots |
| /files | Show file operation summary |
| /images | Manage tracked image references |
| /artifacts | Open the artifacts list |
| /tasks | Open the background tasks panel |
| /log | Show workspace log files |
| /servers | Show active server processes |
| /tests | Run test suites |
| /kill | Kill a process by PID |
| /notifications | Review and manage notifications |
| /remote | Manage remote sandbox connections |
| /reindex | Rebuild the semantic code search index |
| /copy | Copy the last response (or the whole chat) |
| /theme | Switch color theme |
| /init | Generate/update project documentation and graph |
| /mcp | Interactive MCP server management menu |
| /model | Switch the model for main agent, subagents, async agents, or dynamic agents |
| /hooks | Manage lifecycle hooks (list, add, remove, enable, disable) |
| /skills | Interactive skills manager |
| /agents | Custom agent management (view, create, delete) |
| /plugins / /plugin | Plugin management (list, enable, disable) |
| /middleware | List active middleware (/reload-plugins to reload) |
| /reload-plugins | Reload plugin registrations |
| /plan | Invoke the plan-mode agent for investigation and approval |
| /agent-server | Control the local LangGraph server (status, start, stop, restart, logs) |
| /trace | LangSmith tracing management |
| /ralph | Autonomous looping mode (background task execution) |
| /council | Plan a task with the council (propose, critique, vote, judge) |
| /chat | Launch the local browser-based chat UI |
| /cowork / /desktop | Launch the Nova Cowork desktop app |
| /trello | Browser-based task board server |
| /research | Multi-agent research swarm |
| /dream | Run memory consolidation |
| /browser-use | AI-powered browser automation |
| /create | Launch the Skills & Agents web UI |
| /skill:<name> | Directly invoke a skill by name |
| /cron | Manage scheduled (heartbeat) tasks |
| /webhook | Manage the webhook ingress server |
| /prompt | Manage evolving system-prompt templates |
| /refine | Refinement audit trail (history, rollback <id>) |
| /voice | Local voice I/O management |
| /effort | Set reasoning effort level (low, medium, high, off) |
| /vision | Configure image handling |
| /evolution | View the self-evolution log |
| /learning | Toggle the autonomous learning loop (on, off, status) |
| /ingest | Ingest captured sources into wiki pages |
| /ask | Ask a question informed by wiki context |
| /file | File recent conversation knowledge as a wiki page |
| /wiki | List all synthesized pages in the project wiki vault |
| /update | Check for updates immediately |
| /import | Import external conversations (codex, claude, nova) |
| /compare | Compare histories (/compare claude:<id> codex:<id>) |
Command categories
| Category | Commands |
|---|---|
| Session | /save, /sessions, /session, /resume, /clear, /compact |
| Model & reasoning | /model, /effort, /learning, /verbose, /vision |
| Planning & research | /plan, /council, /research, /goal, /steer |
| Extensibility | /skills, /agents, /plugins, /mcp, /hooks, /middleware |
| Integrations | /webhook, /cron, /chat, /cowork, /trello, /browser-use |
| Knowledge | /wiki, /ingest, /ask, /file, /dream |
Council system
/council <task> has several agents propose plans
independently, critique each other anonymously, and vote. A judge picks the top 3 and
nothing is implemented until you approve one. Past council runs are kept in
.nova/council/.
Research swarm
/research fans a question out to 7 research personas: web
researcher, fact checker, literature reviewer, market analyst, financial analyst,
technical researcher, synthesizer.
nova ❯nova -p "..."
Headless mode.
Run a single prompt non-interactively and exit. Built for scripting and CI.
# Basic: run a prompt, print the response uv run nova -p "summarize the changes in this repo" # JSON output, capped at 10 turns, approvals denied uv run nova -p "run the test suite and report failures" \ --output-format json \ --max-turns 10 \ --deny-tools # Stream JSON events uv run nova -p "explain the architecture" --output-format stream-json # Pipe the prompt on stdin echo "explain src/main.py" | uv run nova -p
Output formats
| Format | Description |
|---|---|
| text | Final answer only (default) |
| json | A single result object |
| stream-json | Newline-delimited JSON events |
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error during execution |
| 2 | Max-turns hit |
Runner behavior
headless/runner.py drives a single prompt through the
UI-agnostic event stream (iterate_agent_events) to completion with no human
present.
- prompt from
headless_prompt, format fromheadless_output_format - tool interrupts use
evaluate_tool_actionsunless--deny-tools - a
Noneverdict (ask the user) is converted to an approve - question/plan interrupts resolve to the default response
- counts turns, accumulates text, tracks usage, enforces max-turns
- autosaves the run as a resumable session; never fails on a save error
Headless runs are the exception to the approval rule:
--deny-tools rejects everything, so a pipeline fails closed instead of hanging
on a prompt nobody is there to answer.
nova ❯search_tools *
Tools.
50+ built-in tools across 22 modules. Rarely used tools are deferred behind search_tools, so they cost no context until needed.
File operations
| Tool | Description |
|---|---|
| ls | List files and directories |
| read_file | Read the contents of a file |
| write_file | Create or overwrite a file |
| edit_file | Make targeted edits to existing files |
| glob | Find files matching a pattern |
| grep | Search for text patterns across files |
Shell & execution
| Tool | Description |
|---|---|
| shell | Execute shell commands (local mode) |
| execute | Execute commands in a remote sandbox |
| python_kernel | Run Python in a persistent kernel that keeps state between calls |
| daemon | Start, stop, and tail long-lived background processes |
Web & search
| Tool | Description |
|---|---|
| web_search | Search the web using the Tavily API |
| duckduckgo_search | Web search using DuckDuckGo (no API key) |
| docs_search | Search official documentation sites |
| fetch_url | Fetch and convert web pages to markdown |
| github_trending | Scrape GitHub trending repositories |
| hacker_news | Scrape the Hacker News front page |
| linkedin_jobs | Search LinkedIn job listings (Playwright-based) |
| reddit_posts | Scrape Reddit posts |
| package_info | Get package version and dependency info (PyPI / npm) |
Code intelligence
| Tool | Description |
|---|---|
| code_search | Semantic code search by description or symbol name |
| find_related_code | Find code semantically similar to a known location |
| query_project_graph | Query the project graph for architectural information |
| search_tools | Search and load deferred tools by capability |
Memory & knowledge
| Tool | Description |
|---|---|
| read_memory / write_memory | Read and write persistent markdown agent memories |
| remember / recall | Store and fetch durable cross-session facts by key |
| list_memories / forget | List and delete stored durable memory facts |
| memory_search | Search topic memory by meaning |
| wiki_read / wiki_search / wiki_write / wiki_update_index | Wiki management |
Agent & delegation
| Tool | Description |
|---|---|
| task | Delegate work to subagents for parallel execution |
| write_todos | Create and manage task lists for complex work |
| think | Structured reasoning and reflection before acting |
| ask_user_question | Ask the user a multiple-choice question |
| oracle | Ask several models the same question and have a judge synthesize |
| speak | Speak a short summary aloud via TTS |
| skill_manage | Create, refine, or remove reusable skills |
| sleep_desktop | Put the desktop to sleep (overnight sessions) |
Async agents
| Tool | Description |
|---|---|
| start_async_task | Start a background task on a remote LangGraph server |
| check_async_task | Check status and result of a background task |
| update_async_task | Send updated instructions to a running task |
| cancel_async_task | Cancel a running background task |
| list_async_tasks | List all tracked background tasks |
Background tasks
| Tool | Description |
|---|---|
| list_background_tasks | List agent-launched background shell jobs |
| get_task_status | Get a background task's status, runtime, and exit code |
| get_task_logs | Read the recent output of a background task |
| terminate_task | Stop a running background task |
| restart_task | Restart a background task |
Artifacts & plans
| Tool | Description |
|---|---|
| create_artifact | Create a durable artifact (markdown, code, etc.) |
| update_artifact | Update an existing artifact |
| list_artifacts | List all artifacts in the session |
| enter_plan_mode | Switch to read-only investigation mode |
| exit_plan_mode | Present a plan for user approval |
File recovery
| Tool | Description |
|---|---|
| list_trash | List file snapshots available for recovery |
| restore_file | Restore a deleted or overwritten file from snapshots |
UI & desktop
| Tool | Description |
|---|---|
| ui_inspect / ui_patch / ui_preview / ui_commit / ui_rollback | UI panel management |
Tool search
Only core tools are bound to the model on every call.
search_tools finds the rest on demand. Search covers every currently
available tool, including core and already loaded tools, plus specialist subagents. Use a
capability description, an exact name, a partial name, or a wildcard.
search_tools("playwright browser automation")
search_tools("*") # browse the catalog
MCP tools (serena, playwright, cua-driver, etc.) are discovered by
MCPMiddleware and attached to the main agent. They are granted to subagents
selectively via MCP_TOOLS_BY_SUBAGENT.
nova ❯/agents
Subagents.
In-process specialists, a research swarm, and 12 async background agents.
In-process specialists
| Subagent | Description | Auto-loaded skills |
|---|---|---|
| general-purpose | Any delegated task; the default | — |
| code-explorer | Navigate, understand, and query large codebases | codebase-explorer, graphify |
| refactoring-specialist-agent | Code smells, technical debt, design patterns | improve-codebase-architecture |
| bug-fix-agent | Systematic bug diagnosis and fix | systematic-debugging |
| browser-automation-agent | Web testing, forms, screenshots, data extraction | agent-browser, browser-use, web-research |
Their graphs are compiled on first use, so unused ones cost nothing at start-up.
Research swarm
Dispatched by /research; kept out of the everyday roster and
loaded on demand.
| Subagent | Description |
|---|---|
| web-researcher | Broad web search and source gathering |
| fact-checker | Verifies claims against independent sources |
| literature-reviewer | Academic papers and prior work |
| market-analyst | Markets, competitors, and trends |
| financial-analyst | Stocks and financial data |
| technical-researcher | Libraries, APIs, and technical trade-offs |
| research-synthesizer | Merges the findings into one report |
Async background agents
12 graphs on a remote LangGraph server that Nova launches itself, on demand. No Docker needed. Async agents read, search, and report; the ones that write (documentation, tests, refactoring) do so unattended, so give them a self-contained task. Work that needs your approval along the way belongs with an in-process specialist, because approvals do not reach the server.
| Subagent | Description |
|---|---|
| documentation-update-agent | Auto-synchronize project docs and changelogs with git commits |
| code-review-agent | Review uncommitted/recent changes asynchronously |
| test-generation-agent | Generate/maintain test suites in the background |
| dependency-audit-agent | Audit dependencies for updates and security vulnerabilities |
| refactoring-agent | Analyze and improve code quality in the background |
| plan-scout-agent | Read-only directory scans dispatched during plan mode |
| security-audit-agent | Full security audit (OWASP Top 10, secrets, auth flaws); read-only |
| test-runner-agent | Run the test suite and report failures with likely causes |
| research-agent | Web research with sourced findings |
| general-purpose-async | Scoped coding, investigation, testing, research, or analysis |
| bug-investigation-agent | Trace a reported bug to a likely root cause |
| performance-audit-agent | Investigate performance and resource bottlenecks |
By default, Nova launches its own langgraph dev server on an
ephemeral port (gated on the opt-in agents-server extra). Nothing is started
at boot: the server comes up on the first start_async_task (a few seconds)
and stops when Nova exits. A session that never delegates never pays for it. A server that
will not come up leaves the session as it was (in-process subagents), never blocks it.
Users can create async agents by setting async: true in an
agent.md frontmatter.
Agent-to-agent mailbox
The orchestrator can message its subagents by name and read replies via
the send_agent_message and read_agent_messages tools.
nova ❯memory_search
Memory system.
A three-tier model: Episodic, Semantic, and Procedural.
The three tiers
Episodic
hermes/tracker.py: the durable, time-ordered record of what the agent
actually did. Tool history, counters, per-tool stats, and per-skill effectiveness.
Stored in the durable store at ~/.nova/store.db.
Semantic
agent.md (user model), memories/INDEX.md (topic pointers),
memories/<topic>.md (topic facts), and HABITS.md. Files
are written newest-first and compacted past 12,000 chars.
Procedural
Skills are the procedural memory: reusable workflows the agent can invoke. Created
and refined by Hermes, stored in ~/.nova/skills/.
Durable store
A single sync SqliteStore at ~/.nova/store.db
(with a stdlib-sqlite3 fallback), wrapped by a DualModeStore for both sync and
async access. All Hermes namespaces live under the ("nova", ...) prefix.
AgentMemoryMiddleware
- loads memory into the system prompt at
before_agent - always injects
agent.md,memories/INDEX.md,HABITS.md, learning overview - per-turn retrieval: lexical overlap scoring, top-3 topic bodies
- hot-reloads memory files when they change on disk
- prompt-cache split: the retrieval block sits after the cache breakpoint
Memory tools
| Tool | Description |
|---|---|
| read_memory / write_memory | Read and write persistent markdown agent memories |
| remember / recall | Store and fetch durable cross-session facts by key |
| list_memories / forget | List and delete stored durable memory facts |
| memory_search | Search topic memory by meaning |
nova ❯/skills
Skills system.
50+ built-in skills with progressive disclosure. Install from any public GitHub repo.
A skill is a playbook (SKILL.md) with YAML frontmatter
(name, description required; version,
tags optional) and a Markdown body with canonical sections: When to Use,
Quick Reference, Procedure, Pitfalls, Verification. Optional supporting files, scripts, and
even an executable skill.py entry point can ship alongside.
Skill loading
Skills are loaded from multiple sources in precedence order (later overrides earlier):
User skills
~/.nova/skills/Shared global
~/.agents/skills/Claude skills
~/.claude/skills/Plugin skills
~/.nova/plugins/<name>/skills/Project skills
.agents/skills/,.nova/skills/,.claude/skills/
Caching uses a directory signature (name, mtime, size) per skill, so only
changed directories are re-parsed. A disk cache at
~/.nova/cache/skill_index.json enables cross-process reuse.
Skill retrieval
Hybrid search fuses BM25 (exact terms) with static Model2Vec embeddings
(paraphrases) by reciprocal rank. The embedding model is
minishlab/potion-code-16M.
| Function | Behavior |
|---|---|
| search(query, k=5) | Top-k skills |
| suggest(query, k=3) | Skills that stand out (z-score ≥ 4.5, cosine ≥ 0.4) |
RefreshingSkillsMiddleware is tiered:
| Tier | Behavior |
|---|---|
| Listing | Only most-used skills within a char budget (1% of window) |
| Suggestions | Each new user message matched against the whole library; top picks added as Internal context |
| skills_search | A tool for needs that surface mid-task |
Also provides mid-session refresh when watched skill directories change.
Skill versioning
Every mutation snapshots the prior SKILL.md first:
.history/<version>.md inside the skill dir,
.history/manifest.json as the version log, skills-archive/ for
soft-deleted skills, and origin.json for provenance. restore()
rolls back to any version.
Skill management commands
nova skills list # list all skills nova skills create my-skill # create a new skill nova skills create my-skill --project # project-specific skill nova skills info web-research # view skill details nova skills add owner/repo # install from GitHub nova skills remove <name> # remove a skill nova skills find <query> # search for skills nova skills update <name> # update from source
nova skills add runs the official Skills CLI
(npx --yes skills@latest add) with your arguments unchanged. It requires
Node.js, npm/npx, and Git for repository sources.
nova ❯/mcp
MCP integration.
Extend the agent with Model Context Protocol servers. Tools are eagerly discovered with server-prefixed names to avoid collisions.
Available presets
- playwright
- serena
- context7
- apify
- cua-driver
- brave-search
- memory
- postgres
- google-drive
- fetch
- time
- sqlite
- stripe
- everything
- sequential-thinking
- chrome-devtools
- firecrawl
- tavily
- exa
- perplexity
Perplexity requires an API key. Select it in /mcp to configure it.
Management
nova mcp add brave-search --preset brave-search nova mcp add my-server --transport http --url https://example.com/mcp nova mcp add my-server --transport stdio --command "python -m my_mcp_server" nova mcp list nova mcp remove my-server
MCPMiddleware is inserted dynamically when MCP servers are
configured. It calls list_servers() on every model turn, so it is skipped
entirely when there are no servers. Tools are eagerly discovered before building the
agent graph.
nova ❯/plugins
Plugin system.
Python entry-point based plugins that register slash commands and add middleware at defined slots.
Plugins are discovered via the nova.plugins entry point group
and tracked in ~/.nova/plugins/manifest.json with an enabled list
(read/written atomically).
Plugin capabilities
Slash commands
Custom interactive commands registered into the TUI command palette.
Middleware
Add behavior at named slots in the middleware stack.
Skills
Domain-specific workflows bundled with the plugin.
Lifecycle hooks
before_agent_setup and after_agent_setup.
Middleware slots
| Slot | Target |
|---|---|
| early | Prepend at position 0 |
| before_security | Before SecurityMiddleware |
| before_bootstrap | Before BootstrapMiddleware |
| before_steering | Before SteeringMiddleware |
| before_shell | Before ShellMiddleware |
| before_memory | Before AgentMemoryMiddleware |
| tail | Append at the end |
Plugin management
/plugins # list plugins /plugins enable my-plugin # enable a plugin /plugins disable my-plugin # disable a plugin /reload-plugins # reload plugin registrations
nova ❯/learning
Autonomous learning.
Hermes is Nova's learning and memory subsystem. It runs out-of-band and never blocks the agent's task turn.
The system is orchestrated by NovaLearningMiddleware
(hermes/middleware.py), a thin orchestrator that delegates to four focused
modules:
ToolUsageTracker
Episodic tier: counter, tool history, skill stats.
ReviewRunner
Periodic review lifecycle: trigger, OOB invoke, content persistence.
SkillManager
Skill lifecycle: create, cleanup, refine.
EvolutionEngine
Task-completion skill evolution.
The review loop
Trigger logic (hermes/review.py,
ReviewRunner.should_review()). A review fires when any of these hold (and a
review wasn't just done):
- Failure burst: ≥
FAILURE_BURST(default 3) failed tool calls in the current window - Substantive threshold: count ≥
REVIEW_THRESHOLD(default 10) AND the window contains real work - Hard cap: count ≥ 2× threshold (so all-trivial windows can't defer forever)
- Clean win: real substantive work, zero failures, past the floor
OOB model invocation: the review runs as a separate, out-of-band model call — it is NEVER injected into the agent's task turn.
Content persistence: after the OOB review, the parsed content is applied:
| Review output | Applied to |
|---|---|
<user_model> blocks | agent.md |
<lesson topic="..."> blocks | memories/<topic>.md + INDEX pointer |
<habit> blocks | HABITS.md |
Post-review actions: every review runs
cleanup_legacy_skills_once() and maybe_create_from_review();
every 5th review runs maybe_refine_skills() (one high-failure skill per
cycle); every 10th review runs maybe_curate(),
ThresholdTuner.run_tuning_pass(), and
PromptEvolutionEngine.maybe_auto_evolve().
What Hermes learns
User model
User preferences, communication style, merged into
agent.md.Topic lessons
Cross-session facts/lessons organized by topic.
Good habits
Reusable practices that worked well, stored in
HABITS.md.Skills
Episode-grounded skills created from review
<skill>blocks.Prompt templates
A/B-tested rewrites of system prompt templates.
Verification memory
Per-repo failure patterns that make the inline verifier smarter.
Self-evolution engine
Fires at task completion:
Slice
The task's episodic window.
Score
Complexity via a deterministic heuristic (no LLM).
Invoke
If complex enough (≥ 8), runs an OOB model call returning
<skill>(new) or<level_up skill="name">(improvement).Debate
New skills go through one adversarial critic round before freezing.
Loop engineering enhancements
| Enhancement | Module | What it does |
|---|---|---|
| Inline Verification Loop | core/verification_loop.py, hermes/verifier.py | After each task, an OOB LLM call grades the output against a rubric. On a failing verdict, the agent is re-driven with feedback (up to 3 retries). Fail-open by design. |
| Prompt-Template Hill Climbing | hermes/prompt_evolution.py | Proposes targeted .jinja rewrites, A/B tests them using verifier pass/fail as the quality signal, and promotes or discards. Packaged templates are never modified — overrides live in ~/.nova/prompt_history/. |
| Cron / Heartbeat Scheduler | remote/scheduler.py, commands/cron_handler.py | Proactive scheduled tasks via standard 5-field cron expressions. |
| Threshold Auto-Tuner | hermes/tuner.py | Nudges review-trigger thresholds toward the observed working style. Damped convergence (0.2 weight) with hard floor/ceiling bounds. |
| Webhook Ingress Server | remote/webhook_server.py, remote/webhook_adapters.py | External systems trigger a Nova run with per-source HMAC-SHA256 secrets. |
Key design principles
- Never block the turn: all learning runs OOB or in background tasks.
- Fail-open: any learning failure logs and continues; never breaks the agent.
- Durable persistence: all learning state survives restarts via the LangGraph
BaseStore. - Bounded: every loop has hard caps (max retries, max lessons per review, etc.).
nova ❯/goal rubric
Verification loop.
Code written isn't the same as a task finished. Nova checks the result against what you asked for.
The loop
Task
The user's request.
Understand
Read the codebase, find the relevant code.
Plan
Decide what to change.
Edit
Write the code.
Test
Run the tests.
Verify
Grade the result. Fail? Back to plan.
When verification passes, the run is done, and the verdict and the diff that earned it are stored. When it fails, the failure comes back as feedback and the loop runs again, up to three attempts, then reports honestly instead of guessing.
Grader criteria
Five criteria scored by a separate model call:
- responded to the request
- wrote files
- no errors
- tests pass
- did not modify tests to pass
| Criterion | What it means |
|---|---|
| Responded to request | Did the run address what the user actually asked for? |
| Wrote files | Did the run actually modify the codebase, or just talk about it? |
| No errors | Did the run complete without errors, exceptions, or failures? |
| Tests pass | Do the existing tests still pass after the changes? |
| Did not modify tests | Did the run change the tests to make them pass instead of fixing the code? |
Turning it on
# Grade each finished run (costs one extra model call per turn) /learning on # Hold a specific piece of work to your own criteria /goal rubric <what counts as done>
Off by default. The inline verifier lives in
core/verification_loop.py and hermes/verifier.py. It is
fail-open by design: a verification failure never breaks the run.
nova ❯/remote
Remote bridges.
The bridge runs as background asyncio tasks inside the same event loop as the CLI. A remote message executes like any local prompt.
| Platform | Type | Notes |
|---|---|---|
| Discord | Interactive chat | Messages over 2000 chars are split into chunks |
| Telegram | Interactive chat | Messages over 4096 chars are split; supports voice notes |
| Cron | One-way event source | Scheduled tasks via 5-field cron expressions |
| Webhook | One-way event source | HMAC-SHA256 signed ingress from external systems |
Security
- only allowlisted channel/chat IDs receive responses
/remote allow <ID>manages the allowlist- unauthorised messages are silently ignored (no acknowledgement leaked)
Lifecycle
/remote start discord --token TOKEN --channel ID /remote start telegram --token TOKEN --chat ID /remote stop # gracefully shut down all bridges /remote status # show what is running
Voice notes (Telegram)
Telegram accepts voice notes: they are transcribed with the configured
/voice STT provider and sent to the agent as an ordinary prompt. The
transcript is echoed back so you can see what was heard. In a Telegram forum, each
session gets its own topic, and a question Nova asks you is deleted from the chat once
you answer it.
Cron / heartbeat scheduler
Proactive scheduled tasks via standard 5-field cron expressions. Fired
jobs go on the same queue as remote bridges, so they run like any prompt. Manage with
/cron.
nova cron add "0 9 * * *" "review open PRs" nova cron list nova cron remove <id>
Webhook ingress server
Let external systems (GitHub, Linear, or any signed sender) trigger a
Nova run. Per-source HMAC-SHA256 secrets, timing-safe verification, binds to
127.0.0.1 by default. Manage with /webhook.
nova webhook add <name> --secret <secret> nova webhook list nova webhook remove <name>
Streaming
Response chunks are captured from the agent's output and sent back to the originating platform. For Discord, messages longer than 2,000 characters are split. For Telegram the limit is 4,096. Edit-in-place streaming creates a single "live" reply message and edits it in place on subsequent calls.
nova ❯/voice
Voice I/O.
Speak prompts and hear Nova's prose replies, fully offline.
| Component | Default provider | Description |
|---|---|---|
| STT | Faster-Whisper | Local, open-source (CUDA/CPU) |
| VAD | Silero VAD | Utterance endpointing |
| TTS | Piper | Local, lightweight |
Providers
| Kind | Provider | Notes |
|---|---|---|
| STT | Faster-Whisper | Local, CUDA/CPU |
| STT | Deepgram | Cloud, high-accuracy |
| STT | ElevenLabs | Cloud STT |
| STT | Parakeet | NVIDIA Parakeet via sherpa-onnx |
| TTS | Piper | Lightweight local TTS |
| TTS | ElevenLabs | Cloud TTS |
| TTS | Deepgram | Cloud TTS |
| TTS | Orpheus | LLM-based TTS (~2GB, slower) |
| TTS | Pocket TTS | Kyutai's lightweight local TTS |
Voice modes
Two modes: push-to-talk (ctrl+g, press to start recording,
release to stop) and hands-free (ctrl+l, always-listening with VAD). Code
blocks are stripped before speaking. The speak tool speaks a short summary
aloud.
Voice management
/voice test # verify it works /voice on/off # toggle voice I/O /voice mode ptt|listen # switch mode /voice settings tts orpheus # switch TTS provider /voice settings stt parakeet # switch STT provider
nova ❯/middleware
Middleware stack.
Every model call passes through this chain. The base stack is order-sensitive, outermost to innermost.
| # | Middleware | Purpose |
|---|---|---|
| 0 | AsyncServerOnDemandMiddleware | Starts the LangGraph agent server on first start_async_task |
| 1 | ModelRetryMiddleware | Retries transient failures (429, 5xx, timeout) with exponential backoff |
| 2 | VisionCaptionMiddleware | Converts images to text for text-only models; pass-through for multimodal |
| 3 | NovaLearningMiddleware | Hermes learning loop (periodic review, skill creation) |
| 4 | SecurityMiddleware | Screens URL args for deceptive Unicode/punycode spoofing |
| 5 | BootstrapMiddleware | Workspace bootstrap |
| 6 | SteeringMiddleware | Live steering instructions from /steer |
| 7 | FileTrackerMiddleware | File-op tracking, result truncation |
| 8 | LoopGuardMiddleware | Breaks identical-repeat tool loops (threshold 3) |
| 9 | RubricMiddleware | Self-evaluation against /goal rubric criteria; dormant without rubric |
| 10 | ContextEditingMiddleware | Clears old tool results when the token limit is reached |
| 11 | ShellMiddleware | Shell execution with sandbox support |
| 12 | AgentMemoryMiddleware | Injects NOVA.md/CLAUDE.md project memory into the system prompt |
| 13 | TaskDisciplineMiddleware | Todo list discipline (appended last, in the final system message) |
Additional middleware
Appended after the base stack:
RefreshingSkillsMiddleware— tiered listing + per-turn suggestionsSkillCurationMiddleware— clamps loaded skills to the user-enabled setCodeInterpreterMiddleware— QuickJS eval bridge for dynamic subagent dispatchRepairToolCallsEachStep— repairs malformed tool-call history before every model callToolSearchMiddleware— deferred loading of ~85 tools and ~90 subagentsModelRouterMiddleware— optional, off by defaultHardDenyMiddleware— enforces explicit denies even without HITL interruptextra_middleware— caller-injected (e.g., Cowork's WorkspacePolicy broker)
nova ❯/sessions
Session management.
A composite state object, durable storage, and parallel sessions across git worktrees.
SessionState composite
states/Session.py (741 lines) holds six focused state slices
plus cross-cutting identity fields, using __getattr__/__setattr__
for dynamic field routing.
| Slice | Key fields |
|---|---|
| UISettings | auto_approve, no_splash, plan_mode_enabled, verbose, active_goal |
| AgentRuntimeState | _agent, _backend, _checkpointer, _store, _tools, _model, _sandbox_type, token_tracker |
| RemoteBridgeState | _remote_message_queue, _remote_bridge_manager, _image_tracker, _seen_message_ids |
| BackgroundTaskState | background_ralph_tasks, trello_server, create_server |
| NotificationState | notifications (deque, maxlen 100) |
| WikiState | wiki_root, wiki_enabled, page_count, last_ingest |
Session storage layout
Sessions live in ~/.nova/sessions/<session_id>/:
| File | Contents |
|---|---|
| meta.json | SessionMeta metadata |
| snapshot.json | Authoritative recovery snapshot (v1 format) |
| recent.jsonl | Recent messages, for context injection |
| archive.jsonl | Full message history (not injected) |
| todos.json | Task list state |
| tool_state.json | Last tool outputs |
| memory.md | Declarative memory content |
| workspace_state.json | Git + filesystem state |
| ui_journal.jsonl | UI journal (shell commands, background jobs) |
| imported-context.json | Imported session context |
Four-tier persistence
Checkpointer
LangGraph, SQLite-backed. Persists message history per
thread_id. Primary conversation state.Snapshot
SessionManager's
snapshot.json. The authoritative recovery generation, written atomically.Store
Durable key/value at
~/.nova/store.db. SqliteStore, then stdlib fallback, then in-memory.Semantic files
memory.md,workspace_state.json,ui_journal.jsonl, skills, worktrees, update cache.
Session lifecycle
- saves the incoming prompt before execution
- checkpoints active sessions every five seconds
- saves again when a turn ends
- resume with
nova --continueor/sessions - abrupt termination can lose progress since the last save
Save is serialized via a @serialized_save decorator to
prevent concurrent autosave and final-save interleaving. Restoration validates project
root, repo hash, and NOVA.md checksum, but never blocks on a mismatch.
Parallel sessions
Parallel sessions run as separate OS processes, each bound to its own git
worktree. The child streams ui_events dataclasses to the parent as JSONL; the
parent decodes them back and feeds the existing TUI renderer. Up to four run
concurrently.
| Direction | Messages |
|---|---|
| Parent to child | prompt, interrupt_reply, cancel, shutdown |
| Child to parent | ready, ev, interrupt, turn_done, error |
Session leases are durable, TTL-based, and cross-process
(DEFAULT_TTL = 300s, DEFAULT_RENEW_INTERVAL = 60s). On a lease
conflict, a turn runs unleased rather than blocking. Worktrees live under
~/.nova/worktrees/<repo-name>/<slug>, outside the repo.
nova ❯/context
Context management.
A three-stage pipeline sized to the model's actual context window.
Clear
Older tool results are offloaded to
/cleared/so the agent can read them back.Compact
The conversation is summarized hierarchically via LLM.
Reserve
A hard backstop always keeps an 8k-token reserve.
ContextManager
context/manager.py is a model-aware facade for all
context-window operations:
| Method | Purpose |
|---|---|
| window_size() | Context window size in tokens |
| breakdown() | Token breakdown against the window |
| model_config() | Model configuration |
| budget() | Process-global context budget |
| digest() | Recent conversation digest |
Compaction
Compaction rewrites the whole conversation into one synthetic
HumanMessage carrying the summary. The pre-compaction transcript is archived to
~/.nova/sessions/<thread>/.
System One compaction (experimental) asks Jev or a
compatible local/custom decision model whether each old tool result is still needed, and
clears only results scored stale. Off by default. Configure through /model
→ Decisions to select Jev, Tev1, or Custom System One.
Context meter
The TUI's CTX meter uses the latest main-model input usage when available and an estimated summary/tail breakdown after compaction or resume. SESSION accumulates main-model input and output across tool-loop calls against a configured token budget (1M by default).
nova ❯open safe.book
Security & safety.
Autonomous doesn't mean uncontrolled. Every tool has a tier, and the tiers are yours to set.
Security middleware
security/middleware.py screens URL-bearing tool arguments
for deception: hidden/invisible Unicode (BiDi overrides, zero-width chars, BOM), punycode
domain spoofing (xn-- decoding), and mixed-script or confusable domain
labels. Policy is warn and sanitize: invisible characters are stripped from the URL in
place and the call proceeds; spoofing signals are surfaced as a notice but not blocked.
Human-in-the-loop
hitl/interrupts.py is a configurable interrupt system
requiring user approval before destructive or external operations. 11 tool categories
have schema-driven interrupt specs:
| Category | Tools |
|---|---|
| Destructive | shell, execute, write_file, edit_file |
| External | web_search, fetch_url, http_request, browser_automate |
| Code execution | run_tests, start_dev_server |
| Memory | write_memory, create_memory_structure |
| User interaction | ask_question |
File recovery
Automatic snapshots are taken before destructive operations. Files
targeted by rm are captured before deletion, files overwritten by
write_file have their previous content saved, and files modified by
edit_file have the pre-edit content saved. Snapshots live in
~/.nova/trash/<session-id>/. Files over 10 MB are skipped. Restore via
/restore or the list_trash and restore_file tools.
Other safety layers
| Layer | Purpose |
|---|---|
| path_approval.py | Path-based operation approval for filesystem access outside the project root |
| git_safety.py | Dangerous command detection and injection prevention |
| errors/taxonomy.py | 14 error categories for recovery strategies |
| unicode_security.py | URL safety checking (BiDi, zero-width, BOM, punycode, confusables) |
| delegated_approval.py | HardDenyMiddleware enforces explicit denies even without HITL |
nova ❯--sandbox
Sandbox execution.
Seven providers, from OS-level confinement to hardware-virtualized microVMs.
| Provider | Description |
|---|---|
| os | OS sandbox (default on Linux/macOS — host files, shell confined to workspace) |
| docker | Docker container (opt-in on Windows, with workspace binding) |
| modal | Modal cloud sandbox |
| runloop | Runloop cloud sandbox |
| daytona | Daytona cloud sandbox |
| langsmith | LangSmith Sandboxes (hardware-virtualized microVMs) |
| none | No sandbox (unconfined local execution) |
Sandbox flags
nova --sandbox os # OS sandbox (default on Linux/macOS) nova --sandbox docker # Docker container nova --sandbox langsmith # LangSmith microVMs nova --no-sandbox # force unconfined local execution nova --sandbox-id <id> # reuse an existing sandbox nova --sandbox docker --ports 8080:8080 nova --sandbox langsmith --sandbox-vcpus 2 --sandbox-mem-bytes 8589934592
The default sandbox image is python:3.11-slim. The sandbox
factory (integrations/sandbox_factory.py) creates the appropriate backend
based on the provider type, supporting workspace binding, setup scripts, and resource
configuration.
nova ❯/cowork
Infrastructure.
Surfaces beyond the terminal: notifications, a web chat, and a desktop companion app.
Vixie desktop companion
vixie/ is a background server for desktop notifications and
system tray integration: task completion and status alerts, quick access to Nova status, a
WebSocket server for real-time event streaming, and state mapping (idle, thinking, working,
success, error, user_input, planning).
Agent server launcher
The local langgraph dev server that hosts async agent graphs.
It reserves a port but does not start at boot; the first start_async_task
triggers ensure_started(). Health is confirmed by polling
GET /ok and then the first graph. Stop is graceful (SIGTERM to the process
group, Ctrl+Break on Windows) then force (SIGKILL / taskkill /T /F). A server
that won't come up leaves the session exactly as it was.
Server, Cowork, and tracking
| Component | Description |
|---|---|
| server/ | Local HTTP server with an event adapter, session manager, and WebSocket chat |
| cowork/ | /cowork launches a desktop companion app: FastAPI on a random localhost port, default-deny workspace access with folder grants |
| process_manager.py | Subprocess lifecycle, health checks, and cleanup for dev servers |
| daemons/ | A detached-daemon registry (JSON file-backed pid store) that survives restarts |
| artifacts/ | In-memory, session-scoped registry; content rendered in a sandboxed browser context, never executed on the host |
| tracking/ | File tracker, loop guard, usage tree with cost estimation, tracing, workspace anchoring |
Hooks system
Lifecycle hooks can be Python scripts, shell commands, or any executable.
| Hook | When it fires |
|---|---|
| pre_tool_call | Before a tool is executed (validate inputs, log, modify params) |
| post_tool_call | After a tool completes (process results, log, notify) |
| on_message | When a message is received (filter content, add context) |
| on_error | When an error occurs (custom error handling, recovery) |
nova ❯tree ~/.nova
Directory structure.
Global configuration (~/.nova/)
~/.nova/
agents/default/
agent.md # user model + preferences
memories/ # semantic memory tier
INDEX.md
<topic>.md
skills/
web-research/
SKILL.md
hooks/
pre_tool_call.py
post_tool_call.sh
daemons/
registry.json # detached daemon registry
plans/
<project-slug>/ # global plan archive
plugins/
manifest.json # plugin enable/disable manifest
trash/
<session-id>/ # file recovery snapshots
manifest.json
store.db # durable LangGraph key/value store
Nova.config.json # persistent configuration
logs/
nova.log
ui/
<workspace>/ # saved UI layouts
Project configuration
my-project/
.nova/
NOVA.md # project context and conventions
config.json # project configuration
hooks.json # project-specific hooks
skills/ # project-specific skills
wiki/ # project wiki vault
index.md
log.md
README.md
Clippings/ # Obsidian Web Clipper inbox
wiki/ # synthesized pages
plans/ # approved plans
council/ # past council runs
project-graph.json # project graph
.claude/ # also supported (Claude Code compatible)
.nova.config.json # project-level config (scoped)
nova ❯uv pip install
Optional dependencies.
The base install is kept lean. Heavier features are extras.
# Real-browser automation: /browser-use and the LinkedIn scraper (~330 MB) uv pip install novacode-cli[browser] # The local server the async agents run on uv pip install novacode-cli[agents-server] # Voice I/O (STT + TTS + VAD) - ~2 GB extra uv pip install novacode-cli[voice] # Orpheus TTS - very natural LLM-based local TTS uv pip install novacode-cli[voice-orpheus] # Parakeet STT - NVIDIA local speech-to-text via sherpa-onnx uv pip install novacode-cli[voice-parakeet] # Pocket TTS - lightweight local TTS uv pip install novacode-cli[voice-pocket]
Extras
| Extra | Packages | Description |
|---|---|---|
| browser | browser-use, playwright | Real-browser automation (~330 MB) |
| agents-server | langgraph-cli[inmem] | Local LangGraph server for async agents |
| voice | faster-whisper, silero-vad, piper-tts, sounddevice | Voice I/O (~2 GB) |
| voice-orpheus | orpheus-cpp, llama-cpp-python | Orpheus LLM-based TTS |
| voice-parakeet | sherpa-onnx | NVIDIA Parakeet STT |
| voice-pocket | pocket-tts | Kyutai Pocket TTS |
| server | fastapi, uvicorn | Local HTTP server |
nova ❯nova doctor
Troubleshooting.
Common issues and how to resolve them.
Common issues
| Issue | Solution |
|---|---|
| Python version mismatch | python --version. Use uv venv --python 3.11 |
| Virtual env not activating (Windows) | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser |
| Package installation fails | uv cache clean; uv sync --reinstall |
| Missing dependencies | uv sync --all-extras |
| Import errors | uv pip install -e . --force-reinstall |
nova doctor
Runs six checks and returns exit code 0 when all pass (1 on failures):
Configuration
~/.nova/config.jsonexists and is valid JSON with a provider set.Secrets
Lists configured secrets via the SecretManager.
LLM connection
Ollama tests
/api/tagsand checks allocated context; cloud providers create a model instance.Tavily
Tests the search API if a key is configured.
Permissions
Checks that
secrets.jsonis not readable by others.Voice stack
Checks audio imports, PortAudio, and the default input device.
Diagnostics
nova doctor # validate config + connections nova --version # check version nova paths list # check approved paths
Any UI freeze over one second is logged to
~/.nova/logs/freeze.log. The application log lives at
~/.nova/logs/nova.log.
Getting help
- run
nova doctor - check
~/.nova/logs/freeze.log - open an issue on GitHub
- include
nova --versionoutput