A lightweight, non-blocking, reactive runtime for the Open Workflow specification. Use it to load, validate, and execute workflows written in YAML/JSON—or build them programmatically with our Fluent DSL.
- Features
- Modules
- Installation
- Quick Start
- Detailed Walkthrough
- Fluent Java DSL
- Mermaid Diagrams
- Lifecycle Events
- Errors & Auth
- Development
- License
This reference implementation can run workflows consisting of:
Tasks
SwitchSetDoRaiseListenEmitForkFor/ForEachTry(withCatch/Retry)WaitCall- HTTP
- Basic auth
- Bearer auth
- OAuth2 / OIDC auth
- Digest auth (via Fluent DSL)
- OpenAPI
- Function
- gRPC
- HTTP
Run- Container
- Script
PythonJavascript
- Workflow
- Shell
Schema Validation
- Input / Output validation
Expressions
- Input / Output / Export
- Special keywords:
runtime,workflow,task, …
Error Definitions
- Standard & custom error types
Lifecycle Events
Pending,Started,Suspended,Faulted,Resumed,Cancelled,Completed
This SDK is modular by design—pull in only what you need:
-
openworkflow-impl-core Workflow engine & core interfaces. Depends on generated types and CloudEvents SDK.
-
openworkflow-impl-jackson 👉 Most users add this one. Contains implementation of core features using Jackson library, like JQ expressions, JSON Schema validation, and CloudEvents (de)serialization. Internally, it is an aggregation of smaller modules:
- openworkflow-impl-jq JQ expression implementation
- openworkflow-impl-model Jackson model implementation and Jackson JWT converter for oauth2 calls.
- openworkflow-impl-validation Schema validation implementation
- openworkflow-impl-lifecycle-events Enable publication of lifecycle events as Json cloud events.
- openworkflow-impl-function Jackson Function support.
- openworkflow-impl-json Jackson common utilities shared by all modules in this list
- openworkflow-impl-cron Cron parsing for workflow scheduled execution
- openworkflow-impl-openapi Deserialization support of OpenAPI schemas using Jackson (required for OpenAPI call task to work)
Additionally, The OpenWokflow specification defines a set of call task, which requires additional dependencies, with the exception of HTTP (see section below). You might add those ones needed depending on the feature you are using in your definition:
- openworkflow-impl-grpc gRPC support
- openworkflow-impl-script-python Python support
- openworkflow-impl-script-js Javascript support
- openworkflow-impl-container Docker container support
- openworkflow-impl-a2a A2A protocol support.
There are also companion modules/docs for:
- Fluent DSL (programmatic builder)
- Mermaid (diagramming workflows)
By default, the SDK reference implementation use java.net.HttpRequest to support Http/OpenAPI calls. Therefore, no dependency (besides the jackson modules described above) needs to be added for using Http Call task or downloading http resources.
However, for further configuration of Http functionality, users might include the Jakarta based modules, which will allow customizing jakarta.ws.rs.client.Client in Jakarta EE environments.
* **openworkflow-impl-http** HTTP `Call` task handler, based on JAX-RS client
* **openworkflow-impl-http-jackson** Optimized entity converter for Jackson model
<!-- Core + Jackson (YAML, JQ, JSON Schema, CloudEvents) -->
<dependency>
<groupId>org.openworkflow.sdk</groupId>
<artifactId>openworkflow-impl-jackson</artifactId>
</dependency>
implementation("org.openworkflow.sdk:openworkflow-impl-jackson")Requires Java 21+.
We’ll run a simple workflow that performs an HTTP GET. See the full YAML in examples/simpleGet/src/main/resources/get.yaml.
try (WorkflowApplication appl = WorkflowApplication.builder().build()) {
var output =
appl.workflowDefinition(WorkflowReader.readWorkflowFromClasspath("get.yaml"))
.instance(Map.of("petId", 10))
.start()
.join();
logger.info("Workflow output is {}", output);
}try (WorkflowApplication appl = WorkflowApplication.builder().build()) {
appl.workflowDefinition(WorkflowReader.readWorkflowFromClasspath("get.yaml"))
.instance(Map.of("petId", 10))
.start()
.thenAccept(output -> logger.info("Workflow output is {}", output));
}Example output:
Workflow output is {"id":10,"category":{"id":10,"name":"string"},"name":"doggie",...}
Full examples:
- Blocking: examples/simpleGet/src/main/java/org/openworkflow/sdk/impl/BlockingExample.java
- Non-blocking: examples/simpleGet/src/main/java/org/openworkflow/sdk/impl/NotBlockingExample.java
We’ll coordinate two workflows—one listens for high temperatures and the other emits temperature events:
listen.yamlwaits for an event withtemperature > 38(non-blocking)emit.yamlemits events using a workflow parameter
Create an application (customize thread pools, etc.). WorkflowApplication is AutoCloseable, so use try-with-resources:
try (WorkflowApplication appl = WorkflowApplication.builder().build()) {
WorkflowDefinition listen = appl.workflowDefinition(WorkflowReader.readWorkflowFromClasspath("listen.yaml"));
WorkflowDefinition emit = appl.workflowDefinition(WorkflowReader.readWorkflowFromClasspath("emit.yaml"));
// Start the listener (non-blocking)
listen.instance(Map.of())
.start()
.thenAccept(out -> logger.info("Waiting instance completed with {}", out));
// Emit a low temperature (ignored)
emit.instance(Map.of("temperature", 35)).start().join();
// Emit a high temperature (completes the waiting workflow)
emit.instance(Map.of("temperature", 39)).start().join();
}You’ll see:
Waiting instance completed with [{"temperature":39}]
Source: examples/events/src/main/java/events/EventExample.java
As shown in previous examples, to start a new workflow instance, first a WorkflowInstance is created from a WorkflowDefinition, specifying the desired input, and then start method is invoked over it. Start method returns a CompletableFuture, which might be used to obtain the output, either synchronously or asynchronously.
Once started, and before it completes, a workflow instance execution can be suspended or cancelled. Once cancelled, a workflow instance is done, while a suspended one might be resumed.
Workflow progress might be recorded into DB. See details
Prefer building workflows programmatically with type-safe builders and recipes? 👉 Docs: https://github.com/open-workflow-specification/sdk-java/blob/main/fluent/README.md
Highlights:
- Chainable builders for
Call HTTP,Listen/Emit,Try/Catch/Retry,Switch,Fork, etc. - Reusable “recipes” (e.g.,
http().GET().acceptJSON().endpoint("${ ... }")) - Static helpers for auth (
basic(...),bearer(...),oidc(...), …) and standard error types.
Generate Mermaid diagrams for your workflows right from the SDK. 👉 Docs: https://github.com/open-workflow-specification/sdk-java/blob/main/mermaid/README.md
Great for docs, PRs, and visual reviews.
Every workflow publishes CloudEvents you can subscribe to (in-memory or your own broker):
org.openworkflow.workflow.*→pending,started,suspended,faulted,resumed,cancelled,completedorg.openworkflow.task.*→started,suspended,resumed,cancelled,completed
See impl tests/examples for consuming and asserting on these events.
Errors
- Raise standard errors with versioned URIs (e.g.,
runtime,communication,timeout, …) or custom ones. - Fluent helpers (e.g.,
serverError(),timeoutError()) set both type URI and default HTTP status; override as needed.
Authentication (HTTP Call)
- Basic / Bearer / Digest
- OAuth2 / OpenID Connect (client credentials, etc.)
- Fluent helpers:
basic("user","pass"),bearer("token"),oidc(authority, grant, clientId, clientSecret), …
Prereqs
- Java 21+
- Maven (or Gradle)
Build & Verify
mvn -B clean verifyFormatting & Lint (CI parity)
mvn -B -DskipTests spotless:check checkstyle:checkRun examples
- See
examples/directory for runnable samples.
Apache License 2.0. See LICENSE for details.
Questions or ideas? PRs and issues welcome!