Synapse Ingestion Engine
Synapse is a brokerless, edge-first IoT ingestion engine using a symmetric P2P mesh. Using ZeroMQ, SQLite timeseries database, and Uber H3 spatial analysis, it offers decentralized telemetry ingestion. Every node is identical with no central brokers, no monitors, and no single points of failure. Nodes discover each other automatically via Zero-Touch Provisioning (mDNS/Zeroconf), validate sensor readings locally through H3 spatial corroboration, compress payloads using pluggable strategies (zlib, lz4, zstd), and secure communication via CurveZMQ and Caddy TLS.
Every node is identical: runs main_node.py. No central broker. Fully decentralized ZeroMQ PUB/SUB with dynamic
failover.
True plug-and-play discovery via mDNS/Zeroconf (default), UDP Multicast Beacon, or static CSV peer lists. No hardcoded addresses.
Peering bounds via SYNAPSE_MAX_CONNECTIONS. Node maintains at most X active peers with
reserve failover and self-peering filter.
Real-time localized validation using Uber H3 and pluggable robust estimators (MAD default, Z-score, or AND-hybrid). Leave-one-out corroboration.
Bandwidth reduction (up to 70%) via zlib, lz4, or zstd while keeping spatial H3 topic headers in clear text for native ZMQ filtering.
Telemetry propagation beyond direct range (k-ring 1). Intermediate nodes act as relays with vector loop prevention and duplicate suppression.
Caddy sidecar terminates HTTPS. ZMQ data channel secured by CurveZMQ with dynamic Over-The-Air key exchange and auto-generation.
Local database archiving of node readings in SQLite, exposing REST history query endpoints with age and size-based GC pruning.
Official Helm chart with DaemonSet topology ensures exactly one Synapse node per edge device. Caddy sidecar included. SQLite HostPath persistence.
Synapse Quickstart & Setup Guide
Prerequisites
- Python 3.11+
- Docker (or rootless Podman auto-detected by the
Makefile) - Docker Compose v2
1. Start the P2P Mesh (Recommended)
The Makefile is the primary interface. make start
builds and deploys a simulated local mesh of 4 identical nodes, each alongside its secure Caddy proxy:
2. Accessing the Dashboard
Each node serves its own localized dashboard via HTTPS through the Caddy sidecar. Open your browser and navigate to the secure endpoint bypass the local development certificate warning once:
- Green Hexagons: All active sensors in the H3 cell are healthy and congruent.
- Yellow/Orange Hexagons: One or more sensors are
FAULTYorDEAD. - Red Hexagons: The majority of sensors in the cell have failed local corroboration.
- Connected Peers sidebar: Navigate between the perspectives of all peers in the mesh without centralized aggregation.
3. Manual Python Development Setup
To develop and run a single node directly in Python without Docker:
main_sensor.py and main_monitor.py daemons,
v0.6.0 consolidates everything into a single src/main_node.py entrypoint.
Every instance is a peer: there is no privileged "monitor" role.
P2P Mesh Technical Architecture & System Design
Synapse v0.6.0 adopts a fully Symmetric P2P Mesh model.
Unlike hub-and-spoke topologies that depend on a central broker or monitor daemon, every participant is an
identical
Node that simultaneously senses data, ingests peer telemetry, validates
anomalies, and serves its own operator dashboard.
| Feature | Traditional Hub-and-Spoke | Synapse v0.6.0 P2P Mesh |
|---|---|---|
| Topology | Centralized broker / monitor | Symmetric: every node is identical |
| Discovery | Hardcoded broker address | ZTP via mDNS / UDP Beacon / Static |
| Single Point of Failure | Yes: broker cluster | None: any node loss is transparent |
| Anomaly Detection | Centralized cloud analytics | Local spatial corroboration per node |
| Compression | No / Centralized proxy | Pluggable (zlib, lz4, zstd) with clear-text topic filter |
| Relaying | Centralized routing | Spatial multi-hop with loop prevention path vector |
| Key Management | Manual TLS certificates | Dynamic OTAA Curve key exchange / auto-generation |
| Dashboard | Central web UI | Localized per node, cross-mesh navigation |
| Local History Store | N/A (Forwarded to cloud) | SQLite local timeseries archiving post-corroboration |
| TLS | Optional / external LB | Caddy sidecar per node (automatic) |
| Connection Scaling | Full-mesh (exponential sockets) | Bounded peers + dynamic failover |
Core Components
Unified daemon that orchestrates all components. Resolves node identity (via NODE_ID env or hostname), computes geographic coordinates to H3 cell, then wires
together the MeshNode, GarbageCollector, PeerProvider, and DashboardServer. Handles graceful
shutdown on SIGINT/SIGTERM.
The async ZeroMQ backbone. Binds a PUB socket to broadcast telemetry using
the hybrid binary frame format.
Dynamically connects a SUB socket to discovered
peers. Key responsibilities:
- Active Connection Management: Maintains at most
SYNAPSE_MAX_CONNECTIONSlive ZMQ SUB connections. Excess peers enter a reserve queue with dynamic reconnect failover. - Self-Peering Filter: Automatically removes its own bind address from the peer list, preventing socket waste.
- Pluggable Compression & Decryption: Handles frame parsing, decompressing payloads lazily and decrypting with CurveZMQ.
- Spatial Multi-Hop Relaying: Rewrites payload path vectors, appends own ID, and republishes telemetry within hop limits.
- P2P History Replication: Periodically requests historical logs from peers via HTTP to backfill local storage.
- Rate Limiter: Token-bucket rate-limiting checks prior to registry ingestion.
Pluggable compression strategies implementing a strict protocol. Supports `none` (default), `zlib` (built-in), and optional `lz4` / `zstd` backends. Compresses payload bytes while ZeroMQ clear-text H3 topic prefixes are preserved for routing.
Direct connection interface to the SQLite store database. Manages registry mirroring across process restarts and records post-corroboration sensor data into a high-performance timeseries historical table.
Pluggable discovery layer, selected by SYNAPSE_DISCOVERY env:
- ZeroconfPeerProvider DEFAULT: Publishes and discovers peers via mDNS (Zeroconf/Bonjour). Zero configuration required on local networks.
- BeaconPeerProvider: UDP Multicast beacons. Useful on networks where mDNS is blocked.
- StaticPeerProvider: Comma-separated list of static peer addresses. Suitable for Kubernetes or fixed infrastructure.
Thread-safe in-memory registry protected by threading.RLock. Groups nodes by
H3 cell. All reads return deep copies for safe cross-thread use with Flask.
Optionally persists node rows to SQLite (SYNAPSE_REGISTRY_DB) so state survives node restarts. Prometheus counters remain
in-memory only.
Flask + Waitress serving the glassmorphic operator dashboard and versioned REST endpoints. Exposes `/api/v1/otaa/enroll` for dynamic public key exchange and `/api/v1/timeseries` for querying historical telemetry. Secures all dashboard endpoints with token authentication while bypassing health probes and enrollment handshakes.
Background loop driving timeout markdowns and evictions. Tick routines run check-timeouts (DEAD state transition after silence) and evict-dead-nodes (removal after TTL). Additionally schedules periodic execution of timeseries database pruning routines based on age and record counts.
Data Flow
node_id, H3 cell, and ports. Peers receive beacons and build a
local peer map.
MeshNode connects its ZMQ SUB socket (respecting SYNAPSE_MAX_CONNECTIONS limit) and subscribes to spatial topics of interest.
PING_INTERVAL seconds, prefixed with its h3_cell as the ZMQ topic.
NodeRegistry, then
triggers check_corroboration on the cell.
DashboardServer
serves real-time node state via the REST API. The user can navigate between node dashboards via the
Connected Peers sidebar.
Spatial Validation Mathematical Formalism
1. Geospatial Mesh via H3 Grid
Geographic coordinates are transformed into a single 64-bit integer H3 cell representing a hexagonal region.
The default resolution of 7 covers an average area of 4.3 km² with an edge length of approximately 1.2
km.
Peers are defined strictly as nodes occupying the same cell. Subscriptions extend to the k-ring 1 neighborhood (the 7 immediately adjacent cells) for cross-cell
validation.
2. Node State Machine
Each node in the registry can be in exactly one of three states:
| State | Condition | Role in corroboration |
|---|---|---|
| ALIVE | Received ping within DEATH_TIMEOUT |
Participates as a peer in LOO set |
| FAULTY | Fails spatial corroboration check | Excluded from peer LOO set |
| DEAD | Silent beyond DEATH_TIMEOUT |
Excluded; evicted after EVICTION_TTL |
Any state → ALIVE on next valid ping
(recovery is instantaneous).
3. Pluggable Outlier Detection (Leave-One-Out Corroboration)
When a sensor publishes telemetry, the node triggers a Leave-One-Out
(LOO) test.
For node n reporting value x_n inside cell C, the peer comparison set is:
Corroboration only runs if |P_n| ≥ CORROBORATION_MIN_PEERS (default 3). The
decision rule is pluggable via CORROBORATION_METHOD.
Method: zscore Classic Z-Score
Uses sample mean (μ) and sample standard deviation (σ) over the peer set P_n:
Caveat: μ and σ are non-robust. A single high-variance faulty peer
in P_n
can skew the baseline and mask real outliers. Prefer mad for small cells.
Method: mad Modified Z-Score via Median
Absolute Deviation DEFAULT
Uses the median (m) and the Median Absolute Deviation (MAD) of the peer set, providing a robust estimator unaffected by up to 50% compromised peers:
Modified Z = 0.6745 × |x_n − m| / MAD
The constant 0.6745 scales the denominator to be equivalent to standard Z-scores
under normality.
If the modified Z exceeds ANOMALY_ZSCORE_THRESHOLD (default 2.0), the node status changes to FAULTY.
Method: both AND-Hybrid
A node is marked FAULTY only if both the
zscore and mad methods independently flag it at the
same threshold.
Maximizes precision at the cost of recall highly conservative.
min_peers=4, threshold=2.0. Values: s1=20.1, s2=20.0, s3=20.2, s4=19.9, s5=35.0.
For
s5, peers = {20.1, 20.0, 20.2, 19.9} → median≈20.05,
MAD≈0.10 → Modified Z ≈ 100.3 → FAULTY.
4. ZeroMQ Hybrid Binary Framing
ZeroMQ subscriptions perform spatial topic filtering in clear-text using the H3 cell prefix. The payload is separated by a pipe character and compressed using the selected strategy:
This layout enables edge nodes to leverage ZeroMQ native subscription matching at the socket level without decompressing headers, drastically reducing CPU cycles for unrelated traffic.
5. Spatial Multi-Hop Relaying & Loop Prevention
To extend telemetry propagation beyond direct range (k-ring 1), nodes act as spatial relays by republishing messages under their local topic prefix while keeping coordinates and sender IDs unchanged. To prevent infinite forwarding loops and broadcast storms, the message schema introduces a path vector:
When a node n receives a relayed packet, the loop prevention rule is enforced:
Else if len(relayed_by) ≥ SYNAPSE_RELAY_MAX_HOPS: Discard packet
Else: relayed_by_new = relayed_by + [n] → Republish
6. Historical Duplicate Suppression
To avoid parsing or storing redundant messages propagated from multiple relay paths, the ingestion layer
compares incoming timestamps against the node registry historical cache.
A packet is discarded immediately at the ingest boundary if:
timestamp_incoming ≤ timestamp_registry_last_seen
Flask REST API Endpoint Reference
Each node exposes a versioned JSON REST API at http://<node-host>:8080/api/v1/ (or HTTPS via Caddy on port 8441–844N).
The API is read-only and reflects the local node's perspective of the network not a centralized
view.
SYNAPSE_DASHBOARD_API_KEY is set, requests to /api/v1/* and /metrics require an X-Api-Key header.
The UI will prompt for the key client-side when needed.
| Endpoint | Method | Response | Description |
|---|---|---|---|
| /api/v1/nodes | GET | Array of NodeEntry | All registered nodes with coordinates, last value, and status. Legacy alias: /api/nodes. |
| /api/v1/cells | GET | Dict of Cell Summaries | Per-H3-cell aggregation with alive/faulty/dead counts and centroid. Legacy alias: /api/cells. |
| /api/v1/otaa/enroll | POST | JSON Status Object | Symmetrically exchange and authorize ZMQ CURVE public keys upon discovery. Excluded from dashboard token auth. |
| /api/v1/timeseries | GET | Array of historical readings | Query historical telemetry database. Parameters: node_id, h3_cell, start_time, end_time, limit. Legacy alias: /api/timeseries. |
| /metrics | GET | Prometheus text/plain | Scrapable metrics: message rates, invalid payloads, rate-limited counts, node state gauges. |
| /live | GET | {"status":"ok"} | Kubernetes liveness probe. |
| /ready | GET | JSON Status Object | Readiness probe with nodes_total and nodes_alive counts. |
NodeEntry Schema
| Field | Type | Description |
|---|---|---|
| node_id | string | Unique node identifier. |
| type | string | Sensor type (e.g., "mock", "chaos"). |
| status | string | ALIVE, FAULTY, or DEAD. |
| last_seen | float | Unix timestamp of last received ping. |
| h3_cell | string | H3 index (resolution 7) of the node's location. |
| lat / lon | float | Last known geographic coordinates. |
| last_value | float | Last telemetry reading (shown in °C on dashboard). |
Prometheus Metrics
| Metric | Type | Description |
|---|---|---|
| Synapse_messages_total | Counter | Total valid PING messages processed. |
| Synapse_invalid_payload_total | Counter | Messages dropped due to schema validation failure. |
| Synapse_rate_limited_total | Counter | Messages dropped by the token-bucket rate limiter. |
| Synapse_corroboration_faulty_total | Counter | Total FAULTY transitions triggered by corroboration. |
| Synapse_nodes_alive | Gauge | Current count of ALIVE nodes. |
| Synapse_nodes_faulty | Gauge | Current count of FAULTY nodes. |
| Synapse_nodes_dead | Gauge | Current count of DEAD nodes. |
Example: GET /api/v1/nodes
[
{
"node_id": "node-a1b2",
"type": "mock",
"status": "ALIVE",
"last_seen": 1748389082.5,
"h3_cell": "871fb4670ffffff",
"lat": 45.4642,
"lon": 9.1895,
"last_value": 24.5
},
{
"node_id": "node-c3d4",
"type": "mock",
"status": "FAULTY",
"last_seen": 1748389079.1,
"h3_cell": "871fb4670ffffff",
"lat": 45.4640,
"lon": 9.1890,
"last_value": 999.0
}
]
Example: POST /api/v1/otaa/enroll
Send enrollment requests with a node identifier and public key Z85 string to configure peer authentication dynamically.
{
"node_id": "node-c3d4",
"public_key": "t7.d&F-gV=m]W5hR#c(P/y?Xq+eL*Z@wK8oNU2iv"
}
Example: GET /api/v1/timeseries
Query historical node telemetry readings archived in the local store. Filters: node_id, h3_cell, start_time, end_time, and limit.
[
{
"timestamp": 1748389082.5,
"node_id": "node-a1b2",
"h3_cell": "871fb4670ffffff",
"lat": 45.4642,
"lon": 9.1895,
"value": 24.5,
"status": "ALIVE"
},
{
"timestamp": 1748389079.1,
"node_id": "node-a1b2",
"h3_cell": "871fb4670ffffff",
"lat": 45.4642,
"lon": 9.1895,
"value": 24.1,
"status": "ALIVE"
}
]
Mesh Messaging Protocol & Spatial Relaying
ZeroMQ transmits structured telemetry using lightweight JSON framing. Each message is prefixed with the
sender's h3_cell as the ZMQ topic, allowing subscribers to filter spatially with
zero overhead.
PING Payload Schema
{
"schema_version": 1, // forward-compat version; listener accepts missing as v1
"node_id": "node-a1b2", // resolved from NODE_ID env or hostname
"type": "mock",
"timestamp": 1748389082.12,
"status": "PING",
"h3_cell": "871fb4670ffffff", // also used as ZMQ topic prefix
"relayed_by": ["node-x9y0"], // list of node IDs that relayed this message
"payload": {
"value": 22.45, // required: used in corroboration
"lat": 45.4642,
"lon": 9.1895
}
}
node_id, h3_cell, payload.value) are silently dropped at the ingest boundary.
Dropped payloads increment the Synapse_invalid_payload_total Prometheus counter.
Environment Configuration
| Variable | Default | Description |
|---|---|---|
| SYNAPSE_ZMQ_PORT | 5555 | Port the PUB socket binds to. |
| PING_INTERVAL | 1.0 | Seconds between PING publications. |
| H3_RESOLUTION | 7 | H3 spatial resolution (4.3 km² per cell). |
| SYNAPSE_MAX_CONNECTIONS | 0 (unlimited) | Max active ZMQ SUB connections. Set 8–12 for 50+ node meshes. |
| SYNAPSE_DISCOVERY | zeroconf | Peer discovery mode: zeroconf, beacon,
static.
|
| DEATH_TIMEOUT | 3.0 | Seconds of silence before node → DEAD. |
| EVICTION_TTL | 10.0 | Seconds after DEAD before permanent eviction. |
| CORROBORATION_METHOD | mad | Outlier method: mad, zscore, both. |
| ANOMALY_ZSCORE_THRESHOLD | 2.0 | Score above which a node is flagged FAULTY. |
| CORROBORATION_MIN_PEERS | 3 | Min ALIVE peers required before corroboration runs. |
| RATE_LIMIT_MSG_PER_SEC | 100 | Token-bucket replenish rate per node. |
| RATE_LIMIT_BURST | 20 | Token-bucket burst capacity. |
| SYNAPSE_COMPRESSION | none | Compression strategies: none, zlib, lz4, zstd. |
| SYNAPSE_RELAY_MAX_HOPS | 0 | Hop limit for spatial multi-hop relaying (0 disables relaying). |
| SYNAPSE_OTAA_ENABLED | true | Enable dynamic Over-The-Air Activation key exchange. |
| SYNAPSE_OTAA_TOKEN | synapse-otaa-default | Secret key used to authorize REST key exchange handshakes. |
| SYNAPSE_TIMESERIES_ENABLED | true | Enable local database archiving of node readings in SQLite. |
| SYNAPSE_TIMESERIES_RETENTION_PERIOD | 86400 | History retention window in seconds (defaults to 24 hours). |
| SYNAPSE_TIMESERIES_RETENTION_LIMIT | 1000 | History retention count limit per node. |
| SYNAPSE_REPLICATION_INTERVAL | 30.0 | Seconds between periodic query pull backfills from discovered peers. |
| SYNAPSE_REGISTRY_DB | (none) | SQLite path for node row persistence across restarts. |
| NODE_ID | hostname | Override node identity string. |
| SENSOR_LAT / SENSOR_LON | random (Italy) | Fixed geographic coordinates for the node. |
| SYNAPSE_LOG_FORMAT | text | Log format: text or json (structured).
|
CurveZMQ Security & Caddy TLS Sidecar
Synapse v0.6.0 implements a layered security model: Caddy TLS at the HTTP/dashboard layer, CurveZMQ (Curve25519) with ZAP authentication at the ZMQ data channel layer, and Dynamic OTAA key enrollment.
Layer 1: Caddy TLS Reverse Proxy Sidecar
Every Synapse node in the Docker Compose and Helm deployments is paired with a Caddy proxy sidecar container within the same pod/service. Caddy automatically generates and rotates a self-signed certificate for local development, and can be configured for ACME/Let's Encrypt certificates in production.
Layer 2: CurveZMQ Elliptic Curve Transport Encryption
The ZMQ data channel can be encrypted and authenticated with CurveZMQ (Elliptic Curve Cryptography based on Curve25519). Generate keys and container-specific environment configurations automatically:
Layer 4: Dynamic Over-The-Air Activation (OTAA)
To bypass manual keypair pre-distribution, nodes run symmetrically authorized REST handshakes via POST /api/v1/otaa/enroll upon discovery. Public Curve keys are automatically
registered on the target node, allowing handshake validation at the ZeroMQ ZAP authentication phase.
synapse-admin for HTTP credentials and synapse-otaa-default for enrollment tokens) ensuring deployments are secure
out-of-the-box.
Layer 3: Rate Limiting via Token-Bucket
To mitigate DoS attempts by faulty or flooded nodes, the registry enforces a per-node token-bucket rate limiter:
- Burst Capacity: Maximum burst allowance (
RATE_LIMIT_BURST, default 20 tokens). - Replenish Rate: Token restoration per second (
RATE_LIMIT_MSG_PER_SEC, default 100). - Action: Packets depleting the bucket are dropped and counted in
Synapse_rate_limited_total.
Mesh Node Development & Test Framework
Synapse follows strict TDD practices. The full verification suite ruff auto-fix, pytest, mypy, Helm lint,
and chaos smoke integration runs as a single make verify command.
Running the Full Verification Suite
tests/integration/test_otaa_flow.py PASSED
tests/integration/test_relay_flow.py PASSED
tests/integration/test_timeseries_api.py PASSED
tests/unit/test_timeseries.py PASSED
tests/unit/test_compression.py PASSED
tests/unit/test_corroboration.py PASSED
tests/unit/test_node_registry.py PASSED
... (89 more)
Test Suite Overview
| Test Module | Coverage |
|---|---|
| test_corroboration.py | MAD, Z-score, AND-hybrid, edge cases (zero spread, insufficient peers) |
| test_node_registry.py | State transitions, thread safety, RLock semantics, deep copy returns |
| test_rate_limiter.py | Token bucket drain, replenish, burst enforcement |
| test_zmq_mesh_limits.py | Active connection limits, reserve failover, self-peering filter |
| test_zeroconf_discovery.py | mDNS service registration and peer list resolution |
| test_zmq_curve.py | Curve25519 key generation, ZAP allowlist enforcement |
| test_http_server.py | API endpoint responses, Prometheus metrics, liveness/readiness |
| test_garbage_collector.py | Timeout detection, eviction scheduling |
| test_registry_sqlite.py | SQLite persistence, restart recovery |
| test_peer_discovery.py | Static, beacon, and zeroconf provider interfaces |
| test_event_logger.py | Structured event logging, JSON format output |
| test_main_node.py | Identity resolution, coordinate fallbacks, env parsing |
| test_timeseries.py | SQLite historical logs archiving, filters, SQL-based age/count pruning |
| test_compression.py | Pluggable compression strategies initialization (zlib, lz4, zstd, none) |
| test_compressed_mesh.py | End-to-end ZeroMQ mesh publishing with active compression and decompression |
| test_otaa_flow.py | REST dynamic key exchange handshake and token validation flows |
| test_relay_flow.py | Spatial multi-hop relay topologies, loop prevention, and TTL hop limits |
| test_timeseries_api.py | REST timeseries GET endpoints, filtering parameters, and data retrieval |
Linter & Type Checking
Mesh Ingestion Benchmarking & Performance
Synapse includes a native, container-overhead-free benchmark tool (tools/benchmark.py)
that orchestrates up to 50 in-process simulated nodes via subprocess.Popen with
static peer discovery.
It measures mesh convergence time and aggregate message throughput under intense stress tests.
Key Performance Metrics (N=50 nodes)
SYNAPSE_MAX_CONNECTIONS=8, the bounded mesh converges 17%
faster than a full-mesh at 50 nodes,
while using 84% fewer TCP sockets. The mesh remains fully connected and resilient to
failures the reserve failover mechanism guarantees dynamic re-peering.
Running Benchmarks
Chaos Engineering & Mesh Resilience Testing
Synapse ships two complementary chaos tools: the Chaos Monkey
(tools/chaos_monkey.py) for application-level failure injection,
and Pumba for kernel-level network degradation via tc/netem.
Chaos Monkey Application-Level Failure Injection
KILL MODE
Randomly terminates running Docker sensor containers via SIGKILL. Validates
that the mesh marks them DEAD after DEATH_TIMEOUT and that the reserve failover reconnects surviving peers.
ANOMALY MODE
Broadcasts well-formed PING messages with deliberately extreme values (e.g., 999.0 °C). Tests whether
the H3 spatial corroboration immediately flags rogue nodes as FAULTY.
FLOOD MODE
Floods the ingestion port with malformed payloads and high-velocity packet bursts. Tests schema validation isolation, rate limiter enforcement, and parser stability under storm conditions.
Pumba Network-Level Chaos (Latency & Packet Loss)
Pumba intercepts the network stack of node containers and injects degradation via the Linux kernel's tc/netem subsystem.
This validates the ZeroMQ P2P mesh's resilience to physical network impairment.
| Parameter | Default |
|---|---|
| Target containers | All matching docker-node-* |
| Network latency | 200ms ± 50ms jitter |
| Packet loss | 15% |
| Degradation blocks | 1 min degraded / 2 min normal (cyclic) |
Edge Deployment & Kubernetes Helm Charts
Option 1: Docker Compose (Local / Development)
The Makefile wraps all Docker Compose operations and auto-detects rootless
Podman sockets.
A 4-node mesh with Caddy sidecars starts in seconds:
Option 2: Kubernetes via Helm (Edge Production)
For production deployment on physical edge clusters (K3s, MicroK8s), Synapse provides an official Helm chart implementing a DaemonSet topology guaranteeing exactly one Synapse instance per physical node:
Exactly one Synapse pod per physical edge device. Complements the decentralized P2P architecture perfectly each device runs an independent mesh participant.
Each pod includes a Caddy reverse proxy sidecar for TLS termination. Caddy config injected via ConfigMap.
Node registry persists to a local hostPath volume (default /var/lib/synapse/data).
Survives pod restarts without a distributed database.
Helm Chart: Key Values (charts/synapse/values.yaml)
| Key | Default | Description |
|---|---|---|
| image.repository | ghcr.io/onyks-os/synapse-node | Docker image for the Synapse node. |
| image.tag | latest | Image tag (pin to a release in production). |
| persistence.hostPath | /var/lib/synapse/data | Absolute path on the edge device for SQLite storage. |
| caddyfile | (inline) | Raw Caddy configuration string injected via ConfigMap. |
| node.logFormat | text | text or json structured logging. |
CI/CD Pipeline & Automated Testing
Synapse uses GitHub Actions for fully automated quality assurance and release publishing. No secrets are stored PyPI publishing uses OIDC Trusted Publishing.
- Static analysis:
mypystrict type checking +rufflinting - Unit testing:
pytest(97 tests) - Helm chart linting:
helm lint charts/synapse - Chaos smoke integration: spins up a full Docker Compose topology, runs
tools/ci_chaos_smoke.pyto inject ZMQ anomalies and verify the mesh survives the attack
- Multi-arch Docker images: Builds
linux/amd64+linux/arm64via QEMU and pushes to GHCR (ghcr.io/onyks-os/synapse-node) - PyPI publication: Builds
sdist+wheeland publishes via OIDC Trusted Publishing zero stored secrets
| Published Artifact | Registry | Architectures |
|---|---|---|
| synapse-node Docker image | ghcr.io/onyks-os/synapse-node | linux/amd64, linux/arm64 |
| synapse Python package | PyPI (pypi.org/project/Synapse) | any (pure Python) |
Synapse Project Roadmap & Future Development
Synapse is an evolving research project exploring edge ingestion paradigms.
V1 PROOF OF CONCEPT
COMPLETECore Python ingestion, ZeroMQ PUB/SUB binding, in-memory NodeRegistry, Z-score anomaly detection, primitive status updates, Docker Compose deployment.
V2 SYMMETRIC P2P MESH & SECURE RUNTIME
COMPLETE (v0.2.0)Symmetric P2P mesh with ZTP (mDNS/Zeroconf), Active Connection Management with dynamic reserve failover, self-peering filter, MAD robust outlier detection, CurveZMQ mutual authentication, token-bucket rate limiting, Caddy TLS sidecar, glassmorphic operator dashboard (Leaflet, radial gauge, Chaos console), Kubernetes Helm DaemonSet chart, SQLite registry persistence, 80-test suite, GitHub Actions CD (multi-arch GHCR + PyPI OIDC), native benchmark suite, Pumba network chaos.
V3 COMPRESSION, RELAYING & TIMESERIES
COMPLETE (v0.6.0)Pluggable payload compression strategies (zlib, lz4, zstd), spatial multi-hop relaying with loop prevention path vectors, dynamic Over-The-Air Activation (OTAA) symmetrically enrolling keys via Flask, secure by default fallback modes, and local SQLite timeseries storage archiving post-corroboration readings with automated background garbage collection pruning.
V4 WASM PREDICTIVE RUNTIMES
IN DEVELOPMENTMigrating outlier and anomaly models into WebAssembly (WASM) modules to enable sandboxed cryptographic computation directly on microcontroller layers. Payloads signed at the sensor core before transmission, enabling tamper-evident telemetry without a PKI server.