How it works
Installation
Add yWorkflow to your Java project using Maven or Gradle.
implementation(platform("com.yworkflow:yworkflow-bom:1.0.0"))
implementation("com.yworkflow:yworkflow-engine")
// if you want to use YAML
implementation("com.yworkflow:definition-factory-yaml")
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.yworkflow</groupId>
<artifactId>yworkflow-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>com.yworkflow</groupId>
<artifactId>yworkflow-engine</artifactId>
</dependency>
<dependency>
<groupId>com.yworkflow</groupId>
<artifactId>definition-factory-yaml</artifactId>
</dependency>
Quick Start
Get started with yworkflow in just a few lines of code.
// 1. Initialize the main Workflows object.
var workflows = new DefaultWorkflowsBuilder()
.withInstanceStore(new MemoryWorkflowInstanceStore())
.build();
// 2. Define a minimal workflow in a YAML string.
// `initial-transitions` define how a workflow can be started.
// `states` are the steps the workflow can be in.
var yamlDefinitionString =
"""
workflow:
id: "leave_request"
initial-transitions:
- id: "create_request"
default-result:
state: "draft_leave_request"
states:
- id: "draft_leave_request"
""";
// 3. Parse the YAML string into a formal Workflow object.
var workflow = WorkflowYaml.fromString(yamlDefinitionString).toWorkflow();
workflows.definitions().save(workflow);
// 4. Create an instance of the workflow.
// This simulates a user starting a new leave request.
var workflowInstance =
workflows
.instances()
.init(
workflowId("leave_request"),
transitionId("create_request"));
// 5. Assert the final state of the instance.
assertEquals(WorkflowInstanceState.COMPLETED, workflowInstance.getState());
Workflow Definition
Define workflows using Java API or declarative formats like YAML, XML, and JSON.
var workflow = new Workflow("Access Request Workflow");
workflow.transitions().addInitialTransition(
transition(transitionId("start").name("Create Access Request"))
.defaultResult(result(stateId("initial"))
.enterStatus(resultStatus("pending"))));
workflow.addState(state(stateId("initial").name("Access Request Draft"))
.transitions(
transition(transitionId("submit").name("Submit Access Reques"))
.defaultResult(result(forkId("fork"))
.enterStatus(resultStatus("pending")))));
workflow.addState(state(stateId("approval_1").name("Manager Approval"))
.transitions(
transition(transitionId("deny_1").name("Manager Reject Request"))
.defaultResult(result(stateId("initial"))
.exitStatus(resultStatus("rejected"))
.enterStatus(resultStatus("pending"))),
transition(transitionId("approve_1").name("Manager Approve Request"))
.defaultResult(result(joinId("join"))
.enterStatus(resultStatus("pending")))));
workflow.addState(state(stateId("approval_2").name("Administrator Approval"))
.transitions(
transition(transitionId("deny_2").name("Administrator Reject Request"))
.defaultResult(result(stateId("initial"))
.exitStatus(resultStatus("rejected"))
.enterStatus(resultStatus("pending"))),
transition(transitionId("approve_2").name("Administrator approve request"))
.defaultResult(result(joinId("join"))
.enterStatus(resultStatus("pending")))));
workflow.addState(state(stateId("approved").name("Access Request Approved")));
workflow.addFork(fork(forkId("fork"))
.results(
result(stateId("approval_1"))
.enterStatus(resultStatus("pending")),
result(stateId("approval_2"))
.enterStatus(resultStatus("pending"))));
workflow.addJoin(join(joinId("join"))
.defaultResult(result(stateId("approved"))
.enterStatus(resultStatus("completed")))
.conditions(
conditions(Conditions.Operator.AND,
scriptCondition("join.states.approval_1.status.completed"),
scriptCondition("join.states.approval_2.status.completed")
)
));
{
"id": "Access Request Workflow",
"initial_transitions": [
{
"id": "start", "name": "Create Access Request",
"default_result": { "state": "initial", "enter_status": "pending" }
}
],
"states": [
{
"id": "initial", "name": "Access Request Draft",
"transitions": [
{
"id": "submit", "name": "Submit Access Request",
"default_result": { "fork": "fork", "enter_status": "pending" }
}
]
},
{
"id": "approval_1", "name": "Manager Approval",
"transitions": [
{
"id": "deny_1", "name": "Manager Reject Request",
"default_result": { "state": "initial", "enter_status": "pending", "exit_status": "rejected" }
},
{
"id": "approve_1", "name": "Manager Approve Request",
"default_result": { "join": "join", "enter_status": "pending" }
}
]
},
{
"id": "approval_2", "name": "Administrator Approval",
"transitions": [
{
"id": "deny_2", "name": "Administrator Reject Request",
"default_result": { "state": "initial", "enter_status": "pending", "exit_status": "rejected" }
},
{
"id": "approve_2", "name": "Administrator approve request",
"default_result": { "join": "join", "enter_status": "pending" }
}
]
},
{
"id": "approved", "name": "Access Request Approved"
}
],
"forks": [
{
"id": "fork",
"default_results": [
{"state":"approval_1", "enter_status": "pending"},
{"state":"approval_2", "enter_status": "pending"}
]
}
],
"joins": [
{
"id": "join",
"join_conditions": {
"operator": "AND",
"conditions": [
{
"type": "script", "value": "groovy",
"args": [
{
"name": "script",
"content": "join.approval_1.status.completed"
}
]
},
{
"type": "script", "value": "groovy",
"args": [
{
"name": "script",
"content": "join.approval_2.status.completed"
}
]
}
]
},
"default_result": { "state": "approved", "enter_status": "completed" }
}
]
}
<?xml version="1.0"?>
<workflow xmlns="https://www.yworkflow.com/yworkflow/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.yworkflow.com/yworkflow/1.0
https://www.yworkflow.com/yworkflow/yworkflow_1_0_0.xsd">
<id>Access Request Worfklow</id>
<initial-transitions>
<transition id="start" name="Create Access Request">
<results>
<default-result enter-status="pending" state="initial"/>
</results>
</transition>
</initial-transitions>
<states>
<state id="initial" name="Access Request Draft">
<transitions>
<transition id="submit" name="Submit Access Request">
<results>
<default-result enter-status="pending" fork="fork"/>
</results>
</transition>
</transitions>
</state>
<state id="approval_1" name="Manager Approval">
<transitions>
<transition id="deny_1" name="Manager Reject Request">
<results>
<default-result exit-status="rejected" enter-status="pending" state="initial"/>
</results>
</transition>
<transition id="approve_1" name="Manager Approve Request">
<results>
<default-result enter-status="pending" join="join"/>
</results>
</transition>
</transitions>
</state>
<state id="approval_2" name="Administrator Approval">
<transitions>
<transition id="deny_2" name="Administrator Reject Request">
<results>
<default-result exit-status="rejected" enter-status="pending" state="initial"/>
</results>
</transition>
<transition id="approve_2" name="Administrator approve request">
<results>
<default-result enter-status="pending" join="join"/>
</results>
</transition>
</transitions>
</state>
<state id="approved" name="Access Request Approved"/>
</states>
<forks>
<fork id="fork">
<default-result enter-status="pending" state="approval_1"/>
<default-result enter-status="pending" state="approval_2"/>
</fork>
</forks>
<joins>
<join id="join">
<conditions operator="AND">
<condition type="script" value="groovy">
<arg name="script">join.approval_1.status.completed</arg>
</condition>
<condition type="script" value="groovy">
<arg name="script">join.approval_2.status.completed</arg>
</condition>
</conditions>
<default-result enter-status="completed" state="approved"/>
</join>
</joins>
</workflow>
workflow:
id: "Access Request Worfklow"
initial-transitions:
- id: "start"
name: "Create Access Request"
default-result:
state: "initial"
enter-status: "pending"
states:
- id: "initial"
name: "Access Request Draft"
transitions:
- id: "submit"
name: "Submit Access Request"
default-result:
fork: "fork"
enter-status: "pending"
- id: "approval_1"
name: "Manager Approval"
transitions:
- id: "deny_1"
name: "Manager Reject Request"
default-result:
state: "initial"
exit-status: "rejected"
enter-status: "pending"
- id: "approve_1"
name: "Manager Approve Request"
default-result:
join: "join"
enter-status: "pending"
- id: "approval_2"
name: "Administrator Approval"
transitions:
- id: "deny_2"
name: "Administrator Reject Request"
default-result:
state: "initial"
exit-status: "rejected"
enter-status: "pending"
- id: "approve_2"
name: "Administrator Approve Request"
default-result:
join: "join"
enter-status: "pending"
- id: "approved"
name: "Access Request Approved"
forks:
- id: "fork"
default-results:
- state: "approval_1"
enter-status: "pending"
- state: "approval_2"
enter-status: "pending"
joins:
- id: "join"
condition:
and:
- script: "groovy"
args:
- script: |
join.approval_1.status.completed
- script: "groovy"
args:
- script: |
join.approval_2.status.completed
default-result:
state: "approved"
enter-status: "completed"
AI Integration
Leverage AI capabilities for intelligent workflow decisions and validation.
AI-Powered Features
- • AI Validation: Use AI to validate document content, images, or data
- • Smart Transitions: Let AI decide the optimal workflow path
- • Content Analysis: Analyze and categorize workflow data
- • Predictive Routing: Predict the best next steps based on historical data
workflow:
id: "access-request-with-policy-check"
initial-transitions:
- id: "create_request"
name: "Create Access Request"
default-result:
state: "draft"
enter-status: "pending"
states:
- id: "draft"
name: "Draft Access Request"
transitions:
- id: "submit"
name: "Submit for Policy Check"
default-result:
state: "policy_check"
post-functions:
- alias: "ai"
args:
- prompt: |
You are a corporate policy enforcement AI. Analyze this access request:
Request Reason: ${inputs.reason}
Requested Access: ${inputs.access_level}
User Role: ${inputs.user_role}
Department: ${inputs.department}
Requested Systems: ${inputs.systems}
Company Policies:
- Financial data access requires VP approval
- Customer data access requires manager approval
- Admin access requires dual approval
- Temporary access limited to 30 days
- Sensitive systems require background check
Return JSON response:
{
"compliant": true/false,
"policy_violations": ["list of violations"],
"required_approvals": ["list of required approvers"],
"risk_level": "LOW/MEDIUM/HIGH",
"recommendation": "explanation"
}
- inputs:
- name: "reason"
- name: "access_level"
- name: "user_role"
- name: "department"
- name: "systems"
- id: "policy_check"
name: "Policy Compliance Check"
transitions:
- id: "resolution"
name: "Policy Resolution"
results:
- state: "manager_approval"
condition:
- script: "groovy"
args:
- script: "transients.compliant"
default-result:
state: "rejected"
enter-status: "rejected"
- id: "manager_approval"
name: "Manager Approval"
transitions:
- id: "approve"
name: "Approve"
default-result:
state: "approved"
enter-status: "completed"
- id: "reject"
name: "Reject"
default-result:
state: "rejected"
enter-status: "rejected"
- id: "approved"
name: "Access Granted"
- id: "rejected"
name: "Request Rejected"
workflow:
id: "risk-based-routing"
states:
- id: "access_request"
name: "Access Request"
transitions:
- id: "assess_risk"
name: "Assess Risk Level"
default-result:
state: "risk_assessment"
post-functions:
- alias: "ai"
args:
- prompt: |
You are a security risk assessment AI. Evaluate this access request:
User: ${inputs.user_name}
Role: ${inputs.user_role}
Department: ${inputs.department}
Requested Access: ${inputs.access_level}
Target Systems: ${inputs.target_systems}
User History: ${inputs.user_history}
Request Reason: ${inputs.reason}
Risk Factors:
- High-privilege access (admin, root, financial)
- Sensitive data access (PII, customer data, financial)
- Unusual access patterns
- User with previous violations
- Access outside normal hours
- Large scope of access
Return JSON:
{
"risk_level": "LOW/MEDIUM/HIGH",
"risk_factors": ["list of risk factors"],
"recommended_path": "auto_approve/manager_only/dual_approval/security_review",
"confidence": 0.85,
"explanation": "detailed explanation"
}
- inputs:
- name: "user_name"
- name: "user_role"
- name: "department"
- name: "access_level"
- name: "target_systems"
- name: "user_history"
- name: "reason"
- id: "risk_assessment"
name: "Risk Assessment"
transitions:
- id: "risk_resolution"
name: "Risk Resolution"
results:
- state: "auto_approved"
condition:
- script: "groovy"
args:
- script: "transients.risk_level == 'LOW'"
- state: "manager_approval"
condition:
- script: "groovy"
args:
- script: "transients.risk_level == 'MEDIUM'"
- state: "security_review"
condition:
- script: "groovy"
args:
- script: "transients.risk_level == 'HIGH'"
default-result:
state: "manager_approval"
enter-status: "pending"
workflow:
id: "document-approval-with-ai"
states:
- id: "draft"
name: "Document Draft"
transitions:
- id: "submit"
name: "Submit for AI Review"
default-result:
state: "ai_validation"
post-functions:
- alias: "ai"
args:
- prompt: |
You are a document validation AI. Review this document:
Document Type: ${inputs.document_type}
Content: ${inputs.content}
Author: ${inputs.author}
Department: ${inputs.department}
Validation Criteria:
- Grammar and spelling accuracy
- Compliance with company style guide
- Technical accuracy for technical documents
- Legal compliance for contracts
- Data privacy for sensitive documents
Return JSON:
{
"valid": true/false,
"score": 0.85,
"issues": ["list of issues found"],
"suggestions": ["list of improvements"],
"compliance_status": "COMPLIANT/NON_COMPLIANT"
}
- inputs:
- name: "document_type"
- name: "content"
- name: "author"
- name: "department"
- id: "ai_validation"
name: "AI Content Validation"
transitions:
- id: "validation_resolution"
name: "Validation Resolution"
results:
- state: "human_review"
condition:
- script: "groovy"
args:
- script: "transients.valid"
default-result:
state: "revision_required"
enter-status: "pending"
- id: "human_review"
name: "Human Review"
transitions:
- id: "approve"
name: "Approve"
default-result:
state: "approved"
enter-status: "completed"
- id: "reject"
name: "Reject"
default-result:
state: "revision_required"
enter-status: "pending"
- id: "revision_required"
name: "Revision Required"
- id: "approved"
name: "Document Approved"
Persistence Options
Flexible persistence for both workflow definitions and instances with multiple backend options.
Workflow Definitions
Store workflow definitions in your preferred storage:
// Built-in, no dependency needed
// Perfect for testing and development
implementation(platform("com.yworkflow:yworkflow-bom:1.0.0"))
implementation("com.yworkflow:yworkflow-engine")
// Usage example:
var workflows = new DefaultWorkflowsBuilder()
.withInstanceStore(new MemoryWorkflowInstanceStore())
.build(); // Uses in-memory by default
implementation(platform("com.yworkflow:yworkflow-bom:1.0.0"))
implementation("com.yworkflow:yworkflow-engine")
implementation("com.yworkflow:instance-store-repository-mongodb")
<!-- Usage example: -->
var mongoClient = MongoClients.create("mongodb://localhost:27017");
var jsonWorkflowConverter = new JsonWorkflowConverter();
var workflowInstanceRepository = new MongoWorkflowInstanceRepository(mongoClient);
var workflowDefinitionRepository new MongoWorkflowDefinitionRepository(mongoClient,
jsonWorkflowConverter);
var workflows = new DefaultWorkflowsBuilder()
.withInstanceRepository(workflowInstanceRepository)
.withDefinitionRepository(workflowDefinitionRepository)
.build();
Workflow Instances
Store workflow instances in your preferred database:
// Built-in, no dependency needed
// Perfect for testing and development
implementation(platform("com.yworkflow:yworkflow-bom:1.0.0"))
implementation("com.yworkflow:yworkflow-engine")
// Usage example:
var workflows = new DefaultWorkflowsBuilder()
.withInstanceStore(new MemoryWorkflowInstanceStore())
.build();
implementation(platform("com.yworkflow:yworkflow-bom:1.0.0"))
implementation("com.yworkflow:yworkflow-engine")
implementation("com.yworkflow:instance-store-jdbc-sqlite")
<!-- Usage example: -->
var connectionProvider = JdbcConnectionProvider.from(dataSource);
var store = new SqliteJdbcWorkflowInstanceStore(connectionProvider);
var workflows = new DefaultWorkflowsBuilder()
.withInstanceStore(store)
.build();
implementation(platform("com.yworkflow:yworkflow-bom:1.0.0"))
implementation("com.yworkflow:yworkflow-engine")
implementation("com.yworkflow:instance-store-jdbc-postgresql")
<!-- Usage example: -->
var connectionProvider = JdbcConnectionProvider.from(dataSource);
var store = new PostgreSqlJdbcWorkflowInstanceStore(connectionProvider);
var workflows = new DefaultWorkflowsBuilder()
.withInstanceStore(store)
.build();
implementation(platform("com.yworkflow:yworkflow-bom:1.0.0"))
implementation("com.yworkflow:yworkflow-engine")
implementation("com.yworkflow:instance-store-repository-mongodb")
<!-- Usage example: -->
var mongoClient = MongoClients.create("mongodb://localhost:27017");
var jsonWorkflowConverter = new JsonWorkflowConverter();
var workflowInstanceRepository = new MongoWorkflowInstanceRepository(mongoClient);
var workflowDefinitionRepository new MongoWorkflowDefinitionRepository(mongoClient,
jsonWorkflowConverter);
var workflows = new DefaultWorkflowsBuilder()
.withInstanceRepository(workflowInstanceRepository)
.withDefinitionRepository(workflowDefinitionRepository)
.build();