Ontoz Platform
Ontologica
Ontologica is the business domain-specific language behind Ontoz. It gives humans, systems and AI agents a shared, declarative vocabulary for describing work — not only what happens, but what is allowed to happen.
Ontoz is a definition-driven orchestration platform. A small set of generic engines — orchestrator, rules, data, integration, UI and AI — execute behaviour that is described entirely in declarative artifacts. Those artifacts are Ontologica constructs.
The platform contains no domain logic. A loan origination system, an insurance claims process and an employee onboarding workflow are the same engine running different configuration sets. Adding a business process is a configuration exercise: no platform code changes are required for new flows, new fields, new rules, new integrations or new tenants.
Who this is for
This reference is written for the people who author Ontologica configuration — solution engineers, business analysts, integration developers — and for anyone building tooling that generates Ontoz configuration. It describes what valid configuration looks like and what it means. It is not a guide to any particular deployment.
What a definition looks like
Ontologica is expressed in three complementary artifact languages:
| Artifact | Language | Describes |
|---|---|---|
| Workflow definitions | YAML | The Flow → Stage → Activity → Task → Action hierarchy, rule-set references, allocation and role/access configuration. |
| Data model | GraphQL | Types, inputs, enums and directives describing the data that rules and actions read and write. |
| Business rules | Groovy | Decision, orchestration, assignment and scripting logic. Each rule returns a strongly-typed response. |
UI forms, integration bindings and tenant patches are configured in the same declarative spirit. Everything is versioned, inheritable and hot-reloadable.
Conventions used in this document
| Marker | Meaning |
|---|---|
| required | The property must be present for the construct to load. |
| optional | The property may be omitted; the engine applies a documented default or skips the behaviour. |
| inherited | The property comes from a parent construct (for example BaseDefinition). |
| deprecated | Still functional, but superseded. Do not use in new configuration. |
Property names are given in their JSON/YAML form — that is what appears in configuration files. Types are shown as declared in the platform's construct definitions.
The mental model#
Ontologica organises every construct into six families. Understanding which family a construct belongs to tells you what it is allowed to do.
A seventh family — AI constructs — layers copilots and autonomous agents on top of the others. Critically, AI does not add a parallel execution path: everything an agent does flows back through actions, mutations, integrations and rules, so audit, inheritance and hot-reload semantics stay uniform across human, automated and AI work.
Two invariants worth internalising
Process constructs (Flow, Stage, Activity, Task, Action) describe shape and sequence only. Every decision is delegated to a named rule set. This is what makes a flow readable and what makes a flow's behaviour patchable per tenant without rewriting its structure.
There is no separate permission object. A role's access is exactly the set of Actions it may invoke in the current (stage, role) context, and an Action is the only way data is read or written. Reading is a ReadAction carrying a query; writing is a WriteAction carrying mutations. There is no code path that touches application data outside an action executor.
Anatomy of a flow#
The process hierarchy is strict and has five levels.
| Level | Definition | Lending example | Insurance example |
|---|---|---|---|
| Flow | A complete business process. | Loan Origination | Claims Processing |
| Stage | A major lifecycle phase. Closes when its milestone condition is met. | Application, Evaluation, Approval, Disbursement | Filing, Triage, Investigation, Settlement |
| Activity | A logical group of related tasks within a stage. | Applicant Information, KYC Verification | Damage Assessment, Policy Verification |
| Task | A single unit of work — human, automated, or an integration call. | Fill personal info form, Upload ID document | Upload damage photos, Review adjuster report |
| Action | An operation performed on a task. | Submit, Approve, Reject, Request clarification | Approve claim, Request more information |
A running Flow is a flow instance — one per application, or "case" in business-facing language. It holds the JSONB data payload plus flow state: current stage, open activities, live tasks.
Flow (process)
└── Stage → Activity → Task (process)
├── references → Form Definition (UI)
├── references → Mutation in GraphQL Schema (data)
├── references → Rule Sets (logic)
├── references → Integration API + Mapper (integration)
└── governed by → Stage Role Definition (access)
All wrapped in a Base / Variant configuration chain (config).
Quickstart#
Six artifacts take a business process from nothing to running. The example below sketches an insurance claims flow; the same six steps apply to any domain.
1 · Declare the flow
# flow_definitions.yaml
- definitionKey: insurance-claims
label: "Insurance Claims Processing"
prefix: "CLM"
initialStatus: IN_PROGRESS
stages: # ordered — the flow walks this list by index
- filing
- triage
- investigation
- adjudication
- settlement
initiateFlowMutation: createClaim
applicationDataScreenId: claims-overview
2 · Declare stages, activities and tasks
# stage_definitions.yaml
- definitionKey: triage
label: "Triage"
mandatoryActivities: [initialReview, policyVerification]
possibleActivities: [fraudScreening]
activityOrchestrationRuleSet:
name: TriageActivityOrchestration
ruleType: ACTIVITY_ORCHESTRATION
stageCompletionRuleSet:
name: TriageMilestone
ruleType: MILESTONE_ACHIEVED
# activity_definitions.yaml
- definitionKey: initialReview
label: "Initial Review"
startTasks: [reviewClaimForm]
activityCompletionRuleSet:
name: InitialReviewComplete
ruleType: COMPLETE_ACTIVITY
tasks:
- definitionKey: reviewClaimForm
taskType: HUMAN
screenId: claim-review-screen
clarificationsEnabled: true
allocationStrategy:
assignment:
- allocationStrategyIdentifier: ROLE_BRANCH_CLAIM
data: { roles: [claims_reviewer] }
taskActions:
primaryReadActionName: readClaimDetails
allowedActionNames: [readClaimDetails, updateReviewNotes, approveTriage]
mandatoryActionNames: [approveTriage]
taskMovement:
nextTask: [assignAdjuster]
3 · Declare the data model
# claims-schema.graphqls
extend type CustomerApplicationData {
claimNumber: String
policyNumber: String
claimType: String
incidentDate: String
claimAmount: Float
claimantDetails: ClaimantDetails
}
type ClaimantDetails {
name: String
contactNumber: String
address: String
}
input UpdateClaimDetailsInput {
claimType: String @MappedTo(field: "$.customerApplicationData.claimType")
claimAmount: Float @MappedTo(field: "$.customerApplicationData.claimAmount")
@Min(value: 0, message: "Claim amount cannot be negative")
reviewNotes: String @MappedTo(field: "$.applicationDecisioningData.reviewNotes")
reviewedBy: String @ValueFrom(fromContext: "user.userId")
reviewedAt: String @CurrentTimestamp
}
4 · Write the business rules
// TriageActivityOrchestration.groovy
class TriageActivityOrchestration implements ActivityOrchestrationRuleExecutionTrait {
boolean validateInput() { return ruleInput.applicationData != null }
void ruleImplementation() {
def amount = ruleInput.applicationData?.claimAmount ?: 0
if (amount > 50000) {
ruleOutput.nextActivities.add("detailedInvestigation")
} else {
ruleOutput.nextActivities.add("fastTrackAdjudication")
}
}
}
5 · Configure the UI
// action config for the reviewClaimForm task
export const reviewClaimActions = [
{
label: "Approve Triage",
actionType: "popup",
endpoint: "/api/actions/{flow}/{applicationId}/task/{taskId}/approveTriage",
form: [
{ name: "reviewNotes", type: "textarea", label: "Review Notes", required: true }
],
successMessage: "Triage approved successfully"
}
]
6 · Register the flow and its access
# flow-uam-mapping.yaml — registers the flow with the platform catalog
- flowKey: insurance-claims
productName: motor-insurance
organizationName: insurer-realm
host:
dataLayer: http://data-layer-service
workflow: http://workflow-service
ruleService: http://rule-service
# stage_role_definitions.yaml — what each role may do, per stage
- stage: triage
role: claims_reviewer
visibleTasks: [reviewClaimForm]
topLevelActions:
- { name: cancelClaim, type: global }
- { name: approveTriage, type: task, taskKey: reviewClaimForm }
readAction: readClaimDetails
writeAction: updateClaimDetails
The flow registration file is historically named flow-uam-mapping.yaml. It does not bind tenants — it registers the flow with the platform catalog and routes its service hosts. See Naming conventions.
Process constructs#
Process constructs describe structure. They are loaded from the workflow configuration domain and validated at load time. Each carries a definitionKey that is unique within its type and is how every other construct refers to it.
BaseDefinition#
Base type for FlowDefinition, StageDefinition, ActivityDefinition, TaskDefinition, StageRoleDefinition, StatusDefinition
| Property | Type | Req | Description |
|---|---|---|---|
definitionKey | String | required | Unique identifier (key) for this definition. |
label | String | optional | Human-readable label. |
description | String | optional | Human-readable description of what this construct is or does. |
FlowDefinition#
extends BaseDefinition · flow_definitions.yaml
The root of a business process. Owns the ordered stage list, the initiation mutation, and flow-wide defaults.
| Property | Type | Req | Description |
|---|---|---|---|
definitionKey | String | required inh | Unique identifier for the flow. |
label | String | optional inh | Human-readable label. |
description | String | optional inh | What the flow does. |
stages | List<String> | optional | Stage definition keys that comprise the flow, in execution order — the engine walks this list by index to pick the next stage. |
initiateFlowMutation | String | optional | Mutation executed when the flow is initiated. Its input type defines the shape of initialData on the initiate call. |
initialStatus | String | optional | Application status a new case starts in (e.g. IN_PROGRESS). |
prefix | String | optional | Prefix used when generating application IDs for this flow. |
sideStages | Set<String> | optional | Stage keys that run alongside the main stage sequence, in parallel, without blocking it. Supersedes floatingActivities. |
reportingReadAction | String | optional | Read action used for reporting and analytics. |
migrationFlowWriteAction | String | optional | Write action used for data migration during flow transitions. |
initialDataTransformerRule | String | optional | Rule that transforms the initial input data when the case is created. |
applicationDataScreenId | String | optional | Front-end screen id used to render this flow's application-data view. |
$extends | String | optional | Parent flow definition key this flow inherits configuration from. Java field extendsFrom; JSON name is literally $extends. |
globalReadAction | String | deprecated | Default read action across all stages. Superseded by GlobalStageRoleRead plus the StageRole readAction. |
globalDocumentViewAction | String | deprecated | Global document-view action. Superseded by StageRole documentTreeAction. |
globalDocumentEvalAction | String | deprecated | Global document-evaluation action. Superseded by StageRole documentEvalAction. |
roleBasedGlobalActionsAllowed | Map<String, List<String>> | deprecated | Legacy role → global-action map. Still validated at load time (each action must exist, be a START_ACTIVITY or START_TASK workflow action, and carry a pre-condition rule). Superseded by topLevelActions on StageRoleDefinition. |
activityOrchestrationRuleSet | BusinessRuleSet | deprecated | Flow-level activity orchestration. Retained only as a fallback for stages that declare no per-stage rule. |
floatingActivities | Set<String> | deprecated | Activities that could trigger at any point regardless of stage. Superseded by sideStages. |
StageDefinition#
extends BaseDefinition · stage_definitions.yaml
A major lifecycle phase. A stage is entered in the order given by FlowDefinition.stages, gated by its start rule, and closes when its completion rule signals the milestone is achieved.
| Property | Type | Req | Description |
|---|---|---|---|
definitionKey | String | required inh | Unique identifier for the stage. |
label | String | optional inh | Human-readable label. |
description | String | optional inh | The stage's purpose. |
mandatoryActivities | Set<String> | optional | Activity keys that must complete before the stage can close. |
possibleActivities | Set<String> | optional | Activity keys that may optionally run in this stage. |
startStageRuleSet | BusinessRuleSet | optional | A START_STAGE gate evaluated when the stage is reached. Returning false skips the stage and cascades to the next one. Absent means always start. It does not control when the stage is reached — that is fixed by key order in FlowDefinition.stages. |
activityOrchestrationRuleSet | BusinessRuleSet | optional | Per-stage rule deciding which activities run in this stage and in what order. This is the intended mechanism; the flow-level rule is a deprecated fallback used only when this is null. |
stageCompletionRuleSet | BusinessRuleSet | optional | Rule determining stage completion / milestone achievement. |
ActivityDefinition#
extends BaseDefinition · activity_definitions.yaml
A logical group of related tasks. Activities are started by activity orchestration, never by a hard-coded list on the stage.
| Property | Type | Req | Description |
|---|---|---|---|
definitionKey | String | required inh | Unique identifier for the activity. |
label | String | optional inh | Human-readable label. |
description | String | optional inh | The activity's purpose. |
tasks | List<TaskDefinition> | optional | Task definitions declared inline in this activity. |
taskKeys | List<String> | optional | Definition keys of tasks declared in the separate task configuration. A task key may appear in multiple activities — this is how tasks are reused. |
startTasks | List<String> | optional | Task keys started when the activity is initiated. |
activityStartRuleSet | BusinessRuleSet | optional | A START_ACTIVITY rule that computes which tasks to start, used when no static startTasks set is configured. |
activityCompletionRuleSet | BusinessRuleSet | optional | A COMPLETE_ACTIVITY rule evaluated whenever a task in this activity completes. |
taskOrchestrationRuleset | String | optional | Activity-level rule governing task sequencing. The lowest-priority mechanism for choosing the next task. |
readActivityActionName | String | optional | Read action for retrieving activity data. |
activityInputAction | String | optional | Action providing input data when the activity starts. |
applicationStatus | String | optional | Status applied to the case when this activity completes — set when non-null and the flow is not terminating. It is not applied at activity start. |
applicationStatus fires on activity completion, not on start. Configuration written against older documentation frequently gets this backwards, producing statuses that appear one step early in the timeline.
TaskDefinition#
extends BaseDefinition · declared inline on an activity or in task_definitions.yaml
A single unit of work. Everything about how a piece of work is performed — who does it, what they may do, what happens next, whether it calls an external system — hangs off the task.
| Property | Type | Req | Description |
|---|---|---|---|
definitionKey | String | required inh | Unique identifier for the task. |
label | String | optional inh | Human-readable label. |
description | String | optional inh | The task's purpose. |
taskType | TaskType | optional | Execution model — see TaskType. |
taskActions | TaskActionsDefinition | optional | Which actions are available, mandatory and primary for this task. |
taskMovement | TaskMovementDefinition | optional | Next / move / refer targets and the next-task rule. |
allocationStrategy | AllocationStrategyDefinition | optional | How the task is assigned. See Allocation strategies. |
automatedTaskRuleSet | AutomatedTaskRuleSet | optional | Rules for automated execution (read/write actions plus logic). |
integrationDefinition | IntegrationDefinition | optional | Configuration for synchronous integration and HTTP tasks. |
asyncIntegrationDefinition | AsyncIntegrationDefinition | optional | Configuration for asynchronous integration with callback handling. |
preConditionRule | List<String> | optional | Pre-condition rule names that must pass before this task may start. |
screenId | String | optional | Front-end screen id rendered for this task. |
systemTask | boolean | optional | If true, an internal system task not exposed to end users. |
canReferFurther | boolean | optional | Whether the task can be referred onward to another user or stage. |
timelineAccessAllowed | boolean | optional | Whether users can view the task history / timeline. |
clarificationsEnabled | boolean | optional | Whether clarification threads are enabled on this task. |
taskToPause | List<String> | optional | Task keys to pause when this task executes. |
taskToResume | List<String> | optional | Task keys to resume when this task completes. |
documentEvalActions | List<String> | optional | Document-evaluation action names available in this task. See Documents. |
Task sub-constructs#
TaskType (enum)
| Value | Description |
|---|---|
HUMAN | Performed by an internal system user. Allocation and a form apply. |
EXTERNAL_USER_HUMAN | Performed by an external user — customer, broker, partner. Resolved against the child organisation realm. |
AUTOMATED | Executed by a rule set without user intervention. |
INTEGRATION | Synchronous external call with request/response. |
ASYNC_INTEGRATION | Outbound call plus an inbound callback; the task waits. |
HTTP | Direct HTTP task using a mapper for request/response transformation. |
TaskActionsDefinition
| Property | Type | Req | Description |
|---|---|---|---|
primaryReadActionName | String | optional | Primary read action for fetching task data. |
allowedActionNames | Set<String> | optional | Every action available to users on this task. This set is the gate for task-scoped access. |
mandatoryActionNames | Set<String> | optional | Actions that must run before the task can complete. |
mandatoryActionMessage | Map<String, String> | optional | Per-action message explaining why an action is mandatory. |
TaskMovementDefinition
| Property | Type | Req | Description |
|---|---|---|---|
nextTask | List<String> | optional | Task keys that follow this task in the normal forward flow. Highest priority in task progression. |
moveTask | List<String> | optional | Task keys this task may be moved to (horizontal transition). |
referTask | List<String> | optional | Task keys this task may be referred to (escalation / refer-back). Not part of forward progression. |
nextTaskRuleSet | BusinessRuleSet | optional | Task-level orchestration rule that picks which follow-on task runs, based on outcome. |
BusinessRuleSet
The registration record for a rule inside a definition. Wherever a construct says "rule set", this is the shape.
| Property | Type | Req | Description |
|---|---|---|---|
name | String | optional | Unique name of the rule set. Resolves to a Groovy file on disk. |
ruleType | RuleType | optional | Determines when the rule runs and which response it must return. See Rule types. |
readAction | String | optional | Read action used to fetch data for rule evaluation. |
writeAction | String | optional | Write action executed when the rule decides an outcome. |
internalActivityDataRequired | boolean | optional | Whether evaluation needs internal activity data loaded into the execution context. |
AutomatedTaskRuleSet
Extends BusinessRuleSet with no additional fields — it exists as a distinct type so an AUTOMATED task's rule binding is unambiguous. All five properties above apply; ruleType is typically AUTOMATED, TASK_ORCHESTRATION or SCRIPT.
ActivityTaskReference
| Property | Type | Description |
|---|---|---|
activityName | String | Definition key of the activity this task reference belongs to. |
taskName | String | Definition key of the referenced task. |
StatusDefinition#
extends BaseDefinition
Declares an application status a case can hold, and whether reaching it ends the case.
| Property | Type | Req | Description |
|---|---|---|---|
definitionKey | String | required inh | Unique identifier for the status. |
label | String | optional inh | Human-readable label. |
description | String | optional inh | What this status means. |
terminate | boolean | optional | Whether reaching this status terminates the flow — true marks a terminal state. |
Control flow#
This is the authoritative model for what starts what. Control flow happens at three levels — stage progression, activity orchestration and task orchestration — plus a set of triggers that can start work out-of-band.
Flow initiation#
Nothing runs until a flow is initiated. A flow instance is created by calling the initiate API with an initiation body:
| Field | Req | Meaning |
|---|---|---|
flowDefinitionKey | mandatory | Which flow definition to instantiate. |
branchDetails | mandatory | The branch context the instance is created under, as a map. Downstream allocation strategies resolve users against this branch. |
initialData | required in practice | The initial application data. Its shape is defined by FlowDefinition.initiateFlowMutation — that mutation's input type describes exactly what initialData must contain. |
On success the engine persists the initial application (applying initiateFlowMutation and setting initialStatus) and starts the first stage — the first entry in the flow's ordered stages list. That stage's own startStageRuleSet still applies. Starting the first stage is what kicks off the entire lifecycle.
Stage progression#
Stage order is static: it is the index order of FlowDefinition.stages. Rules cannot reorder stages; they can only decide whether a stage runs.
- When the engine advances, it takes the next key from
stages. - The stage starts only if its
startStageRuleSetreturnsstartStage: true. - A stage with no start rule set always starts. A stage with one is conditional and therefore skippable — if it returns
false, the engine cascades to the next stage in the list.
Stages listed in FlowDefinition.sideStages run alongside the main sequence in parallel and do not block it.
Activity orchestration#
An activity is started only by an activity-orchestration rule set. There is no hard-coded "next activity" list anywhere in the model. The rule decides which activity or activities start next.
| Configured on | Field | Notes |
|---|---|---|
| StageDefinition | activityOrchestrationRuleSet | The primary, per-stage rule. This is what you should configure. |
| FlowDefinition | activityOrchestrationRuleSet deprecated | Flow-level fallback, used only for stages that declare none. |
Precedence: the stage-level rule always wins. mandatoryActivities and possibleActivities on the stage describe what may run and what must complete for the stage to close — they do not themselves start anything.
Task orchestration#
Entering an activity
When an activity starts, its entry-point tasks begin. An activity declares them one of two ways:
startTasks— the explicit list of tasks entered when the activity starts.activityStartRuleSet— aSTART_ACTIVITYrule that computes the task set at runtime, returningtasksToStart.
Task-to-task progression
When a task completes and the activity is not yet complete, the next task inside the same activity is chosen. Three mechanisms are consulted in strict priority order — the first one configured wins:
| # | Mechanism | Field |
|---|---|---|
| 1 | Hard-coded follow-on tasks — highest priority; if present, it decides. | Task.taskMovement.nextTask |
| 2 | Task-level orchestration rule — used when there is no nextTask. Declared on the task's movement block; you will see it referred to as both nextTaskRuleSet (the property name) and the task-level task-orchestration ruleset (its role). | Task.taskMovement.nextTaskRuleSet |
| 3 | Activity-level orchestration rule — the fallback when neither of the above is defined. | Activity.taskOrchestrationRuleset |
referTask is a separate refer-back movement. It is not part of the forward progression priority above.
The completion cascade#
Every time a task completes, the engine walks up the hierarchy before deciding what runs next.
task completes
│
├─▶ 1. Evaluate Activity.activityCompletionRuleSet
│ false → activity still running
│ → start the NEXT TASK (priority order in §Task orchestration)
│ true → activity complete, continue ↓
│
├─▶ 2. Evaluate StageDefinition.stageCompletionRuleSet
│ false → stage still running
│ → ACTIVITY ORCHESTRATION picks the next activity
│ (stage-level rule takes precedence over flow-level)
│ true → stage complete, continue ↓
│
└─▶ 3. Advance to the next stage in FlowDefinition.stages
→ gated by that stage's startStageRuleSet
→ false: skip it and cascade to the stage after it
In one sentence: activity-completion check → (if complete) stage-completion check → (if stage complete) next stage from the ordered list, gated by its start rule → (else) next activity via orchestration → (else) next task.
Out-of-band triggers#
Beyond the cascade, work can be started by three families of triggers.
| Family | Mechanism |
|---|---|
| Automated task rule sets | A task carrying automatedTaskRuleSet runs on its own and can start or advance work with no human action. Its AutomationRuleResponse may carry activitiesToStart, activitiesToEnd, tasksToStart and taskIdsToEnd. |
| Scripts | Groovy scripts that run as a side effect and can start tasks: Action.actionScriptRules, and assignment / reassignment scripts named on a task's allocationStrategy (scripts, or an ASSIGNMENT_RULE strategy's data.ruleName). |
| Workflow actions | Actions whose workflowActionType explicitly starts or moves work: START_TASK (starts taskDefinitionKey), START_ACTIVITY (starts activityDefinitionKey), MOVE_ACTIVITY (transitions to activityDefinitionKey). |
Field cheat sheet#
| Concept | Construct | Field |
|---|---|---|
| Flow initiation body | initiate API | flowDefinitionKey, branchDetails, initialData |
Mutation that shapes initialData | FlowDefinition | initiateFlowMutation |
| Status set on initiate | FlowDefinition | initialStatus |
| First stage started on initiate | FlowDefinition | stages[0] |
| Ordered stage sequence | FlowDefinition | stages |
| Parallel side stages | FlowDefinition | sideStages |
| Stage start gate | StageDefinition | startStageRuleSet |
| Stage completion | StageDefinition | stageCompletionRuleSet |
| Activity orchestration (per stage) | StageDefinition | activityOrchestrationRuleSet |
| Activity orchestration (fallback) | FlowDefinition | activityOrchestrationRuleSet dep |
| Activity entry tasks | ActivityDefinition | startTasks |
| Activity start rule | ActivityDefinition | activityStartRuleSet |
| Activity completion | ActivityDefinition | activityCompletionRuleSet |
| Task orchestration (activity level) | ActivityDefinition | taskOrchestrationRuleset |
| Task orchestration (task level) | TaskDefinition | taskMovement.nextTaskRuleSet |
| Hard-coded next tasks | TaskDefinition | taskMovement.nextTask |
| Refer-back tasks | TaskDefinition | taskMovement.referTask |
| Task pre-conditions | TaskDefinition | preConditionRule |
| Automated task | TaskDefinition | automatedTaskRuleSet |
| Action script | Action | actionScriptRules |
| Assignment / reassignment script | TaskDefinition | allocationStrategy.scripts |
| Start-task action | Action (START_TASK) | taskDefinitionKey |
| Start-activity action | Action (START_ACTIVITY) | activityDefinitionKey |
| Move-activity action | Action (MOVE_ACTIVITY) | activityDefinitionKey |
Referenced-but-undefined targets
If a construct references a task or activity that is not defined in the flow — for example a MOVE_ACTIVITY action pointing at a non-existent activity — the target is still recorded in the flow graph as a thin node marked referencedOnly, and the referencing edge is kept. These are genuine configuration defects and are surfaced by flow analysis tooling rather than silently dropped.
The Action model#
An Action is an operation performed in the context of a task or a stage. Actions are the platform's only data boundary: reading, writing, calling an external system, moving the workflow and touching documents are all actions, dispatched polymorphically by actionType.
Action (base)
| Property | Type | Req | Description |
|---|---|---|---|
name | String | optional | Unique name identifier. This is the key referenced from allowedActionNames, topLevelActions and rule sets. |
description | String | optional | Human-readable description. |
preConditionRule | List<String> | optional | Rules that must return preConditionsMet: true before the action can execute. |
status | ApplicationStatus | optional | Application status to assign when the action runs. |
actionScriptRules | List<String> | optional | Script rules executed as part of the action. May start tasks. |
hardWriteAction | String | optional | Write action force-executed regardless of normal logic. |
hardWriteActionData | Map<String, Object> | optional | Data payload for hardWriteAction. |
systemAllowed | boolean | optional | Whether the system (a non-user caller) may execute this action. |
completeAction | boolean | optional | Whether executing this action completes the task — this is what triggers the completion cascade. |
isCommentRequired | boolean | optional | Whether a user comment is required to execute. |
ActionType#
| Value | Description |
|---|---|
READ | Fetches and displays application data. |
WRITE | Persists data mutations to application state. |
WORKFLOW | Workflow control — start, complete, move, refer. See WorkflowActionType. |
VERIFY | Verifies conditions using a read action. |
INTERNAL_ACTIVITY_READ | Reads data from another activity in the flow. |
EXTERNAL_API | Calls an external API via an integration definition. |
HTTP_MAPPER | HTTP call with custom request/response mapping. |
DOC_EVAL | Uploads or evaluates documents. Declares the document catalog and scopes. |
DOCUMENT_MANAGEMENT_VIEW | Renders the document tree. |
DMS_ACTION | Generic interaction with the document management system. |
ROLE_USER_LIST | Returns the list of users holding a specific role. |
REASSIGN | Reassigns a task to a different user or queue. |
SYSTEM | System-only action, not exposed to users. |
WorkflowActionType#
Applies to actions of type WORKFLOW.
| Value | Description |
|---|---|
START_TASK | Initiates the task named in taskDefinitionKey. |
START_ACTIVITY | Initiates the activity named in activityDefinitionKey. |
COMPLETE_TASK | Completes a task and proceeds to the next. |
MOVE_TASK | Moves a task to an alternate task. |
MOVE_ACTIVITY | Moves an activity to a different stage / transitions to another activity. |
REFER_BACK | Refers or escalates a task to another queue or stage. |
ASSIGN | Assigns a task to a specific user. |
REASSIGN_USERS | Reassigns a task to different users. |
REJECT | Rejects a task and returns to the previous state. |
Action subtypes#
Each subtype fixes its actionType and adds its own payload on top of the base fields.
| Subtype | actionType | Distinct fields |
|---|---|---|
| ReadAction | READ | queryString — the GraphQL / data-retrieval query. Reading data is invoking this. |
| WriteAction | WRITE | mutations — a list of Mutation{name, inputType} applied to the data layer. |
| VerifyAction | VERIFY | readActionName — the read action executed for verification. |
| InternalActivityReadAction | INTERNAL_ACTIVITY_READ | activityDefinitionKey, queryString. |
| ExternalApiAction | EXTERNAL_API | integrationDefinition — API details, mappers, auth. |
| HttpMapperAction | HTTP_MAPPER | writeAction, ibApiDetails (URL, method, headers, auth). |
| DocEvalAction | DOC_EVAL | documents (per-document config), defaultScope. See Document actions. |
| AllDocumentsViewAction | DOCUMENT_MANAGEMENT_VIEW | config (document tree), readAction, ruleSet. |
| DmsAction | DMS_ACTION | writeAction — persists DMS operation results. |
| RoleUserListAction | ROLE_USER_LIST | role — the role id to query users for. |
| ReassignAction | REASSIGN | name is always reassign. |
ActionContext
Every action executes inside a context that rides along to rules, mutations and the audit trail.
| Property | Type | Description |
|---|---|---|
role | String | Role of the user executing the action. |
currentUser | UserJwtDto | User details taken from the JWT. |
taskDefinitionKey / taskId | String | Current task definition key and runtime instance id. |
activityDefinitionKey / activityId | String | Current activity definition key and runtime instance id. |
requestBody | Map<String, Object> | Request payload provided when executing the action. |
Rules#
Business logic in Ontologica lives in rule sets — Groovy classes grouped by rule type. The rule type is the contract: it fixes when the engine invokes the rule and which response object the rule must return. Rules are hot-reloadable; they can be updated at runtime without restarting the platform.
The 16 rule types#
| RuleType | When it runs | Returns |
|---|---|---|
AUTOMATED | Inside an automation task — computes values and may dynamically start or end tasks and activities. | AutomationRuleResponse |
ACTIVITY_ORCHESTRATION | When an activity completes — decides the next set of activities to start. | ActivityOrchestrationRuleResponse |
START_ACTIVITY | When an activity starts — decides which tasks to start, when no static task set is configured. | ActivityStartRuleResponse |
COMPLETE_ACTIVITY | When any task in an activity completes — decides whether the activity is complete. | ActivityCompletionRuleResponse |
TASK_ORCHESTRATION | When a task completes, if it is configured to call a rule set — decides the next tasks. | TaskOrchestrationRuleResponse |
START_STAGE | At stage start — the start-vs-skip gate for a stage. | StartStageRuleResponse |
MILESTONE_ACHIEVED | Decides whether a stage's milestone has been achieved, driving stage completion. | MilestoneAchievedRuleResponse |
PRE_ACTION | Evaluates whether an action's preconditions are met, before it runs or when listing possible actions. | ActionPreConditionRuleResponse |
BUTTON_STATUS_CHECK | Precondition-style check driving button and action availability. Same executor family as PRE_ACTION. | ActionPreConditionRuleResponse |
ASSIGNMENT | Decides task assignment. Used by the ASSIGNMENT_RULE allocation strategy. | AssignmentRuleResponse |
STAGE_ROLE_CONFIG | Decides per-role stage visibility and actions at runtime. | StageRoleConfigRuleResponse |
INTEGRATION_MAPPER | Maps and builds request payloads for outbound integrations. | IntegrationMapperRuleResponse |
ASYNC_INBOUND_CALL_MAPPER | Maps inbound asynchronous callback payloads. | AsyncInboundCallRuleResponse |
ALL_DOCUMENTS_VIEW | Builds the documents view for a flow. | AllDocumentsViewRuleResponse |
OBJECT_TRANSFORMER | Transforms an object. Served via a dedicated transformer endpoint. | ObjectTransformerRuleResponse |
SCRIPT | General-purpose scripting rule. See Script rules. | ScriptRuleResponse |
Validation and deduplication are frequently described as rule types, but they are not members of the RuleType enum. They are separate executors reached via dedicated endpoints with their own request types, not through the generic rule-execution switch.
Execution contract#
Every rule follows the same template-method lifecycle. The engine owns the lifecycle; the script supplies exactly one decision.
- A rule set is a Groovy class implementing the trait for its type —
ScriptExecutionTrait,AssignmentExecutionTrait,ActivityOrchestrationRuleExecutionTrait, and so on. BusinessRuleSet.ruleTypeselects the executor. Each type resolves to a rule executor and a rules subfolder —SCRIPT→script,START_STAGE→stage, and so forth.- Execution: load the pre-compiled class → instantiate → inject
ruleInput,ruleOutput,uamServiceandmasterService→ callexecute()→ return the mutatedruleOutputas the response. - Rule files resolve to
{rules.path}/{flowKey}/{subfolder}/{ruleName}.groovy. Rules may extend other rules, which is how a tenant variant overrides a base rule.
The execution context — ruleInput
Every rule type receives the same uniform context, so logic is portable across flows.
| Field | Meaning |
|---|---|
flowInstance | Live flow-instance data for the case. |
applicationData | The case's application data, as a map. |
internalActivityData | Internal per-activity data, as a map. |
activityDefinitionKey, activityId | The activity context. |
taskDefinitionKey, taskId | The task context. |
taskInput | Input supplied to the task. |
type, actionContext | The rule type and the action context that triggered execution. |
Injected services
| Service | Provides |
|---|---|
uamService | User, role, territory and hierarchy lookups — getUserByUserName, getUsersByRoles, getAllRoles, getAllTerritories, getAllUserHierarchy. Organisation and product are pre-bound. |
masterService | Reference-data lookups — fetchMastersData(masterName[, body]), fetchMastersDataBySlug(...). |
Script rules#
The SCRIPT type is the general-purpose rule. It is what runs behind allocation scripts, and anywhere a flow needs to compute values, call platform services, or start tasks imperatively.
A script rule implements ScriptExecutionTrait and defines two methods:
ruleImplementation()— the body, containing the actual logic.boolean validateInput()— a precondition. Returningfalsecausesexecute()to throwIllegalArgumentException("Invalid input").
class UpdateRiskLimit implements ScriptExecutionTrait {
boolean validateInput() {
return ruleInput.applicationData?.loan?.amount != null
}
void ruleImplementation() {
def amount = ruleInput.applicationData.loan.amount as BigDecimal
def band = masterService.fetchMastersDataBySlug("risk-bands")
def match = band.find { amount >= it.min && amount <= it.max }
if (!match) {
ruleOutput.success = false
ruleOutput.errorMessage = "No risk band configured for amount ${amount}"
return
}
ruleOutput.applicationDataMap = [ riskBand: match.code, riskLimit: match.limit ]
if (match.code == "HIGH") {
ruleOutput.tasksToStart = ["seniorRiskReview"]
}
ruleOutput.success = true
}
}
// A tenant variant simply extends the baseline rule:
class UpdateRiskLimitMg extends UpdateRiskLimit { /* overrides */ }
Boundaries
A script rule can read all request, flow and application data, call the injected UAM and master services, mutate applicationDataMap, request tasksToStart, and set success / errorMessage. It cannot call arbitrary external services beyond those two injected clients, and there is no direct transactional or database write surface exposed to the script other than what those services provide. External calls belong in integrations.
Response reference#
Each rule type returns a strongly-typed response. The engine validates the shape; fields you do not set retain their initialised defaults.
AutomationRuleResponse AUTOMATED
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the automation rule executed successfully. |
errorMessage | String | Error detail when success is false. |
applicationDataMap | Map<String, Object> | Values written back into the case's application data. |
internalActivityDataMap | Map<String, Object> | Values written back into the activity's internal data. |
activitiesToStart | List<ActivityToStartResponse> | Activities to start dynamically, each with its key and seed data. |
activitiesToEnd | List<String> | Definition keys of activities to end. |
tasksToStart | List<String> | Definition keys of tasks to start dynamically. |
taskIdsToEnd | List<String> | Instance ids of running tasks to end. |
applicationStatus | String | Application status to set on the case, if any. |
ActivityOrchestrationRuleResponse ACTIVITY_ORCHESTRATION
| Field | Type | Description |
|---|---|---|
nextActivities | List<String> | Definition keys of the activities to start next, evaluated when an activity completes. |
ActivityStartRuleResponse START_ACTIVITY
| Field | Type | Description |
|---|---|---|
tasksToStart | List<String> | Definition keys of the tasks to start when the activity starts. |
ActivityCompletionRuleResponse COMPLETE_ACTIVITY
| Field | Type | Description |
|---|---|---|
activityCompleted | boolean | Whether the activity is now complete. Evaluated when a task in it completes. |
TaskOrchestrationRuleResponse TASK_ORCHESTRATION
| Field | Type | Description |
|---|---|---|
nextTasks | List<String> | Definition keys of the tasks to start next, evaluated when a task completes. |
StartStageRuleResponse START_STAGE
| Field | Type | Description |
|---|---|---|
startStage | boolean | Whether this stage should start (true) or be skipped (false) when reached. |
MilestoneAchievedRuleResponse MILESTONE_ACHIEVED
| Field | Type | Description |
|---|---|---|
milestoneAchieved | boolean | Whether the stage's milestone is achieved. Drives stage completion. |
ActionPreConditionRuleResponse PRE_ACTION BUTTON_STATUS_CHECK
| Field | Type | Description |
|---|---|---|
preConditionsMet | boolean | Whether the action's preconditions are satisfied. Gates whether the action or button is available. |
messages | List<PreConditionMessage> | Messages to surface — typically why an action is blocked. |
errorMessage | String | Error detail when evaluation itself fails. |
AssignmentRuleResponse ASSIGNMENT
| Field | Type | Description |
|---|---|---|
assigneeDetailList | List<AssigneeDetail> | The resolved assignee(s) for the task. Each AssigneeDetail carries assignee, assigneeStatus and role. |
errorMessage | String | Error detail when assignment resolution fails. |
StageRoleConfigRuleResponse STAGE_ROLE_CONFIG
| Field | Type | Description |
|---|---|---|
visibleTasks | List<String> | Additional task definition keys made visible for the (stage, role) at runtime. |
topLevelActions | List<TopLevelAction> | Additional top-level or global actions granted for the (stage, role) at runtime. |
IntegrationMapperRuleResponse INTEGRATION_MAPPER
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the mapping succeeded. |
errorMessage | String | Error detail when success is false. |
mappedData | Map<String, Object> | The mapped outbound request payload for the integration. |
documents | List<IntegrationDocument> | Documents to attach to the integration call. |
AsyncInboundCallRuleResponse ASYNC_INBOUND_CALL_MAPPER
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the inbound mapping succeeded. |
errorMessage | String | Error detail when success is false. |
mappedData | Map<String, Object> | Values mapped from the inbound callback into application data. |
actionName | String | Action to invoke on receipt of the callback. |
completeTask | boolean | Whether to complete the waiting task on receipt. |
AllDocumentsViewRuleResponse ALL_DOCUMENTS_VIEW
| Field | Type | Description |
|---|---|---|
relevanceList | List<String> | Ordered list of relevant document identifiers for the view. Nodes whose relevance value is absent from this list are dropped. |
scope | String | Document scope selector for the view. |
ObjectTransformerRuleResponse OBJECT_TRANSFORMER
| Field | Type | Description |
|---|---|---|
outputData | Map<String, Object> | The transformed object. |
success | boolean | Whether the transform succeeded. |
errorMessage | String | Error detail when success is false. |
ScriptRuleResponse SCRIPT
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the script succeeded. |
errorMessage | String | Error detail when success is false. |
applicationDataMap | Map<String, Object> | Computed values written back into application data. |
tasksToStart | List<String> | Definition keys of tasks to start dynamically. |
Role access model#
There is no separate permission object in Ontologica. A role's access is exactly the set of Actions it may invoke in the current (stage, role) context, and every Action is the only way data moves.
role ──► action (allowed for this stage+role, or on an assigned task)
│
├─ ReadAction.queryString ──► data-layer query ──► data point (read)
└─ WriteAction.mutations[] ──► data-layer mutation ──► data point (write)
A role acquires actions through exactly two mechanisms:
allowedActionNames.StageRoleDefinition#
extends BaseDefinition · stage_role_definitions.yaml · keyed by (stage, role)
| Property | Type | Description |
|---|---|---|
definitionKey inh | String | Unique identifier for this definition. |
label / description inh | String | Human-readable label and description. |
stage | String | The stage definition key this configuration applies to. |
role | String | The role whose per-stage access this entry configures. |
topLevelActions | List<TopLevelAction> | The global and top-level actions this (stage, role) may invoke. |
ruleSet | BusinessRuleSet | Optional STAGE_ROLE_CONFIG rule returning additional visibleTasks and topLevelActions at runtime. Its result is unioned into the effective configuration. |
visibleTasks | List<String> | Task definition keys the front end should surface for this (stage, role). A presentation hint — it does not itself gate the flow. |
readAction | String | The read action GlobalStageRoleRead delegates to for this (stage, role). |
writeAction | String | The write action a global stage-role write delegates to. |
documentTreeAction | String | A DOCUMENT_MANAGEMENT_VIEW action listing the document tree for this (stage, role). |
documentEvalAction | String | A DOC_EVAL action to upload or view an individual document. |
overviewScreenId | String | Overview screen identifier for the UI. |
TopLevelAction
| Property | Type | Description |
|---|---|---|
name | String | Name of the action this entry grants. Also the allowed-set key used to gate global-action invocation. |
type | ActionStatusType | GLOBAL (a flow- or stage-level global action; serialised as global) or TASK (a task-scoped action; serialised as task). |
taskKey | String | For task-typed actions only: the task definition key used to resolve the live task instance and its assignee. Ignored for global. |
At load time the platform validates that every task-typed top-level action names a real taskKey and that the action appears in that task's taskActions.allowedActionNames. Multi-complete actions are validated to be global-only.
How the effective configuration is resolved
- Read the current user's roles from the identity service, scoped by organisation and product.
- Select every StageRoleDefinition matching
(currentStage, anyOfUserRoles). - Statically union their
visibleTasksandtopLevelActions, deduped by action name (first wins), and take the first non-nullreadAction,writeActionandoverviewScreenId. - Dynamically, for each matched definition carrying a
ruleSet, execute theSTAGE_ROLE_CONFIGrule and union its returned lists into the effective configuration.
Global-action access is therefore the union of static and rule-returned top-level actions. The rule path is how a role gains an action conditionally — for example only when application data meets some threshold.
How access is enforced
| Path | Gate |
|---|---|
| Global action | Non-system callers must pass per-application access validation. Reserved built-in system actions (such as GlobalStageRoleRead) bypass the (stage, role) gate. Otherwise the effective configuration is resolved and the call is rejected with "Action not allowed" unless the requested action name is present in topLevelActions. |
| Task action | Allowed only when the resolved in-progress task instance for the taskKey is one of the current user's tasks and the action is in that task's allowedActionNames. A task assigned to someone else simply is not present in the caller's task set, so the action stays unavailable. |
| Pre-conditions | For both paths, availability additionally requires the action's preConditionRule set to return preConditionsMet: true. |
GlobalStageRoleRead is a built-in system action that resolves the current (stage, role) configuration and runs that configuration's readAction. A role's read access is a ReadAction indirection — never a special case.
Worked example
# stage_role_definitions.yaml
- stage: "Application"
role: "PM"
visibleTasks: [ "applicationTask" ]
topLevelActions:
- { name: "cancelApplication", type: "global" }
- { name: "rejectApplication", type: "global" }
- { name: "getLegalAdvice", type: "global" }
- { name: "completeApplicationTask", type: "task", taskKey: "applicationTask" }
readAction: "readApplicationData"
writeAction: "updateApplicationData"
A user holding role PM on stage Application:
- May invoke the three
globalactions — the validator finds each name in the effectivetopLevelActions. - Gets their data through
GlobalStageRoleRead, which runsreadApplicationData; that ReadAction'squeryStringfetches the data point. - May invoke
completeApplicationTaskonly if the liveapplicationTaskinstance is assigned to them.
Allocation strategies#
Allocation decides who receives a task, and — separately — which users are offered when a task is reassigned.
Configuration#
TaskDefinition.allocationStrategy → AllocationStrategyDefinition
| Property | Type | Description |
|---|---|---|
assignment | List<AssignmentAllocationDetails> | Ordered strategies used to pick the assignee when the task starts. Tried in order; the first returning a non-empty user list wins. |
reassignment | ReassignmentAllocationDetails | Strategy used to compute the list of users offered when the task is reassigned from the support UI. Falls back to assignment[0] when null. |
roundRobin | boolean | If the chosen strategy returns more than one candidate, pick one round-robin rather than leaving a claimable pool. |
scripts | List<String> | Names of SCRIPT rule sets run in order after the assignee is set, on both assignment and reassignment. |
script | String | deprecated Single-script form of scripts. |
AssignmentAllocationDetails
| Property | Type | Description |
|---|---|---|
allocationStrategyIdentifier | String | Which registered strategy to run — see the table below. |
data | Map<String, Object> | Strategy-specific parameters. The valid keys depend entirely on the identifier. |
ReassignmentAllocationDetails
Extends AssignmentAllocationDetails and adds one field:
| Property | Type | Description |
|---|---|---|
open | boolean | If true, the target user is assigned without validating eligibility — the check that the user appears in the strategy's computed allowed-user list is bypassed. If false, the target must be in that list. |
open is frequently misread as placing the task in a shared queue. It does not. It only controls whether eligibility validation is skipped for the chosen reassignment target.
Strategy identifiers#
Each identifier maps to a strategy implementation and a dispatch mode. There are exactly two modes: AUTO_ASSIGN (the system assigns a single user directly) and CLAIM (a pool of eligible users, one of whom claims the task).
| Identifier | Mode | Yields | data keys |
|---|---|---|---|
ROLE_BRANCH_CLAIM | CLAIM | A pool of concrete users holding the given role(s) in the case's branch, expanded from roles via the identity service. It does not yield an abstract role. | role (single) or roles (list); the branch comes from the case's branch details. |
SINGLE_VARIABLE_USER | AUTO_ASSIGN | One computed user, read from a data point. | action — a ReadAction to run first; variable — the path to a {user, role} object. |
MULTIPLE_VARIABLE_USER | CLAIM | Multiple computed users, from comma-separated user / role values at the variable path. The two lists must be the same length. | action, variable. |
ASSIGNMENT_RULE | CLAIM | Whatever the rule returns — a list of AssigneeDetail computed at runtime. | ruleName — an ASSIGNMENT-type rule. |
SYSTEM_USER | AUTO_ASSIGN | The fixed System assignee. Used for automated and integration steps where no human is involved. | none. |
Older material references a ROLE_DEPARTMENT strategy. It does not exist — the five identifiers above are the complete registered set. Likewise there is no strategy that assigns to an abstract role: ROLE_BRANCH_CLAIM always expands role plus branch into concrete users.
Resolution order#
Assignment — a priority-ordered fallback chain
- Try
assignment[0]. If it returns a non-empty user list, use it and stop. - Only if it returns no user, try
assignment[1], and so on. - Once a non-empty list is chosen: one user → assigned directly; many users → a claimable pool, unless
roundRobinis set, in which case one user is picked round-robin per(flow, taskDefinitionKey, branch).
assignment is a fallback chain, not a union. Configuring three strategies does not pool their results together.
Reassignment
When someone reassigns a task from the support UI, the reassignment strategy (or assignment[0] when null) computes the candidate list. The current assignee is stripped out, and the remainder is what the reassigning user may pick from. The open flag then controls whether the chosen target must be in that list.
Allocation scripts
After the assignee is set — on both assignment and reassignment — each rule set named in scripts runs in order as an ordinary SCRIPT rule. It may read flow and application data, call the UAM and master services, write back to application data, and request tasks to start.
allocationStrategy:
assignment:
# 1st choice: the officer recorded on the case
- allocationStrategyIdentifier: "SINGLE_VARIABLE_USER"
data:
action: "getApplicationTaskUser"
variable: "applicationDecisioningData.assignedVariableUsers.applicationTaskUser"
# fallback: anyone with the CO role at the case's branch may claim it
- allocationStrategyIdentifier: "ROLE_BRANCH_CLAIM"
data:
role: "CO"
reassignment:
allocationStrategyIdentifier: "ROLE_BRANCH_CLAIM"
data: { roles: [ "CO", "BM" ] }
open: false
roundRobin: true
scripts: [ "NotifyAssigneeScript" ]
Data layer#
Ontologica has no fixed business schema. Each flow declares its own data model in GraphQL; every instance is stored as JSONB in a small set of generic tables. Adding a field is a schema edit, not a code change.
The three data categories
| Category | Holds |
|---|---|
customerApplicationData | Data supplied by or about the subject of the case — personal information, KYC, the product being applied for. |
applicationDecisioningData | Data produced by the process — decisions, reasons, flags, approvals, computed assignments. |
internalActivityData | Activity-scoped working data, keyed by activity instance id. Isolated per activity execution. |
These three appear together at runtime in an ApplicationDataHolder:
| Property | Type | Description |
|---|---|---|
customerApplicationData | Map<String, Object> | Customer data as a JSON map. |
applicationDecisioningData | Map<String, Object> | Decisioning data as a JSON map. |
internalActivityData | Map<String, Map<String, Object>> | Activity-scoped data keyed by activity instance id. |
internalActivityDataFor | String | The activity instance id currently being queried or modified. |
Directives#
Directives are schema annotations that drive storage, population, validation and encryption behaviour without code. This is what replaces a hand-written persistence layer.
Structural directives
| Directive | Argument | Type | Req | Description |
|---|---|---|---|---|
@MappedTo | field | String (JSONPath) | required | Where to store the field, e.g. $.customerApplicationData.personalInfo.firstName. |
@ValueFrom | fromContext | String (dot path) | optional | Path into the mutation context, e.g. user.userId. Takes precedence over fromData. |
fromData | String (JSONPath) | optional | Extract from existing application data when fromContext is absent. | |
allowNull | Boolean | optional | If true (the default), the field may be null when the source is missing. | |
allowIfParentNull | Boolean | optional | If true, set the field even when the parent object is absent. Default false. | |
@Symmetric | field | String (JSONPath) | required | Marks an input object whose fields all contribute to one parent path — this is what enables partial object updates. |
@CurrentTimestamp | field type | String | Int | required | Injects an ISO instant (String) or epoch seconds (Int) at write time. |
@GenerateRandomId | field type | String | required | Injects a random UUID string at write time. |
@Label | value | String | required | Human-readable display label consumed by the form renderer. |
Validation directives
| Directive | Argument | Type | Req | Description |
|---|---|---|---|---|
@NotBlank | message | String | optional | Error message. Defaults to The field %s is required. |
@Pattern | regexp | String (regex) | optional | Validation pattern. Defaults to .*. |
message | String | optional | Error message on failure. | |
@Min | value | Int | optional | Minimum allowed value, inclusive. Defaults to 0. |
message | String | optional | Error message on failure. | |
@Max | value | Int | optional | Maximum allowed value, inclusive. Defaults to the platform integer maximum. |
message | String | optional | Error message on failure. | |
@DateTimeFormatter | format | String | optional | Date format pattern. Defaults to yyyy/MM/dd. |
message | String | optional | Error message. Defaults to Invalid format. | |
@ValidatePlaintext | regexp | String (regex) | required | Pattern the decrypted plaintext of an EncryptedString must match. |
message | String | optional | Error message. Defaults to Invalid input. | |
@EnumData | source | String | required | Identifier of the reference dataset supplying the enum values. |
identifierInSource | String | required | Key uniquely identifying each option in the source. | |
key | String | required | Source field used as the enum key. | |
value | String | required | Source field used as the enum display value. |
The EncryptedString scalar
A custom scalar providing transparent field-level encryption. It encrypts on the way in and decrypts on the way out, so encryption never appears in flow or rule logic.
| Member | Signature | Behaviour |
|---|---|---|
parseValue | String → String | Encrypts plaintext supplied by the client. |
parseLiteral | StringValue → String | Encrypts literal string values embedded in queries. |
serialize | String → String | Decrypts before sending to the client. |
Because encryption is a scalar concern, validating the underlying plaintext requires @ValidatePlaintext rather than @Pattern.
GraphQL type and field shape
| Property | Type | Req | Description |
|---|---|---|---|
name | String | required | Name of the type or field. |
type | GraphQL type | required | Scalar (String, Int, Float, Boolean, ID, EncryptedString), object, list, or non-null variant. |
description | String | optional | Documentation string. |
directives | List<Directive> | optional | Directives applied to the field or type. |
isNonNull | Boolean | optional | Whether the field is required (!). Null or false means optional. |
A directive itself declares name, the applicableOn locations it is valid in (FIELD_DEFINITION, INPUT_FIELD_DEFINITION, INPUT_OBJECT, ARGUMENT_DEFINITION, SCALAR), and its named arguments.
Queries and mutations#
Query
| Field | Arguments → Returns | Description |
|---|---|---|
allApplicationData | (flow, applicationId) → ApplicationDataHolder | All three data categories for an application. |
internalActivityData | (flow, applicationId, activityDefinitionKey, activityInstanceId) → ApplicationDataHolder | Internal data for one activity instance. |
Mutation
Mutations are the only way application data changes, and they always travel with who / where / why metadata.
| Field | Arguments → Returns | Description |
|---|---|---|
createApplication | (flow, applicationId) → String | Creates a new application and initialises its data structures. |
updateBranchDetails | (applicationId, input, flow, mutationName, inputType, user, activity, task, role, updateAction) → UpdateResult | Representative context-carrying update. Every flow-defined mutation follows this shape. |
Mutation (shared model)
A WriteAction references mutations by this two-field record:
| Property | Type | Description |
|---|---|---|
name | String | Mutation name, e.g. updateBranchDetails. |
inputType | String | GraphQL input type the mutation accepts, e.g. BranchDetailsInput. |
MutationContext
| Property | Type | Description |
|---|---|---|
user | UamUser | Authenticated user initiating the mutation — userId, username, email. |
activity | Instance | Activity instance the mutation occurs in — definitionKey, instanceId. |
task | Instance | Task instance associated with the mutation. |
role | String | Role of the acting user. |
The context is what makes @ValueFrom(fromContext: …) and the audit trail possible without per-flow code.
UpdateResult
| Property | Type | Description |
|---|---|---|
status | boolean | Whether the update succeeded. |
error | String | Error message if it failed; null on success. |
applicationVersion | long | New version of customer data after the update. |
applicationDecisioningDataVersion | long | New version of decisioning data. |
internalActivityDataVersion | long | New version of internal activity data. |
Storage models#
Three generic JSONB tables back every flow on the platform. Each is versioned for optimistic concurrency.
CustomerApplicationData
| Property | Type | Req | Description |
|---|---|---|---|
id | long (PK) | required | Auto-generated record id. |
applicationId | String (unique) | required | Application identifier. |
flow | String | required | Flow definition key this application belongs to. |
applicationVersion | long | required | Incremented on each update. |
applicationData | JSON (JSONB) | optional | The customer-data JSON object. |
modifiedBy | String | required | User who last modified the record. |
createdAt / modifiedAt | Timestamp | optional | Create and last-modified timestamps. |
ApplicationDecisioningData
| Property | Type | Req | Description |
|---|---|---|---|
id | long (PK) | required | Auto-generated record id. |
applicationId | String (unique) | required | Application being decided upon. |
flow | String | required | Flow definition key. |
applicationDecisioningDataVersion | long | required | Incremented on each update. |
applicationDecisioningData | JSON (JSONB) | optional | Decisions, reasons, flags, approvals. |
modifiedBy | String | required | User who last updated the decision. |
createdAt / modifiedAt | Timestamp | optional | Create and last-modified timestamps. |
InternalActivityData
| Property | Type | Req | Description |
|---|---|---|---|
id | long (PK) | required | Auto-generated record id. |
applicationId | String | required | Owning application id. Part of a composite unique key. |
flow | String | required | Flow definition key. |
activityDefinitionKey | String | required | Activity definition. Part of the composite unique key. |
activityInstanceId | String | required | Unique id of this activity execution. Part of the composite unique key. |
internalActivityDataVersion | long | required | Incremented on each update. |
internalActivityData | JSON (JSONB) | optional | Activity-specific JSON — approval levels, verification results. |
modifiedBy | String | required | User who last modified the data. |
createdAt / modifiedAt | Timestamp | optional | Create and last-modified timestamps. |
The write pipeline#
Directives apply in a fixed order on every write. Understanding this order is essential when a value appears to be validated before it is populated, or encrypted before it is validated.
Action (WriteAction) ─ invokes ─▶ Mutation(name, inputType)
│
▼ GraphQL mutation on the per-flow schema
Directives apply, in order:
1. populate @ValueFrom · @CurrentTimestamp · @GenerateRandomId
2. validate @NotBlank · @Pattern · @Min · @Max
@DateTimeFormatter · @ValidatePlaintext
3. encrypt EncryptedString.parseValue
4. place @MappedTo · @Symmetric (into the JSONPath location)
│
▼ persisted to one of
CustomerApplicationData │ ApplicationDecisioningData │ InternalActivityData
(JSONB, version++)
│
▼ emits
AuditLogValue (full snapshot, version, modifiedBy, updateActivity, updateAction)
│
▼ returns
UpdateResult (status + new version numbers)
The mutation context — user, activity, task, role — rides along the entire way. That is what makes @ValueFrom(fromContext: …) and a complete audit trail possible without per-flow code.
Audit and runtime records#
AuditLogKey
| Property | Type | Description |
|---|---|---|
objectType | String | Audited object type — ApplicationData, DecisioningData, and so on. |
objectId | String | Identifier of the audited object instance. |
AuditLogValue
| Property | Type | Req | Description |
|---|---|---|---|
objectType / objectId | String | required | Type and identifier of the modified object. |
value | JSON | optional | Full JSON snapshot at the time of modification. |
version | long | required | Object version after this modification. |
modifiedBy | String | required | User who made the modification. |
modifiedAt | long (epoch ms) | required | When the modification occurred. |
updateActivity | String | optional | Activity key or instance in which the update occurred. |
updateAction | String | optional | Action or mutation that triggered the update. |
The audit log is append-only and immutable, and is archived to object storage for compliance retention.
Runtime timeline records
The platform records processing metrics used by reporting and SLA tracking.
| Record | Fields |
|---|---|
| ActivityProcessingData | activityId, activityName, createdTimestamp, availableTimestamp, assignedTimestamp, completionTimestamp, currentStatus (CREATED / AVAILABLE / ASSIGNED / COMPLETED). |
| StageProcessingData | stageId, stageName, createdTimestamp, entryTimestamp, exitTimestamp, entryThrough, exitThrough, activityList. |
| MilestoneDetails | milestone, accomplishedAt. |
Reference data
Versioned lookup datasets — dropdown options, rate tables, configuration values — are managed centrally and consumed by forms (through @EnumData), by rules (through masterService) and by reports.
| Construct | Purpose | Key properties |
|---|---|---|
| DataDefinition | The catalogue schema for a reference dataset, versioned and lifecycle-managed. | slug, name, data (field schema), activeVersion, draftVersion, active, isCacheable, ownerGroupId, sharedGroupsIds |
| DraftDataDefinition | The editable draft of a definition before publication. | dataDefinition (parent), slug, data, draftVersion |
| DataStorage | A published set of rows conforming to a definition, per language and region. | slug+language+region (unique), data, localization, version, indexStatus |
| DraftDataStorage | Draft rows edited before publish. | draftDataDefinition, data, localization, language, region |
| DataIndex | A lookup index over stored rows, built from chosen key fields, for fast consumer queries. | dataDefinition, slug, indexKey, data |
| History tables | Immutable per-version snapshots enabling audit and rollback. | DataDefinitionHistory, DataStorageHistory, DataIndexHistory |
Lifecycle: a definition or dataset is edited as a draft, then published — which freezes a numbered version into the history tables and flips activeVersion. Datasets are identified by slug and resolved per language and region, with default as the neutral variant.
Identity and access constructs
Access is modelled as (user × role × territory) tuples, extended ad hoc through validated JSON attribute bags rather than schema changes.
| Construct | Purpose | Key properties |
|---|---|---|
| User | An internal system user with encrypted credentials. | userName, emailId, mobileNumber (encrypted), userHierarchies, attributes |
| Customer | An external end user — applicant, guarantor, agent. | userName, emailId, mobileNumber, customerType, permissions, languages, trustedRealms |
| Role | A grantable role with an access level. | roleName, roleShortName, roleLabel, accessLevel |
| Territory | A node in the geographic / organisational tree. | territoryName, territoryLabel, territoryType, parentTerritory, address |
| TerritoryType | The classification / level of a territory, ordered by position. | name, label, position |
| UserHierarchy | The junction binding user → role → (optional) territory, with parent-child links. | user, role, territory, parentId, userHierarchyKey |
| Organization | A realm or tenant, optionally a group container. | name, label, host, isDefault, isGroup, isSharable, groups, metadata |
| Namespace / Product | A namespace groups products; a product is the primary configuration and access unit. | Namespace: name, label · Product: name, label, namespace |
| AttributeValidations | Per-entity, per-attribute validation rules for the custom attribute bags. | tableName, attributeKey, validationConfig |
| FlowUamMapping (Flow Registration) | Registers a flow with the platform catalog and routes its service hosts. Not a tenant binding. | flowKey, productName, organizationName, childOrganizationName, host.{dataLayer, workflow, ruleService} |
| ExchangeTokenMapping | Cross-realm token exchange between the workflow platform and a document system. | losRealm, dmsRealm, clientId, clientSecret, identityProviderName |
Integrations#
External systems are reached through the Integration Broker — a configured, not coded, bridge. Supported transports are REST, SOAP, direct database queries, custom scripts, and asynchronous queues.
| Construct | Purpose |
|---|---|
| External System | A registered endpoint with base URL, authentication type and credentials. |
| Integration API | A specific operation on an external system — method, path, headers, body template, expected response shape. |
| Payload Mapper | An INTEGRATION_MAPPER rule transforming application data into the request payload, and an output mapper transforming the response back into application data. |
| Integration Task | The process-side binding: a task of type INTEGRATION or ASYNC_INTEGRATION referencing an API and its mappers. |
Configuring an integration is four steps: register the external system, define the API, write the input and output mapper rules, then reference the integration from a task or an EXTERNAL_API action.
Synchronous integration#
TaskDefinition.integrationDefinition → IntegrationDefinition
| Property | Type | Req | Description |
|---|---|---|---|
integrationName | String | optional | Internal name of the integration. |
apiName | String | optional | External API name or endpoint identifier. |
method | String | optional | HTTP method — GET, POST, PUT, PATCH, DELETE. |
environment | String | optional | Target environment — dev, staging, prod. |
sendAuth | boolean | optional | Whether to include authentication headers. |
inputMapperRule | String | optional | Rule transforming task data into the API request payload. |
outputMapperRule | String | optional | Rule transforming the API response into application data. |
readAction | String | optional | Read action fetching data before the integration runs. |
writeAction | String | optional | Write action persisting the integration response. |
preIntegrationWriteAction | String | optional | Write action run before calling the integration — for example marking the case in-progress. |
documentUploadReadAction | String | optional | Read action for documents to upload as part of the integration. |
documentUploadEvalAction | String | optional | Evaluation action validating documents before the call. |
Asynchronous integration#
TaskDefinition.asyncIntegrationDefinition → AsyncIntegrationDefinition
An async integration makes an outbound call and then waits. The task stays live; a correlated callback resumes it.
| Property | Type | Req | Description |
|---|---|---|---|
outboundCallDefinition | IntegrationDefinition | optional | The integration definition used for the outbound call. |
inboundCallRuleSet | InboundCallRuleSet | optional | Rules handling the inbound callback and its response mapping. |
timeoutAutomatedTaskDefinitionKey | String | optional | Automated task to run if the callback never arrives. |
allowedActionNames | Set<String> | optional | Actions allowed while the task is waiting for the callback. |
InboundCallRuleSet
| Property | Type | Description |
|---|---|---|
ruleName | String | Name of the ASYNC_INBOUND_CALL_MAPPER rule handling the callback. |
readAction | String | Read action fetching callback data and state before processing. |
The inbound rule returns an AsyncInboundCallRuleResponse: the mapped data to write, optionally an actionName to invoke, and completeTask to decide whether the waiting task should now finish.
- definitionKey: creditBureauCheck
taskType: ASYNC_INTEGRATION
asyncIntegrationDefinition:
outboundCallDefinition:
integrationName: credit-bureau
apiName: soft-pull
method: POST
sendAuth: true
inputMapperRule: CreditBureauRequestMapper
preIntegrationWriteAction: markBureauPullInProgress
inboundCallRuleSet:
ruleName: CreditBureauCallbackMapper
readAction: readApplicationData
timeoutAutomatedTaskDefinitionKey: creditBureauTimeoutHandler
allowedActionNames: [ cancelBureauPull ]
Documents#
A document in Ontologica is not a first-class column. It is a DocumentFolder object stored inside the application-data JSON at a configured path.
Because the stored value is a folder holding a list of documents, every document type is inherently multi-instance — one logical type such as "bank statement" can hold several uploaded files. Single-instance behaviour is opted into explicitly, per document, via singleFileUpload.
The data model
type DocumentFolder
| Field | Type | Req | Description |
|---|---|---|---|
folderId | String! | required | Document-store folder identifier grouping the uploaded files. |
documents | [Document] | optional | The files uploaded into this folder. |
type Document
| Field | Type | Req | Description |
|---|---|---|---|
documentId | String! | required | Document-store identifier. |
fileName | String! | required | Original file name. |
fileType | String! | required | MIME or file type. |
filePath | String | optional | Storage path of the file. |
fileSize | Float | optional | File size. |
The corresponding DocumentInput and DocumentFolderInput types carry relative @MappedTo paths ($.folderId, $.documents, $.fileName, …). They place fields within the folder object; the folder itself is anchored under application data at the document type's path.
How a document path resolves
A document is identified by its documentType, which is a dot-separated path into application data — pointing not at a scalar but at a folder container. On read the platform walks the path segment by segment; on write it reconstructs the nested object graph so the folder lands at exactly that path.
documentType: customerApplicationData.documents.kycDocuments.photoOfCustomer
│
▼
resolves to a DocumentFolder data point at
$.customerApplicationData.documents.kycDocuments.photoOfCustomer
By convention the path is rooted under one of the three data categories. When a file is uploaded, the document-store webhook writes a folder object — folderId plus a list of {documentId, fileName, fileType} — back through the standard document-details write action.
Document actions#
| Action | actionType | Purpose |
|---|---|---|
| DocEvalAction | DOC_EVAL | Upload or evaluate a document. Declares the document catalog and the scopes granted. |
| AllDocumentsViewAction | DOCUMENT_MANAGEMENT_VIEW | Renders the whole document tree for the front end. It does not upload. |
| DmsAction | DMS_ACTION | Generic document-store operation, carrying a writeAction. |
DocEvalAction
| Property | Type | Description |
|---|---|---|
documents | List<DmsEvalConfigDto> | The document catalog this action can upload or evaluate — one entry per documentType. |
defaultScope | List<Scope> | Scopes granted when a document entry does not override them. |
Per-document configuration
| Property | Type | Req | Description |
|---|---|---|---|
documentType | String | required | Dot path to the document-folder data point. Also the lookup key. |
singleFileUpload | boolean | optional | If true, the type expects a single file. Defaults to false. |
documentDataPath | String | optional | Path whose value is attached as document context on upload. |
relevantDataPath | String | optional | Path whose value disambiguates multi-instance items — for example a collateral identifier. |
scope | List<Scope> | optional | Per-document scope override. Falls back to the action's defaultScope. |
AllDocumentsViewAction and the document tree
| Property | Type | Description |
|---|---|---|
config | List<DmsViewConfigDto> | The document tree to render — nested FOLDER and DOCUMENT nodes. |
readAction | String | Read action whose data resolves labelPath and dataPath values. |
ruleSet | String | An ALL_DOCUMENTS_VIEW rule producing the relevance list — which branches to show. |
Each tree node:
| Property | Type | Description |
|---|---|---|
type | ConfigType | FOLDER or DOCUMENT. |
key | String | Stable node id. |
label | String | Static label, often an i18n token. |
labelPath | String | Data path whose value overrides label at render time. If the path is missing, the static label is kept. |
dataPath | String | For DOCUMENT nodes: the documentType path. Its data is attached to the node. |
relevance | String | If set, the node is dropped unless the rule set's relevance list contains this value. |
metadata | Map | Front-end metadata. For DOCUMENT nodes it must include the upload endpoint — the name of the DocEvalAction that owns this document's scopes. |
children | List<DmsViewConfigDto> | Nested nodes. |
For each DOCUMENT node the view resolves its upload endpoint to a DocEvalAction, finds the entry whose documentType matches the node's dataPath, and copies that entry's scope onto the output. The view never declares its own scopes — the eval action is the single source.
labelPath — data-driven labels
labelPath points at a second data point whose value becomes the node's label. A folder node keyed mortgage_1 can carry labelPath: customerApplicationData.collateralDetails.mortgage.mortgage_1.collateralLabel, so the user sees the real collateral description rather than a generic "Mortgage 1". dataPath works the same way but populates the node's data instead of its label.
Scopes#
| Value | Meaning |
|---|---|
UPLOAD | Add a file to the folder. |
UPDATE | Modify or replace a file. |
DELETE | Remove a file. |
VIEW | See the document. |
DOWNLOAD | Download the file. |
Whenever there is no in-progress task — no taskId, or the task's status is not IN_PROGRESS — the effective scope is forced to [VIEW, DOWNLOAD] regardless of configuration. This downgrade is applied consistently at every point where scope is computed, so a completed case cannot be modified through the document surface.
There is no EVAL scope. "Evaluation" is an action type (DOC_EVAL), not a permission.
Wiring documents into a flow
| Level | Field | Effect |
|---|---|---|
| Task | TaskDefinition.documentEvalActions | Names the DocEvalActions available within that task. |
| Stage + role | StageRoleDefinition.documentTreeAction / documentEvalAction | The current view and upload actions for that (stage, role). |
| Flow | FlowDefinition.globalDocumentViewAction / globalDocumentEvalAction dep | Legacy flow-wide defaults, superseded by the stage-role fields above. |
# View action — renders the tree
- name: "allDocumentsView"
actionType: "DOCUMENT_MANAGEMENT_VIEW"
readAction: "readApplicationData"
ruleSet: "AllDocumentsView"
config:
- label: "{{workflowconfig.CUSTOMER}}"
type: "FOLDER"
children:
- label: "{{workflowconfig.PHOTO_OF_CUSTOMER}}"
type: "DOCUMENT"
dataPath: "customerApplicationData.documents.kycDocuments.photoOfCustomer"
metadata:
singleFileUpload: true
uploadConfig: { pathVariable: { uploadEndpoint: uploadDocument } }
# Eval action — referenced by uploadEndpoint, owns the scopes
- name: "uploadDocument"
actionType: "DOC_EVAL"
defaultScope: [ "VIEW", "UPLOAD", "UPDATE", "DELETE", "DOWNLOAD" ]
documents:
- documentType: "customerApplicationData.documents.kycDocuments.photoOfCustomer"
singleFileUpload: true
- documentType: "customerApplicationData.collateralDetails.mortgage.mortgage_1.collateralPicture"
singleFileUpload: false
documentDataPath: "customerApplicationData.customerNumber"
relevantDataPath: "customerApplicationData.collateralDetails.mortgage.mortgage_1.collateralIdentifier"
AI constructs#
Ontologica lets configurators attach language-model behaviour to a flow in two shapes: a Copilot that assists a human inside a human task, and an AI Agent Task that replaces the human entirely. Both share the same configuration surface; the agent adds objective-driven autonomy.
AI constructs add a decision-making layer. They do not add a parallel execution path. The orchestrator treats an agent's final structured output exactly as it treats a human action: it dispatches the chosen Action, which then runs mutations, rules and stage transitions through the normal engines. The agent is simply another way of choosing an action — which is what keeps audit, multi-tenant inheritance and hot-reload semantics uniform across human, automated and AI work.
Copilot
A Copilot is bound to a single human task (HUMAN or EXTERNAL_USER_HUMAN). It shares that task's data context — flow instance, current form draft, attached documents — and operates on the user's behalf within explicit limits.
| Field | Purpose |
|---|---|
prompt | The system prompt describing role, voice and behaviour. May reference flow and task data through templated placeholders. |
allowedActions | Whitelist of actions the copilot may invoke on this task. * permits all; a list permits a subset. Per-action AI permissions on the Action construct override this. |
tools | Named tool bindings the copilot may call. |
skills | References to reusable capability contracts. |
hooks | Lifecycle interceptors. |
promptGuardrails | Natural-language constraints injected into the prompt — refusal patterns, scope limits, tone. |
memory | Optional configuration for short-term (session) and long-term (per-case) memory stores. |
model | Model id, temperature, maximum output tokens. Defaults inherited from tenant configuration. |
Deterministic safety — action-whitelist enforcement, PII redaction, token and step budgets, rate limits, audit logging — is enforced by the runtime, not by the prompt. promptGuardrails carries only the soft, model-side instructions.
AI Agent Task
An agent task is a Task of type AGENTIC, a peer to AUTOMATED and INTEGRATION. It is fully autonomous: no human is allocated, no form is rendered. Its configuration is the Copilot surface plus four objective-driven fields.
| Field | Purpose |
|---|---|
mainObjective | The success criterion in plain language. The agent terminates when it is satisfied. |
successCriteria | Optional structured checks — rule references, required outputs, schema-conformant result — used by the runtime to validate the agent's claimed completion. |
terminationPolicy | Limits and exits: maxSteps, maxWallClockMs, maxTokens, and onLimitExceeded (fail or escalate). |
escalation | Where to hand off on failure, low confidence or guardrail violation — typically a fallback human task or activity. |
Tools#
Tools are the verbs available to the model. Each is a typed function with a schema; the runtime validates arguments before dispatch and writes an audit entry per call. Every tool also carries its own per-binding permission configuration — two copilots can share a tool definition with completely different blast radii.
| Tool | What it does | Per-binding permissions |
|---|---|---|
call_action | Invoke an action from allowedActions. | actions — explicit action-key allow-list. The per-action AI-invocable flag is honoured first; a binding may only narrow it. |
read_data | Read fields from the current case via a GraphQL query. | fields / fieldPaths allow-list. Field-level AI-readable flags are enforced first. |
write_data | Stage a draft mutation. The commit happens only via call_action, which prevents silent writes. | fields writable paths plus a mutations allow-list. Field-level AI-writable flags are enforced first. |
read_document / upload_document | Fetch or attach files in the case's document store. | categories, mimeTypes, maxSizeMb, maxPages. Read and upload are granted independently. |
query_master_data | Read reference datasets by slug. | slugs allow-list (supports glob), optional language and region restriction. |
call_integration | Invoke an Integration API by key, reusing the existing payload mappers. | apis allow-list, optional rateLimit. |
run_subflow | Initiate a child case and optionally wait for completion. | flowKeys allow-list, maxConcurrent, awaitTimeoutMs. |
run_automated_activity | Trigger a configured automated activity — reusing rule-driven logic instead of re-implementing it in a prompt. | activities allow-list. The activity must be marked AI-invocable on its definition. |
run_code | Execute a snippet in a sandboxed runtime for calculations, parsing and data shaping. | languages, librariesAllowed, egressAllowList, maxWallClockMs, maxMemoryMb. Filesystem and network default to deny. |
request_clarification (copilot) | Open a clarification thread to the human operator — the escape hatch when ambiguous. | templates allow-list, optional requiresHumanResponse to block further AI actions until answered. |
ask_human (agent) | Pause and ask a structured question to a designated reviewer. | reviewers (role / user / territory selector), templates, timeoutPolicy. |
handoff_to_agent | Pass control to another copilot or agent task. | targets allow-list of eligible recipients. |
emit_event | Publish a domain event to the event stream. | eventTypes allow-list. |
retrieve_knowledge | Retrieval lookup against a configured corpus — policy documents, prior cases. | corpora allow-list, optional per-corpus tag filter and topK cap. |
explain | Mandatory structured rationale, written to the audit log. | requiredBefore — actions or tool calls that cannot fire until an explain call has been logged in the current step. |
tools:
- read_data:
fields: ["applicant.*", "loan.amount", "loan.purpose"]
- call_action:
actions: ["request-clarification", "flag-for-review"]
- call_integration:
apis: ["credit-bureau-soft-pull"]
rateLimit: "10/min"
- run_automated_activity:
activities: ["fraud-screen-v3", "sanctions-screen-v2"]
- run_subflow:
flowKeys: ["customer-onboarding-mini"]
maxConcurrent: 1
Skills and hooks#
Skills — capability contracts
A Skill is a reusable bundle giving a copilot a named competency without re-specifying it each time. A skill packages a prompt fragment, a required tool set, an action subset it expects to drive, optional few-shot examples, and skill-specific hooks. Skills compose: a copilot lists the skills it has, and the runtime stitches their prompt fragments and tool grants into the final session. Skills are versioned and live in the same configuration chain as every other construct.
Hooks — lifecycle interceptors
Hooks are the AI analogue of action pre-conditions. Each is a function attached at a named extension point, running inside the deterministic runtime — which makes hooks the right place to enforce hard policy. Prompt guardrails live in the model's head; hooks live in the platform's hands.
| Hook point | Typical use |
|---|---|
onSessionStart | Hydrate context, inject a case summary, set the per-session budget. |
beforeToolCall | Veto, rewrite or redact tool arguments; enforce dynamic policy such as "no credit pulls after 18:00". |
afterToolCall | Sanitise results before the model sees them — PII redaction, schema clamping. |
onMessage | Inspect model output; classify, route or block. |
onGuardrailViolation | Decide whether to retry with a corrective message, escalate, or terminate. |
onHandoff | Fired when a copilot escalates to a human or another agent; carries summary and state. |
onSessionEnd | Persist a transcript summary, emit metrics, write the audit entry. |
Layered enforcement#
Three permission layers stack. The narrowest wins, and a capability is permitted only when all three layers allow it.
| # | Layer | Scope |
|---|---|---|
| 1 | Construct-level flags | AI-readable and AI-writable flags on fields; AI-invocable on Actions and automated Activities. Set once, they govern every AI on the platform. |
| 2 | Tool catalog defaults | System-wide caps — for example, sandboxed code execution always carries a hard wall-clock ceiling. |
| 3 | Per-binding allow-list | The configurator's narrowing for this copilot or agent task. |
A binding can never widen what the construct flags or catalog defaults deny.
Human Task ──┬── Form Definition (existing)
└── Copilot
├── prompt + promptGuardrails
├── allowedActions ── references → Actions
├── tools ── bind to → Mutations / Integrations / Subflows / Sandbox
├── skills ── references → Capability contracts
└── hooks ── reuse → Rules engine
AI Agent Task = Task(type=AGENTIC) + the same Copilot surface
+ mainObjective, successCriteria, terminationPolicy, escalation
Multi-tenancy and inheritance#
Constructs are organised into configuration domains — flow, data, rules, integration, UI and access. For multi-tenant deployments those configurations form an inheritance chain.
Product Baseline (e.g. "loan-product")
├── Variant A ("loan-product-nigeria") — extends base, patches local rules
├── Variant B ("loan-product-madagascar") — extends base, patches local forms
└── Variant C ("loan-product-senegal") — extends base, patches local workflows
| Construct | Purpose |
|---|---|
| Product Baseline | The canonical configuration for a product. Tenant-agnostic. |
| Tenant / country variant | A child configuration that extends a baseline and applies patches. Identified by a flow key. |
| Patch | A targeted modification expressed in the config patch DSL. Edits specific fields of the inherited configuration without duplicating it, so it survives baseline upgrades. |
| Flow Registration | The required metadata entry registering a flow with the platform catalog and routing its service hosts. |
Resolution at runtime follows a prototype-chain pattern: a variant's value wins, falling back to its baseline, recursively. At the flow-definition level this is expressed with $extends; rules inherit the same way, and a variant rule can literally extend the baseline rule class.
| What can be patched | Example |
|---|---|
| Workflow stages | Add a compliance stage for a regulated market. |
| Activity definitions | Add a country-specific verification activity. |
| Task assignments | Different role names per country. |
| Business rules | Different approval thresholds per market. |
| Data fields | Country-specific regulatory fields. |
| UI forms | Localised labels, different field visibility. |
| Integrations | Country-specific provider APIs. |
| Deduplication rules | Different duplicate-detection identifiers. |
The practical consequence: define the base process once, create variants with minimal configuration, modify one variant without affecting others, and share improvements across all variants by updating the baseline.
Events#
Every action emits events that downstream systems consume. This is what makes the worklist, audit archive, analytics and notifications derived rather than bolted on.
User or agent action (e.g. "Approve")
↓
Flow management (executes the action, updates state)
↓ emits
Event stream
├──▶ Worklist (updates the task list for all users)
├──▶ Audit archive (long-term compliance storage)
├──▶ Reporting (updates analytics dashboards)
└──▶ Notifications (email / SMS)
| Event type | Emitted when |
|---|---|
Initiate | A new case is created. |
Stage | A stage milestone is achieved. |
Activity | An activity starts or completes. |
Task | A task is assigned, claimed, completed or reassigned. |
Action | A user action is executed — read, write, approve, reject. |
Clarification | A clarification is raised, responded to or closed. |
REJECT | A case is rejected. |
ActionEvent
| Property | Type | Description |
|---|---|---|
applicationId | String | Case the action was executed on. |
flowDefinitionKey | String | Key of the flow definition. |
user | String | User who executed the action. |
taskId / taskDefinitionKey | String | Task instance and definition the action ran on. |
actionName | String | Name of the action executed. |
applicationStatus | ApplicationStatus | Case status after execution. |
type / subType | FlowEventType / String | Event type (always Action) and an optional subtype for categorisation. |
Built-in capabilities#
Every flow gets these without configuration. Knowing what is already provided prevents rebuilding it in rules.
| Capability | Behaviour |
|---|---|
| Task claiming | Users claim tasks from a shared pool produced by a CLAIM-mode allocation strategy. |
| Task reassignment | Reassign to other eligible users, computed by the reassignment strategy. |
| Clarifications | Encrypted request-and-respond threads between users, with a PENDING → RESPONDED → CLOSED lifecycle. Enabled per task via clarificationsEnabled. |
| Timeline / audit trail | Full history of every action on a case, archived for compliance. Exposed per task via timelineAccessAllowed. |
| Document management | Upload, view and evaluate documents with automatic file-type detection and HTML-to-PDF conversion. |
| Refer back | Send work back to a previous stage or user for revision, via referTask and canReferFurther. |
| Auto-save drafts | Forms auto-save in-progress data, encrypted at rest and recoverable across sessions. |
| Worklist | Filterable, full-text searchable task inbox with bookmarking, fast-tracking and read status. |
| Deduplication | Prevents duplicate cases at initiation using configurable identifier matching and distributed locks. |
| Notifications | Event-driven email and SMS with template-based rendering. |
| Reporting | Real-time dashboards with configurable data dimensions, fed from the event stream. |
| Field-level encryption | Transparent encryption of sensitive fields in forms, clarifications and feedback via the EncryptedString scalar. |
| Event streaming | Every action emits an event for downstream consumers. |
Naming conventions#
Ontologica deliberately reuses industry-standard vocabulary where it exists — Flow, Stage, Activity, Task, Action, Mutation, Field, Directive, Rule Set, Hook, Tool, Skill, Copilot — because a shared vocabulary is worth more than a bespoke one.
Principles
- Prefer concrete user-facing terms over implementation terms. Case beats Flow Instance; Draft beats Partial Save Snapshot.
- Avoid jargon that dates. Agentic is fashion; AI Agent positions the product without committing to the buzzword. Master data is dated; reference data is current.
- Drop noise suffixes. Every construct is a definition, so Form Definition is just Form.
- Do not reinvent industry-standard names. They come from elsewhere and the shared vocabulary is the benefit.
- Names must describe the current job, not the historical one. Rename when purpose drifts.
- Acronyms must earn their place.
Presentation names vs. configuration names
The following renames apply to user-facing surfaces only — UI labels, business documentation, support tooling. Internal and persistence names, YAML keys and code identifiers are unchanged, which is why both forms appear in this reference.
| Configuration name | Presentation name | Why |
|---|---|---|
| Flow Instance | Case | The natural business term, and standard across case-management platforms. "Flow Instance" reads like an implementation detail. |
| Floating Activity | Ambient Activity | "Floating" is evocative but does not convey what it does. Superseded structurally by sideStages. |
| Master Data Definition | Reference Data | Modern term in finance and insurance; signals lookup values rather than transactional records. |
| Partial Save Snapshot | Draft | What users already call it. The old name describes the mechanism, not the thing. |
| Form Definition | Form | The Definition suffix is noise. |
| Base Product Definition | Product Baseline | Shorter, and the standard term in multi-tenant configuration systems. |
| UAM Mapping | Flow Registration | A legacy misnomer. The construct no longer maps users to access — it registers a flow with the platform catalog and routes service hosts. It is not a tenant binding: one registered flow serves many tenants. |
| Agentic Task | AI Agent Task | Precise and durable. The related move renames the AUTOMATED task type to Script Task, which accurately describes what it already does. |
| Integration Mapper Rule | Payload Mapper | Tells you what it does on first read. |
Key conventions
- Definition keys are the identity of every construct. They are referenced verbatim from other constructs and from rule code, so they should be stable, lowercase-camel, and meaningful without context —
loanApprovalActivity, notactivity3. - Flow keys identify a specific flow variant, typically
{product}-{market}. - Rule names resolve to file paths. A rule named
TriageMilestoneof typeMILESTONE_ACHIEVEDlives under the flow's stage rules folder. - Action names are the unit of access. Because they appear in
allowedActionNamesandtopLevelActions, they should read as operations:approveTriage,rejectApplication,readClaimDetails.
Deprecations#
These fields still exist and still function. New configuration should use the replacement.
| Deprecated | On | Use instead |
|---|---|---|
activityOrchestrationRuleSet | FlowDefinition | StageDefinition.activityOrchestrationRuleSet — per stage. The flow-level rule is now only a fallback for stages that declare none. |
floatingActivities | FlowDefinition | FlowDefinition.sideStages. |
globalReadAction | FlowDefinition | GlobalStageRoleRead plus StageRoleDefinition.readAction. |
globalDocumentViewAction | FlowDefinition | StageRoleDefinition.documentTreeAction. |
globalDocumentEvalAction | FlowDefinition | StageRoleDefinition.documentEvalAction. |
roleBasedGlobalActionsAllowed | FlowDefinition | StageRoleDefinition.topLevelActions. |
script | AllocationStrategyDefinition | scripts — a list, run in order. |
The legacy global-action endpoints coexist with the stage-role model rather than having been removed. Treat the stage-role path as the intended target for anything new, and migrate legacy configuration opportunistically.
Corrections to earlier documentation
| Claim you may encounter | Correct behaviour |
|---|---|
ROLE_DEPARTMENT is an allocation strategy. | It does not exist. The five registered identifiers are ROLE_BRANCH_CLAIM, SINGLE_VARIABLE_USER, MULTIPLE_VARIABLE_USER, ASSIGNMENT_RULE, SYSTEM_USER. |
ActivityDefinition.applicationStatus is applied when the activity starts. | It is applied when the activity completes, and only when the flow is not terminating. |
open on reassignment means "open queue". | It bypasses eligibility validation for the chosen target. It has nothing to do with queues. |
| Validation and deduplication are rule types. | They are separate executors on dedicated endpoints, not members of the RuleType enum. |
There is an EVAL document scope. | There is not. The scopes are UPLOAD, UPDATE, DELETE, VIEW, DOWNLOAD. "Evaluation" is an action type. |
assignment pools all listed strategies together. | It is a priority-ordered fallback chain. The first strategy returning users wins and the rest are not consulted. |
| A stage's start rule controls when the stage runs. | Stage order is fixed by FlowDefinition.stages. The start rule only decides whether the stage runs or is skipped when reached. |
Construct index#
| Construct | Family | Properties | Section |
|---|---|---|---|
BaseDefinition | Process | 3 | Base definition |
FlowDefinition | Process | 19 | Flow definition |
StageDefinition | Process | 8 | Stage definition |
ActivityDefinition | Process | 12 | Activity definition |
TaskDefinition | Process | 19 | Task definition |
TaskType (enum) | Process | 6 values | Task sub-constructs |
TaskActionsDefinition | Process | 4 | Task sub-constructs |
TaskMovementDefinition | Process | 4 | Task sub-constructs |
ActivityTaskReference | Process | 2 | Task sub-constructs |
StatusDefinition | Process | 4 | Status definition |
Action (base) | Process | 10 | Action model |
ActionType (enum) | Process | 13 values | Action types |
WorkflowActionType (enum) | Process | 9 values | Workflow action types |
ActionContext | Process | 7 | Action subtypes |
BusinessRuleSet | Logic | 5 | Task sub-constructs |
AutomatedTaskRuleSet | Logic | 5 (inherited) | Task sub-constructs |
RuleType (enum) | Logic | 16 values | Rule types |
| Rule responses (16 types) | Logic | — | Response reference |
AllocationStrategyDefinition | Process | 5 | Allocation configuration |
AssignmentAllocationDetails | Process | 2 | Allocation configuration |
ReassignmentAllocationDetails | Process | 3 | Allocation configuration |
StageRoleDefinition | Access | 13 | Stage role definition |
TopLevelAction | Access | 3 | Stage role definition |
ActionStatusType (enum) | Access | GLOBAL, TASK | Stage role definition |
IntegrationDefinition | Integration | 12 | Synchronous integration |
AsyncIntegrationDefinition | Integration | 4 | Asynchronous integration |
InboundCallRuleSet | Integration | 2 | Asynchronous integration |
| GraphQL schema & directives | Data | — | Directives |
ApplicationDataHolder | Data | 4 | Data layer |
| Storage models (3 stores) | Data | — | Storage models |
MutationContext · UpdateResult | Data | 4 · 5 | Queries and mutations |
| Audit & timeline records | Data | — | Audit and runtime |
DocumentFolder · Document | Data | 2 · 5 | Documents |
| Copilot · AI Agent Task | AI | 8 · +4 | AI constructs |
Glossary#
| Term | Definition |
|---|---|
| Action | An operation that can be performed on a task or at stage level. The only path through which data is read or written. |
| Activity | A group of related tasks within a stage. |
| Allocation strategy | The method used to decide who receives a task. |
| Ambient activity | An activity that may run alongside any stage without blocking it. Structurally expressed as a side stage. |
| Case | A running flow — one per application. Internally a flow instance. |
| Clarification | A structured, encrypted message thread between users about a specific task. |
| Definition key | The unique identifier of any construct instance. |
| Definition-driven | The architectural principle that all behaviour derives from declarative constructs, not compiled code. |
| Draft | Auto-saved in-progress form data, encrypted at rest and recoverable across sessions. |
| Fast track | A priority flag on a case, surfaced in the worklist. |
| Flow | A complete business process definition. |
| Flow key | The identifier of a specific flow variant. |
| Flow registration | The required metadata entry registering a flow with the platform catalog and routing its service hosts. Not a tenant binding. |
| Form engine | The component that renders forms from configuration, with expression evaluation and conditional visibility. |
| Hot reload | Rules and configuration reload at runtime without a service restart. |
| Integration | A configured connection to an external system. |
| Milestone | The condition at which a stage is considered complete. |
| Mutation | A GraphQL write operation. The only mechanism that modifies application data. |
| Patch | A targeted configuration modification applied to an inherited baseline. |
| Payload mapper | A rule transforming data into and out of an external API call. |
| Product baseline | The canonical, tenant-agnostic configuration for a product. |
| Reference data | Versioned lookup datasets — dropdown lists, rate tables, configuration values. |
| Rule set | A Groovy script implementing business logic of a single rule type. |
| Script task | A task that executes rules rather than involving a human. Configuration type AUTOMATED. |
| Side stage | A stage that runs in parallel with the main stage sequence without blocking it. |
| Stage | A major phase in the process lifecycle. |
| Task | A single unit of work — human, automated, integration or AI. |
| Territory | A geographic or organisational unit in the user hierarchy. |
| Worklist | The searchable task inbox where users find and claim work. |