nustack

Nu

Docs for Nu, the interaction primitive. Install, learn, and look up.

Every app is a set of interactions between systems: a database, a UI, AI agents, and services. Nu makes interaction the primitive: Refs name what you touch (a UI widget, an LLM endpoint, a memory slot, a KV slot), Interactions describe what to do with them (read, write, branch, iterate, compose). Persistence, reactivity, atomicity, observability, and scalability are inherent, not bolted on.

Get started

The idea

A tiny program is a joy to write:

a = 2
b = 5
print(a + b)

Three lines, one substrate.

Real apps do not stay here. a moves into a database. b comes from a form submission. The result renders in a browser. A background job reruns it when either input changes. Three lines become three hundred: an ORM, a request handler, a template, a websocket, a queue. Almost none of it is about a + b anymore. It is all interaction between substrates.

Nu makes interaction the primitive.

  • Ref. A name for a value, wherever it lives. A KV slot, a UI widget, an LLM endpoint, a remote object.
  • Interaction. What you do with a Ref. Read, write, branch, iterate, compose.
  • Fabric. Binds Refs to a real backend.

Here is the same program with a and b persisted in a KV store:

import nu


class DB(nu.Shape):
    a = nu.kv.IntRef.slot()
    b = nu.kv.IntRef.slot()


# compute a + b and print it
compute = DB.a.set(2) >> DB.b.set(5) >> nu.print(DB.a + DB.b)

# assemble: rocksdb-backed
app = nu.With(
    nu.kv.rocksdb_navigator(".dbsum"),
    body=nu.kv.auto_flow_atomic(compute),
)

nu.run(app)

>> chains interactions in order. Kill the process, run it again, the values are still there.

Same program, but the result lands in a live browser dashboard:

import asyncio
import nu


class DB(nu.Shape):
    a = nu.kv.IntRef.slot()
    b = nu.kv.IntRef.slot()


class Dashboard(nu.ui.Page):
    out = nu.ui.TextRef.slot()


class App(nu.ui.Index):
    pages = nu.ui.Pages({"/": Dashboard})


# compute a + b and render into the dashboard text block
compute = DB.a.set(2) >> DB.b.set(5) >> Dashboard.out.set(DB.a + DB.b)

# assemble: rocksdb-backed, served over the browser
app = nu.With(
    nu.kv.rocksdb_navigator(".dbsum"),
    nu.ui.server(nu.kv.auto_flow_atomic(compute)),
)

asyncio.run(nu.arun(app))

Dashboard.out is a Ref. DB.a is a Ref. One lives in RocksDB, the other in a browser tab. .set(...) on either is the same interaction.

Same primitive, different substrate. One Ref for any resource, one Interaction for any op. Nu doesn't care what the backend is.

What falls out

Because Refs are just names and Interactions are just descriptions, the runtime is free to persist them, replay them, ship them across the network, batch them into a transaction, run them on another machine. Persistence, reactivity, atomicity, observability, and distribution are not features Nu has. They are what falls out of naming interactions instead of executing them.

The same lines that put a + b on a dashboard can, without changing shape:

  • Persist across restarts. The KV slot is already durable.
  • Re-render live on input changes. Wrap in a React interaction.
  • Handle terabytes. Shard the KV Fabric. The Refs do not notice.
  • Run distributed across a cluster. Bind through nu.cluster. The Refs do not notice.

For the algebra underneath (atoms, kinds, forms), see the Explanation section once it lands. For now, pick a card above and start building.

Fabrics

Each fabric binds Refs to a real backend and unlocks a new capability.

FabricWhat
nu.memIn-memory state fabric. Perfect for cache, hot state, and in-process coordination.
nu.kvPersistent state fabric. Refs over a KV backend (RocksDB, LMDB); transactions, snapshots, and change notifications, built in.
nu.uiWeb UI fabric. Same fabric shape as the others, but the Refs are widgets (text, buttons, tables) rendered in the browser and live-updated as your state changes.
nu.proxyProxy fabric. Puts other fabrics on the network. Bind a fabric in one process, use it from another; same Refs, same interactions, over TCP or Unix socket.
nu.httpHTTP fabric: expose Nu Refs as endpoints, or build on top of any HTTP service.
nu.serviceIn-process service fabric: any Python object as a tree of Refs.
nu.llmOpenAI-compatible chat fabric: one wire, N providers.
nu.ccClaude Code as a Ref: prompts from your Nu tree, session brackets, text and metadata back.
nu.mpLocal multiprocessing fabric: teleport subtrees onto spawned worker processes.
nu.clusterCluster compute fabric. Teleport a Nu tree to any worker in your cluster; it runs there and returns the result. Ray under the hood.

Go deeper

On this page