L2 · the LLM boundary PORT — just the protocol + the call-record shape, with
ZERO engine deps (05, GD10). The engine never speaks HTTP; it asks an
LlmAdapter for the next assistant message. Request assembly lives in
adapter.request (L3); the impls in .sdk/.fake. The wall-clock deadline
is applied by run-step! (with-deadline), NOT here — so it covers every impl.
L2 · the LLM boundary PORT — just the protocol + the call-record shape, with ZERO engine deps (05, GD10). The engine never speaks HTTP; it asks an LlmAdapter for the next assistant message. Request assembly lives in `adapter.request` (L3); the impls in `.sdk`/`.fake`. The wall-clock deadline is applied by run-step! (with-deadline), NOT here — so it covers every impl.
L2 · FakeAdapter (05 §5, 10 §1) — the offline test backbone. A PURE function of the request (not a mutable queue), so scripted multi-step runs are deterministic and order-independent. Ignores opts (no streaming/retry); the loop's with-deadline still wraps it, so timeout behavior is uniform.
L2 · FakeAdapter (05 §5, 10 §1) — the offline test backbone. A PURE function of the request (not a mutable queue), so scripted multi-step runs are deterministic and order-independent. Ignores opts (no streaming/retry); the loop's with-deadline still wraps it, so timeout behavior is uniform.
L3 · request assembly (05 §4, GD10). Kept OUT of the port ns so the port stays
engine-dep-free; this requires cache/prompt/payload-io. run-step! calls
build-request with the handle's store, the strong current-view, and cfg.
L3 · request assembly (05 §4, GD10). Kept OUT of the port ns so the port stays engine-dep-free; this requires cache/prompt/payload-io. `run-step!` calls `build-request` with the handle's store, the strong current-view, and cfg.
L2 · SdkAdapter (05 §2, §6) — the ONLY impl that crosses the network. Wraps
llm.sdk/complete. NO internal deadline (run-step! applies with-deadline
around the whole call). Honest-:unknown normalization; maps the SDK Response
onto the engine's bare-:cache call record.
L2 · SdkAdapter (05 §2, §6) — the ONLY impl that crosses the network. Wraps `llm.sdk/complete`. NO internal deadline (run-step! applies with-deadline around the whole call). Honest-:unknown normalization; maps the SDK Response onto the engine's bare-:cache call record.
L5 · THE SDK surface (06). Thin — delegates to the internals and exposes nothing else. Phase 1 ships the clojure harness; the Phase-3/4 rlm harness EXTENDS this same surface (recursion is internal), so these signatures do not change.
L5 · THE SDK surface (06). Thin — delegates to the internals and exposes nothing else. Phase 1 ships the clojure harness; the Phase-3/4 rlm harness EXTENDS this same surface (recursion is internal), so these signatures do not change.
L1 · the prompt-cache contract (08). The SDK owns ALL per-provider marker
placement; the engine owns a stable cache identity and forwards an opaque
passthrough map {:enabled? :ttl :scope-id} on every request.
L1 · the prompt-cache contract (08). The SDK owns ALL per-provider marker
placement; the engine owns a stable cache identity and forwards an opaque
passthrough map `{:enabled? :ttl :scope-id}` on every request.L1 · the per-session capability profile, the named lattice, clamp (gate
meet), validate-profile!, and sci-opts (profile → the map passed to
sci/init). Capability is DENIED BY DEFAULT (04): the SCI ctx grants nothing
except what the profile explicitly injects/whitelists. Takes the host-fn
impls (FINAL/inspect[/lm/rlm]) as DATA, so it never depends on the kernel.
Gated IO (slurp/spit/sh/file-seq/io.reader/…) and the engine fns are injected
into clojure.core, so they are available unqualified AND survive a model
(in-ns …) (the §7 'gated slurp shadow survives in-ns' guarantee — SCI has
no built-in slurp to revert to, and a clojure.core var is referred by every
ns).
L1 · the per-session capability profile, the named lattice, `clamp` (gate meet), `validate-profile!`, and `sci-opts` (profile → the map passed to sci/init). Capability is DENIED BY DEFAULT (04): the SCI ctx grants nothing except what the profile explicitly injects/whitelists. Takes the host-fn impls (FINAL/inspect[/lm/rlm]) as DATA, so it never depends on the kernel. Gated IO (slurp/spit/sh/file-seq/io.reader/…) and the engine fns are injected into `clojure.core`, so they are available unqualified AND survive a model `(in-ns …)` (the §7 'gated slurp shadow survives in-ns' guarantee — SCI has no built-in slurp to revert to, and a clojure.core var is referred by every ns).
L0 · engine-free wrapper over the SDK's STATIC model catalog (01 manifest
note, 05 §6). These are metadata lookups against the bundled models.dev
snapshot — they work offline and are explicitly allowed OUTSIDE the adapter
seam (only complete — an actual provider call — is confined to the
adapter). config resolves the model + context-window, compaction reads
the window, start-session! resolves the provider.
L0 · engine-free wrapper over the SDK's STATIC model catalog (01 manifest note, 05 §6). These are metadata lookups against the bundled models.dev snapshot — they work offline and are explicitly allowed OUTSIDE the adapter seam (only `complete` — an actual provider call — is confined to the adapter). `config` resolves the model + context-window, `compaction` reads the window, `start-session!` resolves the provider.
Agent-operable CLI/control plane over fractal.engine.api.
This namespace is intentionally a thin executable seam. It does not introduce product nouns or alternate runtime semantics: commands open a durable SDK session, perform one usage/inspection action, emit JSON/EDN, and close.
Agent-operable CLI/control plane over fractal.engine.api. This namespace is intentionally a thin executable seam. It does not introduce product nouns or alternate runtime semantics: commands open a durable SDK session, perform one usage/inspection action, emit JSON/EDN, and close.
L3 · compaction (07 §4) — v1's mechanism, adapted to SCI vars + the
event-sourced store. assess/should-compact? estimate request tokens vs the
model window (ceil(chars/4), :unknown-window-chars fallback). compact-session!
summarizes the transcript via the root model into ONE continuation frame,
snapshots the vars for durability, and appends a SINGLE :session/compacted
event (no torn-write window). It does NOT restore/clear the live vars.
L3 · compaction (07 §4) — v1's mechanism, adapted to SCI vars + the event-sourced store. `assess`/`should-compact?` estimate request tokens vs the model window (ceil(chars/4), `:unknown-window-chars` fallback). `compact-session!` summarizes the transcript via the root model into ONE continuation frame, snapshots the vars for durability, and appends a SINGLE `:session/compacted` event (no torn-write window). It does NOT restore/clear the live vars.
L0 · concurrency primitives (engine-free). with-deadline runs a body under
a single wall-clock budget on a DAEMON thread, so a stuck provider call can
neither block JVM exit nor be relied on to stop (an orphaned call may still
run — and cost — after the deadline fires; documented, 07 §3).
Phase 3 adds the bounded fan-out primitive bounded-fanout (≤cap workers, a
daemon pool, dynvar propagation via bound-fn, partial-failure-tolerant) +
a semaphore/with-permit pair (the GLOBAL leaf governor). The recursion ns
composes these; the engine semantics live there, not here.
L0 · concurrency primitives (engine-free). `with-deadline` runs a body under a single wall-clock budget on a DAEMON thread, so a stuck provider call can neither block JVM exit nor be relied on to stop (an orphaned call may still run — and cost — after the deadline fires; documented, 07 §3). Phase 3 adds the bounded fan-out primitive `bounded-fanout` (≤cap workers, a daemon pool, dynvar propagation via `bound-fn`, partial-failure-tolerant) + a `semaphore`/`with-permit` pair (the GLOBAL leaf governor). The recursion ns composes these; the engine semantics live there, not here.
L4 · make-config (07 §1). Normalizes/validates engine config, validates the default capability profile, resolves + stamps :context-window via the static catalog, and RECORDS the adapter choice keyword — it never constructs the adapter instance (start-session! is the sole composition root, GD5).
L4 · make-config (07 §1). Normalizes/validates engine config, validates the default capability profile, resolves + stamps :context-window via the static catalog, and RECORDS the adapter choice keyword — it never constructs the adapter instance (start-session! is the sole composition root, GD5).
L2 · the SCI eval kernel (03). The model's Clojure runs here — in an SCI ctx (one per session), NOT JVM eval. Vars def'd in one eval persist across steps and turns. The loop owns turn/step/message/observation appends; the kernel owns the per-block :eval/added append (the deliberate kernel→store edge).
⚠ SCI 0.8.43 fact (verified): ns resets to user after every separate
eval-string* call, so a standalone (in-ns …) does NOT persist. We instead
bind sci/ns to the session-ns object around EVERY eval — which upholds every
invariant the spec names (vars persist, session isolation, a model (in-ns …)
never strands later evals — the binding re-establishes the session ns each
call) and is pinned by the §7 regression test.
⚠ SCI wraps an exception thrown inside eval in a {:type :sci/error} ExceptionInfo whose CAUSE is the original — so FINAL detection + err->map walk the cause chain.
L2 · the SCI eval kernel (03). The model's Clojure runs here — in an SCI ctx
(one per session), NOT JVM eval. Vars def'd in one eval persist across steps
and turns. The loop owns turn/step/message/observation appends; the kernel
owns the per-block :eval/added append (the deliberate kernel→store edge).
⚠ SCI 0.8.43 fact (verified): *ns* resets to `user` after every separate
`eval-string*` call, so a standalone `(in-ns …)` does NOT persist. We instead
bind `sci/ns` to the session-ns object around EVERY eval — which upholds every
invariant the spec names (vars persist, session isolation, a model `(in-ns …)`
never strands later evals — the binding re-establishes the session ns each
call) and is pinned by the §7 regression test.
⚠ SCI wraps an exception thrown inside eval in a {:type :sci/error} ExceptionInfo
whose CAUSE is the original — so FINAL detection + err->map walk the cause chain.L1 · the per-session live dispatch as a PURE MECHANISM — no store dependency
(09, GD8). store.memory implements the subscribe!/events-since/
notify-transient protocol methods by delegating here; the loop and api only
ever call the port methods. Delivery happens on a per-session daemon
dispatcher thread (lazily started on the first subscriber) so a slow or
throwing subscriber can neither stall nor corrupt a write. Durable events and
transient deltas share one ordered queue; on overflow transient deltas drop
first, a durable skip is a last resort, and either way one coalesced
:subscribe/gap is emitted so a subscriber recovers via events-since.
L1 · the per-session live dispatch as a PURE MECHANISM — no store dependency (09, GD8). `store.memory` implements the `subscribe!`/`events-since`/ `notify-transient` protocol methods by delegating here; the loop and api only ever call the port methods. Delivery happens on a per-session daemon dispatcher thread (lazily started on the first subscriber) so a slow or throwing subscriber can neither stall nor corrupt a write. Durable events and transient deltas share one ordered queue; on overflow transient deltas drop first, a durable skip is a last resort, and either way one coalesced `:subscribe/gap` is emitted so a subscriber recovers via `events-since`.
L1 · observation rendering (03 §5, the v24 doctrine). The model is NOT handed
values — after a batch it gets, per block: captured stdout, the form status,
and the return value rendered FIT-OR-STUB. To look inside a stub it acts —
(inspect x) (orchard-backed) or slices the live var.
L1 · observation rendering (03 §5, the v24 doctrine). The model is NOT handed values — after a batch it gets, per block: captured stdout, the form status, and the return value rendered FIT-OR-STUB. To look inside a stub it acts — `(inspect x)` (orchard-backed) or slices the live var.
L0 · PURE payload primitives (zero engine deps). The Merkle substrate (02 §3,
§9): a blob's id is sha256:<hex> over canonical-bytes, so equal values
dedup to one content-addressed node across every store impl and across
processes. Store-coupled IO (maybe-intern / read-payload / hydrate-message)
lives in fractal.engine.payload-io — NOT here — so store can depend on
this pure ns without a cycle.
L0 · PURE payload primitives (zero engine deps). The Merkle substrate (02 §3, §9): a blob's id is `sha256:<hex>` over `canonical-bytes`, so equal values dedup to one content-addressed node across every store impl and across processes. Store-coupled IO (maybe-intern / read-payload / hydrate-message) lives in `fractal.engine.payload-io` — NOT here — so `store` can depend on this pure ns without a cycle.
L1.5 · store-coupled payload IO (02 §3). Wraps the store's
intern-payload!/read-payload* with the inline/hydrate policy. Built after
store; the PURE payload ns stays store-free so store itself depends
only on it (no cycle).
L1.5 · store-coupled payload IO (02 §3). Wraps the store's `intern-payload!`/`read-payload*` with the inline/hydrate policy. Built after `store`; the PURE `payload` ns stays store-free so `store` itself depends only on it (no cycle).
L1 · the behavioural core (12). Two base system prompts, SELECTED by the harness mode (config-only hot-swap): :clojure → the Phase-1 clojure-harness prompt (operator doctrine for a sandboxed REPL whose only host fns are FINAL/inspect — NO recursion). Unchanged byte-for-byte from Phase 1. :rlm → the v24 recursion doctrine (the recursive host-fn surface, the leaf/child/attach cheapness hierarchy, envelopes, the ≤50 fan-out cap, partial-fanout sentinels, the smell tests, trust discipline). Plus the leaf prompt (a single probabilistic transformation, no REPL) and the compaction prompt. Each is stamped name/version/hash so runs are reproducible and auditable. Role (root vs child) is a per-turn USER-MESSAGE FRAME (child-invocation-frame), never a different system prompt (00 — role as frame).
L1 · the behavioural core (12). Two base system prompts, SELECTED by the
harness mode (config-only hot-swap):
:clojure → the Phase-1 clojure-harness prompt (operator doctrine for a
sandboxed REPL whose only host fns are FINAL/inspect — NO
recursion). Unchanged byte-for-byte from Phase 1.
:rlm → the v24 recursion doctrine (the recursive host-fn surface, the
leaf/child/attach cheapness hierarchy, envelopes, the ≤50
fan-out cap, partial-fanout sentinels, the smell tests, trust discipline).
Plus the leaf prompt (a single probabilistic transformation, no REPL) and the
compaction prompt. Each is stamped name/version/hash so runs are reproducible
and auditable. Role (root vs child) is a per-turn USER-MESSAGE FRAME
(child-invocation-frame), never a different system prompt (00 — role as frame).L4 · the RLM recursion layer (Phase 3). The four model-calling host fns injected into a session's SCI ctx when the harness is :rlm:
(lm input query [mode]) LEAF — ONE bounded provider call (no session, (map-lm inputs query [mode]) LEAF no loop, no lineage); the leaf prompt; mode :string/:edn. map-lm = the leaf fanned out over ≤50 inputs, order-kept. (rlm task) CHILD — a FRESH child session (its own SCI ctx (map-rlm tasks [shared]) CHILD + SessionStore session, inherit-and- clamped capability) running the WHOLE loop to FINAL; returns an ENVELOPE. (attach-rlm handle task [opts]) REUSE — a FRESH derived child restored from a selected immutable source head.
Recursion happens BETWEEN interpreters, in the HOST (03 recursion note): a
child is a normal session in the SAME store. This ns NEVER requires session
(that would cycle: session→recursion); instead session injects an env of
spawn/run/stop closures (dependency inversion, mirroring the v1 reference).
Leaf ≠ child (architecture invariant): a leaf is one adapter call; a child is a full session. Partial fan-out NEVER throws — failed slots become {:fractal/failed true …} sentinels in the :fractal/ ns. Accounting stays honest: a child's usage/cost/cache rides its envelope's :rlm/meta; the root turn's :turn/usage/:turn/cost remain SELF-ONLY (06 §6).
Phase 4 adds the durable recursion data model here: invocation/derivation edges, cross-session lineage, immutable heads, and attach-rlm. The envelope's :rlm/head is the immutable current head plus legacy :vars-ref/session aliases.
L4 · the RLM recursion layer (Phase 3). The four model-calling host fns
injected into a session's SCI ctx when the harness is :rlm:
(lm input query [mode]) LEAF — ONE bounded provider call (no session,
(map-lm inputs query [mode]) LEAF no loop, no lineage); the leaf prompt;
mode :string/:edn. map-lm = the leaf
fanned out over ≤50 inputs, order-kept.
(rlm task) CHILD — a FRESH child session (its own SCI ctx
(map-rlm tasks [shared]) CHILD + SessionStore session, inherit-and-
clamped capability) running the WHOLE
loop to FINAL; returns an ENVELOPE.
(attach-rlm handle task [opts])
REUSE — a FRESH derived child restored from a
selected immutable source head.
Recursion happens BETWEEN interpreters, in the HOST (03 recursion note): a
child is a normal session in the SAME store. This ns NEVER requires `session`
(that would cycle: session→recursion); instead session injects an `env` of
spawn/run/stop closures (dependency inversion, mirroring the v1 reference).
Leaf ≠ child (architecture invariant): a leaf is one adapter call; a child is
a full session. Partial fan-out NEVER throws — failed slots become
{:fractal/failed true …} sentinels in the :fractal/ ns. Accounting stays
honest: a child's usage/cost/cache rides its envelope's :rlm/meta; the root
turn's :turn/usage/:turn/cost remain SELF-ONLY (06 §6).
Phase 4 adds the durable recursion data model here: invocation/derivation
edges, cross-session lineage, immutable heads, and attach-rlm. The envelope's
:rlm/head is the immutable current head plus legacy :vars-ref/session aliases.L4 · session lifecycle + the turn-lock (07 §2/§5). start-session! is the SOLE composition root that constructs the adapter and stashes cfg+adapter on the handle. run-turn!/run-turn-async! gate (stop/max-turns) before the CAS, then drive the step loop. commit-turn!/finalize-turn! live in session-loop (GD4).
L4 · session lifecycle + the turn-lock (07 §2/§5). start-session! is the SOLE composition root that constructs the adapter and stashes cfg+adapter on the handle. run-turn!/run-turn-async! gate (stop/max-turns) before the CAS, then drive the step loop. commit-turn!/finalize-turn! live in session-loop (GD4).
L3 · the STEP loop (07 §3). run-loop! iterates run-step! until
final/error/timeout/budget/stop. The loop owns the turn/step/message/
observation appends + the deadline; the kernel owns the per-block :eval/added.
commit-turn!/finalize-turn! live HERE (not in session) so the loop never
depends on session — that breaks the session↔session-loop cycle (GD4).
L3 · the STEP loop (07 §3). `run-loop!` iterates `run-step!` until final/error/timeout/budget/stop. The loop owns the turn/step/message/ observation appends + the deadline; the kernel owns the per-block :eval/added. `commit-turn!`/`finalize-turn!` live HERE (not in session) so the loop never depends on session — that breaks the session↔session-loop cycle (GD4).
L1 · the SessionStore PORT, the event taxonomy, and the pure fold (02). The
loop talks to this protocol and nothing below it — swap MemoryStore for a
Phase-2 SQLiteStore with zero loop changes. apply-event is PURE (no IO):
store impls call it on the write path; a Phase-2 recovery path folds the log
with it. Depends only on the PURE payload ns (for payload-ref?), never on
payload-io — so there is no cycle.
L1 · the SessionStore PORT, the event taxonomy, and the pure fold (02). The loop talks to this protocol and nothing below it — swap MemoryStore for a Phase-2 SQLiteStore with zero loop changes. `apply-event` is PURE (no IO): store impls call it on the write path; a Phase-2 recovery path folds the log with it. Depends only on the PURE `payload` ns (for `payload-ref?`), never on `payload-io` — so there is no cycle.
L1.5 · the GLOBAL, file-based, content-addressed blob store (02 §3, §9) — the
Phase-2 payload substrate that SqliteStore's intern-payload!/read-payload*
delegate to. A blob's id is sha256:<hex> over payload/canonical-bytes,
computed BYTE-FOR-BYTE the same way MemoryStore addresses its in-memory blobs —
so the same value dedups to the same content node across sessions AND across
processes (the shared Merkle leaf, 02 §9). No sid: blobs are global.
On disk: the canonical EDN bytes are written at <root>/<aa>/<sha256hex>.blob
(sharded by the first two hex chars), read back via clojure.edn. Writes are
atomic (temp file + ATOMIC_MOVE) so a concurrent reader never observes a partial
blob and an idempotent re-write of identical content is a harmless no-op. No
extra dependency — just the JDK filesystem + the pure payload ns.
L1.5 · the GLOBAL, file-based, content-addressed blob store (02 §3, §9) — the Phase-2 payload substrate that SqliteStore's intern-payload!/read-payload* delegate to. A blob's id is `sha256:<hex>` over `payload/canonical-bytes`, computed BYTE-FOR-BYTE the same way MemoryStore addresses its in-memory blobs — so the same value dedups to the same content node across sessions AND across processes (the shared Merkle leaf, 02 §9). No `sid`: blobs are global. On disk: the canonical EDN bytes are written at `<root>/<aa>/<sha256hex>.blob` (sharded by the first two hex chars), read back via `clojure.edn`. Writes are atomic (temp file + ATOMIC_MOVE) so a concurrent reader never observes a partial blob and an idempotent re-write of identical content is a harmless no-op. No extra dependency — just the JDK filesystem + the pure `payload` ns.
L1.5 · MemoryStore — the Phase-1 in-memory SessionStore (02 §7). A global
content-addressed blobs atom (the Merkle substrate, shared across sessions)
plus per-session slots. append-event! stamps ids+ts from the per-session
counters, folds via the pure apply-event, then schedules a non-blocking
live notification OUT of the lock. The live methods delegate to live
(store.memory → live, the deliberate L1.5→L1 edge).
L1.5 · MemoryStore — the Phase-1 in-memory SessionStore (02 §7). A global content-addressed `blobs` atom (the Merkle substrate, shared across sessions) plus per-session slots. `append-event!` stamps ids+ts from the per-session counters, folds via the pure `apply-event`, then schedules a non-blocking live notification OUT of the lock. The live methods delegate to `live` (store.memory → live, the deliberate L1.5→L1 edge).
L1.5 · store-impl-shared slot machinery. Both MemoryStore and SqliteStore key
their live in-process state by :session/id in a :sessions atom of per-session
slots ({:view :lock :dispatch :sci-ctx :busy}). stop-dispatch! is the one
genuinely store-agnostic operation the composition root needs across impls: it
stops a session's live dispatcher thread without the caller knowing which store
it holds (the SessionStore protocol is fixed — 02 §4 — so this is a plain helper,
not a protocol method). Depends only on live (no store dep, no cycle).
L1.5 · store-impl-shared slot machinery. Both MemoryStore and SqliteStore key
their live in-process state by `:session/id` in a `:sessions` atom of per-session
*slots* (`{:view :lock :dispatch :sci-ctx :busy}`). `stop-dispatch!` is the one
genuinely store-agnostic operation the composition root needs across impls: it
stops a session's live dispatcher thread without the caller knowing which store
it holds (the SessionStore protocol is fixed — 02 §4 — so this is a plain helper,
not a protocol method). Depends only on `live` (no store dep, no cycle).L1.5 · SqliteStore — the Phase-2 DURABLE SessionStore (02). Slots under the
SAME SessionStore port as MemoryStore with ZERO loop/kernel/adapter/api
changes; the only composition-root change is start-session! choosing it off
cfg :store. Mirrors MemoryStore's slot machinery (per-session :view/:lock/
:dispatch/:sci-ctx/:busy, the stamp-ids+ts counters, the live
delegation) and adds the durable layer:
• The canonical EVENT LOG + a minimal sessions table live in SQLite, PER SESSION,
keyed by (session_id, the monotonic event_id) — the future head event-range
boundary (02 §9). Raw JDBC, no wrapper dep.
• PAYLOADS live in a GLOBAL, file-based, content-addressed blob store
(blobstore) shared across sessions — no sid, content hash is globally
sufficient (02 §3).
⛔ PERSIST-BEFORE-FOLD (02 §8.2): under the per-session slot lock → stamp id+ts →
durably INSERT the event (committed) → ONLY on success swap! the in-process view
cache → schedule a NON-BLOCKING live notification. A failed persist throws BEFORE
the swap, so it never advances the view. create-session! reopens a persisted
session by FOLDING its durable log with the pure apply-event (deterministic
re-fold ⇒ the same ids, 02 §9) — the recovery path resume builds on.
L1.5 · SqliteStore — the Phase-2 DURABLE SessionStore (02). Slots under the SAME `SessionStore` port as MemoryStore with ZERO loop/kernel/adapter/api changes; the only composition-root change is `start-session!` choosing it off `cfg :store`. Mirrors MemoryStore's slot machinery (per-session `:view`/`:lock`/ `:dispatch`/`:sci-ctx`/`:busy`, the `stamp-ids+ts` counters, the `live` delegation) and adds the durable layer: • The canonical EVENT LOG + a minimal sessions table live in SQLite, PER SESSION, keyed by (`session_id`, the monotonic `event_id`) — the future head event-range boundary (02 §9). Raw JDBC, no wrapper dep. • PAYLOADS live in a GLOBAL, file-based, content-addressed blob store (`blobstore`) shared across sessions — no `sid`, content hash is globally sufficient (02 §3). ⛔ PERSIST-BEFORE-FOLD (02 §8.2): under the per-session slot lock → stamp id+ts → durably INSERT the event (committed) → ONLY on success swap! the in-process view cache → schedule a NON-BLOCKING live notification. A failed persist throws BEFORE the swap, so it never advances the view. `create-session!` reopens a persisted session by FOLDING its durable log with the pure `apply-event` (deterministic re-fold ⇒ the same ids, 02 §9) — the recovery path resume builds on.
SDK-supplied model-facing surfaces.
A surface is an embedder-owned set of namespaced host functions, plus public metadata used to keep SCI injection and prompt truth aligned. The engine owns validation, stamping, capability filtering, prompt rendering, and resume compatibility; embedders own function behavior and world-specific effects.
SDK-supplied model-facing surfaces. A surface is an embedder-owned set of namespaced host functions, plus public metadata used to keep SCI injection and prompt truth aligned. The engine owns validation, stamping, capability filtering, prompt rendering, and resume compatibility; embedders own function behavior and world-specific effects.
L0 · IO-free time helpers. now-str is the one impure fn (reads the wall
clock); everything else here must stay pure so the rest of the engine can
inject a clock where reproducibility matters (10 §4).
L0 · IO-free time helpers. `now-str` is the one impure fn (reads the wall clock); everything else here must stay pure so the rest of the engine can inject a clock where reproducibility matters (10 §4).
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 |