MHS-000InformativePart 2 of 2

OpenMHS Architecture Overview (informative)

OpenMHS 0.9 development draftSections 9–1613 min read2,775 words

Part 2 of 2 · MHS-000 continues from Part 1. The document is split only for page size; the requirements are continuous.

On this page 19 sections
  1. 9. Adapter and bridge model
  2. 9.1 The per-repository deliverable
  3. 9.2 Adapter manifest (example)
  4. 9.3 Bridge families
  5. 9.4 Mapping rules
  6. 9.5 Integration tiers and effort
  7. 10. Conformance
  8. 10.1 Levels
  9. 10.2 Profiles
  10. 10.3 Executable conformance
  11. 11. Host profile
  12. 11.1 MHS-Host behaviours
  13. 11.2 The OpenAI4S reference host
  14. 11.3 The "one call" property
  15. 12. Document map
  16. 13. Adoption path for the corpus
  17. 14. Decision log (alternatives considered)
  18. 15. Security and privacy (summary)
  19. 16. What MHS deliberately leaves to others

9. Adapter and bridge model

9.1 The per-repository deliverable

The default deliverable for an upstream repository is a driver package (driver-profile.md): one Driver class (or a config-only subclass of a family driver) that declares what the device reads, writes and does, with sourced limits and facts, plus a fake backend; the SDK runtime enforces everything else and a gate (python3 -m mhs.driver check <dir> --backend fake) says when the package is finished. The earlier design, a declarative mhs-adapter.json with a bindings.json read by a bridge, remains valid and optional (06). Either way a bridge family runs the mapping: a generic runtime per kind of native interface.

An adapter may declare several devices (e.g., a workcell simulator exposing robot + plate reader + liquid handler).

9.2 Adapter manifest (example)

The manifest below is the shipped example MHS/schema/examples/adapter.gymnasium-cartpole.json. It is valid against adapter.schema.json, whose objects are closed: bindings live in a separate mhs/bindings.json (06 §4), not inside the device capabilities.

json
{
  "$schema": "https://mhs.openai4s.org/schema/0.9/adapter.schema.json",
  "mhs_adapter": "1.0",
  "adapter_id": "com.example.gymnasium-cartpole",
  "title": "Gymnasium CartPole as an MHS simulated device",
  "family": "gymnasium",
  "source": {
    "repo": "https://github.com/Farama-Foundation/Gymnasium",
    "commit": "5f2f9d3",
    "license": "MIT",
    "redistributable": true,
    "path": "mhs/"
  },
  "runtime": {
    "kind": "python",
    "python": ">=3.10",
    "install": ["pip install gymnasium==1.0.0"],
    "entry": "mhs.bridge.gym:main",
    "requirements": ["gymnasium"],
    "gpu": false
  },
  "lifecycle": {
    "start": {"kind": "process", "command": ["python", "-m", "mhs.bridge.gym", "--adapter", "mhs/mhs-adapter.json"]},
    "ready": {"method": "mhs.hello", "deadline_ms": 30000},
    "stop": {"kind": "terminate", "grace_s": 5}
  },
  "devices": [
    {
      "$schema": "https://mhs.openai4s.org/schema/0.9/device.schema.json",
      "mhs_version": "1.0",
      "device_id": "mhs://localhost:7401/gym/CartPole-v1",
      "instance_id": "01J8ZQ3V6Y7M2N4P6R8S0T2V4X",
      "display_name": "CartPole-v1 (Gymnasium simulator)",
      "mode": "simulated",
      "profile": {
        "title": "Cart-pole balancing",
        "summary": "Classic control benchmark: push a cart left or right to keep a pole upright. Demonstrates the MHS world.* capability family and seeded determinism.",
        "tags": ["classic control", "cartpole", "reinforcement learning", "benchmark", "seeded simulation"]
      },
      "resources": [
        {
          "resource_id": "world",
          "kind": "world.sim",
          "title": "CartPole world",
          "revision": 0,
          "hash_exclusions": ["/mono_ms"],
          "state_schema": {
            "type": "object",
            "required": ["cart_position", "pole_angle", "terminated", "truncated"],
            "properties": {
              "cart_position": {"type": "number", "x-mhs-unit": "m"},
              "cart_velocity": {"type": "number", "x-mhs-unit": "m/s"},
              "pole_angle": {"type": "number", "x-mhs-unit": "rad"},
              "pole_angular_velocity": {"type": "number", "x-mhs-unit": "rad/s"},
              "terminated": {"type": "boolean"},
              "truncated": {"type": "boolean"}
            }
          },
          "state": {
            "cart_position": 0,
            "cart_velocity": 0,
            "pole_angle": 0,
            "pole_angular_velocity": 0,
            "terminated": false,
            "truncated": false
          }
        }
      ],
      "capabilities": [
        {
          "capability_id": "cap.world.step.v1",
          "resource": "world",
          "native": "gym.make('CartPole-v1').step(action)",
          "input_schema": {
            "type": "object",
            "required": ["action"],
            "properties": {"action": {"type": "integer", "enum": [0, 1]}}
          },
          "output_schema": {"type": "object", "required": ["observation", "reward", "terminated", "truncated"]},
          "constraints": {"concurrency": "exclusive", "max_duration_ms": 1000},
          "determinism": "seeded",
          "exclusive": true
        },
        {
          "capability_id": "cap.world.reset.v1",
          "resource": "world",
          "native": "gym.make('CartPole-v1').reset(seed=seed)",
          "input_schema": {"type": "object", "properties": {"seed": {"type": "integer", "minimum": 0}}},
          "output_schema": {"type": "object", "required": ["observation"]},
          "determinism": "seeded"
        },
        {
          "capability_id": "cap.world.state.v1",
          "resource": "world",
          "native": "env.unwrapped.state",
          "input_schema": {"type": "object", "properties": {}},
          "output_schema": {"type": "object"},
          "determinism": "seeded"
        }
      ],
      "safety": {
        "risk_class": "R0",
        "envelope": {},
        "interlocks": [],
        "estop": {"kind": "software", "latching": false, "latency_ms": 10, "reset": "mhs.safety.reset"},
        "safe_state": {"description": "Simulation paused; no physical effect", "achieved_by": []}
      },
      "fidelity": {
        "engine": "gymnasium-classic-control",
        "fidelity_level": "F0",
        "determinism": {
          "kind": "seeded",
          "seed_control": "reset_required",
          "notes": "Seed must be supplied on reset; no internal RNG isolation."
        },
        "timestep_ms": 20,
        "realtime_factor": 0,
        "reset": "full",
        "snapshot_restore": false,
        "gaps": ["Rigid-body approximation only", "No actuator saturation model", "Observation noise not modeled"]
      }
    }
  ],
  "conformance_target": {"profile": "MHS-Sim", "level": "CL2"},
  "evidence": {
    "state": "declared",
    "read_by": "static_analysis",
    "entry_points": [
      "gymnasium/envs/classic_control/cartpole.py:CartPoleEnv.step",
      "gymnasium/envs/classic_control/cartpole.py:CartPoleEnv.reset"
    ]
  },
  "stability": "stable",
  "tier": "A",
  "redaction": [],
  "registry": {
    "package_id": "gh.farama-foundation/gymnasium",
    "homepage": "https://gymnasium.farama.org",
    "maintainers": ["Farama Foundation"]
  }
}

9.3 Bridge families

The 0.9 SDK implements these bridge families as runtimes with a Driver class (PythonObjectDriver, SerialDriver, ScpiDriver, GymnasiumDriver, MujocoDriver) and a read-only replay bridge: python-object (import a class/function), serial, scpi (stdlib socket, optional pyvisa), gymnasium, mujoco and replay. The adapter schema also names families that are planned after the pilot: ros2 (rclpy / rosbridge), http-api, sila2, opentrons, micromanager, flowchem, madsci, bluesky-ophyd, qcodes, pylabrobot, lerobot, mavlink, the tag bridges (Modbus, OPC UA, EPICS, Tango, Alpaca) and mcp-proxy. A bridge is generic per family; the driver or adapter supplies the mapping.

9.4 Mapping rules

Declarative transforms are limited to: field path mapping, unit conversion, enumeration mapping, constant injection, clamps (which reject and never truncate), and error-code mapping. Anything else becomes a shim (Python/JS), recorded as binding.kind: "shim" with a file reference. Adapters declare native symbols precisely (module/class/function) and do not rely on undocumented internals; when they do, stability: fragile is declared.

9.5 Integration tiers and effort

TierDefinitionTypical effort
ARunnable backend with a clear entry point; adapter manifest + bridge flags get you to CL2.0.5–2 dev-days
BWrap-able library/SDK; needs a thin shim or bridge family support.2–5 dev-days
CEngine or asset only; needs a scenario/model to become a device.5–15 dev-days
DPeripheral/tooling; not a device (visualizer, docs, dataset, CI helper). Not targeted.—
XNot integrable (empty upstream or inaccessible).—

Adapters move through states: declared → packaged → runnable → conformant → certified, each backed by evidence.


10. Conformance

10.1 Levels

LevelNameRequires
CL0DeclaredValid mhs-adapter.json/device manifest against the OpenMHS 0.9 schemas; no runtime required.
CL1ObservableT1/T2 transport; hello, devices.list/get, schema.get, resource.read, subscribe/unsubscribe; stable revisions.
CL2Actuatingsession.open/close, command with idempotency, receipts, operations.get/cancel, revision conflicts, deadlines.
CL3Governedsafety.status/estop/reset, envelope enforcement, risk classes, permits for gated capabilities, session TTL/heartbeat, safe-state on cancel, MHS.SAFETY.NOT_CERTIFIED disclosure.
CL4ReproducibleEvidence export/verify (hash chain), and for simulated/replay devices a deterministic replay test (same seed ⇒ identical state_hash sequence).
CL5OrchestratedComposition execution with child receipts (reserved in 0.9), multi-device sessions, backpressure/gap semantics, registry publication, and a published conformance report. CL5 is assessed for the MHS-Bridge, MHS-Host and MHS-Registry profiles; MHS-Device and MHS-Sim top out at CL4 (see MHS-001).

10.2 Profiles

  • MHS-Device (hardware): CL0–CL4 as applicable (no replay requirement).
  • MHS-Sim: CL0–CL4; the fidelity contract and the CL4 replay test are mandatory.
  • MHS-Bridge: adapter manifest + at least one device at CL2.
  • MHS-Host: consumes MHS; the behaviours are in 09 (discovery, least privilege, approvals, evidence ledger, mode disclosure).
  • MHS-Registry: record schema validity, signing, search latency bounds.

10.3 Executable conformance

  • The suite (python3 -m mhs.conformance, versioned with the spec) runs test cases against an endpoint and emits a conformance-report.json, here a minimal report that is valid against conformance-report.schema.json (01 §7.1 shows a fuller one):
json
{"report_version": "1.0.0", "suite_version": "1.0.0", "profile": "MHS-Sim",
 "subject": {"kind": "endpoint", "id": "mhs://localhost:7400", "mhs_version": "1.0"},
 "level_claimed": "CL3", "level_achieved": "CL3",
 "tests": [{"id": "SAFE-014", "status": "pass", "level": "CL3",
            "mhs_code": "MHS.SAFETY.ENVELOPE_VIOLATION"}],
 "environment": {"os": "macOS 15.6 arm64", "date": "2026-10-20T07:40:00Z", "suite": "openmhs 0.9.0.dev0"},
 "report_digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
 "issuer": {"kind": "self"},
 "disclaimers": [{"id": "not_certified",
                  "text": "MHS conformance is a behavioural test result, not a safety certification."}]}
  • A registry claim is `{package_or_endpoint, profile, level, suite_version, report_digest, issued_at, issuer_kind}. issuer_kind: self|verified`.
  • Test IDs are stable and requirements-traced; the suite includes negative tests (interlock open, revision conflict, duplicate command id, deadline exceeded, cancellation, mode mismatch).

11. Host profile

11.1 MHS-Host behaviours

A host (agent harness) claiming MHS-Host conformance (09):

  1. discovers endpoints from all configured sources and authenticates;
  2. opens least-privilege sessions and refreshes/closes them correctly;
  3. obtains approvals before calling requires_permit capabilities;
  4. presents mode, fidelity.gaps, risk_class and trust level to the model;
  5. enforces deadlines and cancellation, and never retries an unknown outcome blindly;
  6. records all receipts into an append-only evidence ledger and exports/verifies it;
  7. never claims or implies that MHS replaces hardware safety;
  8. exposes capabilities to the model through at least one of MCP tools, native tools, or a code API, and keeps tool descriptions in sync with schemas.

11.2 The OpenAI4S reference host

OpenAI4S (PKU-YuanGroup/OpenAI4S) is the reference host. The integration is MCP-first: one mhs.mcp projection per endpoint, registered as an ordinary connector that is disabled until an operator enables it, with permits and resets on a separate operator route. How its components map to the host behaviours is described in 09 annex A (informative).

11.3 The "one call" property

For any MHS endpoint — a Rust conveyor workcell, a Python liquid-handler simulator, a MuJoCo arm, a driver package on its fake backend — the same host code path runs. This example drives two different endpoints through one helper; it runs against the SDK:

python
# runnable
from mhs.adapter import load
from mhs.reference import build_endpoint, build_server
from mhs.run import lab

thermostat = load("MHS/sdk/examples/thermostat", backend="fake")
conveyor = build_server(build_endpoint("conveyor", endpoint_id="mhs://localhost:7400", test_profile=False),
                        log_ready=False)

with lab(thermostat, conveyor, ledger=False) as bench:            # one transport API
    for name, capability, payload in (("tutorial-thermostat", "cap.thermal.setpoint.v1", {"target_temperature": 30}),
                                      ("conveyor-workcell", "cap.world.step.v1", {"ticks": 3})):
        receipt = bench[name].invoke(capability, payload)         # one command call for every device
        assert receipt["status"] == "completed"
        state = bench[name].read(bench[name].manifest()["resources"][0]["resource_id"])   # one read
        assert state["revision"] == 1
thermostat.close()
conveyor.close()

No per-repo branches in the host. The differences live in the adapter plane.


12. Document map

DocSubject
README.mdPrecedence, reading order, requirement identifiers
core.mdThe normative core: object model, primitives, reference file, limits, evaluation order, safety duties, receipts, modes, discovery, surfaces, principals, strict mode, persistence
driver-profile.mdThe per-repository driver package, the Driver API, the gate, review, fakes, the sandbox
profiles.mdIndex of the optional profiles
00-architecture.mdThis file: the informative overview
01-conformance.mdLevels, profiles, test suite, report format
02-wire-protocol.mdFull method-by-method reference, errors, examples
03-capability-registry.mdCapability class definitions, versioning, extension rules
04-safety.mdEnvelopes, interlocks, permits, e-stop, audit, threat model
05-fidelity.mdMode and fidelity contract, validation protocol, replay
06-adapters.mdAdapter manifest, bridge families, mapping rules, recipes
07-registry.mdPackage/device/claim records, federation, trust, search
08-transports.mdT1–T6 bindings, MCP projection details, auth
09-host-profile.mdHost requirements; annex A describes the OpenAI4S reference host
10-governance.mdRFC process, versioning, deprecation, licensing
appendix-a-capabilities.mdCore capability catalogue (generated)
appendix-b-errors.mdError code registry (generated)
appendix-c-examples.mdRunnable end-to-end examples (conveyor, lab, arm, hybrid, MCP)
appendix-d-anthropic-mhs.mdRelationship to the Anthropic research preview

13. Adoption path for the corpus

The workspace catalogues 2,975 repos (1,045 lab, 1,922 robotics, 8 unlisted) and clones 2,967. They are not adopted by hand: each becomes, at most, one driver package, produced from a generated task card by a model and checked by a gate, one repository at a time (driver-profile.md, MHS/handoff/). The order of work:

  1. Wave 0 — reference endpoints and four exemplar drivers. The reference conveyor, lab, arm and replay endpoints prove the protocol end to end and produce CL2–CL4 conformance reports; four exemplar driver packages (an async bath, a SCPI lock-in amplifier, a robot arm SDK, a Gymnasium environment) show the pattern.
  2. Wave 1 — a pilot of 20 repositories (direct Python instruments, serial/SCPI devices, Gymnasium/MuJoCo environments, robot SDK drivers on fakes). The exit criterion is that at least 15 pass the gate without any change to the SDK; after it the Driver API is frozen.
  3. Waves 2 and 3 — the dispatchable cards, strict-ready ones first.
  4. Wave 4 — reconnaissance only for the untriaged cards: a model proposes a decision and entry symbols, a maintainer decides.
  5. Waves 5 and 6 — after the post-pilot bridges (ROS, HTTP, PyLabRobot, SiLA2, QCoDeS, ophyd, Micro-Manager, LeRobot, MAVLink, tag bridges, MCP client) and an artifact store exist, and for repositories that need a GPU or a proprietary engine.

Every repo record in the registry states its tier, ring, evidence and next action (07); a passing package is contract_checked, a statement about a fake and never about hardware. No repo is silently marked "supported".


14. Decision log (alternatives considered)

#DecisionAlternative rejectedWhy
D1JSON-RPC 2.0 coreREST resources; gRPC-only; MCP-onlyJSON-RPC is trivially embeddable in stdio/HTTP/WS, batch and notification semantics are already specified, and it has a native mapping to MCP. REST forces verb soup; gRPC blocks stdlib hosts; MCP-only excludes direct code APIs and is tool-shaped, not device-shaped.
D2Sessions as leasesStateless per-callSimulators are stateful, hardware needs attribution and exclusive leases, and cancellation needs a scope to act on.
D3Receipts + revisions + state hashSimple {"ok": true} responsesWithout receipts, an agent cannot distinguish "not done" from "unknown", and evidence is impossible. This is the single largest gap in the preview.
D4Endpoint-enforced safetyHost-enforced policyAny model can be prompt-injected or buggy; a host is the wrong trust boundary for limits.
D5Sim and hardware in one model with explicit modeSeparate sim standardThousands of adopters only have simulators; two standards double the work. But conflating them silently is unsafe — hence mode + fidelity contract and no runtime switching.
D6A Driver class per repository on generic bridge families, with a mechanical gate (reversed in 0.9; the declarative adapter stays optional)A declarative adapter + bindings as the only deliverableThe original decision wrote a manifest and a bindings file per repository. Review of the first design found that too hard for a model to produce and check mechanically; a short decorated Driver class with a fake backend, sourced limits and one gate command is. The runtime, not the driver, enforces safety, so the driver stays a translation.
D7Capability classes versioned separatelyMonolithic protocol versionHardware vocabulary evolves faster than the wire format; separate versioning avoids breaking the wire to add a pipetting nuance.
D8Executable conformance levelsCertification bodyAdoption requires self-service; a registry claim plus reproducible suite is enough to start, with room for third-party verification.
D9Natural-language tags attached to typed capabilitiesDocs/wiki onlyThe preview's tags idea is right, but unstructured prose cannot be validated or searched; attaching tags to schemas keeps both.
D10Registry as static indexCentral live brokerLab networks are air-gapped; static JSON that can be signed and mirrored is deployable; a broker is a single point of failure and a privacy hazard.

15. Security and privacy (summary)

The rules are in core.md, 04 and 08. In brief:

  • Transport authentication is required outside loopback; tokens are opaque and never logged; stdio endpoints inherit the process identity; HTTP checks Host and Origin and the content type.
  • Capability grants are least-privilege and per binding; a session does not gain capabilities after open without re-opening.
  • input_digest binds permits to exact arguments; the approval UI shows the human-readable rendering of the same input.
  • Evidence contains no secrets; adapters declare redaction rules for credentials and PII fields.
  • Endpoints rate-limit and size-limit requests (MHS.LIMIT.*).
  • Registry records are public by design; device state and telemetry are never published to the registry.
  • Supply chain: adapter manifests and driver locks pin source commits and licences. Upstream code runs locally whatever its licence and is never vendored or redistributed; a licence class gates publication of a package, not its execution (driver-profile.md DRV-042).

16. What MHS deliberately leaves to others

  • Model training, prompting, planning and skill learning.
  • Real-time control loops (MHS is a supervisory contract; bridges may use EtherCAT, CAN, ROS control or vendor RT APIs underneath).
  • Physical safety certification, risk assessment and regulatory compliance.
  • Device discovery on the factory floor (mDNS/DNS-SD/OPC UA GDS may be used).
  • Data storage and analysis of scientific results.

These are integration points, and the MHS documents state them explicitly so that no one mistakes MHS conformance for a safety or quality certificate.