One Python Agent Core, Four Ways to Run It: Nova on Server, Web, TUI, and Desktop An open-source project called Nova has released a personal AI agent runtime that runs a single Python agent core across four surfaces: a terminal UI, a web interface, an HTTP API, and a desktop window. All four surfaces share the same agent loop, tool registry, and SQLite store at ~/.nova/nova.db, so sessions, memory, and persona files carry over between them without an export step. The runtime is launched via commands such as `nova serve`, `nova web`, `nova tui`, and `nova desktop`. Nova is an open-source personal AI agent runtime for developers. One Python core is available through terminal, web, desktop, and API, so you get a single local workspace for model providers, tools, sessions, memory, MCP, and sub-agents. The practical problem it addresses is familiar: you start an agent in the terminal to fix a bug, then you want the same setup for a longer task you check from a browser, then you want an API you can script against, then something clickable on the desktop. Without a shared runtime, that becomes four tools, four configs, and four ways for behavior to drift. Nova's answer, in its README's words, is "Your open source AI agent on desktop, terminal, web, and API." The same agent core in nova/ drives the TUI, server, frontend, and desktop. What changes is the surface. What stays the same is the agent loop, the tool registry, and the SQLite store. All four surfaces use the same pieces: ~/.nova/nova.db . The runtime home lives at ~/.nova/ , with config.json , nova.db , logs/nova.log , skills/ , workspace/ , and agents/ alongside it. You can point it elsewhere with NOVA HOME if you keep dotfiles or checkouts isolated. That shared store is what makes switching surfaces uneventful. A session you start in the terminal is stored in the same SQLite file the web UI and desktop read from. Pick a model with /models in the TUI or with the model selector in the web UI. Add persona files like IDENTITY.md , SOUL.md , USER.md , or MEMORY.md and they land in the system prompt no matter which surface you open. Nova exposes the core in four ways: nova serve HTTP server on http://127.0.0.1:8765 nova web built web UI in the browser nova tui OpenTUI terminal client from any directory ./nova-tui equivalent source-checkout launcher nova desktop desktop window nova serve runs a FastAPI backend with an SSE stream at POST /api/chat/stream . nova web serves the built frontend from the same backend address and opens your browser. nova tui is a Bun plus React plus OpenTUI client that streams text, reasoning, tool calls, and inline diffs for edit and write . nova desktop hosts the built frontend in a PyWebView window with the backend on a background thread. Use nova desktop --dev when working against the Vite dev server. Nova's web interface starts with a focused chat composer, a Workspace selector, and a model picker. For frontend work with live reload, run the two halves separately: nova serve cd frontend && npm install && npm run dev Vite proxies /api/ to the backend, overridable with NOVA FRONTEND PROXY TARGET or VITE NOVA API BASE URL . The quickstart https://github.com/bigrivi/nova/blob/main/docs/getting-started/quickstart.md has the full mapping. Pick the surface that fits the moment and keep the same agent underneath. Short fix in the TUI, long-running task in the web UI, scripted call over the API, casual use on desktop. It helps to be precise about what "same agent" means here, because the four surfaces do not look or feel the same, and that is intentional. What stays shared is the state and the loop. Sessions, messages, agents, and memories live in the same SQLite file, under the same runtime home with its config, logs, skills, workspace, and agents folders. The agent loop, the tool registry including whatever MCP servers you connected, the per-session workspace semantics, and the persona files injected into the system prompt all behave the same no matter where you open Nova. That is why stopping a task in one place and continuing it in another needs no export step. The history is already there. What stays different is everything about interaction. The TUI is keyboard-driven with slash commands, Escape to interrupt, inline diffs for file changes, and tree-sitter highlighting. The web UI leans on a thread list, composer, workspace folder picker, memory manager, approval dialog, and language switcher. The desktop hosts that same built frontend in a PyWebView window with the backend on a background thread. The API has no UI at all and instead streams text, reasoning blocks, tool calls, and tool results over SSE for you to render however you like. The tradeoff is straightforward. You get continuity of state without uniformity of interface. Each surface keeps the controls that make sense for its setting, so there is still a small adjustment when you move. The benefit is that the adjustment is only about controls, not about reconfiguring providers, tools, or memory from scratch. Model access lives in ~/.nova/config.json . Only providers and optionally mcp servers sit at the top level. Aliases under providers are yours to name. Nova supports four provider type values: ollama , openai-compatible , openai-response , and anthropic . Ollama runs locally with no API key, openai-response targets the Responses API, and Anthropic supports extended thinking. At the current checkout, openai-response is configured through the config file or API rather than the frontend provider dropdown. If you already run Ollama locally, this minimal config from the documented quickstart is enough to start: { "providers": { "ollama": { "type": "ollama", "options": { "base url": "http://localhost:11434" }, "models": { "qwen2.5:7b": { "name": "qwen2.5:7b", "tools": true } } } } } Swap in whatever model you have pulled. The key part is "tools": true so the agent can actually call tools. The built-in set is fixed and documented: read , write , edit , shell , code run , glob , grep , web search , web fetch , browser use , read image , todo write , ask user , memory tools save memory , search memory , list memories , delete memory , delegate to agent , and skill tools list skills , load skill , install skill . Any MCP server you connect over stdio or SSE/HTTP shows up as extra tools too. code run executes inline Python with dependencies auto-installed to ~/.nova/site-packages/ . Web fetch returns Markdown with a 5MB cap, alongside web search. browser use registers when Playwright imports. Image and document attachments ride on POST /api/chat , with read image returning base64 plus extracted text. Set a per-session workspace folder and shell , code run , glob , and grep respect it. Shell commands pass a three-tier approval gate of blocked, needs approval, and auto-run, with dangerous ones asking over SSE and an optional allowlist. For longer sessions, two-layer compaction trims old tool output to disk and summarizes older turns. The web interface keeps multi-step work visible rather than collapsing it into a single loading state. In the example below, Nova searches for recent open-source agent developments, opens first-party sources, cross-checks claims, and reports progress between rounds. It also catches a misdated OpenHands item before producing the final briefing. Nova reports progress between research rounds, tracks tool calls, and surfaces corrections made during source verification. The shared runtime matters most once you see how different tasks pull on it. Terminal code work with reviewable diffs. Set a per-session workspace folder so file search and shell execution start from the checkout you mean, then work through reading, searching, and editing from the TUI. Successful file changes render as inline diffs you can read before moving on, and Escape interrupts a run that heads the wrong way. The workspace keeps everyday commands scoped to the task, while an explicit working directory still wins when you pass one, so treat it as a scoping aid that reduces mistakes rather than a boundary. This pattern fits tight fix loops where you stay in one repo and want quick review cycles. The TUI takes an instruction, reads a file, applies an edit shown as an inline diff, with model and context status visible. Multi-round web research with visible progress. In the web UI, a research task becomes a series of search and fetch rounds with progress reported between them instead of one long silent wait. Fetched pages arrive as Markdown, the thread keeps tool-call counts and intermediate findings, and corrections surface in the open when a source does not check out. The implication is that verification work stays inspectable. You can follow which sources were opened, what was cross-checked, and where the final briefing diverged from an early lead. Scripted use through the HTTP and SSE endpoint. The same loop is available over HTTP for scripts, with chat streaming text, reasoning, tool calls, and results over SSE and attachments accepted alongside chat requests. Approval prompts for sensitive commands arrive over that stream and are answered through a dedicated approval endpoint, with an allowlist to remember routine approvals. The tradeoff here is control versus convenience. A script gets the full agent behavior including tools and memory, but it also takes on rendering progress, handling approvals, and deciding when to stop and retry. Persistent sessions are the default. Threads, messages, agents, and memories live in SQLite, so you can stop a task in one surface and pick it up in another without exporting state. Memory covers fact , preference , decision , and context types across user , project , and session scopes, with search and optional AI reranking. The frontend includes a memory manager next to the thread list, composer, model selector, workspace folder picker, and approval dialog. The TUI covers /new , /sessions , /clear , /models , /install-skill , and /quit , with Escape to interrupt and inline diffs for edit and write . Skills live as ~/.nova/skills/