Signal conditioning, transformation, and routing in a NATS-native message processor.
monoblok speaks NATS. Point your existing publishers at it, declare the processing rules you need, and let subscribers consume clean, actionable subjects, instead of each having to make sense of raw noise.
Fix noisy input streams once, not in every subscriber.
It is not uncommon for systems to contain some caretaker services that subscribe to ingress NATS subjects to clean up and republish a raw stream before the real business starts. This might include rounding, dedup, deadband, JSON demux, OHLC bars, threshold alerts and so on. High velocity or miniscule changes don't always have value downstream. monoblok lets you declare that tidying work once, leveraging efficient implementations of common tasks as rules at the broker, instead of writing rounding logic N times in N services.
Declare it once, as rules, at the edge.
monoblok speaks NATS. Point your NATS clients at it and the conditioning happens on the way through. Rules live in patchbay, a small DSL. A walked example lives in patchbay.edn. You can also write patchbay files as YAML.
patchbay also lends itself well to help from coding assistants.
- Standalone broker: clients connect directly to monoblok for lightweight NATS-core pub/sub with signal conditioning built in.
- Signal conditioning front door: publishers send raw events to monoblok, monoblok cleans them, then forwards selected subjects to a real NATS cluster.
- Tap into existing NATS: monoblok subscribes to selected subjects on a real NATS cluster, treats them as private patchbay input, then emits only the cleaned or derived subjects your rules choose.
monoblok is written in C with libuv and builds on Linux and macOS. It aims to be simple, lightweight and fast, even on entry level/shared hardware. Smoke tests and load checks are part of the build; dedicated benchmark helpers live in scripts/. The saved benchmark runs span up to 2-18 million msgs/sec across a 2-core ARM VPS, an 8-core x86_64 VPS, and an Apple Silicon M4 Mac mini for simple publish and fan-out workloads. Treat those numbers as directional samples/trends and not capacity promises in the real world. See running tests for tests that exercise the router and parser without network.
tinyblok is an implementation for microcontrollers relaying cleaned sensor data into NATS.
See Overview, Patchbay, and the runnable files in examples/ to better get a feel. Also, there's the introductory blog post and friends.
curl -fsSL https://raw.githubusercontent.com/lexvicacom/monoblok/main/scripts/start.sh | bashThe release helper downloads the latest monoblok (macOS/Linux) and extracts it into the current directory. To run the unpacked binary:
./monoblok-*/monoblok --port 14222 --patchbay ./monoblok-*/patchbay.ednThe directory contains runnable examples. Run the .sh files.
To add as a service on systemd Linux, run scripts/install-systemd.sh.
Multi-arch image:
docker run --rm -p 14222:14222 ghcr.io/lexvicacom/monoblok:latest --port 14222cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/monoblok --port 14222 --patchbay patchbay.ednCompiles cleanly on macOS and Linux. Dependencies are vendored. System openssl required.
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failureFast integration smoke:
cmake --build build --target smokesmoke runs the TCP server smoke, patchbay soundcheck, load-smoke, and
the larger load-soak profile.
The subchecks can also be run directly:
cmake --build build --target soundcheck
cmake --build build --target load-smoke
cmake --build build --target load-soakload-smoke starts a temporary daemon and verifies exact TCP fan-out plus
derived moving-avg, moving-sum, and count! streams. load-soak runs the
same check with a heavier subscriber/message profile.
Benchmark helpers are separate from the test targets because they depend on the
NATS CLI, and the comparison script uses nats-server when available:
scripts/bench.sh
scripts/bench-with-nats-server.shSaved sample output lives in bench-results/. On Linux these
scripts default to monoblok's opt-in libuv io_uring path to match the saved
runs; pass --epoll to benchmark the production-default epoll path.
I've been doing this for a while - while the same-old problems monoblok solves may not be readily apparent - it's simple - it is just rounding numbers and doing basic stats ... those with battle scars are hopefully nodding along. My company can provide services around monoblok. I'd be happy to learn about your environment, requirements and work with you on a proof of concept, case study or complete solution. Drop me a line.
It's 2026, Claude and Codex help a lot. All code is reviewed and iterated upon before being merged.
Personal note: I had a stroke in Dec 2025 and have oddly adapted to typing with one finger with my left hand. I'd probably have given up without these tools, during my recovery. Five months on my typing has got better but it is still error prone. Think this may be as good as it gets!
MIT. See LICENSE.