How it works
This is the one page to read if you want to know what Noeta does under the hood. Three ideas carry the whole design; everything else — crash recovery, audit, replay, suspend and resume, swappable models — follows from them.
1. State is a fold over an event log
Every Task owns one append-only stream of events: the goal, each context the model was shown, each model reply, each tool call and result, each suspend and wake. There is no task table. When anything needs the current state, it folds the stream from the start (or from the latest snapshot) and gets it.
- Crash recovery is free. A dead worker leaves nothing half-saved; the next worker folds the log and carries on.
- Replay is exact. The same log folds to byte-identical state on any machine.
- Audit is built in. The log is the history. Nothing is edited in place.
2. A Task is the only unit of work, and waiting is first class
A chat that runs for weeks, a nightly job, a delegated subagent: each is a Task with its own log. There is no session, no workflow instance. A Task is pending, running, suspended or terminal — and every kind of waiting (a human answer, a timer, a subtask, an external event) is the same suspended status plus a typed wake condition.
- A suspended Task holds no thread, connection or memory. It can wait for months.
- A matching wake is stored durably and resumes the Task exactly once, even if a worker dies in between.
- A worker holds a lease on the Task while it runs, and every write presents the lease, so a Task never has two writers.
3. The kernel has no capabilities; everything is a plugin
File tools, web tools, memory, MCP, sandboxes, storage backends, guards and every model adapter are built-in plugins under noeta.builtins. The kernel reaches them only through the plugin loader's dynamic ref resolution; an import linter fails the build on any static import. Your plugins go through exactly the same loader, validation and merge path as Noeta's own.
Because the kernel cannot import a vendor adapter, it cannot grow a vendor assumption either — see Connect a model for how providers plug in.
Two packages
| Package | What it is | Depends on |
|---|---|---|
noeta-runtime | The kernel: Engine, fold, snapshots, Worker, Dispatcher, lease, context composer. No capability code, no HTTP client. | stdlib only |
noeta-sdk | What you install and import (noeta.sdk): query, Client, Options, @tool, presets, and noeta.builtins. | noeta-runtime, httpx, psycopg |
Both share the noeta. namespace. You install noeta-sdk; noeta-runtime comes with it.
One turn, end to end
- Your code hands a goal to
query()or aClient. - A worker leases the Task and folds its log into state.
- The Engine loops compose → decide → dispatch: build what the model sees, let the policy pick the next action, run the tools, record every result as an event. Guards may veto an action before it runs.
- The loop stops when the Task finishes or has to wait. The worker releases the lease. A waiting Task costs nothing until its wake arrives.
The deployment shape does not change the Engine: one process with SQLite, a worker pool in a service, or several hosts sharing Postgres all fold the same logs. See Deploy.
Read next
- The event log — state = fold(log), snapshots, and crash recovery.
- Tasks and waking — the four statuses, subtasks, and exactly-once wake.
- The engine — one step, the decision vocabulary, and guards versus observers.
- Context and caching — how each prompt is assembled to keep the provider cache warm.
- The plugin system — surfaces, the loader, and what stays locked.