Actor-model agentic UI

Actor-model agentic UI replaces the linear chat assumption with a persisted graph of nodes — each node is an actor with its own chat log, type, disk address, and spawn lineage.

Node and actor mean the same thing here; node is the general graph term, actor matches the concurrency model (mailbox summaries, message routing, no shared mutable transcript).

Problem

Chat UIs assume one thread drifts until the user resets. Agent harnesses break that daily:

  • A coordinator discussion spawns many task nodes (multi-repo runs)

  • A task chat tangents into permissions or CLA policy — that tangent should spawn a discussion child, not pollute the merge log

  • Parallel jobs need a grid; tangents need lineage — same store, different views

Serializing everything produces the wall of repeated 9 of 12 running headers (see screenshot below).

Serialized multi-repo agent updates in one chat scroll

Core claim

Persist the graph on disk. RAM-only actor state loses spawn lineage when the session ends or the model compacts context.

Each node writes:

  • meta.json — type, status, spawnedBy, spawned[], related[], mailbox summary, disk address

  • chat.jsonl — authoritative messages for this node only

Parent and child both record each other’s id before the child accepts traffic. Runtime structs mirror disk 1:1 — no shadow transcript cache.

Node types

Type Role

coordinator

Root orchestrator; continuous top-level voice with summarization

discussion

Exploratory chat; may spawn tasks, discussions, or disambiguation when topic forks

task

Bounded job (repo PR, merge, sync); appears in parallel grid with status dot

disambiguation

Short-lived resolver when parent/child topic boundary is unclear

More subtypes extend the same struct — type is a routing hint, not a separate storage silo.

Spawn on drift

When chat in node A drifts from A’s declared topic:

  1. Harness creates node B with spawnedBy: A

  2. A appends B to spawned[]; both meta.json files flush to disk

  3. A gets a routing marker in its chat; new lines go to B’s chat.jsonl

  4. UI may show B in the grid, graph strip, or fork panel depending on type

Primary trigger: model-proposed spawn — when the user mixes continuation of the current subject with new ideas that deserve their own context.

Secondary: user Spawn tangent, policy (non-task utterance in task node), or disambiguation child when the model cannot resolve the boundary yet.

Metathread

Cross-node audit lives in orchestrator/meta.jsonl:

  • Coordinator utterances and spawn events

  • Line refs into child logs ({ node, line, summary })

  • Agent-generated timeline bookmarks as chat progresses

Interactive typing happens in nodes/{id}/chat.jsonl; the metathread is the spine, not a filtered copy of one mega-scroll.

Graph + views

Node graph with spawn edges, mailboxes, and grid projection

One graph; multiple projections over the same disk store:

  • Harness canvas — rearrangeable conversation previews (thumb + clipped blurb), email-like PM statuses (working / waiting / unread / read / needs you / user-marked completed), archive bin that remembers canvas position. Fundamental inbox face; spatial patterns borrowed from Piles (Piles stays email-domain).

  • Gridtype=task nodes, job status + summary, separate scroll from main thread

  • Fork panel — selected node’s chat.jsonl; title-history index when the topic renames

  • Lineage stripspawnedBy / spawned for the active node

  • Global coordinator thread — continuous chat with summarization; user can back out to global context from any node

  • Temporal layout — planned embeddable widget (see below)

Hierarchical coordinator mode and global personal-context mode are different views, not different stores. Reset = scope filter (archive / trim to bookmark), not delete disk.

Rebase ownership (canvas → demo / Piles pattern / Hornet runtime): agent-harness-canvas rebase plan.

Wait graph

Default: warn. Subagents declare subscriptions:

  • warn — mailbox may be stale; keep working on independent lines

  • enforce — block until terminal status (merges, releases)

Temporal layout (planned)

Parallel nodes do not naturally chapter together. Temporal layout is a view engine — same component, different scope:

  • Global timeline — all activity under the chat root

  • Sub-timeline — one node subtree (widget inside node detail)

Features (phased): fade idle nodes (not delete; respect awaitingUser), horizontal scrubber, token-volume strip, heatmap overlay, zoom-dependent keyword bookmarks in a sidebar. Bookmarks are agent-generated as chat progresses.

Optional epoch snapshots (views/epoch-N.json) when the coordinator explicitly reframes a batch — supplements bookmarks; not the primary nav model.

Relationship to Dev-Centr harness

ACTOR_AGENTIC_UI = graph-grid | serialized | off
ACTOR_GRAPH_EPOCHS = on | off
ACTOR_WAIT_GRAPH = warn | enforce | off
ACTOR_NODE_STORE = jsonl-per-node | off

Defaults when graph-grid: ACTOR_NODE_STORE=jsonl-per-node, ACTOR_WAIT_GRAPH=warn.

Reference runtime: dev-centr/hornet (v0 disk store, v1 Mixr + desk, v2 temporal layout).

DevCentr — Actor-model agentic UI owns disk schema and routing.

Demo

Live demo — harness canvas (PM statuses, drag, archive), grid, fork + title index, epochs, serialized contrast.

Renamed from project inbox

Project inbox named only the task-grid layout. This topic names the underlying node graph; the grid is one view. Project inbox (renamed) redirects here.