Status: proposed cross-project contract. This document maps the existing Yggdrasil, Spindel, Dvergr, and Simmis abstractions before their APIs are consolidated. Names marked provisional describe semantics, not necessarily the next public function names.
There must be one implementation of state forking while still allowing each layer to add its own meaning:
Simmis Proposal / ForkSet durable governance and review
│ adopts or references
Dvergr RunWorld / RoomBranch discourse, execution policy, quiescence
│ wraps
Spindel ForkHandle one fork of a reactive execution world
│ automatically forks
Yggdrasil systems Datahike, Geschichte, CRDTs, other substrates
Higher layers may project, govern, or own a fork. They must not independently implement substrate branches, fork identity, or settlement.
:frozen or :following.Yggdrasil does not own Rooms, Runs, agents, proposals, or execution graphs. Geschichte workspaces and Datahike branches are implementations of this layer, not additional orchestration worlds.
An execution world is a Spindel ExecutionContext containing:
A world fork is the existing Spindel Yggdrasil ForkHandle. Forking the
context creates a CoW reactive overlay and automatically forks each selected
registered Yggdrasil system. Nested forks always fork the effective state of
their immediate parent.
The live handle is a process-local capability. A portable ForkDescriptor (provisional) records the durable basis of the fork:
{:fork/id fork-id
:fork/parent parent-world-id
:fork/purpose :run|:workroom|:particle|:proposal|:experiment
:fork/systems
{system-id {:base-snapshot snapshot-id
:branch branch-id
:head snapshot-id
:mode :frozen|:following
:rights :write}}
:fork/owner owner-id}
The descriptor schema should extend or reuse Spindel's existing distributed workspace checkout/fork descriptor rather than introduce a competing manifest.
A Room is a long-lived social and work environment. It is not a synonym for a Spindel fork.
A discourse branch is an alternate message/participant projection used for an imagined conversation. It need not fork state.
A RoomBranch (provisional) is a Room facade over a Spindel world fork. It adds a bus, conversation projection, participant policy, registration, and control-plane events. It does not own a second substrate fork.
A Run is the durable identity of one causally bounded execution. It is not a fork. A Run may execute in a private world fork, share an ambient world, or produce no substrate changes.
A RunWorld is a Run's lease and policy over one world fork:
{:run/id run-id
:fork/handle live-fork-handle
:room/view work-room
:settlement/policy :automatic|:review|:discard}
Its fork identity, parent, child context, and live settlement capability come from the canonical Spindel handle and are not recreated in Dvergr.
A Proposal/ForkSet is a durable governance object over one or more fork contributions. It adds rationale, contributors, checks, comments, conflicts, authorization, per-scope decisions, and resolution provenance.
It does not implement another execution fork. Promotion adopts an existing fork descriptor and transfers settlement authority. A Proposal message, Tasks, Futures, Feed, and Timelines are projections of that same governance object.
The canonical lifecycle is:
merge
┌────────────▶ merged
│
open ────────────────┼── discard ─▶ discarded
│
└── transfer ─▶ adopted by proposal/room
Only an open handle can be settled. Merge, discard, and transfer consume its settlement authority exactly once. After transfer, only the adopter may settle the fork. A RunWorld cannot retain a hidden second merge/discard path.
The live affine token should not be made copyable merely to make it "fork-aware". It is intentionally process-local authority. Durable ownership and status are facts in the Room/Simmis store; semantic state remains forkable.
Parent control is structural:
Forking and merging are deliberately asymmetric.
Registered Yggdrasil systems are merged or discarded through their native protocols. This includes Datahike data, Geschichte files/history, and registered CRDT systems.
Spindel's generic OverlayBackend contains both semantic values and execution
machinery. Its child delta must not be wholesale merged into the parent:
Pure workflow results therefore return explicitly. When a reactive value should
contribute to its parent, the program supplies an explicit reducer/join, or the
value is promoted to a Yggdrasil-managed convergent system. A later
PSettletableValue-like hook may make selected signal settlement convenient,
but it must remain opt-in and algebra-specific.
Room messages, Run lifecycle, activity, accounting receipts, and proposal facts are durable control-plane facts written to their authoritative stores. They are not recovered by merging arbitrary Spindel engine state.
The universal guarantee is prechecked, journaled, and recoverable, not cross-backend ACID atomicity.
Spindel can preflight every system and then settle them in a deterministic order. Because heterogeneous stores do not share a transaction coordinator, a failure can occur after one system has merged. Settlement must therefore record per-system progress and be safely resumable or compensatable.
A Yggdrasil CompositeSystem may provide a single causal visibility gate where
all readers resolve through that composite, especially for co-located CRDT
systems. It does not make arbitrary external backends universally rollbackable.
Dvergr and Simmis must not claim stronger atomicity than the selected systems
provide.
World creation needs an explicit policy surface:
{:purpose :run|:workroom|:particle|:proposal|:experiment
:systems :all|:none|#{system-id ...}
:mode :overlay|:snapshot
:rights {system-id :write}
:effects :live|:record|:stub
:settlement :automatic|:review|:discard}
The default for a normal isolated Dvergr Run can remain all systems granted to the Room. Simulations and inference should default to no live external effects unless explicitly granted. Eventually Kontor allocations determine both resource rights and the maximum fork policy a child may receive.
Today Spindel accepts only the enforceable :write right. It rejects :read and
:fork instead of placing an unenforced label in the descriptor. Those rights
belong here once the substrate and SCI capability boundary can enforce them.
Needs: canonical handle migration and recoverable settlement. The core path otherwise exists.
A lead Run works in world A. Hiring a researcher creates B = fork(A); that
researcher may create C = fork(B). Accepted C work merges into B, and
accepted B work merges into A. Trunk is never an implicit target.
The canonical nested ownership path now exists: SCI dvergr.agent/hire! and the
spawn_agent / propose_change tool adapters all use Run worlds. Recursive
hire-in! keeps durable facts in the root control Room while forking and settling
against the immediate work-world parent. Paid recursive LLM delegation remains
attenuated until resource-vector splitting exists.
A standalone Run completes in review mode. Promotion transfers its open fork to a durable ForkSet and persists the descriptor as a GC root. The Run becomes a contributor and loses settlement authority. Review may survive restart and settles the adopted world as one affine unit.
The live bridge is dvergr.rooms.forks/adopt!. Its :prepare! callback must
persist the prospective descriptor/owner before Spindel transfers authority.
Successful transfer detaches the transient Room and returns the adopter's sole
process-local ForkHandle; preparation failure leaves the review world open.
If the affine CAS loses a race after preparation, the required :abort!
compensates the prepared durable row. The handle is never persisted.
The prepared descriptor includes :dvergr/room-id,
:dvergr/parent-room-id, and (for a nested isolated world)
:dvergr/parent-fork-id. The durable owner must retain that ancestry until the
child settles; Dvergr's shared topology is its immediate in-process projection.
Adoption starts as whole-world authority. partition-adoption! can then consume
that aggregate handle into an exhaustive tree of disjoint system capabilities.
Each leaf settles exactly once; Dvergr releases the retained structural ancestry
only after every leaf is terminal and the supplied tree proves that no partition
was omitted. A durable adopter prepares the intended plan before partitioning
and commits the exact child descriptors afterward. If that commit fails, the
API returns the error together with all live child handles so recovery cannot
silently lose authority. No proposal layer may accept or dismiss systems by
mutating raw branches outside this capability tree.
Each durable leaf decision goes through settle-adoption!: governance prepares
the intent, Spindel consumes the affine capability, and governance commits the
terminal descriptor as Spindel's single-execution post-commit callback. A
failed durable commit leaves terminal authority and its receipt available to
retry-settlement-commit!; it never recreates an actionable review. Structural
release rejects failed partition persistence, duplicate/substituted handles,
and any durable leaf whose terminal commit is incomplete. Commit callbacks see
only portable operation/descriptor data—never execution contexts or live
systems from Spindel's internal settlement payload. Failed compensation is
returned as explicit recovery state with the durable receipt still attached;
retry-settlement-abort! repairs that durable intent before the still-open
capability can receive a new decision.
Simmis still needs to supply the durable half: store the descriptor as a GC root, index its systems into the existing ForkSet, and journal per-system settlement. After restart it reopens the named Datahike/Geschichte branches under that durable ownership claim; it does not deserialize the old Spindel reactive context.
Several Runs contribute independent forks. The Proposal may retain each contribution for per-agent/per-scope decisions, or construct an additional integration world and merge selected contributions into it. The integration world is another canonical fork, not a special proposal branch implementation.
Needs: multiple adopted descriptors and explicit contribution edges. ForkSet already supplies most governance semantics.
Fork a snapshot of selected state, substitute recorded/stubbed effects, execute a hypothetical conversation or program, return an explicit result, and discard the world. It creates no Proposal unless deliberately promoted.
Needs: selected systems/effect policy. Message-only discourse branching remains available as a cheaper operation when no state isolation is required.
Create N snapshot world forks at a checkpoint. Each particle receives an
independent reactive state and an explicit external-system/effect policy.
Observe evidence, resample descriptors/contexts, and discard unselected
particles. Only an explicitly selected particle can be promoted or merged.
Needs: the inference coordinator must stop using raw
snapshot-context/restore-snapshot for worlds containing Yggdrasil handles;
that path does not invoke PForkable and may alias external state.
Each tree edge forks its node world, applies an action, runs or simulates effects, and accumulates reward/evidence. Pruning consumes and discards the corresponding handles. Transpositions may share immutable snapshots but never writable capabilities.
Needs: cheap nested handles, deterministic seeds/virtual time, selective/stubbed effects, resource accounting, and aggressive lifecycle/GC. No new fork algebra is required.
Long-lived agents observe and communicate in one Room without creating a Run or fork for every message. Runs identify bounded computations when useful; Room signals and speech acts remain the continuous FRP substrate.
Needs: no additional fork primitive. Attention and steering policies compose above the world model.
An agent constructs an immutable Roster/workflow, stores durable program or skill changes in forked Geschichte/Datahike, executes it in a controlled world, and receives a trusted verifier result plus Kontor resource receipts. The world and verifier basis make the environment replayable; reward is not inferred from model prose.
Needs: versioned environment descriptors, fork basis, resource allocation and effect receipts. SCI Vars/atoms may later become more deeply forkable, but durable definitions should remain in owned substrates rather than depend on serializing live evaluator internals.
A child Room that needs independent policy and substrate adopts/detaches a world fork as its durable root. It is no longer an unsettled speculative fork. On restart, it rehydrates from its descriptor and authoritative Room facts.
Needs: adoption and descriptor-based hydration. The current per-Room context provisioning is a partial implementation without the unified lifecycle.
The implementation should satisfy these laws before higher-level APIs depend on it:
ForkHandle with a portable descriptor and single-settlement/transfer
boundary, reusing the distributed descriptor schema.fork-room to call ygg/fork! and retain
its handle.RunWorld as Run policy plus the canonical
handle/Room view (its small atom caches the policy decision, not substrate
state).dvergr.rooms.forks review and settlement through
that handle.dvergr.agent.subagent/hire!, dvergr.room/hire,
dvergr.discourse/hire, and the independent chat.context/fork-sub-chat
hierarchy. All bounded delegation and executable branching is Run-backed;
conversational branches remain message/thread projections.Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |