Business Logic
Agentlang workflows define the dynamic behavior of applications — how data flows between entities, reacts to events, and integrates with external systems.
They are declarative, reactive, and can mix Agentlang patterns with embedded JavaScript for flexibility.
1. Overview
A workflow defines a named unit of logic, triggered manually or by system events. A workflow can:
- Create, update, or delete entities.
- React to CRUD events.
- Execute conditional or iterative logic.
- Call external JavaScript functions or log output.
- Send messages or trigger LLM-powered agents.
2. Workflow Definition
Basic Syntax
workflow myWorkflow {
{Entity {attribute value, ...}}
}Each statement inside a workflow is a pattern, defining what to create, update, or delete.
3. CRUD Patterns
Agentlang supports creating or updating entities using a simple pattern-based syntax:
{EntityName {attribute value, ...}}Examples
{Student {id 1, name "John"}} // a new student instance is created
{Teacher {employeeId 1001, subject "Math"}} // a new teacher instance is created4. Query Expressions
Agentlang supports querying entities within workflows using ? to denote conditions.
Example
{Student {id? 101}} @as [student]The above retrieves the Student entity whose id equals 101.
You can use queried values in later statements using the alias binding student, as in student.name.
To query all instances of an entity, attach ? to the entity name and provide no attributes:
{Student? {}}The default query operator is = (is-equals) which need not be specified. You can attach other comparison operators to ?.
For instance, to query all students who is older than 10 years:
{Student {age?> 10}}The full list of query-operators:
=, <>, !=, <, <=, >, >=, in, like, betweenSome examples:
{Student {age?between [10, 15]}}
{Student {name?like "Mat%"}}4.1 Query and Update
An update operation is combined with a query.
Example:
{Student {id? "101", age age + 1}} // increment the age of the student with id 1015. Conditional and Iterative Flow
5.1 Conditional Execution
if (condition) {
...
} else {
...
}Example
if (Student.grade > 80) {
console.log("Excellent student")
}5.2 Iteration
Agentlang workflows can loop over lists or query results:
for (s in {Student {}}) {
console.log(s.name)
}This iterates through all students.
6. Event Workflows
Workflows are triggered by events, which may be explicitly defined.
Example
event createStudent {
id String,
name String
}
workflow createStudent {
{
Student {
id createStudent.id,
name createStudent.name,
email createStudent.name + createStudent.id + "@school.com"
}
} @as s;
console.log("Student created: " + s.name);
s
}A workflow is triggered when an instance of the event is created:
{
createStudent {
id "101",
name "Joe"
}
}A workflow can also be triggered via HTTP. But for this the event or workflow must be declared as @public.
@public event createStudent {
id String,
name String
}Invoking the event via an HTTP POST:
curl -X POST http://localhost:8080/school.core/createStudent \
-H 'Content-Type: application/json' \
-d '{"id": "102", "name": "Mary"}'7. Extended Workflow Capabilities
7.1 Delete and Upsert Patterns
Delete Pattern
delete {E {id? 1}}Deletes the entity E where id equals 1.
Purge Pattern
The delete pattern only soft-deletes an instance. To permanently remove an instance from the store use purge.
purge {E {id? 1}}Upsert Pattern
{E {id 1, v 10}, @upsert}Updates entity E if id=1 exists, otherwise creates a new one.
| Operation | Behavior |
|---|---|
delete | Removes entities matching a query |
@upsert | Updates if exists, inserts otherwise |
7.2 Pre/Post CRUD Workflows
Workflows can hook into CRUD lifecycle events using @before or @after.
Syntax
workflow @before <op>:<Entity> { ... }
workflow @after <op>:<Entity> { ... }Example
entity E {
id Int @id,
v Int
}
entity F {
id Int @id,
w Int
}
workflow @after create:E {
{F {id? this.id, w PrePostEvents/E.v * 100}}
}
workflow @before delete:E {
delete {F {id? this.id}}
}| Hook | Timing | Use Case |
|---|---|---|
@before create | Before insertion | Validation, initialization |
@after create | After insertion | Cascade updates |
@before update | Before modification | Version check |
@after update | After modification | Trigger notifications |
@before delete | Before deletion | Cleanup child entities |
@after delete | After deletion | Audit trail |
Special Variables
| Variable | Meaning |
|---|---|
this | Refers to the current entity instance |
<ModuleName>/<EntityName> | Refers to other entities within the workflow |
7.3 JavaScript Integration
Agentlang allows you to import and call JavaScript modules for procedural or external logic.
Import Syntax
import "<path-to-js>" @as <alias>Example
module acme.core
import "emailClient.js" @as email
workflow SendMail {
console.log("sending email to " + SendMail.email)
email.sendMail(SendMail.email, SendMail.body)
}emailClient.jsshould export callable JS functions.- Workflows can use JS built-ins like
console.log.
Example with Return Values
import "textUtils.js" @as text
workflow NormalizeAndSave {
text.normalize(NormalizeAndSave.name) @as normalizedName;
{Person {name normalizedName}}
}This normalizes a name using an external JS function before saving it.
To wait for an asynchronous function:
workflow readEmail {
await email.read(readEmail.address)
}Execution Model
- JavaScript runs in a sandboxed context within the Agentlang runtime.
- Functions can be synchronous or asynchronous.
- Return values can be used in subsequent workflow patterns.
7.4 Summary
| Feature | Description |
|---|---|
| delete pattern | Removes entities matching a query |
| upsert pattern | Merges entity state atomically |
| @before/@after workflows | Lifecycle hooks for entities |
| this | Refers to the triggering entity instance |
| import JS modules | Integrate with custom logic |
| console.log | Built-in logging |
| let variables | Local value bindings inside workflows |
Example — Combined Features
module acme.school
import "notify.js" @as notify
entity Student {
id Int @id,
name String,
grade String
}
entity ReportCard {
id Int @id,
studentId Int,
score Int
}
workflow @after create:ReportCard {
if (this.score < 40) {
notify.send("Alert: " + this.studentId + " has failed.")
}
}