Telamin architecture

Event processing as a compiled artifact
Not an interpreted topology

Telamin treats an event-processing graph the way the JVM treats bytecode: as something to be compiled ahead of time, inspected, and executed deterministically. The result is a stack where audit, replay, debugging, and LLM-authoring fall out of one design decision — compile the processor.

This page walks the six layers of that stack — authoring, compilation, artifact, server, plugins, workflow — and states, at each layer, what you get and what a traditional stream framework, ESB, or actor system does instead.

The trade-off you've been asked to live with

Event-processing stacks force you to pick two of three.

Speed, safety, and flexibility. Pick a stream framework and you give up audit. Pick a cluster framework and you give up developer ergonomics. Pick an ESB and you give up determinism and latency. The triangle is forced by interpreting the topology at runtime.

Speed

Raw threads, lock-free queues, microsecond latency. But no audit trail. You can't reproduce a production bug, and you can't show a regulator what happened.

Safety

Heavyweight cluster framework. Snapshots, exactly-once, replay. But the code path is opaque, the dependencies are vast, and "step through" doesn't apply.

Flexibility

Orchestrator-of-orchestrators (Camel, Spring Integration, NiFi). Composable, but you give up deterministic ordering and performance.

Telamin's premise

Compile the processor and the triangle collapses. The artifact is fast (no reflection, no virtual dispatch through framework interfaces). It is safe (deterministic dispatch, byte-exact replay, audit-by-construction). And it is flexible (authored as plain Java, DSL, Spring XML, YAML, or LLM-emitted bean defs — same compiler, same artifact).

The full stack

Six layers, one artifact at the centre.

Authoring flows down into the compiler. The compiler emits an artifact that runs unchanged in every environment from unit test to production. The server and plugins are deployment-shape concerns layered around that artifact, not coupled to it.

The Telamin stack — authoring, compile, artifact, server, plugins, workflowFive authoring channels feed Fluxtion. The compiler emits three artifact shapes — Java source, GraphML, and bytecode. The bytecode artifact runs inside Mongoose, which hosts agents, dispatchers, and pluggable connectors, services, and libraries. The workflow layer wraps the whole thing with tests, debugger, and replay.LAYER 1 · AUTHORINGPlain Java@OnTrigger POJOsDSL builderFlowBuilder chainSpring XMLbean definitionsYAML configdeclarativeLLM-emittedbean defs (provisional patent)LAYER 2 · COMPILATIONFluxtion compilergraph analysis · dispatch order · code-genLAYER 3 · RUNTIME ARTIFACTGenerated .javareadable in IDE · step debuggerGraphMLcytoscape / yEdCompiled .classruns in any JVM, deterministic dispatchLAYER 4 · MONGOOSE SERVERMongoose server — agent-hosted dispatcherAgrona AgentRunner · single-writer sinks · @ServiceRegistered injection · lifecycle hooksthe .class from layer 3 boots unchangedLAYER 5 · PLUGINSConnectorsaeron · chronicle · file · kafka · multicastServicescache · jdbc · admin-rest · loadersLibraries & test supportjson-serialiser · test-supportLAYER 6 · WORKFLOW · plain JUnit · IDE step debugger · file-tap replay · audit log
Layer 1
Authoring

Five authoring shapes, one compiler.

Authoring is decoupled from runtime. The Fluxtion compiler accepts a logical model of the graph in five shapes: plain Java POJOs (the common case), a fluent DSL builder, Spring XML bean definitions, YAML config, or anything else that emits compatible bean definitions — including from an LLM. The same compiler accepts all five and produces the same artifact.

// plain Java — most common authoring shape
public class FilterAndForward {

    private final PriceSink sink;

    public FilterAndForward(PriceSink sink) {
        this.sink = sink;
    }

    @OnEventHandler
    public boolean onPrice(MarketTick tick) {
        if (tick.isStale()) return false;     // no propagation
        sink.publish(tick);
        return true;                           // notify downstream
    }
}
What you ship
  • POJO with one annotation. No framework interface to inherit.
  • Unit-testable with plain JUnit — no special harness for node-level tests.
  • Same node compiles whether authored from Java, DSL, XML, YAML, or an LLM-emitted bean def.
TelaminStream framework / ESB
Same processor, five authoring shapesOne framework, one DSL
Plain POJOs, no framework inheritanceTopology DSL coupled to runtime
LLM, GUI, XML, YAML all hit the same compilerAuthoring tool change = topology rewrite
Layer 2
Compilation

The compiler computes dispatch order. The runtime never has to.

Fluxtion analyses the bean graph at build time. It walks the trigger annotations, resolves the dependency edges, detects cycles, and emits a fixed-shape Java source file. The dispatch order is a property of the compiled artifact — not a runtime decision recomputed per event.

Compile time
Bean defs+ annotationsFluxtion compilertopology analysisdispatch ordersource generation.javaGraphML.class
Runtime — what's on the dispatch path
Event inCompiled .classhandler 1 (direct call)handler 2 (direct call)handler 3 (direct call)Event out
TelaminStream framework / cluster
Dispatch order computed at compile timeReflective dispatch every event
Diagram generated from same analysisArchitecture diagrams rot in Confluence
Topology errors caught by the compilerTopology errors surface in production
Layer 3
Runtime artifact

The artifact is the same model in three shapes — readable, visualisable, runnable.

One compile pass produces three outputs: a generated Java source file (open it in your IDE; it is plain code), a GraphML diagram (the structure auditors and architects look at), and a compiled class (what the JVM actually runs). They cannot drift: they are derived from the same analysis.

.java source

A single readable file. Set a breakpoint on the dispatch line, step through, watch the events flow. The framework is not in the way; there is no framework.

GraphML diagram

Open in yEd or Cytoscape. The picture is the picture of the code — generated from the same graph analysis. Auditors get a diagram that cannot lie about what runs.

.class bytecode

Drop into any JVM. Lambda, embedded app, regulated host, container — same artifact. No framework runtime required. Mongoose is one host; not the only one.

Audit-by-construction

Because dispatch order is a fixed property of the artifact, every event has a single deterministic causal chain through the graph. You don't have to instrument log lines to know what happened — the dispatch order is the trace. Capture the input event log and re-feed it; processor state is bit-identical to the production run. That is what makes Telamin viable in regulated work where reproducibility is mandatory, not a perk.

TelaminStream framework / cluster
Single deterministic causal chain per eventCorrelate across distributed logs
Bit-exact replay from input event logSavepoints + prayer
Step debugger lands in your codeTen frames of framework first
Layer 4
Mongoose server

Mongoose is the production wrapper. The processor doesn't know it's there.

Mongoose hosts the compiled processor on an Agrona AgentRunner, serialises sink writes (single-writer by contract), and exposes a @ServiceRegistered injection point for cross-cutting services. Same processor in unit test, integration test, simulation, and production — the only thing that changes is which plugins are wired up.

SOURCES (agent threads)connector-kafkaagent · poll loopconnector-aeronagent · IPC subscriptionconnector-fileagent · tail loopMongoose dispatcherAgrona AgentRunner · single threadCompiled processor (.class)deterministic dispatch · @OnTrigger chaininit · start · doWork · tearDownsingle-writer to sinks · serial dispatchSERVICES (@ServiceRegistered)svc-cachein-memory or JSON-backedsvc-jdbcHikariCP poolsvc-admin-restJavalin · basic authSINKS (single-writer by dispatcher contract)connector-chroniclebinary tapconnector-fileJSON log · rotationconnector-aeronarchive · downstream IPC
Threading model

One agent per source / sink / service. The dispatcher itself is one agent. Reasoning about concurrency is local — everything an agent sees, it sees on its own thread.

Lifecycle

Four hooks: init, start, doWork, tearDown. Clear ordering, idempotent teardown. Not Spring's seven overlapping stages.

Service injection

Annotate a setter with @ServiceRegistered. Type-matched against the service registry at boot. Swap implementations by YAML config; the processor is unchanged.

TelaminSpring Boot / Akka / cluster framework
Compiled artifact runs in any JVMTopology owned by the cluster
Four lifecycle hooks, clear semanticsSeven overlapping Spring stages
Single-writer sinks by dispatcher contractConcurrent modifications, opaque threading
Layer 5
Plugins

Plain Java POJOs. One Maven module each. No SPI ceremony.

A plugin is a POJO that extends one of three abstract base classes, overrides two or three methods, and ships in its own Maven module. Drop the jar on the classpath, reference the class in YAML or Java config, and it boots. No annotation processor, no buildtime compiler plugin, no framework SPI to register against.

Event source — agent-hosted
public class MyEventSource
        extends AbstractAgentHostedEventSourceService<MyEvent> {

    public MyEventSource() { super("my-source"); }

    @Override public void onStart() { /* open */ }

    @Override public int doWork() {
        int published = 0;
        while (hasNext()) {
            output.publish(nextEvent());
            published++;
        }
        return published;
    }

    @Override public void tearDown() { /* close */ }
}
Message sink — single-writer by contract
public class MySink
        extends AbstractMessageSink<MyEvent>
        implements Lifecycle {

    @Override public void init() { /* open */ }

    @Override
    protected void sendToSink(MyEvent value) {
        // dispatcher guarantees single-writer here
        write(value);
    }

    @Override public void tearDown() { /* close */ }
}
Connectors

aeron · chronicle · file · kafka · multicast. Each is its own module with only its own deps. Pick what you need.

Services

cache · jdbc · admin-rest · admin-telnet · loader-yaml · loader-spring. Injected by type, swapped by config.

Libraries

json-serialiser · test-support. Test support gives you a five-line integration test that boots a real server. No TestContainers, no Docker.

TelaminSpring Boot starters / Quarkus extensions
One Maven module per plugin, deps you chooseStarter pulls 50 transitive deps
Extend abstract class, override two methodsBuildtime compiler-plugin authoring
Drop jar on classpath, reference in YAMLSPI registration + framework boilerplate
Layer 6
Developer workflow

Plain Java tooling at every step. The compiler does the work.

No new IDE, no new build system, no new test runner. Write a processor as a Java POJO. Maven compiles it (the Fluxtion compiler emits the dispatcher as a side-effect of normal mvn package). Test it with the harness. Debug it with the IDE. Replay a captured event log to reproduce a production bug locally.

WritePOJO + annotationCompilemvn packageTestJUnit + harnessRunMongooseServerDebugstep .javaReplayre-feed event logdebug / replay feed back into writeNo framework cluster boot. No 30-second test container. No "step through DispatcherServlet" to find your code.Plain Java tooling, end to end.
TelaminStream framework / cluster framework
Five-line integration tests, real server@SpringBootTest 30s container boot
Reproduce prod bug from captured event logRestore cluster snapshot, diverge anyway
Plain JUnit, plain Maven@SpringBootTest / @QuarkusTest / dev-mode
LLM-friendly architecture

The LLM authors. The compiler enforces determinism.

Spring XML and YAML are not just human authoring shapes — they are the carrier for LLM-emitted logic. The LLM does what LLMs do (synthesise from intent). The compiler does what compilers do (enforce invariants). The result is an event processor that is auditable and replayable even though it was authored by a non-deterministic model. This pattern is the subject of a provisional patent.

Human intentdomain promptLLMprobabilisticSpring XML / YAMLbean definitionsFluxtion compilerenforces invariantsdeterminism · audit · replayDeterministicartifact.class · audit lognon-deterministic zonedeterministic zoneBoundary is the compiler — the artifact carries no LLM at runtime.
LLM at authoring

The non-determinism stays at build time, when a human reviews and approves the emitted bean definitions.

No LLM at runtime

The compiled artifact has no model call on the dispatch path. The auditor reads code, not vendor terms-of-service.

Audit trail starts at the prompt

Prompt → emitted bean defs → compiled artifact → event log. Every step is recorded and reproducible.

Performance

The hot path is one virtual call per @OnTrigger.

The compile-time design removes the usual sources of dispatch overhead. No reflection, no virtual dispatch through framework interfaces, no per-event lambda allocation, no JSON parsing on the dispatch path. What's left is direct method calls the JIT can inline.

Not on the hot path
  • Reflective method lookup
  • Virtual dispatch through framework interfaces
  • Per-event lambda allocation
  • Locks in user code
  • JSON parsing on dispatch (your wire choice)
On the hot path
  • Agrona AgentRunner (LMAX heritage)
  • Per-source single-writer queue
  • One direct method call per @OnTrigger
  • Tunable idle strategy (sleep / busy-spin)
  • For lowest latency: connector-aeron IPC
Honest about benchmarks

A published benchmark suite is on the roadmap. What we can say today are the timings the integration tests land on:

  • Aeron IPC round-trip: ~10 ms wall-clock including embedded driver boot. Steady-state per-event is sub-microsecond.
  • File source → handler → file sink: ~50 µs per event on unoptimised laptop hardware (driven by file I/O, not dispatch).
  • Cache lookup + handler: ~100 ns inclusive (single virtual call).

These are not benchmarks. They are what the test suite happens to measure. Real numbers will land with the next release.

What stays constant

The processor is the constant. The plugins are the variable.

The same compiled .class runs in your unit test, your integration test, your simulation, and your production. The processor doesn't know which environment it's in. The plugin set — which connectors are wired to which feeds — decides.

Compiled processor.class · same artifact, four environmentsno rebuild, no reconfigure of node codeUnit testin-memory feeds + sinksIntegration testtest-support harness · real serverSimulationfile connectors · captured replayProductionaeron + kafka + chronicle

This is the property that makes Telamin defensible in regulated work. The thing under audit is the same code that ran in test, simulation, and production. There is no migration step where determinism could be lost.

Honest about the gaps

The dispatcher core is the hard part. The toolchain is still maturing.

What an architect will want to know before bringing this in:

Test harness

Shipped. mongoose-test-support cuts integration-test boot to five lines. Brand new — feedback welcome.

Standardised metrics

Roadmap. Each plugin exposes counters ad-hoc today. Micrometer / OpenTelemetry wiring is next.

YAML config schema

Roadmap. Typos in property names silently no-op. Schema generation is plumbing-grade work that hasn't happened yet.

Native image (GraalVM)

Builds and cold-starts; benchmark suite pending. The Maven plugin emits GraalVM reachability metadata (tested), reflect-config ships so @ServiceRegistered resolves natively, and the AOT example compiles to a native binary that launches and processes events in ~16 ms — a native executable's cold-start profile. A full native benchmark suite is still to come.

Package namespaces

Mostly consolidated. Fluxtion runtime/builder and Mongoose runtime are already under com.telamin.*; Mongoose plugins joined them in 0.2.12 as com.telamin.mongoose.plugin.*. The Maven plugin still carries a legacy root; canonical com.telamin.* by 2.0.

Public benchmarks

Pending. Architecture removes the usual overhead sources; numbers will land with the next release.

These are catchable in weeks. The dispatcher core — the part that's hard to get right — has been shipping in production at this design point for years.