Sense Data

The Sense stage collects data from your external sources and passes the data to the Reason stage. In each cycle, all configured Sense substages run in order, and the platform merges their results for analysis.

You configure the Sense stage in stage 03 of the Agent Builder. In the agent template YAML, you define the stage under stages.sense.substages. Add one or more substages of different types to collect from multiple sources in a single cycle.

Every Sense substage writes into environmentalData.payload. The property names inside payload depend on the source type (MQTT topic, database query, API endpoint, or CSV file). Your Reason prompts and conditions read from these locations. For the exact mapping, see Where the Platform Stores Sensed Data. Each substage section also notes where the platform stores its data.

Substage Types

Type What it Does

mqtt

Subscribes to MQTT topics and collects messages.

api

Makes HTTP requests to a REST API.

database

Runs an SQL query against a configured database.

csv

Reads and parses a CSV file from a local path or URL.

agent-messages

Collects messages from the agent bus discussion channel.

Sandbox Mode: To run agents without live data sources during development or testing, set HIVEMQ_SANDBOX_MODE=true. The platform replaces configured Sense substages with synthetic data. The full cycle executes without real MQTT brokers, databases, or APIs. See Train Your Agent (Sandbox).

MQTT

Subscribe to MQTT topics and collect messages that arrive within the timeout window:

sense:
  substages:
    - type: mqtt
      name: quality-metrics
      connection: factory-mqtt # Name from your connections: block
      config:
        topics:
          - factory/quality/metrics
          - factory/quality/+/inspection # MQTT wildcards supported
          - factory/sensors/#
        timeoutMs: 15000 # Wait up to 15 seconds for messages

The mqtt substage collects messages into environmentalData.payload, with one entry per topic. In the Reason stage, a large language model (LLM) prompt reads the payload object as {{environmentalData}}, so reference it with {{environmentalData | json}}. For the exact property names, see Where the Platform Stores Sensed Data.

Set timeoutMs to match how often your broker publishes messages. If the timeout is too short, the agent can miss messages. If the timeout is too long, each cycle takes longer. For topics that receive many messages, set a window to get summary values, such as averages, instead of individual messages. For more information, see Windowing and Aggregation.

API

Make HTTP requests to a configured REST API:

sense:
  substages:
    - type: api
      name: erp-data
      connection: erp-api # Name from your connections: block
      config:
        endpoints:
          - name: active-orders # ← becomes the payload key
            path: /api/v1/production-orders/active
            method: GET
            params:
              site: berlin
              status: running

The api substage places the response body of each endpoint in environmentalData.payload, under the endpoint name. For example, environmentalData.payload["active-orders"].

Database

Run an SQL query against a configured database:

sense:
  substages:
    - type: database
      name: recent-defects
      connection: quality-db
      config:
        query:
          name: recent-defects # ← becomes the payload key
          sql: |
            SELECT defect_type, count(*) as count, avg(severity) as avg_severity
            FROM defects
            WHERE created_at > NOW() - INTERVAL '1 hour'
            GROUP BY defect_type
            ORDER BY count DESC
            LIMIT 20

The database substage places the query result in environmentalData.payload, under the query name, as an array of row objects. For example, environmentalData.payload["recent-defects"].

CSV

Read and parse a CSV file from a local path or URL:

sense:
  substages:
    - type: csv
      name: shift-schedule # Becomes the property name in payload
      config:
        path: /data/shift-schedule.csv # Local path or URL

The csv substage places the parsed file in environmentalData.payload under the substage name, as an object with rows, columns, and totalRows. For example, environmentalData.payload["shift-schedule"].

Agent Messages

The agent-messages substage collects messages from the agent bus discussion channel. Use this substage when an agent responds to instructions from other agents or from operators.

sense:
  substages:
    - type: agent-messages
      name: instruction-collector
      config:
        maxMessages: 10
        timeoutMs: 5000

The agent-messages substage places messages in environmentalData.payload.agentMessages.

Windowing and Aggregation

By default, each cycle sees only the raw observations of that cycle. A window buffers observations across multiple cycles and gives the Reason stage aggregated statistics (average, maximum, trend) instead of raw values.

Use a window to detect trends rather than react to individual spikes:

sense:
  window:
    size: 10 # Buffer the last 10 observations
    slide: 1 # Advance by 1 each cycle (rolling window)
    minSize: 5 # Wait until at least 5 observations before forwarding

    aggregations:
      - name: avg_temp
        field: payload.temperature
        function: avg

      - name: max_temp
        field: payload.temperature
        function: max

      - name: temp_slope
        field: payload.temperature
        function: slope # Positive = rising, negative = falling

      - name: reading_count
        function: count # Number of observations in the window

The Reason stage reads aggregated values as _aggregations.<substage-name>.<aggregation-name>:

{{_aggregations.quality-metrics.avg_temp}}
{{_aggregations.quality-metrics.temp_slope}}

Available Aggregation Functions

Function Result

avg

Mean value.

sum

Sum of all values.

min

Smallest value.

max

Largest value.

count

Number of observations.

first

First value in window.

last

Most recent value.

stddev

Standard deviation.

variance

Statistical variance.

median

50th percentile.

p95

95th percentile.

p99

99th percentile.

slope

Linear trend direction.

range

Max minus min.

Payload Interpretation

When your incoming data has a variable or unpredictable structure, the interpret block uses the LLM to normalize the data into a consistent structure before Reason reads it.

Use interpretation when multiple device types publish different payload formats to your topics:

sense:
  substages:
    - type: mqtt
      name: heterogeneous-sensors
      connection: factory-mqtt
      config:
        topics:
          - sensors/+/telemetry
        timeoutMs: 10000

      interpret:
        instructions: |
          Normalise the incoming sensor payload into a consistent structure.
          Extract temperature (in °C), pressure (in hPa), and any alert flags.
        output_schema:
          type: object
          properties:
            temperature_c:
              type: number
            pressure_hpa:
              type: number
            alert:
              type: boolean

The LLM normalizes each unique payload structure once, and the platform caches the result. The platform normalizes subsequent messages with the same structure without another LLM call.

The Reason stage receives the normalized interpreted data alongside the raw original payload.

Where the Platform Stores Sensed Data

Each cycle runs against a shared state object. The Sense stage writes everything that it collects into environmentalData.payload, and the Reason and Reflect stages read from there. The platform fully replaces environmentalData every cycle. The platform discards the sensed data of the previous cycle unless you carry the data forward through memory or a window.

The location of each source in payload depends on the substage type and on whether you configure a window.

Storage Without a Window (Default)

Source Type Source Identifier Memory Location

mqtt

config.topics: [topic1, topic2]

environmentalData.payload[<topic>]: The latest message payload per topic.

database

config.query.name

environmentalData.payload[<queryName>]: Array of row objects.

api

config.endpoints[].name

environmentalData.payload[<endpointName>]: The response body (status, headers, and latency are stripped).

csv

config.name

environmentalData.payload[<csvName>]: { rows, columns, totalRows }.

agent-messages

(fixed key)

environmentalData.payload.agentMessages: Array of messages.

The platform keeps only the latest message per MQTT topic and discards older readings that arrive during the same Sense cycle. If you need all readings, configure a window.

When several substages run in the same cycle, the platform merges their outputs into a single flat payload object. If two substages produce the same property name, the platform keeps the value from the later substage. Keep your topic, query, and endpoint names distinct.

Slash-keyed topics require bracket notation. MQTT topic keys contain /. In prompts and in rule conditions, always use bracket notation, such as {{environmentalData['factory/line1/temperature']}}. Dot notation (environmentalData.factory.line1.temperature) silently returns undefined and your condition never fires.

Storage With a Window

When you add a window block, the property names change. Instead of one entry per topic, query, or endpoint, you get one entry per substage, and the entry holds the full window of observations. Aggregations and window metadata appear in their own top-level fields.

Field Contents

environmentalData.payload[<substageName>]

Array of the observations that the window collected (up to the configured size).

environmentalData._aggregations[<substageName>]

One entry per aggregation you configured ({ <aggregationName>: <number> }).

environmentalData._windowMetadata[<substageName>]

Window size and first and last timestamps.

Because the property names change completely, use either windowed or non-windowed configuration per agent. The same Reason prompt or condition cannot serve both. A windowed substage also produces nothing until its buffer fills. Design your rules and prompts to tolerate a no-data cycle. Treat _aggregations[<substageName>] as possibly undefined.

Next Steps

  • Reason on Data: Analyze the collected data with rules or an LLM and plan actions.

  • Set Up Connections: Define the brokers, databases, and APIs that the Sense substages reference.