A walk through the runtime — the neuro substrate, the hierarchy, the brain, the flow engine, the five-layer memory, the multi-agent primitives, and the NeuroLang foundations they all stand on.
neurosdk/
├── neurosdk/ # Python core: server, framework, neuros, profiles, tests
├── neuro_web/ # Next.js + R3F desktop client
├── neuro_mobile/ # Android (Kotlin/Compose) remote
├── neurolang/ # vendored NeuroLang library (Phase 1.9)
├── experimental/ # prototypes
├── docs/ # architecture + product + website
└── STATUS.md # current phase, last shipped, next up
Backend: localhost:7000. IDE backend: localhost:8000. Web: localhost:3000. LiveKit: localhost:7880.
Three files in a folder. The factory hot-discovers them.
conf.json — name, kind, inputs/outputs, modelcode.py — async def run(state, **kwargs)prompt.txt — optional, for LLM-driven neurosEach run gets state["__llm"] (BaseBrain), state["__prompt"], and a streaming callback. Stdout captured + forwarded as node.log events.
{
"name": "extract_book",
"kind": "skill.web",
"effect": "tool",
"inputs": { "url": "str" },
"output": "dict",
"model": "openai/gpt-4o",
"temperature": 0.2
}
Agency ──▶ Project ──▶ Agent ──▶ Neuro
│ │ │ │
│ │ │ └─ atomic; conf+code+prompt
│ │ └─ router + planner + replier + profile
│ └─ unit of work; default project per agency
└─ workspace; color, emoji, set of agents
Shipped agencies: default (Neuro HQ), upwork, webclaw. Shipped agents: neuro, nl_dev, opencode, openclaw, upwork.
Smart Router — one LLM call asks: direct reply or skill needed?
Planner — for multi-step requests, builds a DAG of skill calls.
Executor — walks the graph node by node, retries on failure, streams progress.
User: "Find my latest screenshot and describe what's on screen"
DAG built by planner:
Node 1: list_files(dir="~/Screenshots", sort="newest")
Node 2: read_file(path=Node1.output[0])
Node 3: describe_image(image=Node2.output)
Node 4: reply(text=Node3.output)
Executor runs node-by-node. Each output feeds the next.
Errors → retries → fallback.
In NeuroLang the same plan is a first-class value: plan.serialize(), plan.replay(), plan.diff(other), plan.hash().
A | B | C. Output of A feeds B, output of B feeds C.
A & B. Both run concurrently via asyncio.gather.
Multi-path with conditions, parallel branches, human-gates, sub-graphs.
Iterative: call tool, observe, continue. Bounded, depth-guarded.
Categorical morphism composition under the hood — associativity, identity hold.
| Layer | Content | Token cost | Trigger |
|---|---|---|---|
| L0 Identity | Agent + user identity (hand-authored) | ~50 | always |
| L1 Critical | AAAK-compressed top facts | ~120 | always |
| L2 Taxonomy | Categories — names + 1-line defs | ~200 | always (as index) |
| L3 Facts | Temporal KG + embeddings | dynamic | topic relevance |
| L4 Drawers | Verbatim source (conversations/*.json) | dynamic | explicit deep-dive |
L0+L1+L2 ≈ 370 tokens always loaded. L3 on match. L4 on deep-dive only.
The taxonomy isn't hardcoded — a local Gemma4 E4B librarian creates, merges, and renames categories as the corpus grows.
memory_extract — msgs → fact JSON (every 15 turns)memory_categorize — route to category, propose newmemory_supersede — close old valid_to on contradictionmemory_consolidate — weekly merge / split / renamememory_l1_refresh — nightly AAAK regenerationTyped property graph in SQLite. Uniform nodes table with kind tag. N-ary typed edges. Temporal validity (valid_from, valid_to) on both. Hypergraph-ready.
Retrieval: Personalised PageRank from seed nodes + vector hybrid. Recency × confidence weights. Top-M packed into the context budget.
Multiple agents share a transcript. A room_mediator picks the next speaker round-robin.
room_create, room_post, room_close, room_mediatorcore/rooms.py, core/rooms_db.py/api/roomsRoomPanel.tsxagent.talk(target, msg)Direct typed messages between agents. The substrate beneath rooms.
Depth-guarded — MAX=4 via TalkDepthExceeded. Prevents infinite loops.
Two neuros: agent_talk, agent_list. Path: core/talk.py.
The seed of categorical mailbox protocols where deadlock and starvation are analysable from types.
talk(target="opencode",
msg="refactor module X")
│
▼ depth=1
opencode replies, calls
talk("upwork", "find related job")
│
▼ depth=2
upwork.talk("neuro", "summary?")
│
▼ depth=3
neuro.talk(...)
│
▼ depth=4 → TalkDepthExceeded
(loop guarded)
Cron-style triggers persisted to schedules.db via APScheduler.
schedule_run — create a triggerschedule_list — inspectschedule_cancel — remove"Every morning at 8 send me the summary" — parsed by core/trigger_parse.py, fired by core/scheduler.py, persisted in core/schedules_db.py.
# Persistence
core/schedules_db.py # SQLite store
core/scheduler.py # APScheduler glue
core/trigger_parse.py # NL → cron
# API
GET /api/schedules
POST /api/schedules
DELETE /api/schedules/{id}
In NeuroLang terms: effect="voice". The standard library wires LiveKit, Twilio/Plivo, ElevenLabs, OpenAI TTS, Whisper, Deepgram, Sarvam — adapters, not magic.
| Profile | Use | Paired Agent |
|---|---|---|
general | Default conversational agent | neuro |
code_dev | Code editing focus | opencode |
neuro_dev | Authoring neuros (meta) | neuro |
neurolang_dev | Authoring NeuroLang flows | nl_dev |
POST /api/profile/switch { "profile": "neurolang_dev" }
GET /api/profile/active
GET /api/profile/list
The Python library. Typed primitives, plans-as-values, composition operators. Vendored at ./neurolang/.
The program. Composed neuros packaged as a runnable, shareable artifact. Apps on PNP Compute are NeuroNets. Manifest: name, version, deps, signature.
The IDE + runtime fused. This repo is the flagship implementation.
| Primitive | Role |
|---|---|
Neuro | Typed unit (identity + behaviour + optional prompt) |
Flow | Composition: |, &, +, DAG, loop |
Plan | First-class — inspect, modify, replay, diff, hash |
Memory | Scoped — discrete / differentiable / HD / episodic / semantic / procedural |
Effect | pure / llm / tool / human / time / voice — tracked in types |
Budget | Latency + cost — statically warned, runtime enforced |
Recovery | fallback / retry / escalate as language primitives |
Mailbox | Message-passing; no shared mutable state |
Agent | Long-lived neuro w/ mailbox + memory + role |
from neurolang import neuro, Flow, Memory, Budget
from neurolang.stdlib import web, reason, memory_neuros
@neuro(effect="tool")
def extract_book_metadata(url: str) -> dict:
"""Scrape book title, author, summary from URL."""
...
@neuro(effect="llm", budget=Budget(cost_usd=0.02))
def summarize(emails: list[Email]) -> str: ...
research_flow: Flow = (
web.search | extract_book_metadata
| reason.summarize | memory_neuros.store
)
research_flow.render(format="mermaid")
research_flow.cost_estimate()
research_flow.effect_signature()
plan = research_flow.plan(query="category theory")
result = plan.run(memory=Memory.discrete())
plan.serialize(); plan.replay()
| Natural Language | Category Theory | Computation / Tensor |
|---|---|---|
| Noun | Object (dim 0) | Tensor index |
| Verb | Morphism (dim 1) | Linear map |
| Adverb | Natural transformation (dim 2) | Higher-order op |
| Sentence | Composed arrow | Computation graph |
| Translation | Equivalence of categories | Reparameterisation |
| Grammar | Category of types (Lambek) | Type system |
| Dim | NeuroLang primitive | NN counterpart |
|---|---|---|
| 0 | Values, tensors, HD vectors, memory cells | Weights, activations, embeddings |
| 1 | Functions, differentiable maps, effects | Layers, activations |
| 2 | Plans, flows, memory scopes (functorial) | Multi-head attention, residuals |
| 3 | Plan transformations, optimisation passes | Architecture search, distillation |
| ∞ | Meta-neuros, self-modifying compiler | Self-modifying architectures |
Design rule: a primitive may be added at dimension n only if it cannot be expressed cleanly at dimension n−1 without loss of structure.
left-adjoint: L : NL → Formal (compile)
⊣
right-adjoint: R : Formal → NL (summarise)
Designed to run inside a private, isolated machine — a dedicated workstation, VM, or container, separate from your personal host OS.
Autonomous agents need access to your screen, files, and inputs. By isolating this, you control exactly what they touch.
Single-user, long-lived. Personal-assistant scope. No multi-tenancy.
| Method | Endpoint | Purpose |
|---|---|---|
POST | /chat | Send a message to the active agent |
GET · POST | /agents · /agents/{type} | List · switch agents |
GET · POST | /api/profile/list · /switch | Profiles |
GET · POST | /api/rooms | Meeting rooms |
GET · POST | /api/schedules | Triggers |
POST | /stream/start | Desktop streaming |
GET | /voice/token | LiveKit voice token |
POST | /mouse/* · /keyboard/send | Input control |