This post walks through building and running a real-world agentic workflow with Agentican and Quarkus.
Specifically, an agentic workflow to automate market research and information sharing:
- Identify the top vendors within a market category.
- Research the positioning and strengths of each vendor.
- Classify the findings as either standard or urgent.
- Draft a brief to share with others in the company.
Prerequisites
- Quarkus
- Java 25
- Maven (or Gradle)
- LLM provider API key
Step 1: Add the dependency
Create a Quarkus app, and add the Agentican Quarkus runtime module:
<dependency>
<groupId>ai.agentican</groupId>
<artifactId>agentican-quarkus-runtime</artifactId>
<version>0.1.0-alpha.4</version>
</dependency>
Step 2: Define agents, skills and the workflow
Create an agentican-catalog.yaml file on the classpath.
This is where you describe:
- Who does the work (agents).
- What they need to do it (skills).
- How they will do it (workflows).
agents:
- id: researcher
name: researcher
role: |
Expert at finding accurate, sourced information about
companies and markets. Quotes sources. Distinguishes
opinion from fact.
- id: writer
name: writer
role: |
Synthesizes research into structured, concise briefs.
Avoids hedging language. Cites concrete evidence.
skills:
- id: web-search
name: web-search
instructions: |
When a question requires external information, call the
search tool first. Quote sources in your answer.
Update the agentican-catalog.yaml file to define the workflow.
workflows:
- id: market-brief
name: market-brief
description: Research vendors in a market and produce a
structured brief
outputStep: deliver
params:
- name: topic
description: Market to research
required: true
- name: vendor_count
description: Number of vendors
defaultValue: "5"
steps:
- name: identify
agent: researcher
skills: [web-search]
instructions: |
Identify the top {{param.vendor_count}} vendors in
{{param.topic}}. Return a JSON array of vendor names
— names only, no commentary.
- name: deep-dive
type: loop
over: identify
steps:
- name: analyze
agent: researcher
skills: [web-search]
instructions: |
Deep-dive vendor {{item}}: positioning, key
strengths, recent news. Quote sources.
- name: classify
agent: writer
instructions: |
Read the per-vendor deep-dives below. If any vendor has
launched a competitive feature in the last 30 days,
return the single word 'urgent'. Otherwise return
'standard'.
Deep-dives: {{step.deep-dive.output}}
dependencies: [deep-dive]
- name: deliver
type: branch
from: classify
default: standard
branches:
- name: urgent
steps:
- name: urgent-brief
agent: writer
instructions: |
Synthesize a vendor brief flagged URGENT for
executive review. Lead with the recent
competitive moves.
Topic: {{param.topic}}
Deep-dives: {{step.deep-dive.output}}
- name: standard
steps:
- name: standard-brief
agent: writer
instructions: |
Synthesize a vendor brief.
Topic: {{param.topic}}
Deep-dives: {{step.deep-dive.output}}
A few things worth flagging:
-
agent: researcherreferences the agent for an agent step. -
outputStepdesignates the step whose output becomes the workflow's result. -
{{param.X}}interpolates workflow inputs into step instructions. -
{{step.X.output}}interpolates an upstream step's output. -
{{item}}is the current value inside a loop iteration. -
type: loopsteps take anoverreference (a step that produced a list). -
type: loopsteps run their nestedstepsonce per item, and in parallel. -
type: branchsteps take afromreference (step used to select branch). -
branches:mutually exclusive steps withdefaultfor unrecognized values.
The framework loads agentican-catalog.yaml from the classpath at boot, or you can define where it's loaded from:
agentican.catalog-config=/etc/agentican/agentican-catalog.yaml
Note: Agents, skills and workflows can be defined via a fluent builder API as well.
Step 3: Configure the models
Agentican loads runtime configuration from application.properties. The minimum is one LLM:
agentican.llm[0].api-key=${ANTHROPIC_API_KEY}
The provider defaults to anthropic, and the model defaults to claude-sonnet-4-5.
OpenAI
agentican.llm[0].provider=openai
agentican.llm[0].api-key=${OPENAI_API_KEY}
agentican.llm[0].model=gpt-4o-mini
Multiple, named LLMs
agentican.llm[0].name=default
agentican.llm[0].api-key=${ANTHROPIC_API_KEY}
agentican.llm[1].name=efficient
agentican.llm[1].provider=openai
agentican.llm[1].api-key=${OPENAI_API_KEY}
agentican.llm[1].model=gpt-4o-mini
Step 4: Create a typed workflow instance
Define the workflow input and output records:
public record ResearchParams(String topic, int vendorCount) {}
public record VendorBrief(String topic, List<Vendor> vendors) {
public record Vendor(String name,
String positioning,
List<String> strengths) {}
}
Then inject the typed workflow, and call it from a REST endpoint:
@Path("/market-brief")
public class VendorBriefResource {
@Inject
@AgenticanWorkflow(name = "market-brief")
Workflow<ResearchParams, VendorBrief> brief;
@POST
@Path("/{topic}")
public VendorBrief generate(@PathParam("topic") String topic) {
return brief.start(new ResearchParams(topic, 5)).await();
}
}
Now, test the endpoint:
curl -X POST http://localhost:8080/market-brief/databases
A few things worth flagging — they're what set this apart from a generic "call an LLM" library:
-
ResearchParams.vendorCountbecomes the workflow parametervendor_countviaSNAKE_CASEmapping. -
start()returns aWorkflowRun<VendorBrief>.await()parses the output step's text into aVendorBrief. -
@AgenticanWorkflow(name = "vendor-brief")resolves the registered workflow at injection time.
The WorkflowRun itself exposes future() for a CompletableFuture<R>, and there's a ReactiveWorkflow<P, R> Mutiny variant for Vert.x stacks.
Step 5: Add tools (MCP and Composio).
Agentican ships two integrations out of the box:
MCP (Model Context Protocol)
There is one config block per server. Tools are auto-discovered:
agentican.mcp[0].slug=github
agentican.mcp[0].name=GitHub
agentican.mcp[0].url=https://mcp.github.com/sse
agentican.mcp[0].headers.Authorization=Bearer ${GITHUB_TOKEN}
Composio
100+ SaaS toolkits — Slack, Notion, Linear, Salesforce, GitHub, Google Workspace:
agentican.composio.api-key=${COMPOSIO_API_KEY}
agentican.composio.user-id=user-123
Tools are reference by name within agent steps:
steps:
- name: research
agent: researcher
tools: [github_search_repositories]
instructions: "Profile open-source vendors in {{param.topic}}."
Where to go next
- Getting Started — install, configure and run workflows
- Core Concepts — architecture, terminology and data flow
- Workflows & Steps — CDI surface, beans, qualifiers, override patterns.
- Agents — defining agents, skills and roles
- Getting Started (Quarkus) — dependency setup, config, first task
- CDI Integration — injection, qualifiers, lifecycle events, bean overrides
- REST API — endpoints, SSE streaming, WebSocket, error codes
- Observability — Micrometer metrics, OTel tracing, Prometheus queries
Structured agentic workflows for the JVM.
Top comments (0)