Reason on Data
The Reason stage evaluates the data that the Sense stage collects and determines the appropriate action. The four Reason substages run in order: analyze → plan → govern → authorize.
The Reason stage is optional, and so are each of the Reason substages.
A simple agent might only need analyze and plan. Add govern when you want safety rules, and authorize to declare explicit permission boundaries.
|
Both Reason modes, deterministic rules and large language model (LLM) prompts, read from the same |
Analyze
The analyze substage produces a structured assessment of what the Sense data means.
Use the analyze substage to classify conditions, detect anomalies, or evaluate thresholds.
Option 1: Deterministic (Rule-Based, No LLM)
Write conditions as JavaScript expressions.
If a condition evaluates to true, the platform adds the results of the rule (type, severity, message) to the analysis output:
reason:
substages:
- type: analyze
name: threshold-check
config:
rules:
- condition: 'temperature.value > 45'
type: temperature_critical_high
severity: critical
message: 'Temperature {{temperature.value}}°C critically exceeds limit of 35°C'
- condition: 'temperature.value > 35 && temperature.value <= 45'
type: temperature_high
severity: high
message: 'Temperature {{temperature.value}}°C exceeds normal limit of 35°C'
- condition: 'humidity.value < 30'
type: humidity_low
severity: high
message: 'Humidity {{humidity.value}}% below minimum of 30%'
Multiple rules can match in the same cycle. Use the deterministic mode for fixed thresholds. The deterministic mode runs with zero LLM cost and minimal latency.
Option 2: LLM-Based (AI Reasoning)
Provide a prompt and define the expected output shape. The LLM analyzes the data and returns structured results:
reason:
substages:
- type: analyze
name: quality-assessment
prompt: |
You are an industrial quality monitoring agent.
Analyze the following quality metrics and identify any anomalies.
Current readings:
{{environmentalData | json}}
Historical patterns:
{{memory.patterns | json}}
Identify anomalies, classify severity (low/medium/high/critical),
and assess overall production health.
outputSchema:
type: object
properties:
anomalies:
type: array
items:
type: object
properties:
metricName:
type: string
severity:
type: string
enum: [low, medium, high, critical]
description:
type: string
overallHealth:
type: string
enum: [healthy, degraded, at-risk, critical]
confidence:
type: number
minimum: 0
maximum: 1
The platform validates the LLM output against outputSchema.
If the output does not match the schema, the platform marks the analyze result as failed, and logs the error.
Results are available in the Plan substage as derivedData.analysis.
Plan
The plan substage decides which actions to execute based on the analysis.
Like analyze, the plan substage supports two modes: deterministic rules and LLM prompts.
Deterministic Plan
Write conditions to select actions.
If the condition of an action evaluates to true, the plan passes the action to the Actuate stage:
reason:
substages:
- type: plan
name: response-planner
config:
objective: 'Alert on threshold violations'
actions:
- action: critical-temperature-alert
type: mqtt_publish
target: factory/alerts/temperature
condition: 'temperature.value > 45 || temperature.value < 5'
priority: 1
params:
severity: critical
message: 'CRITICAL: Temperature {{temperature.value}}°C outside safe range'
- action: temperature-warning
type: mqtt_publish
target: factory/alerts/temperature
condition: 'temperature.value > 35 && temperature.value <= 45'
priority: 2
params:
severity: warning
message: 'WARNING: Temperature {{temperature.value}}°C above normal range'
The platform sorts actions by priority (lower number = higher priority) and passes the actions to the Actuate stage.
LLM-Based Plan
reason:
substages:
- type: plan
name: response-planner
prompt: |
Based on the quality analysis, create a response plan.
Analysis:
{{derivedData.analysis | json}}
Available actions:
- publish-alert: Send alert to MQTT (use for notifications)
- stop-line: Emergency production stop (critical quality failures only)
- log-observation: Record for trending (low severity)
Guidelines:
- critical severity → stop-line + publish-alert
- high severity → publish-alert
- medium/low → log-observation
outputSchema:
type: object
properties:
actions:
type: array
items:
type: object
properties:
action:
type: string
enum: [publish-alert, stop-line, log-observation]
target:
type: string
params:
type: object
confidence:
type: number
Govern
The govern substage applies safety rules to the plan.
Each rule has a condition and an action: approve or reject.
If the condition of a reject rule evaluates to true, the platform discards the plan and skips the Actuate stage for that cycle.
Use the govern substage to limit the number of actions the agent takes in a short time, or to block specific actions under certain conditions:
reason:
substages:
- type: govern
name: safety-governance
rules:
- id: max-actions-per-cycle
condition: 'plan.actions.length <= 5'
action: approve
message: 'Action count within limits'
- id: too-many-actions
condition: 'plan.actions.length > 5'
action: reject
message: 'Too many actions planned ({{plan.actions.length}}). Max is 5 per cycle.'
- id: alert-rate-limit
condition: 'memory.recentActions.length < 50'
action: approve
message: 'Alert rate within acceptable limits'
- id: rate-exceeded
condition: 'memory.recentActions.length >= 50'
action: reject
message: 'Alert rate limit exceeded'
The platform evaluates the rules in order.
The first reject rule that matches stops the cycle.
If no reject matches, the platform approves the plan.
| Field | Required | Description |
|---|---|---|
|
Yes |
Unique name for the rule, shown in logs. |
|
Yes |
JavaScript expression that returns |
|
Yes |
|
|
No |
Log message for when the rule matches. |
Authorize
The authorize substage declares which resources the agent can access.
The authorize substage acts as an allowlist that the runtime checks before the Actuate stage runs:
reason:
substages:
- type: authorize
name: permission-check
type: static
permissions:
- mqtt:publish:factory/quality/alerts
- mqtt:publish:factory/quality/observations
- mqtt:publish:factory/line-control/stop
- email:send:alert-email
- database:write:quality-db
The permission format is <protocol>:<operation>:<resource>. Wildcards (*) are supported at the end of the resource path.
|
Always set the |
Complete Deterministic Example
The following example shows a complete Reason stage that uses all four substages and no LLM:
reason:
substages:
- type: analyze
name: threshold-check
config:
rules:
- condition: "temperature.value > 45"
type: temperature_critical_high
severity: critical
message: "Temperature {{temperature.value}}°C critically exceeds maximum of 35°C"
- condition: "temperature.value > 35 && temperature.value <= 45"
type: temperature_high
severity: high
message: "Temperature {{temperature.value}}°C exceeds maximum of 35°C"
- condition: "humidity.value > 70"
type: humidity_high
severity: high
message: "Humidity {{humidity.value}}% exceeds maximum of 70%"
- type: plan
name: response-planner
config:
objective: "Alert on threshold violations for temperature and humidity"
actions:
- action: critical-temperature-alert
type: mqtt_publish
target: factory/alerts/temperature
condition: "temperature.value > 45 || temperature.value < 5"
priority: 1
params:
severity: critical
message: "CRITICAL: Temperature {{temperature.value}}°C outside safe range"
- action: temperature-warning
type: mqtt_publish
target: factory/alerts/temperature
condition: "temperature.value > 35 && temperature.value <= 45"
priority: 2
params:
severity: warning
message: "WARNING: Temperature {{temperature.value}}°C above normal range"
- type: govern
name: rate-limiter
rules:
- id: alert-rate-limit
condition: "memory.recentActions.length < 10"
action: approve
- id: rate-exceeded
condition: "memory.recentActions.length >= 10"
action: reject
message: "Alert rate limit exceeded — max 10 per window"
- type: authorize
name: permission-check
type: static
permissions:
- mqtt:publish:factory/alerts/*
- email:send:alert-email
Template Variables in Prompts
Use {{variable}} syntax in prompts and rule messages:
| Template | Contents |
|---|---|
|
All Sense data for this cycle (the |
|
Output from the |
|
Agent memory (patterns, recent actions). |
|
History of human feedback responses. |
|
Individual sensor reading from a simulator. |
|
Always add the |
Reason Stage Inputs and Outputs
Reason reads the Sense data from environmentalData.payload (see Where the Platform Stores Sensed Data).
Each Reason substage writes its result into a dedicated property on derivedData.
Within the same cycle, the following Reason substages, Actuate stage, and Reflect stage read the results from these properties.
| Substage | Output Property | Structure |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
The Actuate stage reads derivedData.plan to know which actions to execute.
The Reflect stage reads derivedData.analysis and the evaluation results to assess the cycle. Reference any of these properties in a later LLM prompt with {{derivedData.analysis | json}}.
The platform resets derivedData at the start of every cycle.
If you need a result from this cycle to influence the next cycle, route the result through memory in the Reflect stage. derivedData itself does not survive a cycle boundary.