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.
-
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:
- SAPIENT guidance on GOV.UK: what SAPIENT is, who it's for, and links to the official documents.
- BSI Flex 335 v2.0 from BSI: the specification itself.
- DSTL SAPIENT-Proto-Files on GitHub: the protobuf schema the ICD's messages are defined in.
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).
-
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/... # GoFor Java, add
io.github.tom-mann-ironclad:sapient-bindings:0.1.0from Maven Central (Maven and Gradle snippets). -
Open a basic SAPIENT connection
An Edge Node connects to a Fusion Node and sends a
Registration. The Fusion Node replies with aRegistrationAck. 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:5000Then 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.
-
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.
-
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:5000See the test harness page for installation and how to read the results, and SAPIENT conformance explained for what "conformant" means beyond parsing.