Getting started

How to start developing with SAPIENT

Five steps from reading the standard to a SAPIENT node that has been through a conformance test. Each step links to the tool or document you need for it.

  1. Read the official SAPIENT material

    SAPIENT is specified by BSI Flex 335, the SAPIENT Interface Control Document (ICD). Version 2.0 is current. Start with the official sources:

    Those are authoritative. Where this site and the standard differ, the standard is right.

    Terminology

    BSI Flex 335 v2.0 calls the two kinds of node the Edge Node (a sensor or effector) and the Fusion Node (which receives reports and issues tasks). Older SAPIENT documents and code call them the ASM (Autonomous Sensor Module) and DMM (Decision Making Module).

  2. Choose language bindings

    SAPIENT messages are Protocol Buffers sent over TCP, each preceded by a 4-byte little-endian length. You can generate code from the schema yourself, but the SAPIENT language bindings already include the generated types and the framing for Rust, Python, C#, Go and Java.

    cargo add sapient-rs                 # Rust
    pip install sapient-py               # Python
    dotnet add package Sapient.Bindings  # C#
    go get github.com/tom-mann-ironclad/sapient-bindings/go/sapient/...  # Go

    For Java, add io.github.tom-mann-ironclad:sapient-bindings:0.1.0 from Maven Central (Maven and Gradle snippets).

  3. Open a basic SAPIENT connection

    An Edge Node connects to a Fusion Node and sends a Registration. The Fusion Node replies with a RegistrationAck. Nothing else is valid until that exchange has happened.

    You don't need a real Fusion Node to try this. The test harness can act as one in a live session that logs and checks everything it receives:

    sapient-harness session --role fusion --target 127.0.0.1:5000

    Then register with it. This Python example loads the harness's example Registration, gives it a fresh node ID and timestamp, and prints the reply:

    import socket, uuid
    from pathlib import Path
    
    from google.protobuf import json_format
    from sapient_msg.bsi_flex_335_v2_0.sapient_message_pb2 import SapientMessage
    from sapient_py import read_frame, write_frame
    
    msg = json_format.Parse(Path("01-registration.json").read_text(), SapientMessage())
    msg.node_id = str(uuid.uuid4())
    msg.timestamp.GetCurrentTime()
    
    with socket.create_connection(("127.0.0.1", 5000)) as sock:
        stream = sock.makefile("rwb")
        write_frame(stream, msg)
        stream.flush()
        print(read_frame(stream, SapientMessage))  # registration_ack { acceptance: true ... }

    The harness prints every message in both directions and any findings, so you can see straight away if something you sent breaks a rule.

  4. Inspect the traffic in Wireshark

    Once bytes are moving, look at them. The SAPIENT Wireshark dissector decodes each message on a TCP stream into named fields, so you can check what your node actually sent rather than what you meant it to send. It's often the quickest way to settle an integration argument.

  5. Test your implementation with the harness

    When your node can hold a session, run the harness's automated scenario against it. It plays the opposite role, drives registration, status reporting, detections, tasking and alerts, and reports every conformance finding with a stable rule ID:

    # You're building an Edge Node: the harness listens as a Fusion Node
    sapient-harness run --role fusion --target 0.0.0.0:5000
    
    # You're building a Fusion Node: the harness connects as an Edge Node
    sapient-harness run --role edge --target fusion-node.example:5000

    See the test harness page for installation and how to read the results, and SAPIENT conformance explained for what "conformant" means beyond parsing.