Causal Block
A typed pattern for ordering events across a distributed system when wall-clock time alone is not enough. Each call returns a Hybrid Logical Clock (HLC) tuple (physicalMs, logical, nodeId) strictly greater than any tuple the node has previously issued or merged — even within the same millisecond, even when the local clock is briefly behind.
HLC is prior art. The algorithm was published by Kulkarni, Demirbas, Madappa, Avva & Leone in 2014; we don't claim it. What we expose is a hosted, per-customer, tier-gated HLC surface whose physical-ms floor is sourced from the same Spiral-anchored, NTP/NTS/PTP-disciplined clock that powers every /v1/spiral response — the Spiral coupling is the anchored clock described in the patent pending Spiral provisional.
Standard+ tier covers /v1/causal/now and /v1/causal/merge; Pro+ adds the pure partial-order /v1/causal/compare. Metered separately from the snippet / briefing / deep meters at $0.001 per op (default; configurable per deployment).
Wiring it without forgetting
The two-call shape (now on send, merge on receive) is small, but the accuracy of every later compare depends on every receiver actually calling merge on every stamped message it gets. The recommended pattern is to wrap your message bus once — in one file — so per-call sites can't forget.
// fleet.ts — written once, used everywhere
import { TemporalBlock } from "temporalblock";
const tb = new TemporalBlock({ apiKey: process.env.TEMPORALBLOCK_API_KEY! });
const NODE_ID = process.env.NODE_ID!;
export async function publish(topic: string, payload: object) {
const { hlc } = await tb.causal.now({ nodeId: NODE_ID });
return bus.publish(topic, { ...payload, _causal: hlc });
}
export async function subscribe(
topic: string,
handler: (msg: any) => Promise<void>,
) {
return bus.subscribe(topic, async (msg) => {
if (msg._causal) {
await tb.causal.merge({ nodeId: NODE_ID, remotes: [msg._causal] });
}
return handler(msg);
});
}The SDK also ships auto-merge adapters for the most common transports — drop them in instead of writing the wrapper yourself:
tb.causal.fetch({ nodeId })— fetch-shaped wrapper that stamps outgoing requests inX-Causal-Stampand merges any stamp on the response.tb.causal.expressMiddleware({ nodeId })— Express middleware that merges the inboundX-Causal-Stampheader before your handler runs.tb.causal.wrapHandler({ nodeId, extract }, handler)— generic wrapper for any message bus (Kafka, MQTT, ROS 2, NATS) — you supply a tinyextractfunction that returns the stamp from your message shape.
All three are pure SDK glue — they hit the same /v1/causal/{now,merge} endpoints you'd call by hand, billed identically.
Temporal Spiral is patent pending — U.S. Provisional Application No. 64/065,213 (filed 2026-05-14).