Skip to content

Tech stack

Quick reference for every library and tool in nixx. Each entry covers what it does, why it's here, and links to the real documentation.


Python

Python 3.12. The entire backend, CLI, and TUI are Python. 3.12 brings faster startup and better error messages. Type annotations are enforced throughout (disallow_untyped_defs = true).


FastAPI

The API server. Handles all HTTP routes - the OpenAI-compatible /v1/chat/completions, /v1/sources, /health, and debug endpoints. Built on Starlette and Pydantic. Request/response models are defined as Pydantic BaseModel subclasses and validated automatically. Async-first, so it integrates cleanly with asyncpg and httpx.


Uvicorn

The ASGI server that runs FastAPI. Handles the actual TCP connections, worker processes, and HTTP parsing. In development: single process, optional --reload. In production: multiple workers would be configured here.


Pydantic / pydantic-settings

Pydantic is used for request/response validation in FastAPI - define a class, FastAPI handles parsing and error responses automatically. pydantic-settings extends this for config: NixxConfig reads from .env with NIXX_ prefix, with type coercion and validation built in.


asyncpg

Low-level async PostgreSQL driver. Used directly (no ORM) for all database operations. Faster than SQLAlchemy's async adapter and gives full control over queries. The pgvector codec is registered on each connection via register_vector() so vector columns are handled transparently as Python lists of floats.


PostgreSQL + pgvector

PostgreSQL is the only database, running as a Docker container (pgvector/pgvector:pg16 image, container name student-postgres). pgvector is a Postgres extension that adds a vector column type and vector similarity operators (<=> for cosine distance, <-> for L2). HNSW indexes on memories and summaries make approximate nearest-neighbour search fast at scale.

Four tables across two memory systems:

  • Episodic (automatic): buffer (append-only transcript with tsvector + GIN index for full-text search) and summaries (LLM-generated summaries with vector embeddings, tags, and extracted entities).
  • Semantic (curated): sources (named units from buffer sections or external documents) and memories (embedded chunks for vector recall).

  • PostgreSQL docs

  • pgvector GitHub
  • HNSW indexing explanation
  • PostgreSQL full-text search

llama.cpp

LLM backend. nixx talks to an OpenAI-compatible endpoint for chat completions. It's configured to use the promptly gateway (promptlyapi.com/v1) - an experimental inference API we run. The model it serves and its context window change over time, so nixx never hardcodes them: it fetches the current model from /v1/models and context length from /props at runtime (gpt-oss-20b / 8192 are fallback defaults). promptly currently proxies a local llama.cpp on port 8502; embeddings are served locally by a separate llama.cpp on port 8082.


httpx

Async HTTP client used by the LLM client to talk to llama.cpp, and by the TUI to call the nixx server. Supports streaming responses via client.stream(), which is how token-by-token SSE streaming is consumed. Drop-in replacement for requests with async support.


Textual

Framework for building terminal UIs in Python. The nixx chat TUI is built on it. Key concepts:

  • Widget tree - UI is a composable tree of widgets, like the DOM. compose() defines the structure; widgets can be mounted/removed at runtime.
  • CSS - layout and styling uses a Textual-flavoured subset of CSS, rendered to any terminal.
  • Event system - on_input_submitted, on_key, on_mount etc. Events bubble up the widget tree.
  • Workers - run_worker() runs async coroutines without blocking the UI thread, enabling streaming tokens while keeping input responsive.
  • Actions - methods prefixed action_ that can be bound to keys or exposed in the command palette.
  • Command palette - ctrl+\ fuzzy-searchable popup of all available commands.

Made by the same team as Rich (below).


Rich

Terminal formatting library. Used in the CLI (nixx status, nixx serve output) for coloured text, tables, and markup. Textual is built on top of Rich's rendering engine. Rich markup like [bold green]text[/] works inside both.


Ruff

Fast Python linter and formatter (written in Rust). Replaces flake8, isort, and most pylint use cases. Configured in pyproject.toml with line length 100. Run with ruff check src/.


mypy

Static type checker. Configured in pyproject.toml with disallow_untyped_defs = true and python_version = "3.12". Run with mypy src/. All public functions must have type annotations.


pytest + pytest-asyncio

Test runner. All tests live in tests/. pytest-asyncio enables async def test functions. The conftest.py fixtures provide isolated config (via tmp_path), mock HTTP clients, and mock memory stores. Run with pytest.


pgweb

Lightweight web-based PostgreSQL browser. Single Go binary, runs as a local web server on port 8081. Provides a graphical interface for browsing tables, running queries, and exporting data without heavy IDE tooling. Managed via systemd (nixx-pgweb.service).


Tailscale

WireGuard-based mesh VPN for secure remote access. Enables SSH into the dev machine from a phone (Termius) or any other device on the tailnet without exposing ports to the public internet. Runs as a systemd service (tailscaled).


systemd

Service orchestration for the nixx components. A nixx.target groups the stack: nixx-server, nixx-embed, and pgweb. These units are enabled for auto-boot on the production machine. Unit files live in scripts/ and are symlinked into /etc/systemd/system/.

Start the group manually when needed with sudo systemctl start nixx.target.

Note: systemctl restart nixx.target does not cascade to individual services - a target restart only affects the target unit itself. To reload code changes, restart the specific service directly: sudo systemctl restart nixx-server.