Architecture¶
nous is built around a tick-driven engine that orchestrates subsystem
physics, estimator updates, and self-model claims. A FastMCP server
sits on top, exposing the engine to a controller. The deployment
target is a single VM.
Layers¶
- Engine (
src/nous/engine.py). Holds subsystems, estimators, and the self-model.tick()advances every subsystem bydt, feeds each estimator its observation, and refreshes the self-model. - Subsystems (
src/nous/subsystems/). Each subsystem implements theSubsystemProtocol (step / truth / sensor_obs). Curves and limits come from the hardware profile. - Estimators (
src/nous/estimators/). Each estimator implements theEstimatorProtocol (predict / update / state). The simplest filter that meets the model card's covariance bound is the right choice. - Self-model (
src/nous/self_model/). Aggregates estimator state into capability claims (endurance,thermal_headroom,inference_capacity) with calibrated quantiles. - State machine (
src/nous/state/). Explicit-table FSM over the mission posture; vocabularies forOperatorStateandCommsState. - Server (
src/nous/server.py). FastMCP server. Every tool call runs through the audited runner. - Runner + policy + audit (
src/nous/{runner,policy,audit}.py). Tier classification, admission, JSONL audit (output hashed only). - Interop adapters (
src/nous/interop/). CoT, SensorThings, MISB KLV, NMEA 0183, STANAG 4774/4778, MQTT. - OAuth issuer (
src/nous/auth/). File-backed; single-client by default.
Data flow¶
A tick:
profile -> Subsystem.step(dt) -> Subsystem.sensor_obs() -> Estimator.update()
Estimator.predict(dt) -> Estimate -> SelfModel.assess() -> Capability claims
A tool call:
Controller -> FastMCP -> runner.run(...)
classify -> admit/refuse
execute work coroutine
truncate output
AuditLogger.write(record)
return body
External surfaces¶
- MCP tools -- the seventeen-tool surface is documented in tool-reference.md. The development line has the full L1 read surface (one read tool per subsystem plus estimator summary); mutating tools (scenario load / inject, comms send, state transition) are queued for BL-014 and BL-022.
- OAuth issuer -- file-backed, single-client by default. The
Caddyfile template gates
/authorizeand/.well-known/oauth-*on the operator's CIDR plus the Anthropic ranges. - Audit JSONL -- append-only at
$NOUS_HOME/audit.jsonl. Output bodies are SHA-256 hashed, never written. - Interop adapters -- documented in
docs/conformance/.
Boundaries¶
What nous is not:
- Not a real device. Outputs that look like operational telemetry (CoT, MQTT, MISB KLV) are simulated.
- Not a learned self-model. The self-model is parametric and reviewable.
- Not a multi-operator system. The v0.1 simulation is single-operator.
- Not a mesh / DTN stack. Comms are point-to-point.
See LIMITATIONS.md for the full list.
Where to extend¶
- A new subsystem: add a module under
src/nous/subsystems/, wire it intoEngine.__init__, ship a model card underdocs/model-cards/. See AGENTS.md. - A new estimator: pair it with the subsystem and add a model card.
- A new MCP tool: register it in
server.py, classify it inpolicy.py, regeneratetool-reference.mdwithmake schema. - A new adapter: implement the
AdapterProtocol, document its conformance posture underdocs/conformance/.