Skip to content

quarkiverse/quarkus-flow

Repository files navigation

Quarkus Flow

Version

Native Compilation Nightly Quarkus ecosystem CI Quarkus Platform Nightly Build with Integration Tests Build

Quarkus Flow is a lightweight, low-dependency, production-grade workflow engine for Quarkus, built on the Serverless Workflow specification CNCF sandbox project.

Use it to model classic workflows and Agentic AI orchestrations, with first-class CDI/Quarkus ergonomics.

📚 Docs: https://docs.quarkiverse.io/quarkus-flow/dev/

🤖 Agentic (LangChain4j):

Why Quarkus Flow?

  • 🧩 Specification-compliant workflows via a fluent Java DSL
  • Fast start & low footprint (Quarkus/native-friendly)
  • 🔌 CDI-first: build-time discovery → CDI injection, no registries to wire
  • 🧪 Great DX: inject your workflow class or the compiled WorkflowDefinition
  • 🤝 Agentic AI ready: orchestrate LangChain4j agents as workflow tasks (with loops + human-in-the-loop)

🚀 Try it First (Optional)

Want to see Quarkus Flow in action before adding it to your project? Use our pre-built Docker runner to explore workflows without writing any code:

curl -fsSL https://raw.githubusercontent.com/quarkiverse/quarkus-flow/main/runner/app/quickstart.sh | bash

💡 This is just for exploration! The Docker runner lets you try Quarkus Flow features quickly, but the real power comes from integrating it into your Quarkus application below.

Or use Docker directly
# 1. Create a workflow directory with an example
mkdir -p ~/quarkus-flow-quickstart/workflows
cat > ~/quarkus-flow-quickstart/workflows/hello.yaml << 'EOF'
document:
  dsl: '1.0.0'
  namespace: demo
  name: hello-world
  version: '1.0.0'
do:
  - greet:
      set:
        message: '${ "Hello, " + .name + "!" }'
EOF

# 2. Run Quarkus Flow (foreground, Ctrl+C to stop)
docker run --rm \
  -p 8080:8080 \
  -v ~/quarkus-flow-quickstart/workflows:/deployments/workflows:ro \
  quay.io/quarkiverse/quarkus-flow-runner:latest-minimal

# 3. In another terminal, try the workflow
curl -X POST "http://localhost:8080/q/flow/exec/demo/hello-world/1.0.0?wait=true" \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice"}' | jq

# Visit dashboard: http://localhost:8080
# Stop: Ctrl+C in the Docker terminal

Note: Workflows are loaded at startup. To load modified/new workflows, restart the container.

More runner options (docker-compose, production variants)

Using docker-compose:

git clone https://github.com/quarkiverse/quarkus-flow.git
cd quarkus-flow/runner/app
docker-compose up

Production variants:

See runner/app/ for complete documentation.

Quick Start

Add Quarkus Flow to your Quarkus application:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.quarkiverse.flow</groupId>
      <artifactId>quarkus-flow-bom</artifactId>
      <version>RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

Then add the dependency (version managed by BOM):

<dependencies>
  <dependency>
    <groupId>io.quarkiverse.flow</groupId>
    <artifactId>quarkus-flow</artifactId>
  </dependency>
</dependencies>

Create a workflow (extend io.quarkiverse.flow.Flow):

import jakarta.enterprise.context.ApplicationScoped;
import io.quarkiverse.flow.Flow;
import io.serverlessworkflow.api.types.Workflow;
import io.quarkiverse.flow.dsl.FlowWorkflowBuilder;

import static io.quarkiverse.flow.dsl.FlowDSL.*;

@ApplicationScoped
public class HelloWorkflow extends Flow {
  @Override
  public Workflow descriptor() {
    return FlowWorkflowBuilder.workflow("hello")
      .tasks(set("{ message: \"hello world!\" }"))
      .build();
  }
}

Run:

./mvnw quarkus:dev

Next steps:


LangChain4j Integration (Agentic AI Workflows)

Quarkus Flow supports three complementary ways to use LangChain4j:

  1. Java DSL tasks — call LangChain4j beans from Flow tasks via function(…). Use this when you want full control of the workflow topology and to mix AI with HTTP, messaging, timers, long-running instances, etc.
  2. Annotations → generated workflows — declare agentic workflow patterns with LangChain4j Agentic Workflow API annotations (@SequenceAgent, @ParallelAgent, …) and let Quarkus Flow generate/register workflows for you.
  3. Hybrid — declare patterns with annotations, then call them from a larger Java DSL workflow via function(…).

Docs:

1) Java DSL tasks (call LangChain4j beans)

Dependencies

<dependency>
  <groupId>io.quarkiverse.flow</groupId>
  <artifactId>quarkus-flow</artifactId>
</dependency>

<!-- Choose ONE LangChain4j provider (Ollama, OpenAI, …) -->
<dependency>
  <groupId>io.quarkiverse.langchain4j</groupId>
  <artifactId>quarkus-langchain4j-ollama</artifactId>
</dependency>

LangChain4j annotations you’ll use here are the classic AI-service ones, e.g. @RegisterAiService, @SystemMessage, @UserMessage, @MemoryId, @V:

import jakarta.enterprise.context.ApplicationScoped;

import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import io.quarkiverse.langchain4j.RegisterAiService;

@RegisterAiService
@ApplicationScoped
@SystemMessage("You draft a short, friendly newsletter paragraph. Return ONLY the final draft text.")
public interface DrafterAgent {
  @UserMessage("Brief:
{{brief}}")
  String draft(@MemoryId String memoryId, @V("brief") String brief);
}

Then orchestrate it from a Flow using regular tasks:

// pseudo-snippet: call any CDI bean method with function(…)
// function("draft", drafterAgent::draft, String.class)

2) Annotations → generated workflows (LangChain4j Agentic Workflow API)

quarkus-flow-langchain4j is only required when you use LangChain4j’s agentic module (langchain4j-agentic / quarkus-langchain4j-agentic). See: https://docs.langchain4j.dev/tutorials/agents

Dependencies

<dependency>
  <groupId>io.quarkiverse.flow</groupId>
  <artifactId>quarkus-flow</artifactId>
</dependency>

<!-- Quarkus Flow ↔ LangChain4j agentic integration -->
<dependency>
  <groupId>io.quarkiverse.flow</groupId>
  <artifactId>quarkus-flow-langchain4j</artifactId>
</dependency>

<!-- LangChain4j Agentic (workflow API + annotations like @SequenceAgent/@ParallelAgent) -->
<dependency>
  <groupId>io.quarkiverse.langchain4j</groupId>
  <artifactId>quarkus-langchain4j-agentic</artifactId>
</dependency>

<!-- Choose ONE LangChain4j provider -->
<dependency>
  <groupId>io.quarkiverse.langchain4j</groupId>
  <artifactId>quarkus-langchain4j-ollama</artifactId>
</dependency>

Annotations you’ll use here come from the Agentic Workflow API, e.g. @SequenceAgent, @ParallelAgent, @LoopAgent, @ConditionalAgent. Quarkus Flow discovers these methods at build time and registers generated workflows automatically.

import dev.langchain4j.agentic.declarative.SequenceAgent;

public final class Agents {

  // A generated workflow: chain sub-agents sequentially
  public interface StoryCreatorWithConfigurableStyleEditor {
    @SequenceAgent(outputKey = "story", subAgents = { CreativeWriter.class, AudienceEditor.class, StyleEditor.class })
      String write(@V("topic") String topic, @V("style") String style, @V("audience") String audience);
  }

  // pseudo-snippet
  public interface CreativeWriter {

  }

  // pseudo-snippet
  public interface AudienceEditor {

  }

  // pseudo-snippet
  public interface StyleEditor {

  }
}

Content supressed on purpose, see the complete example here: https://github.com/quarkiverse/quarkus-flow/tree/main/examples/langchain4j-agentic-workflow.

3) Hybrid (call a generated agentic workflow from a larger Flow)

Define the agentic topology with annotations (as above), then inject the generated bean and call it from your main workflow using function(…), continuing with non-AI tasks (HTTP, messaging, timers, HITL, …).

Messaging (TL;DR)

No extra artifact needed—auto-activates if you add a connector like Kafka:

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-messaging-kafka</artifactId>
</dependency>

Then configure:

quarkus.flow.messaging.defaults-enabled=true
mp.messaging.incoming.flow-in.connector=smallrye-kafka
mp.messaging.outgoing.flow-out.connector=smallrye-kafka

See the Messaging doc for full details.

Examples

This repository contains a growing list of end-to-end examples in the examples/ directory, covering various use cases and integrations. To see the full list, check the examples/ directory.

  • Docs snippets under docs/modules/ROOT/examples/

Using SNAPSHOT versions

Want to try the latest unreleased changes? SNAPSHOT artifacts are published to the Maven Central snapshots repository. Register it in your pom.xml:

<repositories>
  <repository>
    <id>central-snapshots</id>
    <url>https://central.sonatype.com/repository/maven-snapshots/</url>
    <releases>
      <enabled>false</enabled>
    </releases>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

Then import the BOM using the 1.0.0-SNAPSHOT version:

<dependency>
  <groupId>io.quarkiverse.flow</groupId>
  <artifactId>quarkus-flow-bom</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>

Contributing

Issues & PRs welcome! Please:

  • run ./mvnw -q -DskipTests install before opening PRs
  • keep docs in docs/ (Antora). Dev locally with:
./mvnw -pl docs -am quarkus:dev
# press 'w' when Quarkus starts to open the docs site

License: Apache-2.0

About

Workflow Runtime Engine based on the Serverless Workflow Specification (CNCF Sandbox project) for Agentic Workflows

Topics

Resources

License

Contributing

Stars

106 stars

Watchers

3 watching

Forks

Contributors