Skip to content

Getting Started with BLOGE ​

This guide walks from a single node to a small production-style setup. Every section shows both the Java builder style and the equivalent .bloge DSL so teams can choose the authoring style that fits their workflow.

Prerequisites ​

  • Java 25+
  • Maven 3.9+

Add the BLOGE dependencies you need to your pom.xml. At minimum, bloge-core is always required. See Appendix: Maven dependencies for the full coordinates of all modules.

Available modules ​

ModuleDescriptionWhen to add
bloge-coreCore engine with zero external dependencies (java.base only)Always
bloge-execution-controlFramework-neutral deterministic control plans and typed doublesWhen tests need controlled call-site behavior
bloge-capability-processorOptional compile-time capability contract inference for typed Java operators and functionsWhen builds should publish richer capability metadata
bloge-dslExternal DSL parser and compiler for .bloge filesWhen loading .bloge files
bloge-dsl-caffeineCaffeine-backed graph compilation cacheWhen DSL compilation needs TTL or size-bounded caching
bloge-runtime-spiDurable runtime facade and timer/runtime SPIAdvanced durable runtime wiring
bloge-durableDurable execution store contracts and in-memory reference storesLong-running or resumable flows
bloge-durable-mybatisMyBatis and Flyway persistence backend for durable storesProduction database persistence
bloge-durable-codecCheckpoint codec implementations for durable moduleTogether with bloge-durable
bloge-event-journalAppend-only execution event streamExecution timelines, retention, and operations views
bloge-session-extSession/phase/round runtime and DSL extensionConversational or multi-round flows
bloge-session-durableDurable bridge for session checkpoints and recoveryRestart-safe sessions
bloge-state-extEvent-driven state machine runtime and DSL extensionExplicit state/transition workflows
bloge-state-durableDurable bridge for state-machine checkpoints and recoveryRestart-safe state machines
bloge-agent-extAgent loop runtime and DSL extensionLLM agents with tools and memory
bloge-springSpring Boot auto-configuration for BLOGESpring Boot apps
bloge-spring-webDurable REST APIs and embedded /bloge-consoleOperational web layer
bloge-metrics-otelMicrometer metrics, Micrometer Tracing spans, OpenTelemetry context propagation, SLF4J MDC propagationObservability
bloge-dispatch-kafkaKafka dispatch bridge for durable work itemsPush dispatch across process boundaries
bloge-camunda-bridgeLightweight Camunda external task bridgeCamunda interoperability
bloge-common-operatorsProduction-grade common operator library — HTTP, DB, Messaging, AI/LLM, Transform, Notification, Approval, Storage, Crypto, ValidationPre-built operator library
bloge-functions-cryptoHash, crypto, encoding functions and secret SPISecure expression functions
bloge-lintLint tool and CLI for .bloge DSL filesDSL authoring or CI lint
bloge-maven-pluginOperator metadata export and lint integrationBuild-time metadata and checks
bloge-testTest tools: MockOperator, GraphTestRunner, DslTestHelperTesting
bloge-verificationPreview business-contract verification over real BLOGE graphsWhen customer scenarios must produce reviewable verdicts and evidence
bloge-starter-loan-approvalRunnable Spring Boot durable loan-approval golden pathWhen following the end-to-end verification tutorial
bloge-bpmn-transformerBPMN 2.0 XML to BLOGE DSL and Graph translator for legacy system migrationBPMN migration
bloge-scriptOptional sandboxed Groovy script execution for bloge script nodesScript nodes

1. Single-node echo graph ​

The smallest useful graph is one node that reads context and returns a value.

Java API ​

java
Graph graph = Graph.builder("echo")
    .node("echo", (Map<String, Object> input, OperatorContext ctx) ->
        Map.of("message", ctx.graphContext().get("message", String.class)))
    .build();

GraphResult result = GraphEngine.builder().build()
    .execute(graph, new GraphContext(Map.of("message", "hello")));

DSL ​

bloge
graph echo {
  node echo : EchoOperator {
    input {
      message = ctx.message
    }
  }
}
java
DefaultOperatorRegistry registry = new DefaultOperatorRegistry();
registry.register("EchoOperator", (input, ctx) -> input);

Graph graph = new GraphLoader(registry).load(dslSource);
GraphResult result = GraphEngine.builder().registry(registry).build()
    .execute(graph, new GraphContext(Map.of("message", "hello")));

What to notice:

  • Java is ideal when operators and schemas already live in code.
  • DSL is ideal when you want a reviewable artifact that can be edited without recompiling Java classes.

2. Two-node sequential graph ​

Now add a downstream node that depends on the first node's output.

Java API ​

java
Graph graph = Graph.builder("greetUser")
    .node("fetchUser", fetchUserOperator)
    .node("formatGreeting", formatGreetingOperator)
        .dependsOn("fetchUser")
    .build();

DSL ​

bloge
graph greetUser {
  node fetchUser : FetchUserOperator {
    input {
      userId = ctx.userId
    }
  }

  node formatGreeting : FormatGreetingOperator {
    input {
      user = fetchUser.output
    }
  }
}

The DSL compiler infers the dependency from fetchUser.output, so you do not have to repeat depends_on unless you want to make the edge explicit.


3. Parallel fan-out plus branch ​

BLOGE becomes interesting when multiple upstream calls can run concurrently and a later step decides which path to take.

Java API ​

java
Graph graph = Graph.builder("orderDecision")
    .node("fetchUser", fetchUserOperator)
    .node("fetchProducts", fetchProductsOperator)
    .node("calcPrice", calcPriceOperator)
        .dependsOn("fetchUser", "fetchProducts")
    .branch("calcPrice")
        .on("approved")
        .when(value -> Boolean.TRUE.equals(value), "createOrder")
        .otherwise("rejectOrder")
    .node("createOrder", createOrderOperator)
    .node("rejectOrder", rejectOrderOperator)
    .build();

DSL ​

bloge
graph orderDecision {
  node fetchUser : FetchUserOperator {
    input {
      userId = ctx.userId
    }
  }

  node fetchProducts : FetchProductsOperator {
    input {
      productIds = ctx.productIds
    }
  }

  node calcPrice : CalcPriceOperator {
    input {
      user = fetchUser.output
      products = fetchProducts.output
    }
  }

  branch on calcPrice.output.approved {
    true -> createOrder
    otherwise -> rejectOrder
  }

  node createOrder : CreateOrderOperator {}
  node rejectOrder : RejectOrderOperator {}
}

What to notice:

  • fetchUser and fetchProducts can run in parallel because nothing depends on the other.
  • the branch is control flow, not data transformation; use transform when you only want to compute a value.

4. Java and DSL are equivalent authoring styles ​

The same business graph can be expressed in either form. A practical workflow is:

  1. prototype the graph in DSL
  2. prove behavior with tests or golden baselines
  3. move stable operator logic into Java classes
  4. keep the graph shape in DSL or express it directly through the Java API

Java API ​

java
Graph graph = Graph.builder("ticketRouting")
    .node("fetchCustomer", fetchCustomerOperator)
    .node("analyzeSentiment", sentimentOperator)
        .dependsOn("fetchCustomer")
    .branch("analyzeSentiment")
        .on("priority")
        .when(value -> "vip".equals(value), "assignVipAgent")
        .when(value -> "normal".equals(value), "assignNormalAgent")
        .otherwise("autoResolve")
    .node("assignVipAgent", assignVipAgentOperator)
    .node("assignNormalAgent", assignNormalAgentOperator)
    .node("autoResolve", autoResolveOperator)
    .build();

DSL ​

bloge
graph ticketRouting {
  node fetchCustomer : FetchCustomerOperator {
    input {
      ticketId = ctx.ticketId
    }
  }

  node analyzeSentiment : AnalyzeSentimentOperator {
    input {
      customer = fetchCustomer.output
    }
  }

  branch on analyzeSentiment.output.priority {
    "vip" -> assignVipAgent
    "normal" -> assignNormalAgent
    otherwise -> autoResolve
  }

  node assignVipAgent : AssignVipAgentOperator {}
  node assignNormalAgent : AssignNormalAgentOperator {}
  node autoResolve : AutoResolveOperator {}
}

Use the Java style when type-safe composition inside the same codebase is more important than external authoring. Use DSL when product, operations, or tooling teams need a standalone graph artifact.


5. Spring Boot integration ​

bloge-spring lets a normal Spring Boot app publish operators and load .bloge files automatically.

Java API inside Spring Boot ​

java
@Configuration
class BlogeGraphs {
    @Bean
    Graph orderGraph() {
        return Graph.builder("orderGraph")
            .node("fetchUser", new FetchUserOperator())
            .build();
    }
}

DSL inside Spring Boot ​

Add the dependency:

xml
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-spring</artifactId>
    <version>${bloge.version}</version>
</dependency>

Create an operator bean:

java
@BlogeOperator("FetchUserOperator")
@Component
class FetchUserOperator implements Operator<Map<String, Object>, Map<String, Object>> {
    @Override
    public Map<String, Object> execute(Map<String, Object> input, OperatorContext ctx) {
        return Map.of("id", input.get("userId"));
    }
}

Create src/main/resources/bloge/order-graph.bloge:

bloge
graph orderGraph {
  node fetchUser : FetchUserOperator {
    input {
      userId = ctx.userId
    }
  }
}

At runtime, inject GraphEngine and the discovered graphs, then execute the graph that matches your route or use case.


Next steps ​

  • Browse Example Catalog for verified DSL fixtures from the source conformance suite.
  • For customer business correctness, start with BLOGE Verify and the loan approval walkthrough.
  • Read Full Specification for the full language contract.
  • If you need long-running conversational flows, continue with the session / phase / round extension docs in the repository and the DSL reference in this site.
  • If you need production persistence or observability, continue with Durable Flows and Observability.

Appendix: Maven dependencies ​

All BLOGE modules share the same groupId and version. Copy the coordinates for the modules your project requires.

xml
<!-- Core engine — always required -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-core</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Business contract verification — normally test-scoped -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-verification</artifactId>
    <version>${bloge.version}</version>
    <scope>test</scope>
</dependency>

<!-- External DSL parser and compiler for .bloge files -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-dsl</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Durable runtime store contracts and in-memory reference stores -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-durable</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- MyBatis/Flyway database persistence for durable stores -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-durable-mybatis</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Checkpoint codec implementations for durable module -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-durable-codec</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Session/phase/round extension runtime and compiler -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-session-ext</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Durable bridge for session checkpoints and recovery -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-session-durable</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- State-machine extension runtime and compiler -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-state-ext</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Agent loop extension runtime and compiler -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-agent-ext</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Spring Boot auto-configuration for BLOGE -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-spring</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Observability: Micrometer metrics, Micrometer Tracing spans, OpenTelemetry, SLF4J MDC -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-metrics-otel</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Production-grade common operator library: HTTP, DB, Messaging, AI/LLM, Transform, etc. -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-common-operators</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Lint tool and CLI for .bloge DSL files -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-lint</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Test tools: MockOperator, GraphTestRunner, DslTestHelper -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-test</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- BPMN 2.0 XML to BLOGE DSL and Graph translator -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-bpmn-transformer</artifactId>
    <version>${bloge.version}</version>
</dependency>

<!-- Optional sandboxed Groovy script execution for bloge script nodes -->
<dependency>
    <groupId>com.leanowtech.bloge</groupId>
    <artifactId>bloge-script</artifactId>
    <version>${bloge.version}</version>
</dependency>