Ontologica

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:

ArtifactLanguageDescribes
Workflow definitionsYAMLThe Flow → Stage → Activity → Task → Action hierarchy, rule-set references, allocation and role/access configuration.
Data modelGraphQLTypes, inputs, enums and directives describing the data that rules and actions read and write.
Business rulesGroovyDecision, 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

MarkerMeaning
requiredThe property must be present for the construct to load.
optionalThe property may be omitted; the engine applies a documented default or skips the behaviour.
inheritedThe property comes from a parent construct (for example BaseDefinition).
deprecatedStill 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.

ProcessPure structure: what work happens, in what order. Contains no logic — it references rule sets by key.
LogicRule sets: Groovy scripts grouped by rule type. The type fixes when the rule runs and what it must return.
DataA per-flow GraphQL schema over generic JSONB storage. Directives drive mapping, validation and encryption.
IntegrationRegistered external systems, APIs and payload mappers, reached through the Integration Broker.
UIForm definitions, fields and expressions. Forms are rendered dynamically; there is no per-flow UI code.
ConfigurationBaselines, tenant variants and patches. Resolution follows a prototype chain: variant wins, then base.

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

Invariant 1 — Structure holds no logic

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.

Invariant 2 — Every access is action-based

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.

LevelDefinitionLending exampleInsurance example
FlowA complete business process.Loan OriginationClaims Processing
StageA major lifecycle phase. Closes when its milestone condition is met.Application, Evaluation, Approval, DisbursementFiling, Triage, Investigation, Settlement
ActivityA logical group of related tasks within a stage.Applicant Information, KYC VerificationDamage Assessment, Policy Verification
TaskA single unit of work — human, automated, or an integration call.Fill personal info form, Upload ID documentUpload damage photos, Review adjuster report
ActionAn operation performed on a task.Submit, Approve, Reject, Request clarificationApprove 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
Naming note

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

PropertyTypeReqDescription
definitionKeyStringrequiredUnique identifier (key) for this definition.
labelStringoptionalHuman-readable label.
descriptionStringoptionalHuman-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.

PropertyTypeReqDescription
definitionKeyStringrequired inhUnique identifier for the flow.
labelStringoptional inhHuman-readable label.
descriptionStringoptional inhWhat the flow does.
stagesList<String>optionalStage definition keys that comprise the flow, in execution order — the engine walks this list by index to pick the next stage.
initiateFlowMutationStringoptionalMutation executed when the flow is initiated. Its input type defines the shape of initialData on the initiate call.
initialStatusStringoptionalApplication status a new case starts in (e.g. IN_PROGRESS).
prefixStringoptionalPrefix used when generating application IDs for this flow.
sideStagesSet<String>optionalStage keys that run alongside the main stage sequence, in parallel, without blocking it. Supersedes floatingActivities.
reportingReadActionStringoptionalRead action used for reporting and analytics.
migrationFlowWriteActionStringoptionalWrite action used for data migration during flow transitions.
initialDataTransformerRuleStringoptionalRule that transforms the initial input data when the case is created.
applicationDataScreenIdStringoptionalFront-end screen id used to render this flow's application-data view.
$extendsStringoptionalParent flow definition key this flow inherits configuration from. Java field extendsFrom; JSON name is literally $extends.
globalReadActionStringdeprecatedDefault read action across all stages. Superseded by GlobalStageRoleRead plus the StageRole readAction.
globalDocumentViewActionStringdeprecatedGlobal document-view action. Superseded by StageRole documentTreeAction.
globalDocumentEvalActionStringdeprecatedGlobal document-evaluation action. Superseded by StageRole documentEvalAction.
roleBasedGlobalActionsAllowedMap<String, List<String>>deprecatedLegacy 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.
activityOrchestrationRuleSetBusinessRuleSetdeprecatedFlow-level activity orchestration. Retained only as a fallback for stages that declare no per-stage rule.
floatingActivitiesSet<String>deprecatedActivities 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.

PropertyTypeReqDescription
definitionKeyStringrequired inhUnique identifier for the stage.
labelStringoptional inhHuman-readable label.
descriptionStringoptional inhThe stage's purpose.
mandatoryActivitiesSet<String>optionalActivity keys that must complete before the stage can close.
possibleActivitiesSet<String>optionalActivity keys that may optionally run in this stage.
startStageRuleSetBusinessRuleSetoptionalA 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.
activityOrchestrationRuleSetBusinessRuleSetoptionalPer-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.
stageCompletionRuleSetBusinessRuleSetoptionalRule 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.

PropertyTypeReqDescription
definitionKeyStringrequired inhUnique identifier for the activity.
labelStringoptional inhHuman-readable label.
descriptionStringoptional inhThe activity's purpose.
tasksList<TaskDefinition>optionalTask definitions declared inline in this activity.
taskKeysList<String>optionalDefinition keys of tasks declared in the separate task configuration. A task key may appear in multiple activities — this is how tasks are reused.
startTasksList<String>optionalTask keys started when the activity is initiated.
activityStartRuleSetBusinessRuleSetoptionalA START_ACTIVITY rule that computes which tasks to start, used when no static startTasks set is configured.
activityCompletionRuleSetBusinessRuleSetoptionalA COMPLETE_ACTIVITY rule evaluated whenever a task in this activity completes.
taskOrchestrationRulesetStringoptionalActivity-level rule governing task sequencing. The lowest-priority mechanism for choosing the next task.
readActivityActionNameStringoptionalRead action for retrieving activity data.
activityInputActionStringoptionalAction providing input data when the activity starts.
applicationStatusStringoptionalStatus 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.
Common misreading

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.

PropertyTypeReqDescription
definitionKeyStringrequired inhUnique identifier for the task.
labelStringoptional inhHuman-readable label.
descriptionStringoptional inhThe task's purpose.
taskTypeTaskTypeoptionalExecution model — see TaskType.
taskActionsTaskActionsDefinitionoptionalWhich actions are available, mandatory and primary for this task.
taskMovementTaskMovementDefinitionoptionalNext / move / refer targets and the next-task rule.
allocationStrategyAllocationStrategyDefinitionoptionalHow the task is assigned. See Allocation strategies.
automatedTaskRuleSetAutomatedTaskRuleSetoptionalRules for automated execution (read/write actions plus logic).
integrationDefinitionIntegrationDefinitionoptionalConfiguration for synchronous integration and HTTP tasks.
asyncIntegrationDefinitionAsyncIntegrationDefinitionoptionalConfiguration for asynchronous integration with callback handling.
preConditionRuleList<String>optionalPre-condition rule names that must pass before this task may start.
screenIdStringoptionalFront-end screen id rendered for this task.
systemTaskbooleanoptionalIf true, an internal system task not exposed to end users.
canReferFurtherbooleanoptionalWhether the task can be referred onward to another user or stage.
timelineAccessAllowedbooleanoptionalWhether users can view the task history / timeline.
clarificationsEnabledbooleanoptionalWhether clarification threads are enabled on this task.
taskToPauseList<String>optionalTask keys to pause when this task executes.
taskToResumeList<String>optionalTask keys to resume when this task completes.
documentEvalActionsList<String>optionalDocument-evaluation action names available in this task. See Documents.

Task sub-constructs#

TaskType (enum)

ValueDescription
HUMANPerformed by an internal system user. Allocation and a form apply.
EXTERNAL_USER_HUMANPerformed by an external user — customer, broker, partner. Resolved against the child organisation realm.
AUTOMATEDExecuted by a rule set without user intervention.
INTEGRATIONSynchronous external call with request/response.
ASYNC_INTEGRATIONOutbound call plus an inbound callback; the task waits.
HTTPDirect HTTP task using a mapper for request/response transformation.

TaskActionsDefinition

PropertyTypeReqDescription
primaryReadActionNameStringoptionalPrimary read action for fetching task data.
allowedActionNamesSet<String>optionalEvery action available to users on this task. This set is the gate for task-scoped access.
mandatoryActionNamesSet<String>optionalActions that must run before the task can complete.
mandatoryActionMessageMap<String, String>optionalPer-action message explaining why an action is mandatory.

TaskMovementDefinition

PropertyTypeReqDescription
nextTaskList<String>optionalTask keys that follow this task in the normal forward flow. Highest priority in task progression.
moveTaskList<String>optionalTask keys this task may be moved to (horizontal transition).
referTaskList<String>optionalTask keys this task may be referred to (escalation / refer-back). Not part of forward progression.
nextTaskRuleSetBusinessRuleSetoptionalTask-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.

PropertyTypeReqDescription
nameStringoptionalUnique name of the rule set. Resolves to a Groovy file on disk.
ruleTypeRuleTypeoptionalDetermines when the rule runs and which response it must return. See Rule types.
readActionStringoptionalRead action used to fetch data for rule evaluation.
writeActionStringoptionalWrite action executed when the rule decides an outcome.
internalActivityDataRequiredbooleanoptionalWhether 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

PropertyTypeDescription
activityNameStringDefinition key of the activity this task reference belongs to.
taskNameStringDefinition key of the referenced task.

StatusDefinition#

extends BaseDefinition

Declares an application status a case can hold, and whether reaching it ends the case.

PropertyTypeReqDescription
definitionKeyStringrequired inhUnique identifier for the status.
labelStringoptional inhHuman-readable label.
descriptionStringoptional inhWhat this status means.
terminatebooleanoptionalWhether 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:

FieldReqMeaning
flowDefinitionKeymandatoryWhich flow definition to instantiate.
branchDetailsmandatoryThe branch context the instance is created under, as a map. Downstream allocation strategies resolve users against this branch.
initialDatarequired in practiceThe 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.

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 onFieldNotes
StageDefinitionactivityOrchestrationRuleSetThe primary, per-stage rule. This is what you should configure.
FlowDefinitionactivityOrchestrationRuleSet deprecatedFlow-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:

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:

#MechanismField
1Hard-coded follow-on tasks — highest priority; if present, it decides.Task.taskMovement.nextTask
2Task-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
3Activity-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.

FamilyMechanism
Automated task rule setsA 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.
ScriptsGroovy 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 actionsActions whose workflowActionType explicitly starts or moves work: START_TASK (starts taskDefinitionKey), START_ACTIVITY (starts activityDefinitionKey), MOVE_ACTIVITY (transitions to activityDefinitionKey).

Field cheat sheet#

ConceptConstructField
Flow initiation bodyinitiate APIflowDefinitionKey, branchDetails, initialData
Mutation that shapes initialDataFlowDefinitioninitiateFlowMutation
Status set on initiateFlowDefinitioninitialStatus
First stage started on initiateFlowDefinitionstages[0]
Ordered stage sequenceFlowDefinitionstages
Parallel side stagesFlowDefinitionsideStages
Stage start gateStageDefinitionstartStageRuleSet
Stage completionStageDefinitionstageCompletionRuleSet
Activity orchestration (per stage)StageDefinitionactivityOrchestrationRuleSet
Activity orchestration (fallback)FlowDefinitionactivityOrchestrationRuleSet dep
Activity entry tasksActivityDefinitionstartTasks
Activity start ruleActivityDefinitionactivityStartRuleSet
Activity completionActivityDefinitionactivityCompletionRuleSet
Task orchestration (activity level)ActivityDefinitiontaskOrchestrationRuleset
Task orchestration (task level)TaskDefinitiontaskMovement.nextTaskRuleSet
Hard-coded next tasksTaskDefinitiontaskMovement.nextTask
Refer-back tasksTaskDefinitiontaskMovement.referTask
Task pre-conditionsTaskDefinitionpreConditionRule
Automated taskTaskDefinitionautomatedTaskRuleSet
Action scriptActionactionScriptRules
Assignment / reassignment scriptTaskDefinitionallocationStrategy.scripts
Start-task actionAction (START_TASK)taskDefinitionKey
Start-activity actionAction (START_ACTIVITY)activityDefinitionKey
Move-activity actionAction (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)

PropertyTypeReqDescription
nameStringoptionalUnique name identifier. This is the key referenced from allowedActionNames, topLevelActions and rule sets.
descriptionStringoptionalHuman-readable description.
preConditionRuleList<String>optionalRules that must return preConditionsMet: true before the action can execute.
statusApplicationStatusoptionalApplication status to assign when the action runs.
actionScriptRulesList<String>optionalScript rules executed as part of the action. May start tasks.
hardWriteActionStringoptionalWrite action force-executed regardless of normal logic.
hardWriteActionDataMap<String, Object>optionalData payload for hardWriteAction.
systemAllowedbooleanoptionalWhether the system (a non-user caller) may execute this action.
completeActionbooleanoptionalWhether executing this action completes the task — this is what triggers the completion cascade.
isCommentRequiredbooleanoptionalWhether a user comment is required to execute.

ActionType#

ValueDescription
READFetches and displays application data.
WRITEPersists data mutations to application state.
WORKFLOWWorkflow control — start, complete, move, refer. See WorkflowActionType.
VERIFYVerifies conditions using a read action.
INTERNAL_ACTIVITY_READReads data from another activity in the flow.
EXTERNAL_APICalls an external API via an integration definition.
HTTP_MAPPERHTTP call with custom request/response mapping.
DOC_EVALUploads or evaluates documents. Declares the document catalog and scopes.
DOCUMENT_MANAGEMENT_VIEWRenders the document tree.
DMS_ACTIONGeneric interaction with the document management system.
ROLE_USER_LISTReturns the list of users holding a specific role.
REASSIGNReassigns a task to a different user or queue.
SYSTEMSystem-only action, not exposed to users.

WorkflowActionType#

Applies to actions of type WORKFLOW.

ValueDescription
START_TASKInitiates the task named in taskDefinitionKey.
START_ACTIVITYInitiates the activity named in activityDefinitionKey.
COMPLETE_TASKCompletes a task and proceeds to the next.
MOVE_TASKMoves a task to an alternate task.
MOVE_ACTIVITYMoves an activity to a different stage / transitions to another activity.
REFER_BACKRefers or escalates a task to another queue or stage.
ASSIGNAssigns a task to a specific user.
REASSIGN_USERSReassigns a task to different users.
REJECTRejects 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.

SubtypeactionTypeDistinct fields
ReadActionREADqueryString — the GraphQL / data-retrieval query. Reading data is invoking this.
WriteActionWRITEmutations — a list of Mutation{name, inputType} applied to the data layer.
VerifyActionVERIFYreadActionName — the read action executed for verification.
InternalActivityReadActionINTERNAL_ACTIVITY_READactivityDefinitionKey, queryString.
ExternalApiActionEXTERNAL_APIintegrationDefinition — API details, mappers, auth.
HttpMapperActionHTTP_MAPPERwriteAction, ibApiDetails (URL, method, headers, auth).
DocEvalActionDOC_EVALdocuments (per-document config), defaultScope. See Document actions.
AllDocumentsViewActionDOCUMENT_MANAGEMENT_VIEWconfig (document tree), readAction, ruleSet.
DmsActionDMS_ACTIONwriteAction — persists DMS operation results.
RoleUserListActionROLE_USER_LISTrole — the role id to query users for.
ReassignActionREASSIGNname is always reassign.

ActionContext

Every action executes inside a context that rides along to rules, mutations and the audit trail.

PropertyTypeDescription
roleStringRole of the user executing the action.
currentUserUserJwtDtoUser details taken from the JWT.
taskDefinitionKey / taskIdStringCurrent task definition key and runtime instance id.
activityDefinitionKey / activityIdStringCurrent activity definition key and runtime instance id.
requestBodyMap<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#

RuleTypeWhen it runsReturns
AUTOMATEDInside an automation task — computes values and may dynamically start or end tasks and activities.AutomationRuleResponse
ACTIVITY_ORCHESTRATIONWhen an activity completes — decides the next set of activities to start.ActivityOrchestrationRuleResponse
START_ACTIVITYWhen an activity starts — decides which tasks to start, when no static task set is configured.ActivityStartRuleResponse
COMPLETE_ACTIVITYWhen any task in an activity completes — decides whether the activity is complete.ActivityCompletionRuleResponse
TASK_ORCHESTRATIONWhen a task completes, if it is configured to call a rule set — decides the next tasks.TaskOrchestrationRuleResponse
START_STAGEAt stage start — the start-vs-skip gate for a stage.StartStageRuleResponse
MILESTONE_ACHIEVEDDecides whether a stage's milestone has been achieved, driving stage completion.MilestoneAchievedRuleResponse
PRE_ACTIONEvaluates whether an action's preconditions are met, before it runs or when listing possible actions.ActionPreConditionRuleResponse
BUTTON_STATUS_CHECKPrecondition-style check driving button and action availability. Same executor family as PRE_ACTION.ActionPreConditionRuleResponse
ASSIGNMENTDecides task assignment. Used by the ASSIGNMENT_RULE allocation strategy.AssignmentRuleResponse
STAGE_ROLE_CONFIGDecides per-role stage visibility and actions at runtime.StageRoleConfigRuleResponse
INTEGRATION_MAPPERMaps and builds request payloads for outbound integrations.IntegrationMapperRuleResponse
ASYNC_INBOUND_CALL_MAPPERMaps inbound asynchronous callback payloads.AsyncInboundCallRuleResponse
ALL_DOCUMENTS_VIEWBuilds the documents view for a flow.AllDocumentsViewRuleResponse
OBJECT_TRANSFORMERTransforms an object. Served via a dedicated transformer endpoint.ObjectTransformerRuleResponse
SCRIPTGeneral-purpose scripting rule. See Script rules.ScriptRuleResponse
Not rule types

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.

  1. A rule set is a Groovy class implementing the trait for its type — ScriptExecutionTrait, AssignmentExecutionTrait, ActivityOrchestrationRuleExecutionTrait, and so on.
  2. BusinessRuleSet.ruleType selects the executor. Each type resolves to a rule executor and a rules subfolder — SCRIPTscript, START_STAGEstage, and so forth.
  3. Execution: load the pre-compiled class → instantiate → inject ruleInput, ruleOutput, uamService and masterService → call execute() → return the mutated ruleOutput as the response.
  4. 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.

FieldMeaning
flowInstanceLive flow-instance data for the case.
applicationDataThe case's application data, as a map.
internalActivityDataInternal per-activity data, as a map.
activityDefinitionKey, activityIdThe activity context.
taskDefinitionKey, taskIdThe task context.
taskInputInput supplied to the task.
type, actionContextThe rule type and the action context that triggered execution.

Injected services

ServiceProvides
uamServiceUser, role, territory and hierarchy lookups — getUserByUserName, getUsersByRoles, getAllRoles, getAllTerritories, getAllUserHierarchy. Organisation and product are pre-bound.
masterServiceReference-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:

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

FieldTypeDescription
successbooleanWhether the automation rule executed successfully.
errorMessageStringError detail when success is false.
applicationDataMapMap<String, Object>Values written back into the case's application data.
internalActivityDataMapMap<String, Object>Values written back into the activity's internal data.
activitiesToStartList<ActivityToStartResponse>Activities to start dynamically, each with its key and seed data.
activitiesToEndList<String>Definition keys of activities to end.
tasksToStartList<String>Definition keys of tasks to start dynamically.
taskIdsToEndList<String>Instance ids of running tasks to end.
applicationStatusStringApplication status to set on the case, if any.

ActivityOrchestrationRuleResponse ACTIVITY_ORCHESTRATION

FieldTypeDescription
nextActivitiesList<String>Definition keys of the activities to start next, evaluated when an activity completes.

ActivityStartRuleResponse START_ACTIVITY

FieldTypeDescription
tasksToStartList<String>Definition keys of the tasks to start when the activity starts.

ActivityCompletionRuleResponse COMPLETE_ACTIVITY

FieldTypeDescription
activityCompletedbooleanWhether the activity is now complete. Evaluated when a task in it completes.

TaskOrchestrationRuleResponse TASK_ORCHESTRATION

FieldTypeDescription
nextTasksList<String>Definition keys of the tasks to start next, evaluated when a task completes.

StartStageRuleResponse START_STAGE

FieldTypeDescription
startStagebooleanWhether this stage should start (true) or be skipped (false) when reached.

MilestoneAchievedRuleResponse MILESTONE_ACHIEVED

FieldTypeDescription
milestoneAchievedbooleanWhether the stage's milestone is achieved. Drives stage completion.

ActionPreConditionRuleResponse PRE_ACTION BUTTON_STATUS_CHECK

FieldTypeDescription
preConditionsMetbooleanWhether the action's preconditions are satisfied. Gates whether the action or button is available.
messagesList<PreConditionMessage>Messages to surface — typically why an action is blocked.
errorMessageStringError detail when evaluation itself fails.

AssignmentRuleResponse ASSIGNMENT

FieldTypeDescription
assigneeDetailListList<AssigneeDetail>The resolved assignee(s) for the task. Each AssigneeDetail carries assignee, assigneeStatus and role.
errorMessageStringError detail when assignment resolution fails.

StageRoleConfigRuleResponse STAGE_ROLE_CONFIG

FieldTypeDescription
visibleTasksList<String>Additional task definition keys made visible for the (stage, role) at runtime.
topLevelActionsList<TopLevelAction>Additional top-level or global actions granted for the (stage, role) at runtime.

IntegrationMapperRuleResponse INTEGRATION_MAPPER

FieldTypeDescription
successbooleanWhether the mapping succeeded.
errorMessageStringError detail when success is false.
mappedDataMap<String, Object>The mapped outbound request payload for the integration.
documentsList<IntegrationDocument>Documents to attach to the integration call.

AsyncInboundCallRuleResponse ASYNC_INBOUND_CALL_MAPPER

FieldTypeDescription
successbooleanWhether the inbound mapping succeeded.
errorMessageStringError detail when success is false.
mappedDataMap<String, Object>Values mapped from the inbound callback into application data.
actionNameStringAction to invoke on receipt of the callback.
completeTaskbooleanWhether to complete the waiting task on receipt.

AllDocumentsViewRuleResponse ALL_DOCUMENTS_VIEW

FieldTypeDescription
relevanceListList<String>Ordered list of relevant document identifiers for the view. Nodes whose relevance value is absent from this list are dropped.
scopeStringDocument scope selector for the view.

ObjectTransformerRuleResponse OBJECT_TRANSFORMER

FieldTypeDescription
outputDataMap<String, Object>The transformed object.
successbooleanWhether the transform succeeded.
errorMessageStringError detail when success is false.

ScriptRuleResponse SCRIPT

FieldTypeDescription
successbooleanWhether the script succeeded.
errorMessageStringError detail when success is false.
applicationDataMapMap<String, Object>Computed values written back into application data.
tasksToStartList<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:

1 · Stage-role configurationFor the current stage and the user's role, a StageRoleDefinition lists top-level actions, visible tasks and the read/write actions the role may invoke.
2 · Task assignmentBeing assigned a live task instance — via an allocation strategy — confers the ability to invoke that task's allowedActionNames.

StageRoleDefinition#

extends BaseDefinition · stage_role_definitions.yaml · keyed by (stage, role)

PropertyTypeDescription
definitionKey inhStringUnique identifier for this definition.
label / description inhStringHuman-readable label and description.
stageStringThe stage definition key this configuration applies to.
roleStringThe role whose per-stage access this entry configures.
topLevelActionsList<TopLevelAction>The global and top-level actions this (stage, role) may invoke.
ruleSetBusinessRuleSetOptional STAGE_ROLE_CONFIG rule returning additional visibleTasks and topLevelActions at runtime. Its result is unioned into the effective configuration.
visibleTasksList<String>Task definition keys the front end should surface for this (stage, role). A presentation hint — it does not itself gate the flow.
readActionStringThe read action GlobalStageRoleRead delegates to for this (stage, role).
writeActionStringThe write action a global stage-role write delegates to.
documentTreeActionStringA DOCUMENT_MANAGEMENT_VIEW action listing the document tree for this (stage, role).
documentEvalActionStringA DOC_EVAL action to upload or view an individual document.
overviewScreenIdStringOverview screen identifier for the UI.

TopLevelAction

PropertyTypeDescription
nameStringName of the action this entry grants. Also the allowed-set key used to gate global-action invocation.
typeActionStatusTypeGLOBAL (a flow- or stage-level global action; serialised as global) or TASK (a task-scoped action; serialised as task).
taskKeyStringFor 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

  1. Read the current user's roles from the identity service, scoped by organisation and product.
  2. Select every StageRoleDefinition matching (currentStage, anyOfUserRoles).
  3. Statically union their visibleTasks and topLevelActions, deduped by action name (first wins), and take the first non-null readAction, writeAction and overviewScreenId.
  4. Dynamically, for each matched definition carrying a ruleSet, execute the STAGE_ROLE_CONFIG rule 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

PathGate
Global actionNon-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 actionAllowed 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-conditionsFor both paths, availability additionally requires the action's preConditionRule set to return preConditionsMet: true.
Read access is itself an action

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:

Allocation strategies#

Allocation decides who receives a task, and — separately — which users are offered when a task is reassigned.

Configuration#

TaskDefinition.allocationStrategy → AllocationStrategyDefinition

PropertyTypeDescription
assignmentList<AssignmentAllocationDetails>Ordered strategies used to pick the assignee when the task starts. Tried in order; the first returning a non-empty user list wins.
reassignmentReassignmentAllocationDetailsStrategy used to compute the list of users offered when the task is reassigned from the support UI. Falls back to assignment[0] when null.
roundRobinbooleanIf the chosen strategy returns more than one candidate, pick one round-robin rather than leaving a claimable pool.
scriptsList<String>Names of SCRIPT rule sets run in order after the assignee is set, on both assignment and reassignment.
scriptStringdeprecated Single-script form of scripts.

AssignmentAllocationDetails

PropertyTypeDescription
allocationStrategyIdentifierStringWhich registered strategy to run — see the table below.
dataMap<String, Object>Strategy-specific parameters. The valid keys depend entirely on the identifier.

ReassignmentAllocationDetails

Extends AssignmentAllocationDetails and adds one field:

PropertyTypeDescription
openbooleanIf 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.
Not an "open queue" flag

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).

IdentifierModeYieldsdata keys
ROLE_BRANCH_CLAIMCLAIMA 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_USERAUTO_ASSIGNOne computed user, read from a data point.action — a ReadAction to run first; variable — the path to a {user, role} object.
MULTIPLE_VARIABLE_USERCLAIMMultiple computed users, from comma-separated user / role values at the variable path. The two lists must be the same length.action, variable.
ASSIGNMENT_RULECLAIMWhatever the rule returns — a list of AssigneeDetail computed at runtime.ruleName — an ASSIGNMENT-type rule.
SYSTEM_USERAUTO_ASSIGNThe fixed System assignee. Used for automated and integration steps where no human is involved.none.
Correction

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

  1. Try assignment[0]. If it returns a non-empty user list, use it and stop.
  2. Only if it returns no user, try assignment[1], and so on.
  3. Once a non-empty list is chosen: one user → assigned directly; many users → a claimable pool, unless roundRobin is 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

CategoryHolds
customerApplicationDataData supplied by or about the subject of the case — personal information, KYC, the product being applied for.
applicationDecisioningDataData produced by the process — decisions, reasons, flags, approvals, computed assignments.
internalActivityDataActivity-scoped working data, keyed by activity instance id. Isolated per activity execution.

These three appear together at runtime in an ApplicationDataHolder:

PropertyTypeDescription
customerApplicationDataMap<String, Object>Customer data as a JSON map.
applicationDecisioningDataMap<String, Object>Decisioning data as a JSON map.
internalActivityDataMap<String, Map<String, Object>>Activity-scoped data keyed by activity instance id.
internalActivityDataForStringThe 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

DirectiveArgumentTypeReqDescription
@MappedTofieldString (JSONPath)requiredWhere to store the field, e.g. $.customerApplicationData.personalInfo.firstName.
@ValueFromfromContextString (dot path)optionalPath into the mutation context, e.g. user.userId. Takes precedence over fromData.
fromDataString (JSONPath)optionalExtract from existing application data when fromContext is absent.
allowNullBooleanoptionalIf true (the default), the field may be null when the source is missing.
allowIfParentNullBooleanoptionalIf true, set the field even when the parent object is absent. Default false.
@SymmetricfieldString (JSONPath)requiredMarks an input object whose fields all contribute to one parent path — this is what enables partial object updates.
@CurrentTimestampfield typeString | IntrequiredInjects an ISO instant (String) or epoch seconds (Int) at write time.
@GenerateRandomIdfield typeStringrequiredInjects a random UUID string at write time.
@LabelvalueStringrequiredHuman-readable display label consumed by the form renderer.

Validation directives

DirectiveArgumentTypeReqDescription
@NotBlankmessageStringoptionalError message. Defaults to The field %s is required.
@PatternregexpString (regex)optionalValidation pattern. Defaults to .*.
messageStringoptionalError message on failure.
@MinvalueIntoptionalMinimum allowed value, inclusive. Defaults to 0.
messageStringoptionalError message on failure.
@MaxvalueIntoptionalMaximum allowed value, inclusive. Defaults to the platform integer maximum.
messageStringoptionalError message on failure.
@DateTimeFormatterformatStringoptionalDate format pattern. Defaults to yyyy/MM/dd.
messageStringoptionalError message. Defaults to Invalid format.
@ValidatePlaintextregexpString (regex)requiredPattern the decrypted plaintext of an EncryptedString must match.
messageStringoptionalError message. Defaults to Invalid input.
@EnumDatasourceStringrequiredIdentifier of the reference dataset supplying the enum values.
identifierInSourceStringrequiredKey uniquely identifying each option in the source.
keyStringrequiredSource field used as the enum key.
valueStringrequiredSource 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.

MemberSignatureBehaviour
parseValueString → StringEncrypts plaintext supplied by the client.
parseLiteralStringValue → StringEncrypts literal string values embedded in queries.
serializeString → StringDecrypts 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

PropertyTypeReqDescription
nameStringrequiredName of the type or field.
typeGraphQL typerequiredScalar (String, Int, Float, Boolean, ID, EncryptedString), object, list, or non-null variant.
descriptionStringoptionalDocumentation string.
directivesList<Directive>optionalDirectives applied to the field or type.
isNonNullBooleanoptionalWhether 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

FieldArguments → ReturnsDescription
allApplicationData(flow, applicationId) → ApplicationDataHolderAll three data categories for an application.
internalActivityData(flow, applicationId, activityDefinitionKey, activityInstanceId) → ApplicationDataHolderInternal data for one activity instance.

Mutation

Mutations are the only way application data changes, and they always travel with who / where / why metadata.

FieldArguments → ReturnsDescription
createApplication(flow, applicationId) → StringCreates a new application and initialises its data structures.
updateBranchDetails(applicationId, input, flow, mutationName, inputType, user, activity, task, role, updateAction) → UpdateResultRepresentative context-carrying update. Every flow-defined mutation follows this shape.

Mutation (shared model)

A WriteAction references mutations by this two-field record:

PropertyTypeDescription
nameStringMutation name, e.g. updateBranchDetails.
inputTypeStringGraphQL input type the mutation accepts, e.g. BranchDetailsInput.

MutationContext

PropertyTypeDescription
userUamUserAuthenticated user initiating the mutation — userId, username, email.
activityInstanceActivity instance the mutation occurs in — definitionKey, instanceId.
taskInstanceTask instance associated with the mutation.
roleStringRole of the acting user.

The context is what makes @ValueFrom(fromContext: …) and the audit trail possible without per-flow code.

UpdateResult

PropertyTypeDescription
statusbooleanWhether the update succeeded.
errorStringError message if it failed; null on success.
applicationVersionlongNew version of customer data after the update.
applicationDecisioningDataVersionlongNew version of decisioning data.
internalActivityDataVersionlongNew version of internal activity data.

Storage models#

Three generic JSONB tables back every flow on the platform. Each is versioned for optimistic concurrency.

CustomerApplicationData

PropertyTypeReqDescription
idlong (PK)requiredAuto-generated record id.
applicationIdString (unique)requiredApplication identifier.
flowStringrequiredFlow definition key this application belongs to.
applicationVersionlongrequiredIncremented on each update.
applicationDataJSON (JSONB)optionalThe customer-data JSON object.
modifiedByStringrequiredUser who last modified the record.
createdAt / modifiedAtTimestampoptionalCreate and last-modified timestamps.

ApplicationDecisioningData

PropertyTypeReqDescription
idlong (PK)requiredAuto-generated record id.
applicationIdString (unique)requiredApplication being decided upon.
flowStringrequiredFlow definition key.
applicationDecisioningDataVersionlongrequiredIncremented on each update.
applicationDecisioningDataJSON (JSONB)optionalDecisions, reasons, flags, approvals.
modifiedByStringrequiredUser who last updated the decision.
createdAt / modifiedAtTimestampoptionalCreate and last-modified timestamps.

InternalActivityData

PropertyTypeReqDescription
idlong (PK)requiredAuto-generated record id.
applicationIdStringrequiredOwning application id. Part of a composite unique key.
flowStringrequiredFlow definition key.
activityDefinitionKeyStringrequiredActivity definition. Part of the composite unique key.
activityInstanceIdStringrequiredUnique id of this activity execution. Part of the composite unique key.
internalActivityDataVersionlongrequiredIncremented on each update.
internalActivityDataJSON (JSONB)optionalActivity-specific JSON — approval levels, verification results.
modifiedByStringrequiredUser who last modified the data.
createdAt / modifiedAtTimestampoptionalCreate 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

PropertyTypeDescription
objectTypeStringAudited object type — ApplicationData, DecisioningData, and so on.
objectIdStringIdentifier of the audited object instance.

AuditLogValue

PropertyTypeReqDescription
objectType / objectIdStringrequiredType and identifier of the modified object.
valueJSONoptionalFull JSON snapshot at the time of modification.
versionlongrequiredObject version after this modification.
modifiedByStringrequiredUser who made the modification.
modifiedAtlong (epoch ms)requiredWhen the modification occurred.
updateActivityStringoptionalActivity key or instance in which the update occurred.
updateActionStringoptionalAction 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.

RecordFields
ActivityProcessingDataactivityId, activityName, createdTimestamp, availableTimestamp, assignedTimestamp, completionTimestamp, currentStatus (CREATED / AVAILABLE / ASSIGNED / COMPLETED).
StageProcessingDatastageId, stageName, createdTimestamp, entryTimestamp, exitTimestamp, entryThrough, exitThrough, activityList.
MilestoneDetailsmilestone, 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.

ConstructPurposeKey properties
DataDefinitionThe catalogue schema for a reference dataset, versioned and lifecycle-managed.slug, name, data (field schema), activeVersion, draftVersion, active, isCacheable, ownerGroupId, sharedGroupsIds
DraftDataDefinitionThe editable draft of a definition before publication.dataDefinition (parent), slug, data, draftVersion
DataStorageA published set of rows conforming to a definition, per language and region.slug+language+region (unique), data, localization, version, indexStatus
DraftDataStorageDraft rows edited before publish.draftDataDefinition, data, localization, language, region
DataIndexA lookup index over stored rows, built from chosen key fields, for fast consumer queries.dataDefinition, slug, indexKey, data
History tablesImmutable 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.

ConstructPurposeKey properties
UserAn internal system user with encrypted credentials.userName, emailId, mobileNumber (encrypted), userHierarchies, attributes
CustomerAn external end user — applicant, guarantor, agent.userName, emailId, mobileNumber, customerType, permissions, languages, trustedRealms
RoleA grantable role with an access level.roleName, roleShortName, roleLabel, accessLevel
TerritoryA node in the geographic / organisational tree.territoryName, territoryLabel, territoryType, parentTerritory, address
TerritoryTypeThe classification / level of a territory, ordered by position.name, label, position
UserHierarchyThe junction binding user → role → (optional) territory, with parent-child links.user, role, territory, parentId, userHierarchyKey
OrganizationA realm or tenant, optionally a group container.name, label, host, isDefault, isGroup, isSharable, groups, metadata
Namespace / ProductA namespace groups products; a product is the primary configuration and access unit.Namespace: name, label · Product: name, label, namespace
AttributeValidationsPer-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}
ExchangeTokenMappingCross-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.

ConstructPurpose
External SystemA registered endpoint with base URL, authentication type and credentials.
Integration APIA specific operation on an external system — method, path, headers, body template, expected response shape.
Payload MapperAn INTEGRATION_MAPPER rule transforming application data into the request payload, and an output mapper transforming the response back into application data.
Integration TaskThe 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

PropertyTypeReqDescription
integrationNameStringoptionalInternal name of the integration.
apiNameStringoptionalExternal API name or endpoint identifier.
methodStringoptionalHTTP method — GET, POST, PUT, PATCH, DELETE.
environmentStringoptionalTarget environment — dev, staging, prod.
sendAuthbooleanoptionalWhether to include authentication headers.
inputMapperRuleStringoptionalRule transforming task data into the API request payload.
outputMapperRuleStringoptionalRule transforming the API response into application data.
readActionStringoptionalRead action fetching data before the integration runs.
writeActionStringoptionalWrite action persisting the integration response.
preIntegrationWriteActionStringoptionalWrite action run before calling the integration — for example marking the case in-progress.
documentUploadReadActionStringoptionalRead action for documents to upload as part of the integration.
documentUploadEvalActionStringoptionalEvaluation 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.

PropertyTypeReqDescription
outboundCallDefinitionIntegrationDefinitionoptionalThe integration definition used for the outbound call.
inboundCallRuleSetInboundCallRuleSetoptionalRules handling the inbound callback and its response mapping.
timeoutAutomatedTaskDefinitionKeyStringoptionalAutomated task to run if the callback never arrives.
allowedActionNamesSet<String>optionalActions allowed while the task is waiting for the callback.

InboundCallRuleSet

PropertyTypeDescription
ruleNameStringName of the ASYNC_INBOUND_CALL_MAPPER rule handling the callback.
readActionStringRead 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.

Everything is a folder

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

FieldTypeReqDescription
folderIdString!requiredDocument-store folder identifier grouping the uploaded files.
documents[Document]optionalThe files uploaded into this folder.

type Document

FieldTypeReqDescription
documentIdString!requiredDocument-store identifier.
fileNameString!requiredOriginal file name.
fileTypeString!requiredMIME or file type.
filePathStringoptionalStorage path of the file.
fileSizeFloatoptionalFile 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#

ActionactionTypePurpose
DocEvalActionDOC_EVALUpload or evaluate a document. Declares the document catalog and the scopes granted.
AllDocumentsViewActionDOCUMENT_MANAGEMENT_VIEWRenders the whole document tree for the front end. It does not upload.
DmsActionDMS_ACTIONGeneric document-store operation, carrying a writeAction.

DocEvalAction

PropertyTypeDescription
documentsList<DmsEvalConfigDto>The document catalog this action can upload or evaluate — one entry per documentType.
defaultScopeList<Scope>Scopes granted when a document entry does not override them.

Per-document configuration

PropertyTypeReqDescription
documentTypeStringrequiredDot path to the document-folder data point. Also the lookup key.
singleFileUploadbooleanoptionalIf true, the type expects a single file. Defaults to false.
documentDataPathStringoptionalPath whose value is attached as document context on upload.
relevantDataPathStringoptionalPath whose value disambiguates multi-instance items — for example a collateral identifier.
scopeList<Scope>optionalPer-document scope override. Falls back to the action's defaultScope.

AllDocumentsViewAction and the document tree

PropertyTypeDescription
configList<DmsViewConfigDto>The document tree to render — nested FOLDER and DOCUMENT nodes.
readActionStringRead action whose data resolves labelPath and dataPath values.
ruleSetStringAn ALL_DOCUMENTS_VIEW rule producing the relevance list — which branches to show.

Each tree node:

PropertyTypeDescription
typeConfigTypeFOLDER or DOCUMENT.
keyStringStable node id.
labelStringStatic label, often an i18n token.
labelPathStringData path whose value overrides label at render time. If the path is missing, the static label is kept.
dataPathStringFor DOCUMENT nodes: the documentType path. Its data is attached to the node.
relevanceStringIf set, the node is dropped unless the rule set's relevance list contains this value.
metadataMapFront-end metadata. For DOCUMENT nodes it must include the upload endpoint — the name of the DocEvalAction that owns this document's scopes.
childrenList<DmsViewConfigDto>Nested nodes.
Scopes are not duplicated

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#

ValueMeaning
UPLOADAdd a file to the folder.
UPDATEModify or replace a file.
DELETERemove a file.
VIEWSee the document.
DOWNLOADDownload the file.
Read-only downgrade

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

LevelFieldEffect
TaskTaskDefinition.documentEvalActionsNames the DocEvalActions available within that task.
Stage + roleStageRoleDefinition.documentTreeAction / documentEvalActionThe current view and upload actions for that (stage, role).
FlowFlowDefinition.globalDocumentViewAction / globalDocumentEvalAction depLegacy 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.

The governing principle

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.

FieldPurpose
promptThe system prompt describing role, voice and behaviour. May reference flow and task data through templated placeholders.
allowedActionsWhitelist 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.
toolsNamed tool bindings the copilot may call.
skillsReferences to reusable capability contracts.
hooksLifecycle interceptors.
promptGuardrailsNatural-language constraints injected into the prompt — refusal patterns, scope limits, tone.
memoryOptional configuration for short-term (session) and long-term (per-case) memory stores.
modelModel 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.

FieldPurpose
mainObjectiveThe success criterion in plain language. The agent terminates when it is satisfied.
successCriteriaOptional structured checks — rule references, required outputs, schema-conformant result — used by the runtime to validate the agent's claimed completion.
terminationPolicyLimits and exits: maxSteps, maxWallClockMs, maxTokens, and onLimitExceeded (fail or escalate).
escalationWhere 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.

ToolWhat it doesPer-binding permissions
call_actionInvoke 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_dataRead fields from the current case via a GraphQL query.fields / fieldPaths allow-list. Field-level AI-readable flags are enforced first.
write_dataStage 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_documentFetch or attach files in the case's document store.categories, mimeTypes, maxSizeMb, maxPages. Read and upload are granted independently.
query_master_dataRead reference datasets by slug.slugs allow-list (supports glob), optional language and region restriction.
call_integrationInvoke an Integration API by key, reusing the existing payload mappers.apis allow-list, optional rateLimit.
run_subflowInitiate a child case and optionally wait for completion.flowKeys allow-list, maxConcurrent, awaitTimeoutMs.
run_automated_activityTrigger 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_codeExecute 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_agentPass control to another copilot or agent task.targets allow-list of eligible recipients.
emit_eventPublish a domain event to the event stream.eventTypes allow-list.
retrieve_knowledgeRetrieval lookup against a configured corpus — policy documents, prior cases.corpora allow-list, optional per-corpus tag filter and topK cap.
explainMandatory 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 pointTypical use
onSessionStartHydrate context, inject a case summary, set the per-session budget.
beforeToolCallVeto, rewrite or redact tool arguments; enforce dynamic policy such as "no credit pulls after 18:00".
afterToolCallSanitise results before the model sees them — PII redaction, schema clamping.
onMessageInspect model output; classify, route or block.
onGuardrailViolationDecide whether to retry with a corrective message, escalate, or terminate.
onHandoffFired when a copilot escalates to a human or another agent; carries summary and state.
onSessionEndPersist 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.

#LayerScope
1Construct-level flagsAI-readable and AI-writable flags on fields; AI-invocable on Actions and automated Activities. Set once, they govern every AI on the platform.
2Tool catalog defaultsSystem-wide caps — for example, sandboxed code execution always carries a hard wall-clock ceiling.
3Per-binding allow-listThe 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
ConstructPurpose
Product BaselineThe canonical configuration for a product. Tenant-agnostic.
Tenant / country variantA child configuration that extends a baseline and applies patches. Identified by a flow key.
PatchA targeted modification expressed in the config patch DSL. Edits specific fields of the inherited configuration without duplicating it, so it survives baseline upgrades.
Flow RegistrationThe 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 patchedExample
Workflow stagesAdd a compliance stage for a regulated market.
Activity definitionsAdd a country-specific verification activity.
Task assignmentsDifferent role names per country.
Business rulesDifferent approval thresholds per market.
Data fieldsCountry-specific regulatory fields.
UI formsLocalised labels, different field visibility.
IntegrationsCountry-specific provider APIs.
Deduplication rulesDifferent 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 typeEmitted when
InitiateA new case is created.
StageA stage milestone is achieved.
ActivityAn activity starts or completes.
TaskA task is assigned, claimed, completed or reassigned.
ActionA user action is executed — read, write, approve, reject.
ClarificationA clarification is raised, responded to or closed.
REJECTA case is rejected.

ActionEvent

PropertyTypeDescription
applicationIdStringCase the action was executed on.
flowDefinitionKeyStringKey of the flow definition.
userStringUser who executed the action.
taskId / taskDefinitionKeyStringTask instance and definition the action ran on.
actionNameStringName of the action executed.
applicationStatusApplicationStatusCase status after execution.
type / subTypeFlowEventType / StringEvent 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.

CapabilityBehaviour
Task claimingUsers claim tasks from a shared pool produced by a CLAIM-mode allocation strategy.
Task reassignmentReassign to other eligible users, computed by the reassignment strategy.
ClarificationsEncrypted request-and-respond threads between users, with a PENDING → RESPONDED → CLOSED lifecycle. Enabled per task via clarificationsEnabled.
Timeline / audit trailFull history of every action on a case, archived for compliance. Exposed per task via timelineAccessAllowed.
Document managementUpload, view and evaluate documents with automatic file-type detection and HTML-to-PDF conversion.
Refer backSend work back to a previous stage or user for revision, via referTask and canReferFurther.
Auto-save draftsForms auto-save in-progress data, encrypted at rest and recoverable across sessions.
WorklistFilterable, full-text searchable task inbox with bookmarking, fast-tracking and read status.
DeduplicationPrevents duplicate cases at initiation using configurable identifier matching and distributed locks.
NotificationsEvent-driven email and SMS with template-based rendering.
ReportingReal-time dashboards with configurable data dimensions, fed from the event stream.
Field-level encryptionTransparent encryption of sensitive fields in forms, clarifications and feedback via the EncryptedString scalar.
Event streamingEvery 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

  1. Prefer concrete user-facing terms over implementation terms. Case beats Flow Instance; Draft beats Partial Save Snapshot.
  2. 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.
  3. Drop noise suffixes. Every construct is a definition, so Form Definition is just Form.
  4. Do not reinvent industry-standard names. They come from elsewhere and the shared vocabulary is the benefit.
  5. Names must describe the current job, not the historical one. Rename when purpose drifts.
  6. 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 namePresentation nameWhy
Flow InstanceCaseThe natural business term, and standard across case-management platforms. "Flow Instance" reads like an implementation detail.
Floating ActivityAmbient Activity"Floating" is evocative but does not convey what it does. Superseded structurally by sideStages.
Master Data DefinitionReference DataModern term in finance and insurance; signals lookup values rather than transactional records.
Partial Save SnapshotDraftWhat users already call it. The old name describes the mechanism, not the thing.
Form DefinitionFormThe Definition suffix is noise.
Base Product DefinitionProduct BaselineShorter, and the standard term in multi-tenant configuration systems.
UAM MappingFlow RegistrationA 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 TaskAI Agent TaskPrecise and durable. The related move renames the AUTOMATED task type to Script Task, which accurately describes what it already does.
Integration Mapper RulePayload MapperTells you what it does on first read.

Key conventions

Deprecations#

These fields still exist and still function. New configuration should use the replacement.

DeprecatedOnUse instead
activityOrchestrationRuleSetFlowDefinitionStageDefinition.activityOrchestrationRuleSet — per stage. The flow-level rule is now only a fallback for stages that declare none.
floatingActivitiesFlowDefinitionFlowDefinition.sideStages.
globalReadActionFlowDefinitionGlobalStageRoleRead plus StageRoleDefinition.readAction.
globalDocumentViewActionFlowDefinitionStageRoleDefinition.documentTreeAction.
globalDocumentEvalActionFlowDefinitionStageRoleDefinition.documentEvalAction.
roleBasedGlobalActionsAllowedFlowDefinitionStageRoleDefinition.topLevelActions.
scriptAllocationStrategyDefinitionscripts — 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 encounterCorrect 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#

ConstructFamilyPropertiesSection
BaseDefinitionProcess3Base definition
FlowDefinitionProcess19Flow definition
StageDefinitionProcess8Stage definition
ActivityDefinitionProcess12Activity definition
TaskDefinitionProcess19Task definition
TaskType (enum)Process6 valuesTask sub-constructs
TaskActionsDefinitionProcess4Task sub-constructs
TaskMovementDefinitionProcess4Task sub-constructs
ActivityTaskReferenceProcess2Task sub-constructs
StatusDefinitionProcess4Status definition
Action (base)Process10Action model
ActionType (enum)Process13 valuesAction types
WorkflowActionType (enum)Process9 valuesWorkflow action types
ActionContextProcess7Action subtypes
BusinessRuleSetLogic5Task sub-constructs
AutomatedTaskRuleSetLogic5 (inherited)Task sub-constructs
RuleType (enum)Logic16 valuesRule types
Rule responses (16 types)LogicResponse reference
AllocationStrategyDefinitionProcess5Allocation configuration
AssignmentAllocationDetailsProcess2Allocation configuration
ReassignmentAllocationDetailsProcess3Allocation configuration
StageRoleDefinitionAccess13Stage role definition
TopLevelActionAccess3Stage role definition
ActionStatusType (enum)AccessGLOBAL, TASKStage role definition
IntegrationDefinitionIntegration12Synchronous integration
AsyncIntegrationDefinitionIntegration4Asynchronous integration
InboundCallRuleSetIntegration2Asynchronous integration
GraphQL schema & directivesDataDirectives
ApplicationDataHolderData4Data layer
Storage models (3 stores)DataStorage models
MutationContext · UpdateResultData4 · 5Queries and mutations
Audit & timeline recordsDataAudit and runtime
DocumentFolder · DocumentData2 · 5Documents
Copilot · AI Agent TaskAI8 · +4AI constructs

Glossary#

TermDefinition
ActionAn operation that can be performed on a task or at stage level. The only path through which data is read or written.
ActivityA group of related tasks within a stage.
Allocation strategyThe method used to decide who receives a task.
Ambient activityAn activity that may run alongside any stage without blocking it. Structurally expressed as a side stage.
CaseA running flow — one per application. Internally a flow instance.
ClarificationA structured, encrypted message thread between users about a specific task.
Definition keyThe unique identifier of any construct instance.
Definition-drivenThe architectural principle that all behaviour derives from declarative constructs, not compiled code.
DraftAuto-saved in-progress form data, encrypted at rest and recoverable across sessions.
Fast trackA priority flag on a case, surfaced in the worklist.
FlowA complete business process definition.
Flow keyThe identifier of a specific flow variant.
Flow registrationThe required metadata entry registering a flow with the platform catalog and routing its service hosts. Not a tenant binding.
Form engineThe component that renders forms from configuration, with expression evaluation and conditional visibility.
Hot reloadRules and configuration reload at runtime without a service restart.
IntegrationA configured connection to an external system.
MilestoneThe condition at which a stage is considered complete.
MutationA GraphQL write operation. The only mechanism that modifies application data.
PatchA targeted configuration modification applied to an inherited baseline.
Payload mapperA rule transforming data into and out of an external API call.
Product baselineThe canonical, tenant-agnostic configuration for a product.
Reference dataVersioned lookup datasets — dropdown lists, rate tables, configuration values.
Rule setA Groovy script implementing business logic of a single rule type.
Script taskA task that executes rules rather than involving a human. Configuration type AUTOMATED.
Side stageA stage that runs in parallel with the main stage sequence without blocking it.
StageA major phase in the process lifecycle.
TaskA single unit of work — human, automated, integration or AI.
TerritoryA geographic or organisational unit in the user hierarchy.
WorklistThe searchable task inbox where users find and claim work.