Getting started
Build the SDK, run the test suite, and watch a complete commercial loop — an OEM buying units, a camera activating, frames being metered, an invoice coming out — on your own machine in about ten minutes.
What you need#
| Requirement | Version | Notes |
|---|---|---|
| CMake | ≥ 3.16 | |
| C++ compiler | C++17 | GCC 7+, Clang 6+, MSVC 2019+ |
| OpenSSL | ≥ 1.1.1 | Ed25519 verification. libssl is optional and only needed for HTTPS. |
| Python | ≥ 3.11 | Licensing server, xcaicxctl, and the Python binding |
| ONNX Runtime | optional | Required for production inference. See Backends. |
OpenSSL is the only hard dependency, and it is already in every camera BSP. Everything else in the core is in-tree.
1. Build everything and run the tests#
make allThat creates a virtualenv, configures and builds the core, generates the test fixtures, and runs all four suites:
test_license 45 checks signatures, forgery, binding, expiry/grace,
rollback, revocation
test_engine 63 checks ABI safety, entitlements, stream caps, formats,
zones, quota
server/tests 16 checks activation, seat accounting, replay dedupe,
revocation, invoicing
bindings/python/tests 14 checks binding correctness, error mapping, metering138 checks in total. The build is clean under -Wall -Wextra -Wpedantic.
Note
The licence suites deliberately run tokens minted by the Python signer through the C++ verifier. Those are two independent implementations of the same format, and the drift between them is the thing that actually breaks in the field — so it is the thing the tests aim at.
2. Start the licensing authority#
In one terminal:
make serverThis runs the FastAPI licensing authority on :8000. On first run it generates a signing keypair under server/keys/ if one does not exist.
Do not
The signing key is the root of trust for every licence you will ever issue. If it leaks, anyone can mint licences for your SDK and the only remedy is shipping new firmware with a new compiled-in public key. For anything beyond local evaluation, read Running the authority before you generate the key you intend to keep.
3. Watch the whole commercial loop#
In a second terminal:
make demoThe demo registers an OEM, sells them a batch, boots the SDK on a camera holding only the batch key, activates it, runs frames through the pipeline, ships the usage spool, and rates the period:
[2] registering an OEM customer and selling a batch
batch : B-2026-1C4417D5 (5 units)
[3] booting the SDK on a camera that holds only the batch key
activated as : LIC-D3ACF708DB6048AB
bound device : b2cd209a6826bd8b33c0fdaad6304106
batch now : 1/5 activated
[4] running 20 frames through the pipeline
event: LINE_CROSS zone=doorway track=1
event: ZONE_ENTER zone=packing-bay track=1
metered inferences: 20
[5] heartbeat: shipping the usage spool to the server
server recorded: 20 inferences, 20 frames, 1 record(s)
[6] fleet and invoice
XCAICX OEM Industrial (detection + defect + PPE)Every step in that output corresponds to something documented here: activation is Licensing, the events are Zones, tripwires & events, the counting is Metering & billing, and the endpoints are the REST API.
4. Point it at your own frames#
The fastest way to see the SDK on real imagery is the Python binding, which accepts anything with the buffer protocol — including a numpy array straight out of OpenCV.
import cv2
import xcaicx
cap = cv2.VideoCapture(0)
with xcaicx.Engine(license_path="unit.token", state_dir="./state") as eng:
with eng.stream("webcam", modules=xcaicx.Module.DETECT) as s:
while True:
ok, frame = cap.read()
if not ok:
break
h, w = frame.shape[:2]
result = s.process(frame, width=w, height=h,
fmt=xcaicx.PixelFormat.BGR8)
for d in result.detections:
x, y, bw, bh = d.box.to_pixels(w, h)
cv2.rectangle(frame, (x, y), (x + bw, y + bh), (0, 255, 0), 2)
cv2.putText(frame, f"{d.class_name} {d.score:.2f}", (x, y - 6),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
cv2.imshow("xcaicx", frame)
if cv2.waitKey(1) == 27:
breaknumpy is not a dependency of the binding — it just works if you already have it.
Careful
What you will see from the reference backend on a webcam is edges and blobs, classified by aspect ratio. That is the honest behaviour of a heuristic detector and exactly why production deployments ship models. If it looks unimpressive on real imagery, the demo is working correctly.
Where to go next#
- Embedding in firmware → Quickstart: C, then OEM integration
- Understanding the moving parts → How the SDK is put together
- Getting a licence into a camera that will never see the internet → Air-gapped deployment
- Making it fast enough on a weak SoC → Performance & tuning