Pollen 🟢 Ported to Amalgame — package v0.3.0

Pollen

Amalgame's peer-to-peer data bus + declarative workflow orchestrator. No central broker, no ZooKeeper cluster, no SPOF — every node talks directly to the others, and they all read the same workflow.json on a shared network mount to know what to do at each step. Sister project to Mosaic: where Mosaic handles your inbound HTTP traffic, Pollen distributes data between your services and coordinates their processing.

Why "Pollen"

Pollen travels without a central coordinator: carried from flower to flower by autonomous carriers, it transports the most valuable thing to propagate — genetic information. Each carrier knows where to go, the pollen knows what to become. That is exactly the execution model we're building: autonomous nodes that emit and receive directly, on a network where coordination lives in the shared data (the workflow.json), not in a conductor.

Done: the Amalgame port has shipped

Pollen was a Node.js prototype (TARMeule). It is now an Amalgame package, amalgame-pollen v0.3.0 — reusable, installable via amc package add pollen, validated by ~200 test assertions. Three repos make up the product:

  • amalgame-pollen (v0.3.0) — the official AM library: transport, capability registry, and the v3 workflow engine. Embeddable in a Mosaic app or any AM program.
  • pollen — a reference CLI binary (TCP transport), ported from the TARMeule prototype.
  • pollen-manager — the workflow.json web editor + executions dashboard (Mosaic app, in progress).

Two layers: a peer-to-peer bus and a workflow orchestrator

Pollen doesn't look like RabbitMQ, Kafka or NATS — which are all central brokers. Pollen is closer to a mix of ZeroMQ (for transport) and Argo Workflows (for orchestration), but fully decentralized:

  • Transport — the amalgame-pollen package uses long-lived TCP connections, newline-delimited JSON (one message = one line), with an application-level ACK. Direct node to node, no broker in between.
  • Coordination — a workflow.json file (schema pollen/v3) on a shared network mount. It describes the actions (abstract topics) and the entries (who reacts to what, and how). Each server reads the file, identifies its role and runs its part.

The workflow.json is the orchestrator. There is no "orchestrator" process to run. The file is declarative, the nodes are autonomous — each one knows what to do at every step.

When to use Pollen

  • Local network / LAN — IoT, SCADA, industrial sensors, factory supervision
  • Distributed processing pipelines — a transformation chain (acquisition → filtering → aggregation → archiving) across several machines
  • Symmetric topologies — no client/server relationship, every node emits and receives
  • Zero infra to provision — no dedicated VM, no Docker compose for a broker, no workflow server
  • Orchestration in the data — changing the topology = editing one JSON file, no redeploy
  • Resilient to network breaks — a node that comes back re-reads workflow.json and resumes its place

workflow.json v3 — the declarative orchestrator

The core idea: no process decides who does what. The decision lives in a JSON file dropped on a shared network mount (NFS, SMB, cluster share). The pollen/v3 schema brings a real control-flow engine — no longer just a static DAG.

// workflow.json — example: a temperature processing chain
{
  "schema":  "pollen/v3",
  "name":    "telemetry-pipeline",
  "version": 1,

  // actions = abstract topics, resolved via the capability registry
  "actions": {
    "filter":  { "topic": "temperature.filtered" },
    "archive": { "topic": "temperature.archive" },
    "alert":   { "topic": "ops.alert" }
  },

  // entries = handlers triggered by an incoming topic
  "entries": [
    {
      "name": "main",
      "on":   "temperature.raw",
      "do": [
        { "type": "call", "action": "filter" },
        { "type": "if", "cases": [
            { "when": "msg.data.value > 80",
              "do": { "type": "call", "action": "alert", "mode": "all" } },
            { "else": true,
              "do": { "type": "call", "action": "archive" } }
        ] }
      ]
    }
  ]
}

The v3 engine is a tree-walker that runs a sequence of typed steps:

  • call — invoke an action; mode: "one" | "all" (one provider or all), on_error: "fail" | "log" | "drop"
  • if — first-match branching (cases with when + else: true)
  • for / while — iterate a list, loop bounded by maxIter
  • set — mutate execution state via a CEL-lite expression
  • goto + anchor — jump between entries (with params / returns, call stack up to 64 frames) and a named resumption point for retry patterns

Changing the topology = editing one JSON file. The loader validates the schema (undefined entries, goto cycles, anchors, expression syntax) before execution.

Amalgame API — a node that follows the workflow

The server-side app is minimal: declare your role and the shared dir, load the v3 workflow, advertise your capabilities, then block in the listen loop. Pollen handles the rest (v3 dispatch, routing to providers, load balancing).

namespace App
import Amalgame.Pollen

public class Program {
    public static void Main(string[] args) {
        Pollen.WorkflowSetSharedDir("./shared")
        Pollen.WorkflowSetSelf("filter-1", "127.0.0.1", 5000)
        Pollen.WorkflowLoadV3("./shared/workflow.json")

        // Advertise this node's capabilities + read the others' registry
        Pollen.StartCapabilityWriter("filter-1", "127.0.0.1", 5000)
        Pollen.StartCapabilityReader()
        Pollen.SetLoadBalance(true)        // registry-resolved forwarding

        Pollen.StartListener(5000)         // TCP loop: receive, v3 dispatch, re-emit
    }
}

Inject a message into the workflow from the outside (a sensor, a Mosaic app, a script):

// fire-and-forget
Pollen.Publish("proc-01.lan", 5000, "temperature.raw", 1, dataJson)

// wait for the application-level ACK (timeout in ms)
Pollen.PublishSync("proc-01.lan", 5000, "temperature.raw", 1, dataJson, 2000)

Shipped bricks (from the TARMeule prototype)

The Node.js prototype (github.com/BastienMOUGET/TARMeule) served as the functional reference. Here's what v0.3.0 actually implements:

shipped

TCP transport + ACK

TCP connections, JSON envelopes one per line (messageId, type, topic, data, timestamp), application-level ACK. TCP guarantees ordering and no in-stream duplicates.

shipped

v3 workflow engine

JSON → AST loader, validator (8 rules), tree-walking dispatcher. Steps call / goto / anchor / if / for / while / set.

shipped

CEL-lite expressions

Lexer + Pratt parser + evaluator. Arithmetic, comparisons, booleans, in, ternary; builtins len, int, float, string, contains, startsWith… Paths state.X, params.Y, msg.data.Z.

shipped

Capability registry + load balancing

Each node advertises its actions in capabilities/. The workflow's actions are resolved at runtime to a concrete provider, with a power-of-two-choices load balancer.

shipped

State + execution tracing

Per-execution state persisted atomically in sharedDir/state/. Every hop is recorded in sharedDir/executions/ — the basis of the manager's live dashboard.

v0.4.0

AES-256 encryption

Optional packet encryption (shared key), planned for v0.4.0 once amalgame-crypto stabilizes. Today: cleartext JSON payload (trusted network).

Pollen Manager — the visual editor

pollen-manager is a Mosaic application (served on :3000) that reads/writes workflow.json and surfaces the live executions each node writes into sharedDir/executions/. It is not a control plane: Pollen stays choreography-based (every node knows its part) — the manager edits the score and visualizes runs.

  • REST API GET/PUT /api/workflow (read/write + validation), /api/executions, /api/capabilities, POST /api/inject
  • SVG DAG render + v3 workflow flowchart
  • Drag & drop editor, live execution overlay on the graph, SYNC broadcast on save — in progress

Status: v0.1.0-dev, phase 4.0 scaffold. The build is temporarily blocked by an Amalgame packager limitation (classes in sibling sources files aren't linked yet) — tracked upstream in the compiler.

Why it was ported to Amalgame

The Node.js prototype was functional but heavy to deploy on the target devices (sensors, industrial gateways, PLCs): Node.js and its ~50 MB runtime, process keep-alive, npm install… The AM port gives:

  • A single native binary — a few MB, starts in milliseconds
  • No runtime to install — deployable on Raspberry Pi, Linux PLCs, Windows embedded
  • Bounded RAM, no Node.js GC pauses — predictable real-time behavior
  • Reusable — a package, not a frozen binary: embeddable in a Mosaic app (HTTP → Pollen bridge)
  • amalgame-service integration — systemd daemon or native Windows service (upcoming)
  • Encryption via amalgame-crypto — will share the AES code of the rest of the ecosystem (v0.4.0)

Roadmap

v0.1 → v0.3

The core (shipped)

TCP transport + ACK, v3 workflow engine (tree-walker + 8 validation rules), CEL-lite expressions, capability registry + power-of-two load balancing, per-execution state + tracing.

v0.4

Security & observability

AES-256 encryption (shared key) via amalgame-crypto. Prometheus metrics. Richer schema validation on emit/receive.

v0.5+

QoS & Mosaic bridge

Configurable QoS modes (fire-and-forget / ack-required / at-least-once) per action. Re-landing the Mosaic bridge (expose a Pollen topic as a WebSocket, and vice versa) to wire a web dashboard to sensors.

v1.x

Identity & mature manager

Public-key authentication (Ed25519) + per-topic ACLs. Manager: drag & drop nodes, live execution overlay, manual intervention (force-ACK, replay).

What Pollen is not

  • Not a durable broker — no persistent queue, no Kafka-style replay. A missed message is lost (unless retried within the ACK window).
  • Not a full Temporal / Argo Workflows — the v3 engine does control flow (if/for/while/goto + state), but no durable execution history, no transactional saga with rollback.
  • Not multi-datacenter — designed for LAN or VPN-LAN. Not meant to cross the open Internet.
  • Not a Mosaic replacement — to expose a web API to clients outside the LAN, that's Mosaic.
  • Not a transactional MOM — no cross-topic atomic transactions, no dead-letter queue, no global ordering guarantees.

For those cases, the ecosystem offers the right third-party tools: Kafka for durable replay, RabbitMQ for transactional workflows, MQTT for broker-centralized IoT. Pollen plays in the "real-time LAN pipeline, no broker, no orchestration server" slot.

Try Pollen

Pollen is ported to Amalgame (package v0.3.0) and usable. The visual manager and AES encryption follow.