Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Research positioning

The companion vault (../sms-research, see wiki/thesis.md) argues that safe live self-modification needs three things no shipped system combined: a substrate with revertible effects and reactive dependencies (Cordis / Spatiotemporal Composability), a judge outside the agent’s write set (the lesson of the Darwin Gödel Machine’s objective hacking), and persistence with an audit trail (what DeepSeek’s dsh deliberately skipped — “scratch, not memory”). sms-baseline is the attempt to have all three, packaged so that ordinary applications can adopt it.

The four questions, answered for sms-baseline

The vault compares systems along what / who / when / judge and the lifecycle Bootstrap → Propose → Evaluate → Commit → Serve. Our row:

sms-baseline
What is modifiedthe running application, as plugins: keys provided, extension-point contributions (routes, collections, fields, hooks, tools, prompts), and agent code. The unit of change is the fiber — exactly what the substrate can swap atomically (not functions like SelfEvolve, not whole containers like MOSS).
Who proposesthe model, through plugin_define; humans through the same judge API
Whenlive, in the same conversation; Commit = the plugin/installed event + content-addressed blob; Serve = the fiber is active and reachable through http/agent/collections
Judgethe judge system plugin: gates (manifest, trust, source-lint, load-in-throwaway-executor) → policy (sensitive scopes/points → human) → mount → invariants; rollback restores the previous version from log + blobs
Unreachability of the judgestructural, not hidden: judge key and gate/invariant points require system trust checked in the kernel on every access; MountAuthorization minted only via KernelApi, which agent contexts never receive; system ids reserved; the executor bridge re-checks inject and trust per call
BoundaryQuickJS-in-WASM executor: own heap, memory limit, CPU deadline, JSON-only bridge. The Node executor is labelled steering, not a security boundary, as dsh labels node:vm.
Persistenceevent-sourced (plugin/* fold into the target view), blobs by hash; SQLite, Postgres, D1, Durable Objects (drivers/store/*); files on S3 / R2 (drivers/objects/*)
Tenancykernel-per-tenant; the substrate never sees two tenants

Concepts from the vault and where they live here

ConceptHere
revertible-effectsclosed vocabulary provide/contribute; AppliedEffect.undo derived by the kernel; LIFO unwind (kernel.ts undoAll)
spatiotemporal-composability (Thm 63, provider outlives consumers)deactivate() unloads dependents first, settle() re-activates what became satisfiable
plugin-architecture five requirementsclosed effects, per-fiber isolation, reactive re-wiring, judge outside the write set, persistence as a separate axis
project-trust-gate (load-time trust is not enough)gates run at propose time and invariants run after every mount; trust is re-checked at every effect
transactional-no-regressionmount = checkpoint (previous version in log) → act (activate) → judge (invariants) → commit or full undo. Batch size K = one plugin activation.
objective-hacking / belief 6the judge’s inputs (gate, invariant) are system-only; but see Open questions on indirect contamination
dynamic-plugin-runtime (dsh)plugin_define → judge → kernel instead of a file loader; approval is a policy (sensitivePoints), not baked in
agent-operating-system (process boundary vs self-modification)one traditional Worker + DO per tenant; QuickJS inside; Dynamic Workers rejected for v1
event-sourced-session-logchat/*, judge/*, fiber/* events are audit; plugin/* are state
evaluator-co-evolutioninvariants are owned by system plugins; they can evolve only through a code release, never at run time

Threat model over the extension points (MLAS-style pass)

Stages: Propose (model calls plugin_define), Evaluate (gates/human), Commit (log + blob), Serve (fiber active).

SurfaceAttackWhere it is stopped
inject: ['judge'] / provide: ['judge']reach or replace the judgetrust gate (E) and kernel trust check (S); test agent plugins cannot reach system-only keys
contributes.gate / invariantweaken the evaluatorminContributorTrust: system (E, S)
id collision (judge, http, …)replace a system fiberRESERVED_ID (E, S); judge requires agent. prefix
forged / replayed authorizationmount without the judgenonce bound to id+version+code hash, single-use (C)
code escapes (process, fetch, import)I/O from agent codesource-lint (E); QuickJS has none of them (S); Node executor strips them (steering only)
runaway CPU / memorydenial of service inside the processQuickJS sliceMs interrupt + memoryLimitBytes; Node executor resourceLimits
route contribution shadowing /api/*hijack admin routesroutes match in contribution order (system first); add route to sensitivePoints if agents may add routes; the admin routes need the bearer token regardless
collection-hook with side effectsemissions outside the effect vocabulary (belief 8)not undoable by design; hooks run inside collections which catches and logs; keep external effects in system plugins
prompt contributionsteer the model’s later proposals (prompt injection from a plugin)recorded and visible in /api/catalog; treat prompt as sensitive if plugins come from untrusted tenants’ agents
indirect judge contaminationan agent-contributed collection/tool changes what an invariant readsinvariants should read kernel state (kernel.has, fibers), not collection data — documented rule, not enforced
cross-tenantone tenant’s agent plugin affects anotherkernel-per-tenant, separate stores; no shared executor instances

Open questions (deliberately not solved here)

  1. Emissions. activate() code cannot do I/O in QuickJS, but a system-provided service it invokes might. The vocabulary covers registry effects only; side effects through services are the plugin owner’s problem. A “compensating action” contract for services is future work.
  2. Evaluator co-evolution. Invariants are frozen per release. The vault’s RQGM answer (freeze per epoch, promote against held-out ground truth) would need a second, offline judge.
  3. The human gate at scale. needs-human is a policy on scopes/points. Per-tenant approvers, quorum, and expiry are host concerns to build on /api/approvals.
  4. Regulatory. A self-modifying production system is a substantial modification generator in EU AI Act terms; the event log is the evidence trail. Nothing here claims conformity.

Status (2026-08-28)

Implemented and tested: kernel guarantees (15 tests), both executors incl. interrupt/memory limits, judge gates/approval/rollback, collections contract on SQLite / Postgres (PGlite) / D1- and Durable-Object-shaped storage, object storage (S3, R2), node/fastify/cloudflare hosts, the system plugins (admin-api, agent-loop, audit, auth, automation, collections, http, judge, meta, orm, rbac, rpc, scheduler), createBaseline + createTenantPool, end-to-end prompt → judge → mount → restart → undo, and a real pnpm add git+…#tag&path: install of the built packages from a scratch clone. Not run by pnpm test: wrangler/workerd (Cloudflare pieces are tested against structural fakes) and a network Postgres (PGlite stands in), and the CLI/HTTP model drivers against live providers (SMS_LIVE_MODELS=1) or live buckets (SMS_LIVE_OBJECTS=1).