EnfinitOSEnfinitOS
DevelopersRobotics & flight
Production-ready scaffold

Robotics SDK — TypeScript

Geofencing, kinematic envelopes, telemetry heartbeats, emergency stop. Composes Renderer Core for the policy + proof plane.

@enfinitos/sdk-roboticsSubstrate ROBOTICSTypeScript
Install

Get the SDK

npm install @enfinitos/sdk-robotics

About this status badge

Typed, tested, documented, and grounded in the 2026 platform reality. Awaiting first customer-integration validation.

README

The developer-facing documentation in full

Rendered from packages/sdks/robotics-ts/README.md at build time — the same source the package ships with.

@enfinitos/sdk-robotics

EnfinitOS reference SDK for the ROBOTICS substrate.

A robotic-fleet operator (Starship-style sidewalk delivery, a Nuro fleet, a warehouse VDA-5050 AGV fleet, a ROS 2 cobot deployment, a Cobalt security patrol) embeds this SDK so each robot can:

  1. Receive versioned behavioural policies from the EnfinitOS rights/policy plane.
  2. Acknowledge policies idempotently with a monotonic version.
  3. Report behavioural events (rule fires, violations, skips) back to the platform's audit ledger.
  4. Heartbeat telemetry (location, battery, speed, sensor health).
  5. Receive or raise emergency stops on a priority channel that never sits behind queued traffic.
  6. Survive transport drops with bounded backlog + exponential reconnection.

The SDK is fleet-agnostic: it speaks one canonical wire contract to EnfinitOS and exposes adapters for the four fleet patterns the team has surveyed (ROS 2, VDA 5050, Starship-style REST+WS, a generic-template adapter). Plug in your fleet's specific control plane in src/adapters/ — the policy/audit machinery is the same.

Platform-side counterpart. This SDK consumes the platform's /v1/robotics/connect WebSocket endpoint. That endpoint is a separate engineering item — it is not part of this SDK ship. The SDK targets the documented wire contract in src/types.ts; the platform-side service to accept these connections, persist the audit stream, and dispatch policy pushes is tracked as its own tranche.

Architecture

                          ┌──────────────────────────┐
                          │   EnfinitOS Platform     │
                          │  (rights, policy, audit) │
                          └────────────┬─────────────┘
                                       │  WebSocket
                                       │  (JWT in handshake)
                                       │
   ┌────────────── (1) policy_push ────▼─────────────┐
   │                                                  │
   │    ┌────────────────────────────────────┐        │
   │    │      EnfinitOSRobotClient          │        │
   │    │                                    │        │
   │    │   ┌──────────┐    ┌──────────┐     │        │
   │    │   │ Policy   │    │Lifecycle │     │        │
   │    │   │ Resolver │    │Controller│     │        │
   │    │   └──────────┘    └──────────┘     │        │
   │    │                                    │        │
   │    │   ┌──────────┐    ┌──────────┐     │        │
   │    │   │Behaviour │    │Emergency │     │        │
   │    │   │ Reporter │    │   Stop   │     │        │
   │    │   └──────────┘    └──────────┘     │        │
   │    └────────────────────────────────────┘        │
   │                                                  │
   └──────────────────────────────────────────────────┘
                   │                  ▲
   (2) policy_ack  │                  │ (4) emergency_stop
   (3) behavioural │                  │     (priority channel —
       event       │                  │      never queued)
   (5) telemetry   │                  │
                   ▼                  │
   ┌──────────────────────────────────┴───────────────┐
   │           Adapter (ROS 2 / VDA 5050 /            │
   │            Starship-style / custom)              │
   └──────────────────────────────────────────────────┘
                              │
                              ▼
                  Fleet's own control plane
                  (publishers, instantActions,
                   diagnostic topics, etc.)

Research synthesis — why this shape

The SDK borrows from five existing patterns:

Pattern sourceWhat we adopted
ROS 2 managed-node lifecycleFive-state machine (CONFIGURED / ACTIVE / SUSPENDED / ERROR / TERMINATED). ERROR must convalesce through SUSPENDED — ISO 10218.
VDA 5050 (Toyota / Linde / BMW)Five-channel topology (order, instantActions, state, visualization, connection) inspired our separate priority channel for emergency stops. Our instantActions equivalent is sendImmediate().
Starship Technologies (sidewalk delivery)REST + WebSocket telemetry @ 1–5 Hz; remote-operator handoff via a state transition. Inspired REQUIRE_HUMAN_OPERATOR reporting.
Boston Dynamics Spot SDKgRPC E-Stop service is never queued behind other traffic. We adopted that for emergencyStop().
Nuro / Refraction AI / CobaltRules-based geofencing + remote oversight ⇒ exclusion-zone reporting + forced boolean for safety-system overrides.

Getting started

Install

pnpm add @enfinitos/sdk-robotics

Five-minute hello-world

import { EnfinitOSRobotClient } from "@enfinitos/sdk-robotics";

const client = new EnfinitOSRobotClient({
  orgId: "org_acme",
  robotId: "robot_001",
  fleetId: "fleet_main",
  authToken: process.env.ENFINITOS_JWT!,
  apiBaseUrl: "https://api.enfinitos.com",
});

// 1) wire policy receipt
client.subscribePolicy(async (policy) => {
  console.log(`policy v${policy.version} with ${policy.rules.length} rules`);
  // TODO: load each rule into your control plane, then ack.
  await client.acknowledgePolicy(policy.version);
});

// 2) wire emergency stop receipt
client.onEmergencyStopReceived(async (cmd) => {
  console.error(`E-STOP from ${cmd.issuedBy}: ${cmd.reason}`);
  // halt motion, transition to SUSPENDED.
});

// 3) connect
await client.connect();

// 4) heartbeat
client.startTelemetryHeartbeat({
  intervalMs: 1000,
  buildReport: () => ({
    reportedAt: new Date().toISOString(),
    location: { lat: 51.5, lng: -0.1 },
    batteryPct: 87,
    speedKph: 5.4,
    headingDeg: 90,
    state: client.getState(),
  }),
});

Lifecycle states

StateWhat it meansReachable from
CONFIGUREDConnected and authenticated; awaiting first policy.(initial)
ACTIVEHas a policy and is executing missions.CONFIGURED, SUSPENDED
SUSPENDEDPaused (operator intervention, low battery, soft fault).CONFIGURED, ACTIVE, ERROR
ERRORHard fault. Must transition through SUSPENDED before re-activating.(any non-terminal)
TERMINATEDTerminal. Client must be reconstructed to reconnect.(any non-terminal)

The ERROR → SUSPENDED requirement is intentional: it matches ISO 10218 robotics-safety guidance, forcing an operator to acknowledge the fault before the robot can move again.

Policy update flow

   PLATFORM                                     ROBOT (SDK)
       │                                            │
       │   policy_push { version: 7, rules: […] }   │
       │ ─────────────────────────────────────────► │
       │                                            │ ─┐  apply()
       │                                            │  │  fan out to
       │                                            │  │  subscribers
       │                                            │ ◄┘
       │                                            │
       │                                            │ ─┐  application
       │                                            │  │  decides ack
       │                                            │  │  is safe
       │                                            │ ◄┘
       │     policy_ack { policyVersion: 7,         │
       │       robotState: "ACTIVE", ackedAt: … }   │
       │ ◄───────────────────────────────────────── │

The platform considers a policy "live" only after the robot acks. Out-of-order pushes (which happen on reconnect when the server flushes a buffered older version after the most recent one) are silently dropped by the resolver; stale ack attempts are also dropped client-side.

Behavioural rule kinds

The eleven BehaviourRule kinds the SDK speaks today (mirroring apps/api/src/modules/rights/contracts/scope.ts):

KindConvenience helperNotes
YIELD_TO_PEDESTRIANSreportYieldEvent()sidewalk-delivery; the rule_fired event
MAX_SPEED_KPHreportSpeedExceedance()rule_violated when observed exceeds limit
EXCLUSION_ZONEreportExclusionZoneEntry()breach with forced boolean for safety overrides
OPERATING_HOURSgeneric reportBehaviouralEvent()rule_skipped outside window
REQUIRE_HUMAN_OPERATORgenericrule_fired on remote-operator handoff
DONT_DISPLAY_WHILE_MOVINGgenericAUTOMOTIVE substrate cross-over
DRIVER_ATTENTION_REQUIREDgenericAUTOMOTIVE
INTEGRATE_WITH_VEHICLE_DISTRACTION_SYSTEMgenericAUTOMOTIVE
PASSENGER_DISPLAY_ONLYgenericAUTOMOTIVE
REQUIRE_HANDS_FREEgenericAUTOMOTIVE
CUSTOMgenericescape hatch for fleet-specific rules

The four BehaviouralEventType values:

  • rule_fired — rule activated and complied with.
  • rule_violated — rule could not be honoured (compliance audit).
  • rule_skipped — not applicable.
  • rule_unknown — firmware does not implement the rule. Reported so the platform never silently allows a policy a robot can't enforce.

Adapter pattern

Each fleet ships an adapter that implements four small interfaces in src/adapters/_template/spi.ts:

InterfaceResponsibility
FleetCommandSinkapply EnfinitOS policy onto the fleet's native command vocabulary
FleetEventSourcetranslate native fleet events into BehaviouralEvents
FleetTelemetrySourcebuild TelemetryReports from native pose/battery/sensors
FleetLifecycleHookoptional — react to lifecycle transitions

Adapter skeletons are shipped for:

  • adapters/ros2.ts — ROS 2 (rclnodejs / rclpy), maps onto managed-node lifecycle, latched topics for policy publication.
  • adapters/vda5050.ts — VDA 5050 v2, instantActions for most policy rules, MQTT broker injected.

Customer-specific shapes (Starship, Nuro, Cobalt) follow the same template; we ship the two with the broadest install base.

Telemetry pattern

The heartbeat is opt-in (startTelemetryHeartbeat(opts)). Recommended cadence: 1 Hz for sidewalk delivery and warehouse AGVs; up to 5 Hz for autonomous-vehicle telemetry. The platform throttles ingest above 10 Hz to protect the audit ledger.

Report shape (TelemetryReport) is intentionally small: location, battery, speed, heading, state, free-form sensorHealth. Keep sensorHealth keys stable across reports so the SRE dashboard's time series stay coherent.

Emergency stop semantics

  • Priority channel. The SDK's sendImmediate() bypasses the normal outbound queue. An emergency stop fires even if a policy ack or telemetry frame is mid-send.
  • Idempotent. commandId is the dedup key. The SDK drops duplicate incoming commands.
  • Never queued behind reconnect backoff. If the WS is down when the application calls emergencyStop(), the message sits at the head of the priority queue and is the FIRST thing flushed when the socket re-opens.
  • Lifecycle. Robot-side emergencyStop() auto-transitions to SUSPENDED. Inbound emergency stops do NOT auto-transition — the application controlling the robot decides what "halt" means and reports the state change back via the normal lifecycle channel.

Sample integration — minimal viable robot

import { EnfinitOSRobotClient } from "@enfinitos/sdk-robotics";

async function main() {
  const client = new EnfinitOSRobotClient({
    orgId: "org_acme",
    robotId: "robot_001",
    fleetId: "fleet_main",
    authToken: process.env.ENFINITOS_JWT!,
    apiBaseUrl: "https://api.enfinitos.com",
  });

  client.subscribePolicy(async (policy) => {
    console.log(`got policy v${policy.version}`);
    await client.acknowledgePolicy(policy.version);
  });

  await client.connect();

  // one heartbeat
  await client.reportTelemetry({
    reportedAt: new Date().toISOString(),
    location: { lat: 51.5, lng: -0.1 },
    batteryPct: 87,
    speedKph: 0,
    headingDeg: 90,
    state: client.getState(),
  });

  // one behavioural event
  await client.reportYieldEvent({
    occurredAt: new Date().toISOString(),
    location: { lat: 51.5, lng: -0.1 },
    detectedPedestrians: 1,
    closestDistanceM: 1.8,
  });

  await new Promise((r) => setTimeout(r, 500));
  await client.disconnect();
}

main();

What's SDK-side vs platform-side

ConcernThis SDKPlatform tranche (separate)
Wire protocol (WireMessage)✅ defined here✅ implemented by platform-side server
/v1/robotics/connect WS endpoint⏳ separate work item
Audit-log persistence⏳ separate work item
JWT issuancereuses the existing /auth/* plane
Policy authoring UIalready shipped in apps/web/.../compose
Adapters (ROS 2, VDA 5050, custom)✅ skeletons(customer-owned)

See also

  • apps/api/src/modules/rights/contracts/scope.tsBehaviourRule source-of-truth on the platform side.
  • packages/adapters/_template — sibling DOOH adapter SPI with the same shape.
  • docs/launch/substrate-readiness-matrix.md — ROBOTICS substrate readiness tracker.
API reference

Hit the HTTP surface directly

The Robotics SDK — TypeScript is a thin client over the same governed HTTP API every other SDK calls. The full OpenAPI 3.1 reference lives on the docs site.

Sandbox

Run this SDK against a real tenant

The hosted sandbox is the fastest way to verify Robotics SDK — TypeScript against a real EnfinitOS tenant before committing to a pilot. Launching Q4 2026.