Sold out online, still selling in-store.
A nightly sync means channels disagree for hours. A stream means every channel sees the same count within moments of the sale.
Rules and margins, applied in-flight
Ingest competitor feeds, demand signals and stock levels as streams. Rule stages encode your floors, margins and brand constraints deterministically; an LLM stage can review only the sensitive moves. New price out as an event — to web, app, marketplace and shelf-edge at once.
One live count per SKU, every channel
Keyed state per SKU maintains a live position, updated by every order, return and stock move the moment it happens. A stream-stream join correlates an order with its fulfilment; thresholds fire reorder and stop-sell actions before the oversell, not after.
Decide on the session, in the session
Window the live clickstream per visitor — views, carts, hesitations — and hand the enriched context to a rule stage for the obvious (abandoned cart, back-in-stock) and an LLM for the judgment calls. The response reaches the shopper while the tab is still open.
Channels subscribe — they don't sync
Web, app, store systems, marketplaces: each is a subscriber to the same topics, not a copy waiting for tonight's job. E-commerce platforms plug in through webhook sources; ERPs and legacy stores through JDBC and files; whatever remains, through the HTTP API.
Why it holds up
Built for peak-season reality.
Retries ≠ double orders
Dedup by key and idempotency guards absorb webhook retries and flaky networks — a resent event doesn't decrement stock twice.
Event-time truth
Windows follow when things happened, watermarks handle stragglers, and genuinely late events land in a DLQ instead of silently corrupting counts.
Recoverable state
Per-agent offsets and checkpointed window state survive a restart — your inventory position doesn't reset because a node did.
What it looks like
A live inventory guard is one file.
Orders and stock moves merge into one keyed position per SKU; thresholds act before the oversell.
1# pulse.yaml — inventory guard
2source:
3 kind: webhook # orders + stock moves in
4
5stages:
6 - name: position
7 engine: streaming
8 operators:
9 - aggregate:
10 keyBy: sku
11 fields:
12 sold: sumWhere(type == 'order')
13 received: sumWhere(type == 'restock')
14
15 - name: guard
16 engine: rule-based
17 rules:
18 - "received - sold < safety_stock"
19
20 - name: act
21 engine: mcp
22 mcpTools: [ commerce.setAvailability ]
23
24sink:
25 kind: webhook # ops alerting
26 url: ${secret:OPS_WEBHOOK}
27- 1
Scaffold.
pulse new inventory --source webhook --stage streaming:position --stage rule-based:guard --stage mcp:act --sink webhook - 2
Point your platform at it.
Register the webhook URL in your commerce platform — orders and stock events flow in as they happen.
- 3
Deploy & watch.
pulse deploy . && pulse events tail --topic inventory.guard.outEvery low-stock decision, live.
- 4
Let channels subscribe.
Web, app and store systems read the same topics via the API or SSE — no more nightly sync.
Sell the last unit once.
See orders and stock merge into a live position in minutes — no install, no signup. Then self-host it next to your stack.
Pulse is free and self-hosted. Multi-node HA, geo-replication and governance come with StreamFlow Enterprise.