Skip to content

lexvicacom/monoblok

Repository files navigation

monoblok

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.

Rationale

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.

monoblok round and squelch demo

Common ways of running monoblok:

  • 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.

Tiny and fast

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.

Read more

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.

monoblok deployment modes

Run it

Binary

curl -fsSL https://raw.githubusercontent.com/lexvicacom/monoblok/main/scripts/start.sh | bash

The 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.edn

The directory contains runnable examples. Run the .sh files.

To add as a service on systemd Linux, run scripts/install-systemd.sh.

Container

Multi-arch image:

docker run --rm -p 14222:14222 ghcr.io/lexvicacom/monoblok:latest --port 14222

Build

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/monoblok --port 14222 --patchbay patchbay.edn

Compiles cleanly on macOS and Linux. Dependencies are vendored. System openssl required.

Running tests

cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure

Fast integration smoke:

cmake --build build --target smoke

smoke 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-soak

load-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.sh

Saved 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.

Support

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.

AI

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!

License

MIT. See LICENSE.