NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #5976 most downloaded on pub.dev
Nomos 2 Dart client — generated domain values, intent payloads and application lifecycle types over the typed Nomos kernel protocol and USDA custody model.
Last release 22 days ago
27 Aug 2026
Ships on a steady schedule
a new release about every 8 days
Nearly every release is documented
notes for 56 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
2 months old
100 releases · first in 2026
One column per month.
Offer ack decoupled from watch fan-out (co2's 2.08s 3×3-grid report): the durable acknowledgement (plan + gate + fold + git write) resolves before any
recentSpans/spanEvents with no new API: payload-encode,
compat-preflight, bridge-ipc, gate-fold, watch-nudge, response-delivery (git-write is not
separable client-side — plan+gate+fold+write is ONE wasm call). Older runner bundles degrade cleanly
(no bridge-leg spans).The burn-down wave. Dead-letter queue surface on the session plane: deadLetters(), retryDeadLetter(), discardDeadLetter(), salvage(), absorbSalvage()
deadLetters(),
retryDeadLetter(), discardDeadLetter(), salvage(), absorbSalvage() — with the local-only
retry/absorb fixes and the salvage-shape parking fix (refused work is NEVER silently dropped).
nomos_headless.dart exports the full session surface. Requires Nomos Cloud ≥ the 2026-07-11
burn-down deploy for the fleet DLQ sweep lanes (/dlq-summary, /dlq-sweep) and the
content-addressed large-deploy staging lane.Structural: the session-delegation-gap class is closed. All event-dispatch registries (watch subscriptions, compat watches, custody/sync/signal/flame/
_eventPlane seam that
resolves to the plane owning the message loop — the base class is correct for NomosSession
automatically, and all 17 hand-written per-method session overrides are DELETED (including the
0.48.1 watchPendingConflicts fix, whose regression test still passes — the proof). Five
latent unreported instances of the same bug fixed en passant: session.custodyEvents (dead
stream), connectedSessions (empty), connect()-on-session state stamping, checkCompat()
caching, noteLocalSpan() (dead buffer). A source-level tripwire test fails the suite if a
future Stream-returning method bypasses the seam.No silent hangs — the standing harness property. Every NomosTestHarness lifecycle phase now has a deadline (overridable via the new phaseTimeout param
NomosTestHarness lifecycle phase now
has a deadline (overridable via the new phaseTimeout param) and throws a typed
HarnessPhaseTimeout naming the phase (e.g. "3b: keyed reconnect of 'catalogue'"), workspace,
elapsed time, the awaited bridge op, and likely causes — a wedge is a 30-second named exception,
never a 40-minute bisection. Every phase logs terse enter/exit diagnostics. Disposal deadline
breaches are logged, not thrown — teardown always completes.deviceKeyed cluster hang report): harness phase 3b
(keygen + keyed reconnect) had no timeout and no diagnostics — any wedge there hung silently
after "4 session(s) connected". Additionally two runner/realm defects fixed: the stale session
record stayed routable during an async re-open (concurrent ops could hit the disposed holon —
now an atomic replace with a fast typed refusal in the window), and a re-open with new
credentials but no restoreFrom silently kept the OLD identity (the fresh authorSecret was
never installed) — an identity-bearing option change now forces an in-place re-mount over
resident custody.cluster(deviceKeyed:) completes, devicePublicKey
populated, colocated attested read signed by the re-opened key, disposal completes.Fix: local-only `autoSync()` deadlocked the multi-workspace plane. A local:// session's autoSync registered the full cloud machinery (doorbell WebSock
autoSync() deadlocked the multi-workspace plane. A local:// session's
autoSync registered the full cloud machinery (doorbell WebSocket retry loop, fallback timers,
intent-offer POSTs that could never land) — the future never completed, the runner dispatcher
starved, sibling queries and listWorkspaces() hung, and teardown wedged. autoSync() on a
local-only session now registers nothing and returns immediately; sync() is a true no-op
(localOnly: true summary); a local:// holon performs ZERO network attempts. (co2's acceptance
test implemented verbatim; failed before, passes after.)acquireSession(workspace, {ifAbsentCredentials}) — atomic single-flight session
acquisition: reuses a connected session, joins an in-flight open (concurrent calls yield the
same handle, one connect), opens local-only for workspaces the plane already knows
(mounted/parked/resident custody — credentials never invoked), and only calls
ifAbsentCredentials (exactly once) when a genuine cloud open is required.Fix: `NomosSession.watchPendingConflicts()` never emitted. The session overrode every other reactive read to register on the parent plane (which owns
NomosSession.watchPendingConflicts() never emitted. The session overrode every other
reactive read to register on the parent plane (which owns the message loop) but omitted this one —
a session-bound generated client's conflict stream registered on the session's own dead controller
registry and never delivered an event. Now delegates like watch/watchById/watchActivity.
Regression test: a session-level subscription must emit its first snapshot. (Reported by co2 with
the exact fix — thank you.)Root-bridge generic writes (offer/offerDirective/offerIntent/offerCreates/createWorkspace) are @Deprecated in app code — kept for CLI/admin tooling; t…
NomosSession: XClient.bind(session) async preflight factory (structural interface
compat, typed DomainClientSessionMismatch at construction), all dispatch through the session,
births infer the parent from the session (no loose parent strings), engine.follow(NomosRef)
mounts by ref, NomosOfferOutcome.bornRefs. The kernel's generic "no active installed law declares
domain 'x'" is wrapped into the context-rich DomainNotInstalledForSession (session identity, both
workspaces, active domain keys/hashes, the four possible causes).offer/offerDirective/offerIntent/offerCreates/createWorkspace)
are @Deprecated in app code — kept for CLI/admin tooling; the session-bound generated surface is
the path.NomosSession.pendingConflicts() / watchPendingConflicts() — the maintained Surfaced-conflict
"decisions needed" read (derived, not drained).resetWorkspaceCustody, seedWorkspaceFromDeployJson, assertDomainInstalled,
session.assertCompatible(XClient.interface).@githolon/dsl 0.72.0 codegen.Fix: `NomosBridge.createWorkspace` hardcoded `domain: "workspaces"` in the underlying signed offer — a tenant birthing through their OWN platform's cu
NomosBridge.createWorkspace hardcoded domain: "workspaces" in the underlying signed offer —
a tenant birthing through their OWN platform's custom law (e.g. a birthEstateWorkspace directive under a
co2_platform domain) was refused, because the sealed intent always claimed domain: "workspaces"
regardless of which law actually declares the requested directiveId. Added a domain parameter
(default "workspaces", fully back-compatible) — call
bridge.createWorkspace(domain: 'co2_platform', directiveId: 'birthEstateWorkspace', domainHash: ..., ...)
to birth through a custom platform law. This release was overdue: the fix landed in nomos_flutter
0.52.2's bundled JS runtime, but this Dart-level API surface lives in nomos_client and was never
republished alongside it — a real release-process gap, not a client-side workaround. Requires
nomos_flutter >= 0.52.2 to match the bundled runtime behavior.Custody lifecycle on NomosBridge/NomosSession: connect(..., onCustodyBreak: CustodyBreakPolicy), custodyStatus(), the custodyEvents stream, resolveCus
NomosBridge/NomosSession: connect(..., onCustodyBreak: CustodyBreakPolicy),
custodyStatus(), the custodyEvents stream, resolveCustodyBreak() (the ask lane — put the decision in
front of the user), salvagedIntents/reofferSalvaged/discardSalvaged. A rebirth/supersession is a
first-class typed event: named truthfully, decided by the app, local work never silently adopted nor lost.
Requires nomos_types >= 0.1.4.offerOutcome(...) — the one outcome-returning offer lane generated clients now call for EVERY directive: returns NomosOfferOutcome with workspace-stam
offerOutcome(...) — the one outcome-returning offer lane generated clients now call for EVERY directive:
returns NomosOfferOutcome with workspace-stamped created (NomosCreated gains workspace + a
NomosRef get ref view). Activity raw rows carry created + workspace. Requires nomos_types >= 0.1.3.Activity-feed runtime reads on NomosBridge/NomosSession: activityLog({base, limit}) — the committed intent log as raw rows {intentId, domain, directiv
NomosBridge/NomosSession: activityLog({base, limit}) — the committed
intent log as raw rows {intentId, domain, directiveId, actorSubject, occurredAt, payload} (decoded
payload; the verified author; the physical HLC) — and watchActivity({base}), a stream re-deriving the
feed on every sync tick. Generic (raw Maps); the generated renderActivity (from directives' declared
.activity() metadata) types them into ActivityEvents. Requires nomos_types >= 0.1.2.NomosBridge.foreignReader({cloud}) — a NomosForeignReader backed by the device's multi-workspace bridge plane, so a generated ForeignRef (t.foreignRef
NomosBridge.foreignReader({cloud}) — a NomosForeignReader backed by the device's multi-workspace bridge
plane, so a generated ForeignRef (t.foreignRef) resolves against real data: it mounts the foreign
workspace on demand (connect(session: ws, allowUnborn: true), idempotent) and reads it
(session(ws).queryById(id)); watch re-reads on each sync tick. A locator resolver, not a foreign key —
the foreign holon is mounted only when you resolve. Requires nomos_types >= 0.1.1 (the ForeignRef types).Nothing published for this version
NomosTestHarness emits named phase-progress diagnostics (install → spawn runner → await ready → connect, plus per-session progress in cluster) and eac
NomosTestHarness emits named phase-progress diagnostics (install → spawn runner → await ready → connect, plus per-session progress in cluster) and each connect() carries a connectTimeout (default 120s) that throws a NAMED remedy instead of hanging — so a multi-test AppSim run can tell install vs runner-wait vs session-block vs deadlock (co2 feedback).connect(maxMounted: …) — the realm's mounted-workspace budget (LRU park/remount above it); useful on memory-constrained devices holding many local wor
connect(maxMounted: …) — the realm's mounted-workspace budget (LRU park/remount above it); useful on memory-constrained devices holding many local workspaces.NomosTestHarness.ephemeral now connects a DECOY session alongside the workspace under test, and harness.bridge is a NomosSession HANDLE pinned to it (existing tenant tests work unchanged). Sole-session inference therefore never silently passes under the harness — an op that forgot its session refuses in your first test with the same multiple sessions connected — pass session a real multi-workspace app raises. Opt out with decoySession: false.NomosBridge.open(...) — connect + pinned NomosSession handle in one call (final home = await bridge.open(workspace: …); HomeClient(home)): the recommended plane/handle shape; the bare bridge methods remain one-workspace sugar.Multi-session compat surface: watchCompatibility takes an optional session; NomosSession pins its compat watch, compat, and onLawChanged to ITS worksp
watchCompatibility takes an optional session; NomosSession pins its compat watch, compat, and onLawChanged to ITS workspace (per-session lawChanged scoping — previously a multi-session plane's compat verdict was whichever session synced last, and a session's compat watch refused on a >1-session plane).SPLIT: the pure data core (wire types, offer codec, NomosReads, aggregate meta, schema validation, error info) moved to the new nomos_types package; n
nomos_types package; nomos_client depends on and re-exports it, so existing imports are unchanged. Frontend/UI code can now depend on nomos_types alone.Doc fix: NomosBridge.attestedRead docs now match the runtime — the call answers { entry: {queryId, result, attestation: …} }; pass result['entry'] as
NomosBridge.attestedRead docs now match the runtime — the call answers { entry: {queryId, result, attestation: …} }; pass result['entry'] as one offerDirective attestations element.Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
SPATIAL READS: NomosBbox + NomosBridge.spatialWithin(spatialId, bbox) + watchSpatial(...) — the R*Tree probe surfaces on the bridge; generated clients
NomosBbox + NomosBridge.spatialWithin(spatialId, bbox) + watchSpatial(...) — the R*Tree probe surfaces on the bridge; generated clients (tooling ≥0.46) emit typed sitesByBounds({required NomosBbox bbox}) + watch accessors.NomosFieldMeta.fromBirth — the registry surfaces BIRTH-PRESENCE LAW (.fromBirth() fields, tooling ≥0.42): a gate invariant guarantees the field presen
NomosFieldMeta.fromBirth — the registry surfaces BIRTH-PRESENCE LAW (.fromBirth() fields, tooling ≥0.42): a gate invariant guarantees the field present on every row, and the generated read models type it non-nullable.RUNTIME AGGREGATE METADATA: NomosAggregateMeta / NomosFieldMeta / mergeAggregateMeta (src/aggregate_meta.dart) — the support types for the generated p
NomosAggregateMeta / NomosFieldMeta / mergeAggregateMeta (src/aggregate_meta.dart) — the support types for the generated per-domain const Map<String, NomosAggregateMeta> <domain>AggregateMeta registry (nomos-compile ≥0.41 tooling). Generic surfaces (history/audit UIs, op renderers, in-app agents) resolve NomosAggregateMeta.typeOfId(op.aggregate) → field kinds, enum wire values, VO/variant names, and the typed fromJson decoder — the compiler's knowledge emitted as data, derived from the law's own declarations.LAW-MINTED IDS RETURN TO THE CALLER: NomosBridge.offerCreates(...) → NomosOfferOutcome{head, created} — a .creates plan mints its aggregate id inside
NomosBridge.offerCreates(...) → NomosOfferOutcome{head, created} — a .creates plan mints its aggregate id inside the sealed intent (payloads never carry one); the offer now hands the minted ids back, so generated create methods return the typed id with no query-after round-trip. New types NomosOfferOutcome / NomosCreated.NomosBridge.mintId(typeTag) — reserve a kernel-minted typed id (<TypeTag>_<uuidv7>) via the holon's front-door mint, for app-side references. (.creates payloads still carry NO id — the law mints those.)nomos-compile ≥0.38 tooling): .creates(...) directive methods now return Future<NomosOfferOutcome> instead of Future<String> — outcome.created.single.id is the new aggregate's typed id.NomosTestHarness (nomos_headless.dart): ephemeral real-law fixtures — one call births a throwaway cloud workspace, deploys compiled *.deploy.json law,
NomosTestHarness (nomos_headless.dart): ephemeral real-law fixtures — one call births a throwaway cloud workspace, deploys compiled *.deploy.json law, and hands out independent client replicas (connect(clientId:)) over the node runner. Identity defaults to the githolon login --agent session (~/.holon/credentials.json). Live-proven: birth → deploy → write on one replica → converge + typed read on another, 14s end-to-end.package:nomos_client/nomos_headless.dart): NodeRunnerTransport — a BridgeTransport over the @githolon/client node runner (runner/node-entry.mjs) as a plain child process (NDJSON stdio). flutter test / dart test / CI drive the REAL githolon (byte-identical wasm, real ledger, real gate) through NomosBridge + the generated typed clients — no Flutter plugins, no WebView, no assets. Requires node on PATH + a resolvable @githolon/client (auto-resolved from the app's node_modules, or pass entry:). Proven end-to-end: connect → offerDirective → sync(admit) → typed query, and the same test green under both dart test and flutter test.TYPED SNAPSHOT RECOVERY (corrupt local custody): NomosBridge.connect(recover: true) recovers IN-PLACE from a corrupt restoreFrom snapshot — salvages l
NomosBridge.connect(recover: true) recovers IN-PLACE from a corrupt restoreFrom snapshot — salvages local-only authored writes (via the fallible intents_above, which stops at a missing-ancestor gap) + the DLQ, refolds FRESH from cloud, re-offers the salvaged work (deduped), re-queues the DLQ. The report rides bridge.lastRecovery = {salvagedWrites, requeuedDeadLetters, unsalvageable} — a write the current law refuses lands in unsalvageable + the DLQ (surfaced, never dropped). Also holon.salvage() / holon.absorbSalvage(). Closes the restoreFrom-leaves-read-model-empty case.TIER-2 SYNC SIZE: NomosBridge.syncSize() → {bytes, kind} — how many bytes this workspace would transfer to catch up, WITHOUT downloading (a HEAD on th
NomosBridge.syncSize() → {bytes, kind} — how many bytes this workspace would transfer to catch up, WITHOUT downloading (a HEAD on the serving pack; the host answers Content-Length, cached ~15s). Sum across open workspaces for an aggregate "X MB to sync" total before any download.SYNC STATE + REAL LOADING BARS: NomosBridge gains syncStatus (Stream — phase/ahead/behind/saved/onMain/deadLetters/transfer/lastSyncedAt, derived from
NomosBridge gains syncStatus (Stream<SyncStatus> — phase/ahead/behind/saved/onMain/deadLetters/transfer/lastSyncedAt, derived from sync rounds + doorbell + transfer + a 4s metrics poll), transferProgress (Stream<TransferProgress> — live pack byte-progress; total is the host Content-Length so the bar is truthful, never estimated), and currentStatus. New types: SyncStatus, SyncPhase, TransferProgress.createWorkspace / shareWith no longer require authorSecret — it defaults to the connection's signing key (the home device key NomosScope.home loaded).
createWorkspace / shareWith no longer require authorSecret — it defaults to the connection's signing key (the home device key NomosScope.home loaded). A frontend dev never threads a key through make-workspace or share.NomosBridge.shareWith — one-call cross-custody share (sign quote + deliver recordShare to the subjects home). Closes the shared-with-me loop.
NomosBridge.shareWith — one-call cross-custody share (sign quote + deliver recordShare to the subjects home). Closes the shared-with-me loop.NomosBridge.offerIntent (canonical write verb; offerDirective kept as alias) + one-call NomosBridge.createWorkspace (sign + relay a control-plane offe
NomosBridge.offerIntent (canonical write verb; offerDirective kept as alias) + one-call NomosBridge.createWorkspace (sign + relay a control-plane offer).NomosBridge.noteLocalSpan(...) — inject a locally-measured span (e.g. the Dart-side durable save, the "saved to disk" number) into the span stream so
NomosBridge.noteLocalSpan(...) — inject a locally-measured span (e.g. the Dart-side durable save, the
"saved to disk" number) into the span stream so it appears on the flame chart AND the per-phase stats
exactly like a kernel span. Additive; used by nomos_flutter's durable-save-on-write.NomosBridge.connect accepts the internal allowUnborn opt-in used by NomosScope.home, so the home-birth ceremony can boot a local bridge before the hom
NomosBridge.connect accepts the internal allowUnborn opt-in used by NomosScope.home, so the
home-birth ceremony can boot a local bridge before the home workspace has a remote main. The default
remains strict for ordinary workspaces.NomosBridgeError now carries structured NomosErrorInfo alongside the existing human-readable message. The envelope includes stable code/component/oper
NomosBridgeError now carries structured NomosErrorInfo alongside the existing human-readable
message. The envelope includes stable code/component/operation fields, workspace/domain/directive
context, trace/span ids, arbitrary attributes, and toTelemetryAttributes() for future OpenTelemetry
export without taking an SDK dependency.Authority-aware: NomosBridge.offerDirective(domain, directiveId, payload, {actor, domainHash}) — generated clients route every offer through THE ONE e
NomosBridge.offerDirective(domain, directiveId, payload, {actor, domainHash}) — generated
clients route every offer through THE ONE encoder (encodeIntentOfferBytes in @githolon/client); no
per-client envelope encoding. New typed MissingOfferAuthority — a .requires(...) directive authored
with no actor throws BEFORE submit (an actorless gated offer cannot be generated). Lockstep jump to 0.20.0.Lockstep bump with the birth-primitive release (see @githolon/dsl 0.17.0): birth is one law primitive (birthChild), the platform-creator tier collapse
@githolon/dsl 0.17.0): birth is one law primitive
(birthChild), the platform-creator tier collapsed onto #creator, grantCreation takes a user or key
subject. The Dart wire types track the current /v2 governance surface.First pub.dev release: kernel wire types, NomosBridge protocol, typed offer/query/watch surface.
NomosBridge protocol, typed offer/query/watch surface.Your coding agent can read these notes before it upgrades. Set up the MCP server →