Skip to main content
This page is for anyone reading, extending, or debugging the open-source unifyai/unify runtime they just deployed locally. The per-feature developer sub-sections elsewhere in these docs (communication, workspace, tasks, learning, …) go deep on individual subsystems; this is the top-level map.

How it works

A persistent interaction loop (ConversationManager) stays present across every medium and keeps thinking while work is in flight. When something needs deeper reasoning, it dispatches a background reasoner (Actor) that writes Python plans over a back office of typed state managers. Every operation returns a live, steerable handle, and those handles nest — a correction you make in chat propagates down through the dispatched action into whatever manager call is currently running.

Steerable handles — the universal protocol

Every public manager method returns one — the same ask, interject, pause, resume, stop surface at every level of the call stack:
When the Actor calls primitives.contacts.ask(...), the ContactManager returns its own handle — nested inside the Actor’s, which is nested inside the ConversationManager’s. Steering at any level propagates down through the live call stack as a typed signal any inner loop can act on, not as an abort or a queued prompt.

CodeAct — the Actor writes Python programs

Rather than emitting one JSON tool call at a time, the Actor writes a single sandboxed Python program per turn over typed primitives.*:
A memory lookup → external check → memory write becomes one coherent plan with real variables, loops, and control flow.

Project structure

Where to start reading

The full breakdown — async tool loop internals, event bus, primitive registry, hosted deployment SPI — lives in the repo’s ARCHITECTURE.md.

Running the tests

Tests exercise the real system — steerable handles, CodeAct, manager composition, nested tool loops — against real LLMs whose responses are cached per unique input, not mocked:
First run makes live LLM calls; subsequent runs replay from cache in milliseconds. See the repo’s tests/README.md for the full philosophy — delete the cache and you’re re-evaluating against live models.