Proposal 045: Sensorium as a Local Enaction Stratum¶
Based on:
doc/normative/20-vision/VISION.mddoc/normative/40-constitution/CONSTITUTION.mddoc/normative/50-constitutional-ops/AUTONOMY-LEVELS.mddoc/normative/50-constitutional-ops/EMERGENCY-ACTIVATION-CRITERIA.mddoc/project/20-memos/orbiplex-monus.mddoc/project/20-memos/emergency-signal-v1-invariants.mddoc/project/30-stories/story-009-bielik-blog-arca.mddoc/project/40-proposals/013-whisper-social-signal-exchange.mddoc/project/40-proposals/019-supervised-local-http-json-middleware-executor.mddoc/project/40-proposals/022-monus-as-host-granted-local-observation-middleware.mddoc/project/60-solutions/000-node/000-node.mddoc/project/60-solutions/009-monus/009-monus.md
Status¶
Draft
Date¶
2026-04-18
Executive Summary¶
Sensorium already appears in the Orbiplex corpus as the Node's layer of contact with reality. The Vision describes it as the layer of adapters to the world: public-network readers, environmental sensors, microphones, cameras, GPS, weather, energy, safety signals, and other signal sources. The Constitution defines it as the organ that provides signals grounding intelligence in reality and limiting narrative or model drift.
Other documents already assume this role:
- emergency operations describe a
sensorium -> evaluation -> activationpipeline, - autonomy levels treat sensorium event logging and aggregation as routine bounded node activities,
emergency-signal.v1acceptssource/type = sensorium,- Monus can consume Sensorium-derived summaries when preparing local concern drafts,
- Whisper preserves
monus-sensorium-derivedprovenance when local observations materially shaped an outgoing social signal, - story 009 treats Sensorium as connector access to external sources such as arXiv, GitHub repositories, mailing lists, and news feeds,
- the Node solution already allows a sensorium provider to attach as a Node-scoped role through explicit protocol and API contracts.
This proposal makes that implied layer explicit, while widening the name of the layer from observation to enaction: Sensorium admits observations, but it also mediates intentional directives and the audit/outcome records through which a node acts in the world without losing policy, traceability, or consent.
The core maxim is:
Sensorium is not a grand connector specification. It is a thin stratum for local enaction, where complexity lives in connectors and Sensorium normalizes only the minimal exchange contract for observations, directives, diagnostics, and artifacts.
Sensorium should therefore be implemented first as a supervised local module or Node-attached component in the spirit of proposal 019. It should expose boring, bounded host-granted capabilities for observation submission, directive invocation, query, summary, status, and audit. It should not become a universal ontology of the outside world, a transport authority, a surveillance platform, or a replacement for domain modules such as Monus, Whisper, Arca, or emergency evaluation.
Problem¶
The system needs contact with external reality, but "connectors to the world" can become an unbounded design sink. If every connector type forces a new global protocol, Sensorium becomes too large before the Node can use it. If every consumer speaks directly to each connector, Monus, Arca, emergency evaluation, and future modules all acquire duplicated adapter logic and uneven policy checks.
The design tension is:
- connectors are necessarily messy because the outside world is messy,
- consumers need stable local observations, not raw connector-specific chaos,
- the Node must retain consent, minimization, audit, and capability boundaries,
- the protocol core should not absorb every sensor, API, OS integration, or data feed shape.
Without a thin Sensorium stratum, the system is pulled toward one of two bad forms:
- a large
SENSORIUM-CONNECTOR-SPECthat tries to standardize every possible connector class too early; - ad-hoc side channels where each module reads local files, shells out, calls external APIs, or watches devices under its own private policy.
Both forms complect connector mechanics with domain reasoning.
Decision¶
Ontological Preamble¶
Sensorium is the node's organ of contact with reality. Contact is not
unidirectional: every act of observation has a physical and informational
footprint (a camera indicator LED, a Bluetooth presence beacon, a network
probe, a disk access timestamp), and every directive has an observational
aspect (the result of a git push is itself news about the world). The four
lanes defined below — directive, observation, diagnostic, artifact — are a
classification of intent and grant class, not a claim about causality
or directionality. A single connector may legitimately span several lanes;
a purely observational grant still commits the operator to whatever
incidental effects the connector declares it cannot avoid.
This proposal explicitly rejects the input-organ / output-organ split. Treating perception and action as two separate sub-systems is a Cartesian relic that enactivist cognitive science (Varela, Thompson, Rosch) has repeatedly shown to misdescribe how organisms actually engage with the world. An organism's sensorimotor surface is one coupled loop, not two plumbing systems meeting in the middle. Orbiplex Sensorium honors this: it is a sensorimotor organ, where perception and action form a single contact surface with the world.
Intentional action is therefore a first-class Sensorium function, not
a concession, not an escape hatch, and not a secondary lane bolted onto a
primarily perceptual component. A connector that performs a git push,
emits a Bluetooth beacon, toggles a GPIO pin, or executes an allowed shell
command is exercising the same organ as a connector that reads GitHub
releases or watches a file — the organ of contact with the world.
Story-009 should therefore be read in two layers: its Phase 1 research
path is observation-only Sensorium consumption, while commit/push belongs
to an explicit Arca-mediated OS directive path with narrower grants.
What the directive lane buys is not raw capacity to affect the world: capacity-to-act is inherent to an organ of contact; permission-to-act is always grant-bound and policy-mediated. The directive lane therefore provides a sharper grant and audit regime: directive grants are narrower than observation grants, require explicit allowlist entries, and every directive emits a corresponding audit outcome. Successful directives that produce facts about the world may also emit linked observations that close the sensorimotor loop — the act itself becomes news about the world.
This framing follows the project's broader commitment to honoring the mechanics of the world rather than pretending processes are cleanly separable, while still holding contract boundaries firm where they protect the operator.
Stratum Definition¶
Define Sensorium v1 as a local enaction stratum:
- connectors own adaptation from concrete external systems into local observations,
- Sensorium owns admission, minimal normalization, local policy enforcement, traceability, and queryable read models,
- consumers such as Monus, Arca, emergency evaluation, and local agents consume host-granted Sensorium capabilities,
- network publication remains outside Sensorium and is handled by the appropriate protocol layer.
The implementation architecture is:
sensorium-coreis the Node-attached Sensorium Core component that owns admission, normalization, policy, read models, and the consumer-facing capability surface; in the current Node implementation this core is a Rust organ integrated into the daemon, while older Pythonsensorium-corecode is only a retired reference,- every Sensorium connector is a separate middleware module registered with the
host as
module_role: "sensorium-connector", - connectors communicate through the standard middleware init/report,
host-capability,
local-input-invoke.v1, andpeer-message-invoke.v1envelopes, - Sensorium does not define or own a second plugin API for connectors.
Nomenclature: Core, Connector, Action, Package¶
Sensorium terminology intentionally separates the stable organ from the replaceable adapters around it.
| Term | Meaning |
|---|---|
| Sensorium organ | The node's local sensorimotor contact surface with the world: observation, directive mediation, diagnostics, artifacts, policy, audit, and minimal normalization. |
Sensorium Core / sensorium-core |
The mediator and contract boundary of the organ. It exposes public Sensorium capabilities such as sensorium.directive.invoke, admits observations, resolves action ids, selects connectors, records outcomes, and hides connector implementation details from consumers. |
| Sensorium connector | A separate middleware module that adapts one class of external contact to Sensorium. It is not a plugin loaded by sensorium-core; it is a daemon-hosted middleware participant reached through the standard host capability dispatch layer. |
Sensorium OS connector / sensorium-os |
One concrete connector middleware for allowlisted operating-system actions. A deployment may replace it or create another connector with a different module_id, connector_id, action catalog, and implementation. |
| Connector action | A declarative entry in a connector's action catalog, for example story009.review.publish. An action is not a middleware module; it is an operation exposed by a connector and mediated by sensorium-core. |
| Middleware package | An installable artifact that may carry connector code, scripts, action declarations, UI fragments, and config fragments. A package can extend a connector without becoming the organ itself. |
This naming matters for authority. Consumers such as Arca, Dator, Monus, or a
role module do not depend on "the OS connector" as an object. They depend on a
Sensorium capability and an action contract. sensorium-core maps that contract
to a concrete connector under operator policy. That lets an operator replace
sensorium-os with another connector implementation, or run several connector
modules with different names and grants, without changing consumer code.
This is also distinct from json_e / json_e_flow. JSON-e Flow is an executor
backend and a concrete flow config is treated as one operational middleware
component. It is not a Sensorium organ and it does not mediate connector
selection. A JSON-e Flow may call sensorium.directive.invoke, but then it is
just another consumer of the Sensorium Core boundary.
This is not a compromise. It follows the same stratification Orbiplex already uses for autonomous units of local work: supervised middleware, explicit grants, module reports, readiness, shutdown, restart counters, and audit traces. Connector isolation is a feature, not overhead to be hidden.
Sensorium composition uses two existing Orbiplex primitives rather than a new pipeline engine:
- Point-to-point capability invocation for connector ->
sensorium-coreadmission. This is request/response and pull-shaped: a connector submits a candidate observation, orsensorium-coreinvokes a reactive connector with a directive. - Local Agora topic publication for
sensorium-core-> consumers distribution. This is push-shaped: after admission,sensorium-corerepublishes the normalized observation to a local Agora topic such aslocal/sensorium/observations/{signal-kind}so Monus, Arca, emergency evaluation, UI, and future consumers can subscribe without coupling to the connector.
This makes Sensorium a mediated bus, not a Rack/Express/Ring-style interceptor chain. The daemon's middleware "chains" are request lifecycle stages inside the daemon; domain composition is explicit and capability-routed. A pipeline exists only when a module intentionally builds one, as Arca does for workflow steps.
Topology summary:
Connector middleware modules
sensorium.github.releases
sensorium.arxiv.search
sensorium.os.action
|
| directive/result lanes over middleware invoke envelopes
| observation submit over host capability bridge
v
+---------------------------------------------------------------+
| sensorium-core middleware |
| |
| mediated admission pipeline |
| validate -> redact -> policy-gate -> admit/quarantine/reject |
| -> store -> publish |
+---------------------------------------------------------------+
|
| admitted observations only
v
+---------------------------------------------------------------+
| local Agora bus |
| local/sensorium/observations/{signal-kind} |
| local ACL + retention + SSE subscription |
+---------------------------------------------------------------+
|
| pull query or push subscription
v
Monus Arca emergency-eval UI future consumers
Invariant: consumers never call connector modules directly.
Goals¶
- Keep Sensorium local-first and capability-bound.
- Put connector complexity at the edge, not in the core Sensorium contract.
- Provide a small common observation shape usable by multiple local consumers.
- Preserve provenance: connector id, source reference, confidence, sensitivity, and policy.
- Make observation ingestion and query auditable.
- Support both human-facing summaries and machine-facing structured observations.
- Allow generalized connectors where useful, including an OS connector, without giving them ambient unrestricted power.
Non-Goals¶
- Define a full taxonomy of all connector types.
- Define a network-wide Sensorium federation protocol in v1.
- Make Sensorium a transport or publication authority.
- Let Sensorium directly publish
whisper-signal.v1,agora-record.v1, or emergency activation artifacts. - Replace Monus signal weighting, Whisper publication, Arca orchestration, or emergency evaluation.
- Give connectors unrestricted shell, filesystem, camera, microphone, network, or memory access.
- Freeze one global ontology for external reality.
- Define a Sensorium-specific plugin API parallel to the existing middleware extension surface.
Out of Scope for v1¶
The following items are intentionally outside the v1 acceptance boundary:
- mandatory OS connector support on every node,
- invasive connector classes such as microphone, camera, health/wearable, location, private inbox, or browser-history readers,
- federated Sensorium read-through to a neighboring node,
- a Seed Directory-backed connector class registry,
- streaming transport as a requirement,
- an in-process plugin system for Sensorium connectors,
- runtime addition of OS allowlist entries without an operator-signed configuration change,
- and treating the v1 schemas as immutable forever; additive evolution remains possible through explicit versioning and compatibility rules.
Proposed Model¶
1. Layer Split¶
The v1 stack is:
External world
-> Connector middleware module
-> Standard middleware invoke / host capability envelopes
-> Sensorium admission and minimal normalization
-> Local Agora topic publication
-> Local Sensorium observation store/read model
-> Pull queries and push subscriptions for Monus / Arca / emergency evaluation / UI
-> Optional downstream protocol layer
The key boundary is between connector and Sensorium:
- the connector knows how to talk to arXiv, GitHub, a local microphone, an OS command allowlist, a wearable, a weather endpoint, or a local file watcher;
- Sensorium only knows that an admitted observation has a source, time, kind, confidence, sensitivity, provenance, and policy, with subject and summary present when they carry useful meaning.
- consumers never route to connectors directly; they route to
sensorium-core, which selects and invokes connector modules when active observation is needed.
2. Connector Responsibility¶
A connector is responsible for:
- concrete integration with one external source or source family,
- authentication to that source if needed,
- polling, streaming, scraping, shelling out, device reading, or API calling,
- transforming raw source output into a small observation candidate,
- attaching connector-local evidence references,
- classifying sensitivity before submission,
- applying source-specific pre-redaction before Sensorium admission when possible,
- surfacing health and last-observed status,
- registering itself through middleware init/report as
module_role: "sensorium-connector"with connector metadata.
Connector-side redaction is useful but never authoritative. It is a source adapter optimization: the connector may know that one source field is always unsafe to emit. Sensorium still owns admission-time redaction, quarantine, rejection, and the final policy visible to consumers.
A connector module report should declare at least:
module_role: "sensorium-connector",connector_class,connector_sensitivity_baseline,- offered
action_idvalues for action-oriented connectors, - offered
signal_kindvalues for source-specific observation connectors, - the connector-facing capability names the host may grant,
- and
connector_incidental_effects: a declared, operator-visible list of footprint effects that the connector cannot avoid while active, even when only an observation-lane grant is in use. Typical entries arecamera-indicator-led,bluetooth-presence-beacon,network-probe-traffic,disk-access-timestamp-update, andradio-emission. This field makes the ontological preamble concrete: it is the connector's honest declaration that contact is not free. The host UI surfaces these effects at grant time, and admission audit records retain them for after-the-fact review.
The role marker is for discovery and routing. Capability names remain the unit of grant and authorization. Incidental-effect declarations are neither a grant nor a capability — they are a transparency contract that binds the host UI and the audit trail.
Connectors MAY be specialized, for example:
sensorium.github.releases,sensorium.arxiv.search,sensorium.weather.local,sensorium.microphone.alarm,sensorium.wearable.heart-rate.
Connectors MAY also be generalized when the operator can define a safe bounded dictionary of actions. The primary example is an OS connector.
3. Connector I/O Lanes¶
The Unix stdin / stdout / stderr split is a useful inspiration for
connector design, but the Sensorium contract should model logical lanes, not
process streams. A connector may run as a process, local HTTP service, in-process
adapter, queue consumer, or future streaming worker. The common contract is the
shape of exchange, not the transport mechanics.
These lanes are carried by the standard middleware peer/local-input envelopes and host-capability calls. They are not a new Sensorium transport.
A reactive connector SHOULD expose up to four logical lanes:
- Directive lane — host or Sensorium instructions to the connector. This is
the
stdin-inspired lane: action id, filters, query, observation window, timeout, byte budget, redaction profile, and policy constraints. - Observation lane — normal structured output. This is the
stdout-inspired lane: JSON observations, summaries, timelines, or other data that can be represented as text-shaped JSON. - Diagnostic lane — structured errors, warnings, partial-failure notices,
retry hints, and degradation reports. This is the
stderr-inspired lane, but it remains JSON and is not mixed with observations. - Artifact lane — optional raw or binary outputs, such as audio snippets, images, raw telemetry, HTML captures, dumps, or source payloads. These SHOULD be returned by reference rather than inline when they are large, sensitive, or not naturally JSON-shaped.
This split keeps three facts separate:
- what the connector was asked to do,
- what it observed about the world,
- and what happened inside the connector while trying to observe it.
For example:
{
"schema": "sensorium-connector-directive.v1",
"invocation/id": "inv:local:01J...",
"connector/id": "sensorium.os.action",
"action/id": "git_recent_commits",
"params": {
"limit": 20
},
"budget": {
"timeout_ms": 5000,
"max_output_bytes": 65536
},
"policy": {
"allow_artifacts": false,
"redaction_profile": "default"
}
}
A connector response may contain observations, diagnostics, artifacts, or a combination of those lanes:
{
"schema": "sensorium-connector-result.v1",
"invocation/id": "inv:local:01J...",
"status": "partial",
"observations": [
{
"schema": "sensorium-observation.v1",
"schema/v": 1,
"connector/id": "sensorium.github.releases",
"signal/kind": "release",
"subject/kind": "github-repository",
"subject/id": "speakleash/bielik",
"summary": {
"lang": "en",
"text": "A new Bielik release candidate was observed."
}
}
],
"diagnostics": [
{
"level": "warning",
"kind": "rate-limit-near",
"message": "GitHub API budget is close to exhaustion.",
"retry_after_sec": 900
}
],
"artifacts": [
{
"artifact/ref": "orbiplex:blob:sha256:...",
"media_type": "application/json",
"role": "raw-source-response",
"sensitivity/class": "public"
}
]
}
The lane-level invariants are:
- diagnostics are not observations,
- raw artifacts are evidence or source material, not normalized observations by default,
- every directive should carry an invocation id, timeout, and output budget,
- every directive action must be finite and timeout-governed; Sensorium connectors, including the OS connector, must not use directive execution to host long-lived daemons, watchers, subscriptions, model workers, or open-ended streams. Long-running behavior belongs in a separately supervised middleware module or connector; a directive may only invoke a bounded command that samples, checks, transforms, or triggers one action and then returns. Asynchrony, threads, watchers, queues, caches, and streaming are allowed behind the invoked script boundary, but the directive boundary must linearize them into one bounded invocation result,
- a directive that needs longer work may use the explicit deferred-operation extension from Proposal 055: the initial invocation still returns quickly with an operation handle, while the host owns retry cadence, expiry, cancellation, and final timeout policy. Deferred mode is not the default sync contract,
- every artifact should carry media type, sensitivity class, and preferably a content-addressed reference,
- partial success is valid: observations may coexist with diagnostics,
- a connector may emit an operational observation that a submitted action result
was invalid, but that observation must be a normal admitted world/control fact
(for example
ai.orbiplex.sensorium/action-invalid), not a replacement for the structured diagnostic or the directive outcome, - the directive lane never bypasses host-granted capability policy.
The v1 lane mapping is:
- directive lane:
local-input-invoke.v1orpeer-message-invoke.v1dispatched bysensorium-coreto a connector module, - observation lane:
sensorium.observe.submithost capability call from the connector tosensorium-core, - diagnostic lane: a structured field in the same invoke or submit response, never mixed into the observation list,
- artifact lane: reference to a host-owned artifact store entry, such as the
existing module artifact write surface (
POST /v1/module/artifact/write).
The lane mapping covers connector -> sensorium-core communication. It does not
define consumer fan-out. Consumer fan-out is handled after admission through
pull queries and local Agora topic subscriptions.
4. Generalized OS Connector¶
An OS connector MAY expose a whitelist such as:
{
"actions": {
"git_recent_commits": {
"argv": ["git", "log", "--oneline", "-n", "{limit}"],
"cwd_policy": "configured-repository",
"params": {
"limit": { "type": "integer", "minimum": 1, "maximum": 50 }
}
},
"disk_free": {
"argv": ["df", "-h", "{path}"],
"params": {
"path": { "type": "string", "enum": ["/", "/var", "/tmp"] }
}
}
}
}
The connector MUST treat this as action -> argv, not as raw arbitrary shell
strings. A safe OS connector should enforce:
- an explicit action allowlist,
- typed parameter validation,
- no shell interpolation by default,
- timeout,
- output byte cap,
- stderr capture policy,
- working-directory allowlist,
- environment allowlist,
- redaction rules,
- per-consumer capability grants,
- and audit events for every invocation.
No action may be added, removed, or changed at runtime without an operator-signed configuration change. A distribution may ship a reference OS connector, but it remains an optional concrete connector to the local operating system, not a built-in Sensorium privilege and not a requirement for Sensorium MVP.
This gives operators a practical adapter to local reality without turning Sensorium into ambient shell access.
Directive Invocation Contract¶
Consumers such as Arca, Dator, or local agents that need to use a Sensorium
connector for intentional action do not address connectors directly and do
not hold connector-level capabilities. They address sensorium-core through
one mediated capability, by action_id, with typed parameters.
Invocation path¶
consumer (Arca / Dator / agent)
│ capability: sensorium.directive.invoke
▼
sensorium-core
│ grant check, parameter schema validation, allowlist resolution
│ (local-input-invoke or peer-message-invoke)
▼
target connector (e.g. sensorium.connector.os,
sensorium.connector.git)
│ typed execution
▼
sensorium-core
│ emits audit outcome; optionally emits world-fact observation
▼
result to caller, carrying outcome/id and observation/ids
sensorium-core mediates every directive. Consumers never talk to a
specific connector module and never discover connector_id values. This
keeps policy enforcement, audit, and outcome/observation linkage in one place, and
lets the operator replace a connector implementation without touching any
consumer.
Addressing model¶
action_idis a flat, globally enumerable string managed by the operator in the signed allowlist configuration (dotted notation recommended:os.process.spawn-read-only,git.push,bluetooth.beacon.emit),connector_idis implementation metadata held bysensorium-coreand never exposed to consumers,- the allowlist entry binds an
action_idto aconnector_id, a typed parameter schema, and execution limits, - consumers discover available actions through
sensorium.directive.list, which returns only those the caller may invoke together with their parameter schemas (a HATEOAS-shaped discovery surface).
Consumer-side capability grants are scoped against action_id patterns
(for example sensorium.directive.invoke scoped to os.process.* for an Arca
workflow run), not against connector_id.
Directive envelope and result¶
The directive envelope, the result envelope returned to the caller, and the audit-only outcome record are defined as v1 schemas:
doc/schemas/sensorium-directive.v1.schema.jsondoc/schemas/sensorium-directive-result.v1.schema.jsondoc/schemas/sensorium-directive-outcome.v1.schema.json
These files carry "x-dia-status": "draft" because proposal 045 is still a
draft proposal, but they are no longer candidate contracts. They are the
implementation-facing v1 schemas for Sensorium directive invocation, caller
results, and audit-only outcomes.
Request envelope (sensorium-directive.v1), semantic summary:
schema— tagsensorium-directive.v1.schema/v— schema version, currently1.directive/id— opaque identifier assigned by the issuer (ULID recommended); threads the request to its outcome and any observations.directive/issued_at— RFC 3339 timestamp.issuer— identity of the invoking party.participant/did:keyis the sovereign participant axis;module_ididentifies the local module when applicable;node_idMAY identify the local node context. At least one ofparticipant/did:keyormodule_idis required.issuer_delegation— optional proposal-032DelegationProoffor proxy-key signing. In v1, sub-delegation chains are not supported;max_chain_depth, when present, MUST be0. Ifissuer_delegationis present, the directive signature MUST be produced byissuer_delegation.proxy_key, andissuer_delegation.principal_keyMUST derive toissuer.participant/did:key. Verifiers MUST normalizeissuer.participant/did:keyto theparticipant:did:key:...canonical form before comparing it to the participant derived fromissuer_delegation.principal_key.signature— optional Ed25519 signature over the canonical directive payload. It is required by schema whenissuer_delegationis present.idempotency/key— optional caller-provided key used with issuer andaction_idto make async/retryable directive retries safe.action_id— public, operator-allowlisted action identifier (dotted notation, e.g.os.process.spawn-read-only,git.push). Consumers address actions byaction_id, never byconnector_id.parameters— typed peraction_id, validated bysensorium-coreagainst the allowlist entry's parameter schema before dispatch. No raw command strings, script bodies, or SQL.evidence/inputs— optional artifact references using the minimal artifact-lane contract below.timing.timeout_msandtiming.mode— bounded duration.timing.timeout_msis the directive-level deadline enforced bysensorium-core: it covers the interval from directive admission through connector dispatch and execution to final outcome recording. The operator-signed action allowlist MUST definedefault_timeout_msandmax_timeout_ms;sensorium-coreMUST reject or clamp requests exceedingmax_timeout_ms. On expiry, exactly onesensorium-directive-outcome.v1is written withoutcome/status: "timed_out"andpolicy/decision.decision: "timeout".deadline_at— optional absolute RFC 3339 deadline propagated from the caller's enclosing workflow or service dispatch. When present,sensorium-coreand the connector enforce the smaller of the local timeout/max-timeout and the remaining time untildeadline_at. This prevents asymmetric traces where the role module, Sensorium outcome, and connector execution report different timeout boundaries for the same directive.syncreturns final status;asyncreturnsstatus: "admitted"and the caller reconciles completion through the audit outcome and optional linked observations filtered bycorrelation/id.correlation/id— optional opaque thread through a higher-level plan (Arca workflow run step, Dator task dispatch, agent plan).
Result envelope (sensorium-directive-result.v1), semantic summary:
schema— tagsensorium-directive-result.v1.schema/v— schema version, currently1.directive/id— echo of the request.correlation/id— optional echo of the request correlation id.status—admitted|completed|failed|timed_out|rejected.result— typed peraction_idagainst the allowlist entry's result schema; absent or null forrejectedand asyncadmitted.outcome/id— always present; identifier of thesensorium-directive-outcome.v1audit record (see Loop closure invariant below). Outcome records are audit-only and never reach Agora topics.observation/ids— always present; empty list means no world-fact observation has been produced, one element is the ordinary case, many elements represent multi-emit directives.artifacts— references to produced artifacts.diagnostics— optional connector hints (info/warn/error).
Outcome record (sensorium-directive-outcome.v1), semantic summary:
schema— tagsensorium-directive-outcome.v1.schema/v— schema version, currently1.outcome/id— audit outcome identifier; exactly one per directive.directive/id— id of the originating directive.outcome/status—admitted|completed|failed|timed_out|rejected.outcome/recorded_at— time at whichsensorium-corewrote the audit record.directive/signature_digest— optionalsha256:...digest of the originating directive signature bytes, preserving audit linkage without duplicating the full signature in every outcome record.action_id,issuer,connector/id, andconnector/kind— dispatch context; connector fields may be absent when rejection happened before connector selection.connector/dispatched_at— optional time at whichsensorium-coredispatched the directive to the selected connector.connector/responded_at— optional time at whichsensorium-corereceived the terminal connector response; absent when timeout happens before a response arrives.started_at,completed_at, andduration_ms— optional connector or execution telemetry. These are not source/instrument event times; facts discovered in the world belong in linkedsensorium-observation.v1records.policy/decision— compact reason/retryability summary;decisionis one ofadmit,reject,timeout, orfail.retry/attempts— number of execution attempts made for this outcome.issuer_delegation— optional proof copied from the originating directive when proxy-key signing was used.audit/store— optional host-owned audit sink reference; outcomes are retrieved through restrictedsensorium.audit.*capabilities.observation/ids— zero or more linked observations produced by the directive.artifactsanddiagnostics— references and structured diagnostic hints, never a replacement for the audit status.
Key modeling decisions:
- Parameters are typed per
action_id, validated bysensorium-coreagainst the schema held in the allowlist entry before the connector is invoked. No field is a raw command string or a free-form script body. An action likeos.process.spawn-read-onlytakes structured arguments; there is nocommand: "rsync -avz ..."escape hatch. evidence/inputspasses large inputs by artifact reference rather than inline, aligning with the artifact lane.- Issuer delegation follows proposal 032.
issuer_delegationis an inlineDelegationProofand is excluded from the surrounding directive signature payload. The proof carries its ownprincipal_signature; the surrounding directive signature is verified withproxy_key. Sensorium treats the proof as open-world data for forward compatibility, but verifies only the proposal-032 compact proof payload fields. correlation/idthreads directives through Arca workflow runs, Dator task dispatches, or agent plans, so the audit trail preserves causal chains.- Sync vs async is a
timing.modeflag, not a separate endpoint.asyncreturnsstatus: "admitted"immediately together with anoutcome/id. Completion is recorded in the host-owned audit trail; if the directive also produces a world-fact observation, consumers with suitable grants may observe the linkedsensorium-observation.v1throughlocal/sensorium/observations/{signal-kind}filtered bycorrelation/id. outcome/idis mandatory;observation/idsis always a list. Every directive produces exactly onesensorium-directive-outcome.v1audit record (see Loop closure invariant below); only directives whose execution produces a fact about the world also produce one or more linkedsensorium-observation.v1records. Rejected-at-admission directives carryoutcome/idand an emptyobservation/idslist; completed directives that touch the world carry one or more observation ids.
Connector-side declaration¶
Connectors declare invocable actions in their module report, alongside observations they emit without prompting:
{
"module_role": "sensorium-connector",
"connector_class": "OS",
"connector_sensitivity_baseline": "high",
"connector_incidental_effects": [
"disk-access-timestamp-update",
"network-emission"
],
"actions": [
{
"action_id": "os.process.spawn-read-only",
"parameters_schema": { "$ref": "schemas/os.process.spawn-read-only.params.v1.json" },
"result_schema": { "$ref": "schemas/os.process.spawn-read-only.result.v1.json" },
"emits_observation_kind": "git/fetch-result",
"default_timeout_ms": 30000,
"max_timeout_ms": 300000,
"execution_mode_support": "sync-only",
"deferred_profile": {
"preferred_retry_after_seconds": 15,
"preferred_max_ttl_seconds": 1800
},
"requires_grant": "sensorium.directive.invoke:os.process.spawn-read-only",
"artifact_outputs": ["stdout", "stderr"],
"reentrancy": "parallel"
}
],
"observations": [
{
"signal_kind": "filesystem/change",
"signal_family": "filesystem/change",
"emits_without_directive": true
}
]
}
The actions block is a proposal from the connector. It does not
become invocable until the operator promotes matching entries into the
signed allowlist; the module report alone grants nothing. This keeps the
allowlist the single authority over what the node may actually do to the
world, and keeps connector authors honest about what they are offering.
execution_mode_support is an operator-approved action property, not a caller
preference. The safe default is sync-only; timing.mode = "async" is rejected
before dispatch unless the signed allowlist entry says either or async-only.
deferred_profile carries connector/action hints only. The host still clamps
retry cadence and maximum lifetime through its deferred-operation policy.
Loop closure invariant¶
Every directive — whether it completes, fails, times out, or is rejected
at admission — results in exactly one sensorium-directive-outcome.v1
record written to the audit trail, with matching correlation/id and an
appropriate outcome/status (completed, failed, timed_out,
rejected). sensorium-directive-outcome.v1 records are not
published to local Agora topics and are not reachable through
consumer-facing subscription surfaces; they are reachable only through
host-owned audit capabilities.
Directives whose execution produces one or more facts about the world
additionally emit sensorium-observation.v1 records, linked to the
outcome by correlation/id and by mutual directive/id, outcome/id,
and observation/ids references. Only sensorium-observation.v1
reaches local/sensorium/observations/{signal-kind} topics.
The directive result envelope returned to the caller always carries
outcome/id and observation/ids; the latter is empty unless the
directive produced world-fact observations. This is how the
enactive loop closes without conflating ontological categories: the
act itself is recorded as an audit outcome, and the consequence in the
world — when there is one — is recorded as an observation.
Artifact-lane minimal contract¶
Sensorium v1 does not define a full artifact store. It only defines the reference shape that directive, result, outcome, and observation envelopes may use when a value is too large, binary, or policy-sensitive to embed inline.
The minimal artifact reference is:
{
"artifact/id": "sha256:...",
"role": "stdout",
"media_type": "application/json",
"size_bytes": 1234
}
Rules:
artifact/idis eithersha256:...ormemarium-blob:....roleis one ofstdout,stderr,produced-file, orraw-capture.media_typeandsize_bytesare optional hints.- The artifact content is stored and governed outside the envelope; the envelope only carries an auditable reference.
Hard rails¶
- Consumers MUST NOT select
connector_id; onlyaction_idis a public handle. action_identries MUST NOT be added, removed, or changed at runtime without an operator-signed allowlist update.- A single
action_idMUST NOT accept a raw shell string, raw script body, or raw SQL as a parameter. If a shell-runner shape is genuinely required, the action takes ascript_idreferring to a signed, stored script in the host-owned module store. - Every directive, regardless of outcome, MUST emit exactly one
sensorium-directive-outcome.v1audit record. No silent execution. sensorium-directive-outcome.v1MUST NOT be published to the local Agora bus. Outcome records are reachable only through host-owned audit capabilities.
5. Sensorium Responsibility¶
Sensorium is responsible for:
- admitting or rejecting connector-submitted observation candidates,
- assigning stable local observation identifiers,
- enforcing local policy gates,
- normalizing into the minimal observation contract,
- storing recent observations or forwarding them to Memarium under policy,
- deriving read models such as timelines, topic summaries, and connector status,
- exposing host-granted query and summary capabilities,
- publishing admitted observations to local Agora topics under policy,
- emitting audit records for admission, rejection, query, and redaction.
Sensorium SHOULD NOT embed connector-specific parsers in its core. If a source requires special parsing, that logic belongs in the connector.
Connector discovery and routing¶
sensorium-core discovers connectors through middleware role registration. It
does not own a connector plugin registry and does not load connector code.
The daemon remains the source of active module reports. sensorium-core asks the
host for modules whose report declares module_role: "sensorium-connector" and
then routes directives to those modules through the same invoke envelopes used by
other supervised middleware flows.
Consumers such as Monus, Arca, emergency evaluation, and UI code MUST NOT bypass
sensorium-core to invoke connectors directly. Their stable dependency is the
Sensorium capability surface, not the connector fleet.
Mediated admission and local bus distribution¶
The left side of Sensorium is mediated and ordered:
connector -> sensorium.observe.submit -> validate -> redact -> policy-gate
-> admit/quarantine/reject -> store -> publish
Those phases may short-circuit. Rejection and quarantine are valid results and must produce diagnostics and audit records.
The right side is a local event bus:
sensorium-core -> Agora local topic: local/sensorium/observations/{signal-kind}
-> Monus / Arca / emergency-eval / UI / future consumers
After admission, sensorium-core SHOULD republish the normalized observation on
a local Agora topic. The recommended default topic shape is:
local/sensorium/observations/{signal-kind}
The local/ prefix follows proposal 046 and is part of the contract:
Sensorium observation topics are node-local bus topics and MUST NOT be
federated by default.
For example:
local/sensorium/observations/github-release
local/sensorium/observations/arxiv-paper
local/sensorium/observations/feed-item
Topic ACL, retention, and subscription policy MUST derive from the admitted
observation's admission.consumer_scopes, sensitivity class, and connector
class. Public release-feed observations and health/wearable observations should
not share the same retention or ACL merely because both are Sensorium records.
Local Sensorium topics MUST NOT be federated by default; cross-node Sensorium
read-through or replication remains v2/open work.
One shared local/sensorium/observations topic with subscriber-side filtering remains
possible, but is not the recommended default because retention and policy differ
too much between connector classes.
Local Agora loopback cost¶
Using Agora as the local Sensorium bus does not currently mean an in-process shortcut. In the current Node shape, Agora v1 is a separate supervised process and Sensorium is another supervised component. A single admitted observation may therefore cross loopback more than once:
sensorium-core process
-> HTTP loopback to daemon host capability bridge
-> HTTP loopback to agora-service
-> agora-core inside agora-service
-> relay backend
If signing is performed through a separate host capability, the full path may also include a signing round-trip before ingest. This is acceptable for the observation lane because an admitted observation is already a durable, policy-gated fact that may pay for signing, canonicalization, persistence, and audit.
The optimization rule is:
- do not fight loopback for low-frequency observations,
- do not send diagnostics through Agora,
- do not send raw high-frequency samples through Agora,
- batch observation ingest before considering transport changes,
- consider Unix domain sockets or another local transport optimization only as a separate proposal after measurements show the need,
- do not embed
agora-coreinside Sensorium merely to avoid loopback.
Embedding Agora inside Sensorium would collapse the boundary this proposal is trying to preserve. Sensorium should not need to know Agora signing domains, backend details, relay internals, or storage mechanics. It publishes admitted facts through the host-owned capability surface and lets the host route to the current Agora implementation.
Redaction authority¶
Sensorium is authoritative for the final admitted observation. The connector may submit a pre-redacted candidate or a redaction hint, but Sensorium decides:
- whether the candidate can be admitted as-is,
- whether it must be transformed into a redacted observation,
- whether it must be quarantined for operator or policy review,
- or whether it must be rejected with diagnostics.
If a connector cannot redact a candidate and Sensorium has no policy for the candidate's sensitivity class, Sensorium MUST fail closed. The default outcome is quarantine when the payload can be safely retained locally without consumer access; otherwise the outcome is rejection with a diagnostic record. Quarantined observations are not visible to Monus, Arca, Whisper, emergency evaluation, or other consumers until a policy grants release.
6. Minimal Observation Contract¶
The initial contract is intentionally boring. The sensorium-observation.v1
schema lives in:
doc/schemas/sensorium-observation.v1.schema.json
It carries "x-dia-status": "draft" because proposal 045 remains draft, but
the schema itself is the v1 implementation contract for admitted local
observations.
Example shape:
{
"schema": "sensorium-observation.v1",
"schema/v": 1,
"observation/id": "obs:local:01J...",
"invocation/id": "inv:local:01J...",
"directive/id": "drv_01JGABCD...",
"outcome/id": "dout_01JG...",
"correlation/id": "arca-workflow-run-...-step-3",
"connector/id": "sensorium.github.releases",
"connector/kind": "public-network-reader",
"observed/at": "2026-04-18T10:00:00Z",
"connector/submitted_at": "2026-04-18T10:00:01Z",
"ingested/at": "2026-04-18T10:00:02Z",
"signal/kind": "release",
"subject/kind": "github-repository",
"subject/id": "speakleash/bielik",
"summary": {
"lang": "en",
"text": "A new Bielik release candidate was observed."
},
"confidence": {
"class": "high",
"rationale": "Observed from the upstream repository release feed."
},
"freshness": {
"ttl_sec": 86400
},
"sensitivity": {
"class": "public",
"redaction": "none"
},
"source/ref": {
"kind": "url",
"value": "https://github.com/speakleash/bielik/releases"
},
"evidence/refs": [],
"policy/hints": {
"shareable": false,
"memarium_admit_hint": true,
"requested_consumer_scopes": ["monus.read", "arca.read"]
},
"admission": {
"status": "admitted",
"redaction_status": "not-needed",
"memarium_admit": true,
"consumer_scopes": ["monus.read", "arca.read"],
"store": {
"record/id": "module-store:sensorium:obs:local:01J...",
"ttl_sec": 86400
},
"publish_topics": ["local/sensorium/observations/release"]
}
}
The shape is not meant to be a universal ontology. It is a common local envelope for observations. Domain-specific payloads MAY be attached later, but consumers should be able to make basic policy decisions from the envelope alone.
summary, subject/kind, and subject/id are optional in the v1 schema.
Text summaries are useful for human-facing facts such as releases or feed items,
but numeric samples and high-frequency aggregates should not be forced to invent
prose. Subjectless observations MAY omit subject fields; node-self measurements
SHOULD use a stable subject/kind: "self" convention rather than blank strings.
Observation timing has three distinct clocks:
observed/atis the source or instrument event time: when the thing happened in the world, according to the best available source clock.connector/submitted_atis optional connector telemetry: when the connector emitted or submitted the candidate observation tosensorium-core.ingested/atis Sensorium admission time: whensensorium-coreaccepted and wrote the admitted observation record.
This separation lets consumers reason about source lag
(connector/submitted_at - observed/at) separately from Sensorium admission lag
(ingested/at - connector/submitted_at). Connectors that cannot provide a
meaningful source/instrument timestamp SHOULD set observed/at to the time they
observed the event locally and MAY omit connector/submitted_at.
signal/kind and source/ref.kind use the lowercase slash-separated token
convention from proposal 046, extended with optional reverse-DNS vendor
prefixes (see Signal naming rule below). When an admitted observation is
published to Agora, each admission.publish_topics entry MUST match:
local/sensorium/observations/{signal-kind}
The normative JSON Schema pattern is:
^local/sensorium/observations/[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*(/[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*)*$
Signal naming rule¶
signal/kind is the authoritative, collision-resistant identifier.
Each /-separated segment is a dotted chain of lowercase tokens, which
allows connectors to carry reverse-DNS vendor prefixes when collision with
other providers is possible:
- bare short names (
release,github-release,filesystem/change) are legal and live in the community-common namespace; operators accept collision risk, - dotted prefixes (
com.apple.ios.accelerometer/x-axis,ai.orbiplex.workflow.completed) give vendor-owned, collision-free namespacing under RFC 1035-style domain ownership semantics, - Orbiplex-owned kinds SHOULD use the
ai.orbiplex.*prefix per proposal 046.
signal/family is an optional, connector-declared twin key that carries
the vendor-independent family name alongside the authoritative
signal/kind. It MUST NOT contain dots; the no-dot constraint is the
formal distinction between the community-common family namespace and the
dotted vendor namespace. Examples:
signal/kind |
signal/family |
|---|---|
release |
release |
com.apple.ios.accelerometer/x-axis |
accelerometer/x-axis |
org.otherdao.workflow.completed |
workflow/completed |
ai.orbiplex.workflow.completed |
workflow/completed |
The signal/family value is the connector's honest declaration of what
family of signal it is emitting. sensorium-core does not derive family
from signal/kind; consumers querying across providers (e.g. "any
accelerometer") use sensorium.observe.query filtered by
signal/family. Topic publication remains on signal/kind only; a
dedicated family-axis topic space is not introduced in v1 (a consumer
needing bus-level fan-in across vendors can subscribe broadly and filter
on the envelope).
Connectors declare both values in their module report alongside each emitted observation kind, so the operator sees the vendor-vs-family split at grant time:
"observations": [
{
"signal_kind": "com.apple.ios.accelerometer/x-axis",
"signal_family": "accelerometer/x-axis",
"emits_without_directive": true
}
]
Because the v1 schema describes the admitted record, not the pre-admission
connector submission, admission.store and admission.publish_topics are
required. admission.store carries the Node-owned module-store reference and
TTL metadata; admission.publish_topics carries the local Agora topic or topics
on which the observation was made available under ACL.
confidence.class in this proposal is Sensorium-local and intentionally not the
same contract as the emergency C0-C4 credibility scale. A promotion rule may
map Sensorium confidence into emergency credibility when creating an
emergency-signal.v1, but that mapping belongs at the emergency boundary rather
than in the base observation envelope.
policy/hints are connector-supplied requests or suggestions. Hint fields should
be visibly named as hints, for example memarium_admit_hint. admission is
the Sensorium-authored decision and is the only policy section that consumers may
treat as authoritative.
Reactive observations SHOULD carry invocation/id, directive/id,
outcome/id, and correlation/id so the
trace connects directive, connector execution, diagnostics, artifacts, and final
admission. Autonomous observations MAY instead carry a schedule, subscription, or
source-event reference once those shapes exist.
7. Host Capability and Subscription Surface¶
The first useful surface is split by direction.
Submit-side capabilities¶
Connector -> sensorium-core:
sensorium.observe.submit
sensorium.connector.*
sensorium.observe.submit admits a connector-produced observation candidate.
sensorium.connector.* capability names are connector-facing grant units such
as sensorium.connector.github.releases or sensorium.connector.os.
Internal dispatch (sensorium-core -> connector)¶
These are not consumer-facing and are not granted to modules outside
sensorium-core. They are the internal transport by which
sensorium-core reaches a connector after a consumer directive has been
admitted through sensorium.directive.invoke (see Directive Invocation
Contract above):
sensorium.connector.list (internal: connector inventory + declared classes)
sensorium.connector.status (internal: health, last success/error, freshness)
sensorium.connector.invoke (internal: dispatch an admitted directive to a connector)
sensorium.connector.invoke MUST NOT be granted to consumer modules.
Consumers always use sensorium.directive.invoke, which internally
resolves the action_id through the signed allowlist and performs the
actual connector-facing dispatch. This preserves single-point admission,
connector_id hiding, automatic outcome emission, and optional observation
linkage on loop closure.
Consumer-side directive capabilities¶
Consumer -> sensorium-core:
sensorium.directive.list
sensorium.directive.invoke
Consumer-side observation pull capabilities¶
Consumer -> sensorium-core:
sensorium.observe.query
sensorium.observation.get
sensorium.topic.summary
sensorium.health
For a supervised HTTP/JSON module, these may be exposed as local host capability requests rather than public network APIs. The Node grants them per module and per operator policy.
Suggested behavior:
sensorium.directive.invokesubmits asensorium-directive.v1with a publicaction_idand typed parameters;sensorium-corevalidates, dispatches, and returns the directive outcome together with linkedobservation/ids(empty when the directive produced no world-fact observations) (see Directive Invocation Contract).sensorium.directive.listreturns theaction_idvalues the caller is authorized to invoke, each with its parameter schema — a HATEOAS-shaped discovery surface.sensorium.observe.submitadmits a connector-produced observation candidate (connector ->sensorium-core, submit-side).sensorium.observe.queryreturns bounded observation records by time, subject, signal kind, connector, or sensitivity class.sensorium.observation.getreturns one observation by id if the caller has scope.sensorium.topic.summaryreturns a compact local summary for a topic or subject class.sensorium.healthreports module readiness and degraded dependencies.
Subject timelines are a query profile, not a separate v1 capability, unless a real consumer later needs a distinct optimized surface.
Consumer-side push subscriptions¶
Consumer -> local Agora:
subscribe local/sensorium/observations/{signal-kind}
After admission, consumers may subscribe to local Agora topics such as
local/sensorium/observations/github-release or
local/sensorium/observations/feed-item.
This uses the existing Agora topic-addressed pub/sub substrate and SSE
subscription path; it does not introduce a new bus engine.
The subscription path is still policy-gated. Consumers see only topics and records allowed by local ACL, admitted consumer scopes, and sensitivity policy.
8. Relationship to Monus¶
Monus consumes Sensorium, but Sensorium does not replace Monus.
- Sensorium observes and normalizes local reality-facing signals.
- Monus weighs admitted local signals over time.
- Monus prepares candidate concern drafts, recommendations, or do-not-publish decisions.
- Whisper publication remains a separate Node-owned and policy-gated path.
If Sensorium materially shaped a Whisper-bound concern through Monus, downstream
provenance should preserve monus-sensorium-derived.
9. Relationship to Emergency Evaluation¶
Emergency evaluation may consume Sensorium observations, but Sensorium does not decide emergency activation.
emergency-signal.v1 already sits above raw connector telemetry and below
activation decisions. Sensorium may supply source observations that an emergency
pipeline transforms into emergency-signal.v1, but trigger classification,
corroboration thresholds, TC5 degraded-trust behavior, activation, TTL, and
post-crisis review remain emergency-domain responsibilities.
10. Relationship to Arca¶
Arca may consume Sensorium summaries as workflow inputs. For example, story 009 uses a research node with connectors to arXiv, GitHub repositories, mailing lists, and news feeds.
The healthy boundary is:
- Sensorium provides observations and summaries,
- Arca orchestrates workflow intent and task progression,
- external artifact movement remains in the chosen data plane, such as git, INAC, or another explicitly selected substrate.
Arca should not learn how to poll every external source itself when a local Sensorium capability can provide a bounded observation surface.
Story 009 can be the first full non-emergency Sensorium consumer because its research step can use observation records produced by an allowlisted OS connector. The OS connector opens the practical world first: network reads, git inspection, feed fetches, and similar operations can initially be modeled as operator-signed actions without introducing a separate connector class for each source.
The story remains stratified: Phase 1 research consumes admitted Sensorium facts
through sensorium.observe.query by subject/kind, subject/id,
signal/kind, and freshness; commit/push stays on the Arca task path. That Arca
task may later use sensorium.directive.invoke against the OS connector to run
the actual git commit or git push action under the signed allowlist.
11. Relationship to Memarium¶
Sensorium observations may be ephemeral or durable.
Memarium is the organ of durable memory and knowledge. Sensorium may forward selected observations into Memarium when policy allows durability. Sensorium should not assume that every observation deserves permanent storage.
A useful default split is:
- Sensorium keeps short-lived operational observations and connector state,
- Memarium preserves admitted observations that should not disappear,
- audit traces record why an observation was admitted, redacted, rejected, expired, or promoted.
12. Relationship to Whisper¶
Sensorium should not publish whispers.
Sensorium-originated signals can become part of a local reasoning chain:
Sensorium observation -> Monus weighting -> candidate concern draft
-> Node/Whisper review -> optional whisper-signal.v1 publication
This preserves the difference between:
- raw local observation,
- local interpretation,
- social-signal publication,
- and distributed correlation.
Acute personal emergencies should still prefer local help or emergency-assistance paths before Whisper. Whisper is for correlation-worthy distributed patterns, not the first response to likely cardiac arrest, fire, collapse, or comparable direct danger.
Policy and Safety¶
Sensorium is powerful because it touches reality. Its default safety posture must therefore be conservative:
- consent before invasive sources,
- data minimization by default,
- local-first processing,
- context separation between connectors and consumers,
- explicit capability grants,
- no ambient connector access to Node memory,
- no ambient consumer access to all observations,
- redaction before broader consumption,
- auditability for connector actions and observation reads,
- fail-closed behavior for high-sensitivity or high-risk connector classes.
Sensitive connector classes such as microphone, camera, health sensor, location, browser history, filesystem watcher, OS, and private inbox reader should require explicit operator policy and visible UI state.
Baseline connector class policy:
| Connector class | Sensitivity baseline | Default policy |
|---|---|---|
public-network-reader |
public |
admit locally with bounded TTL; no network publication |
feed-reader / mailing-list-reader |
public or community |
admit locally when source is public or explicitly configured |
OS |
operational-sensitive |
disabled by default; requires operator-visible grant screen, host-owned audit, and operator-signed action allowlist |
filesystem-watcher / private-inbox-reader |
private |
fail closed; explicit operator policy and redaction required |
microphone / camera / health-wearable / location |
sensitive-personal |
fail closed; visible UI state and explicit consent required |
Deployment Shape¶
The default architecture is:
Node host
-> sensorium-core middleware
-> sensorium-connector middleware modules
sensorium-core declares consumer-facing capabilities such as
sensorium.observe.query, sensorium.topic.summary,
sensorium.directive.invoke, and sensorium.directive.list. The
sensorium.connector.* family is reserved for internal
sensorium-core -> connector dispatch and is never granted to
consumer modules.
Each connector is a separate middleware module declaring
module_role: "sensorium-connector" and connector-facing capabilities such as
sensorium.connector.github.releases or sensorium.connector.os.
This keeps one extension mechanism:
- middleware init and module report for registration,
- host capability grants for authority,
- supervised lifecycle for readiness, shutdown, and restart,
- daemon traces for directive -> observation -> diagnostic accountability,
- independent language/runtime choice per connector.
The cost is process overhead. That cost buys isolation: a broken USB wearable
driver, hanging arXiv scraper, or camera crash should not take down
sensorium-core or unrelated connectors.
Deployment escape hatches¶
High-frequency sensor streams should not roundtrip every raw sample through HTTP. The connector should aggregate locally and submit only admitted observation candidates, for example "acoustic anomaly detected in a 4s window", with raw data kept behind artifact references when policy allows. Raw samples should not be published per-sample to local Agora topics; the connector boundary protects the bus from high-frequency flood.
Small devices such as SBCs may run only a few connectors. If measurements show
that a specific connector needs an in-process fast path, that fast path MAY be
implemented inside sensorium-core or as a tightly coupled sidecar, but it must
preserve the same directive/result/observation contracts and must not create a
general Sensorium plugin API.
Sub-10ms local reaction loops are also connector-specific exceptions. They may use a local fast path for detection, then emit normal Sensorium observations for admission, audit, and downstream consumption.
No-Sensorium Mode¶
Absence of Sensorium is a valid Node configuration. A Node without configured connectors remains a valid Node.
Consumers such as Monus or Arca MUST treat missing Sensorium capabilities as a degraded input condition, not as a runtime error. They may show reduced functionality, skip Sensorium-derived enrichment, or request operator configuration, but they must not fail the whole workflow merely because no Sensorium provider is attached.
Invariants¶
- Sensorium is local-first.
- Connectors adapt; Sensorium normalizes.
- Sensorium observations are not external network publications.
- Local Agora publication is a local bus mechanism and MUST NOT imply federation.
- Consumers receive only host-granted views.
- Connector-specific logic does not leak into every consumer.
- Raw sensitive data is not retained or shared unless policy explicitly allows it.
- Downstream artifacts preserve provenance when Sensorium materially contributed.
- Sensorium MUST NOT publish Whisper artifacts.
- Sensorium MUST NOT decide emergency activation.
- Sensorium MUST NOT own Arca workflow authority.
- Every Sensorium connector is a middleware module by default.
sensorium-coredoes not expose a connector plugin API.- Consumers MUST NOT bypass
sensorium-coreto reach connector modules. - Consumers reach observations either by pull capability queries or by push subscription to local Agora topics.
- Consumers MUST NOT become implicit next steps in a connector pipeline.
- OS is an optional connector class, not a built-in Sensorium privilege.
- No OS allowlist entry may be changed without an operator-signed configuration update.
- A single connector MAY declare and hold grants on multiple lanes;
observation-only grants still require explicit operator acknowledgement
of the connector's declared
connector_incidental_effects, and those effects are retained in the admission audit trail. - Sensorium observations are multi-consumer by construction; adding a consumer is a configuration change (grants, subscriptions), not a contract change in Sensorium or in any connector.
- Directive outcomes and world observations are separate record kinds.
sensorium-directive-outcome.v1records are audit-only and MUST NOT be published to local Agora topics. Onlysensorium-observation.v1records, which describe facts about the world, reach consumer subscription surfaces. - Absence of Sensorium is a valid Node configuration; consumers MUST degrade, not crash.
Resolved Design Decisions¶
The following decisions close the v1 design questions:
sensorium-observation.v1is promoted todoc/schemas/sensorium-observation.v1.schema.json. It is the implementation-facing v1 contract for admitted observations.- Admitted observations are stored in the Node-owned generic module store with TTL. Sensorium may keep read models and indexes, but the durable local substrate is host-owned.
- The first reference connector class is
OS: an allowlisted operating-system connector. It opens practical access to network tools, git, feeds, and local commands without defining one connector class per external source in Phase 1. - Local observation publication uses per-kind local Agora topics. The topic
shape is
local/sensorium/observations/{signal-kind}, following proposal - Sensorium observations are never published to public/federated topics by default. The v1 observation schema validates this topic shape.
- Story 009 Phase 1 uses Sensorium only for research facts, queried by
subject/kind,subject/id,signal/kind, and freshness. Commit/push remains on the Arca task path and may later invoke the OS connector to run allowlistedgit commitorgit pushactions. - Connector discovery uses both mechanisms:
module_role: "sensorium-connector"for discovery/routing andsensorium.connector.*capabilities for grants. - OS connector definitions and action allowlists are host-owned module store records. Simple public-network readers may begin with static configuration, but signed action definitions use host-owned storage.
- The minimal UI for OS is an operator-visible grant screen plus audit. Camera, microphone, location, and comparable invasive connectors require active UI status before they are enabled.
sensorium-directive.v1,sensorium-directive-result.v1, andsensorium-directive-outcome.v1are promoted to v1 schema files. They remain draft-status contracts because the implementation is not complete, but they are no longer candidate shapes.- Rejected directive outcomes are reachable only through host-owned audit capabilities. No restricted internal-only Agora topic is introduced until a concrete consumer, such as emergency evaluation, requires it.
- Cross-node Sensorium read-through is not part of v1. A future design may add a separate protocol and gateway for trusted-neighbor observation access.
- Connector classes do not need a catalog in v1. Local module reports and grants are enough until federated connector interchange becomes real.
- The first production directive path should exercise a small OS action before
any invasive or high-risk connector is attempted. The reference action id is
os.process.spawn-read-only, initially used for a constrainedgit fetch origin <branch>against a configured repository. It is intentionally useful but bounded: it may update local git metadata and perform network egress, so it testsconnector_incidental_effects, allowlist policy, directive outcome, artifact references, and optional observation loop closure without makinggit commitorgit pushpart of story-009 Phase 1.
Implementation Acceptance Checks¶
The schemas are promoted, but the implementation still needs to prove the contracts in a narrow end-to-end path:
sensorium-observation.v1: connector ->sensorium-coreadmission -> Node-owned module store with TTL -> local Agora topiclocal/sensorium/observations/{signal-kind}.sensorium-directive.v1: consumer ->sensorium.directive.invoke-> allowlist resolution byaction_id-> internalsensorium.connector.invoke.sensorium-directive-outcome.v1: exactly one audit-only outcome per directive, written to the Node-owned module store and reachable only through restrictedsensorium.audit.*capabilities.sensorium-directive-result.v1: caller response always carriesoutcome/idandobservation/ids; async callers can reconcile later through audit and observation links.- Artifact lane: produced stdout/stderr/files/raw captures are referenced by
artifact/idandrole, not embedded by default. - Delegation: if a directive carries
issuer_delegation, validation follows proposal 032 withmax_chain_depth: 0.
Implementation Sketch¶
Phase 0:
- create a supervised Sensorium module skeleton,
- define the module report extension for
module_role: "sensorium-connector"and connector metadata, - implement connector list/status and health,
- implement
sensorium.observe.submitwith in-memory admission, - implement no-sensorium degradation behavior for consumers,
- adopt the v1 schemas for
sensorium-observation.v1,sensorium-directive.v1,sensorium-directive-result.v1, andsensorium-directive-outcome.v1, - adopt proposal 046 topic naming for admitted observations:
local/sensorium/observations/{signal-kind}.
Phase 1:
- persist admitted observations in the Node-owned generic module store with TTL,
- expose bounded query, get, topic summary, and local Agora subscription paths,
- implement
sensorium.directive.invoke(consumer-facing) and the internalsensorium.connector.invokedispatch for the OS connector, - represent OS connector definitions and signed action allowlist entries as host-owned module store records,
- add audit events for submit/query/get,
- publish admitted observations to
local/sensorium/observations/{signal-kind}with local ACL and retention policy, - satisfy story-009 research input through observation queries over facts produced by observation-only connectors where possible,
- implement the reference OS action
os.process.spawn-read-onlyfor a boundedgit fetch origin <branch>path, withconnector_incidental_effectsincluding disk metadata changes and network egress.
Phase 2:
- add additional connector classes where they remove friction compared with OS actions (for example public-network reader, feed reader, local file watcher),
- add active UI status for invasive connector classes before camera, microphone, location, health wearable, or comparable sensors are enabled,
- allow Monus and Arca to consume Sensorium summaries through explicit host grants.
Phase 3:
- define promotion rules from Sensorium observation to
emergency-signal.v1, Monus concern draft, or Memarium durable fact. - add further production action ids only after the OS reference path has proven allowlist, audit, artifact, and loop-closure behavior.