Skip to main content
Version: 2.7-dev

UNS (Unified Namespace) Nodes

Overview

The Unified Namespace (UNS) is MaestroHub's central data fabric that organizes all operational data into a hierarchical topic tree following the ISA-95 model (enterprise / site / area / line / cell). UNS nodes allow pipelines to interact with this namespace — publishing live data, retrieving historical records, discovering topics, and triggering workflows when new data arrives.

Unlike industrial or database connector nodes, UNS nodes do not require an external connection profile. They communicate directly with the built-in UNS Manager service, making them zero-configuration from a connectivity standpoint.

Topic Structure

Every UNS topic path is prefixed with a version string that scopes the namespace schema. The current default version is mHv1.0.

mHv1.0/enterprise/site/area/machine/temperature
└─────┘ └──────────────────────────────────────┘
version topic path

The system automatically prepends the version prefix if it is not already present in the configured topic. In the UI, a version selector dropdown lets you choose the active version while you type the topic path.

Available Nodes

NodeType IDCategoryPurpose
UNS Subscribe Triggertrigger.uns.subscribeTriggerStarts a pipeline when data is published to matching UNS topics
UNS Publishsystem.uns.publishUNSPublishes data to a UNS topic
UNS Publish (Batch)system.uns.publishBatchUNSPublishes an array of records to UNS topics atomically in one storage commit
UNS Fetch Datasystem.uns.fetchdataUNSRetrieves recent data from a UNS topic
UNS Search Nodessystem.uns.searchnodesUNSSearches the namespace for topics by keyword

UNS Topic Selector

The UNS Publish, UNS Publish (Batch), and UNS Fetch Data nodes share a specialized UNS Topic Selector control for configuring the target topic. Understanding this component helps you work with any UNS node that requires a topic.

How It Works

  1. Version Selector — a dropdown on the left side of the field displays the available namespace versions (fetched from the backend). The default version (mHv1.0) is pre-selected.
  2. Topic Path Input — a text input where you type the topic path. As you type (minimum 2 characters), the system searches existing topics and shows autocomplete suggestions in a dropdown.
  3. Expression Support — the field accepts pipeline expressions ({{ }} syntax). When an expression is detected, autocomplete is disabled and a live preview evaluates the expression against available upstream data.
  4. Full Topic Preview — below the input, a preview badge shows the complete resolved path including the version prefix (e.g., mHv1.0/enterprise/site/area/machine/temperature).

Expression Preview States

StateIndicatorMeaning
EvaluatingSpinnerExpression is being evaluated.
SuccessGreen checkmarkExpression resolved successfully; shows the resolved value.
Missing dataInfo icon (muted)Upstream node data not yet available — run upstream nodes first.
ErrorRed alertSyntax error or evaluation failure in the expression.

UNS Publish

UNS Publish node configuration

UNS Publish Node

Overview

The UNS Publish node writes data to a UNS topic. It is the primary way pipelines push processed results, enriched telemetry, calculated KPIs, or control signals back into the Unified Namespace for other systems and pipelines to consume.

Publishing is synchronous — the node waits for confirmation from the UNS Manager before completing, ensuring reliable delivery.

Node Handles

HandlePositionDescription
Input (in)LeftReceives data from the upstream node.
Output (out)RightSends the publish confirmation and metadata to downstream nodes.

Parameters

FieldUI ControlData TypeRequiredDefaultValidationDescription
UNS TopicUNS Topic Selector (version dropdown + path input with autocomplete)stringYes""Must not be empty after expression resolutionFull UNS topic path. The version prefix is auto-prepended if missing. Supports expressions.
ValueExpression Field (multiline textarea with preview)anyYes""Must not be empty or nullData to publish. Accepts literal values, JSON objects, or expressions that resolve to any type.
Data SourceExpression Field (single-line input with preview)stringNo"" (auto-generated)Identifier for the data source. If left empty, defaults to pipeline:{pipelineName}:{pipelineId}. Supports expressions.

Settings

Description

A free-text area for documenting the node's purpose.

Execution Settings

SettingOptionsDefaultDescription
Timeout (seconds)1–600Pipeline defaultMaximum execution time for this node.
Retry on TimeoutPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry if the node times out.
Retry on FailPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry on failure. When Enabled, reveals Advanced Retry Configuration.
On ErrorPipeline Default / Stop Pipeline / Continue ExecutionPipeline DefaultBehavior when the node fails after all retries.

Advanced Retry Configuration (visible when Retry on Fail = Enabled)

FieldTypeDefaultRangeDescription
Max Attemptsnumber31–10Maximum retry attempts.
Initial Delay (ms)number1000100–30,000Wait before first retry.
Max Delay (ms)number1200001,000–300,000Upper bound for backoff delay.
Multipliernumber2.01.0–5.0Exponential backoff multiplier.
Jitter Factornumber0.10–0.5Random jitter.

Output Data Structure

On successful publish, the node produces:

{
"published": true,
"topic": "mHv1.0/enterprise/site/area/machine/temperature",
"value": { "temperature": 72.5, "unit": "F" },
"source": "pipeline:Temp-Monitor:abc-123",
"timestamp": "2026-02-11T14:15:00Z"
}
FieldTypeDescription
publishedbooleanAlways true on success.
topicstringThe full topic path the data was published to (including version prefix).
valueanyThe value that was published, as resolved from the input expression.
sourcestringThe source identifier used for this publish operation.
timestampstringISO 8601 timestamp of when the publish occurred (UTC).

Referencing in Downstream Nodes

{{ $node["UNS Publish"].published }}   → true
{{ $node["UNS Publish"].topic }} → the full topic path
{{ $node["UNS Publish"].timestamp }} → when it was published

Validation Rules

RuleError Message
Node name is required"UNS Publish node must have a name"
UNS topic is required"UNS topic is required"
Value is required"Value is required"
Topic must resolve to non-empty string"topic resolved to empty string"

Usage Examples

Publish Transformed Sensor Data

FieldValue
UNS TopicmHv1.0/acme-corp/plant-1/assembly/robot-arm/temperature
Value{{ $node["Set"].data }}
Data Source(empty — auto-generated)

The pipeline reads a raw sensor value, transforms it with a Set node, and publishes the enriched result back to the UNS.

Publish Aggregated KPIs

FieldValue
UNS TopicmHv1.0/acme-corp/plant-1/kpis/oee
Value{"oee": {{ $node["Calculate OEE"].result }}, "shift": "morning", "timestamp": "{{ $execution.startedAt }}"}
Data Sourcekpi-calculator

Publishes a calculated OEE metric with context about the shift and execution time.

Dynamic Topic from Trigger Data

FieldValue
UNS Topic{{ $trigger._metadata.topic }}/processed
Value{{ $node["Transform"].output }}
Data Source(empty)

Appends /processed to the original trigger topic, creating a parallel processed-data topic hierarchy.


UNS Publish (Batch)

UNS Publish (Batch) node configuration

UNS Publish (Batch) Node

Overview

The UNS Publish (Batch) node writes an array of records to the Unified Namespace in a single atomic storage commit. It is the high-volume counterpart to UNS Publish: instead of one topic and one value, you provide an Items expression that resolves to an array, plus per-item templates for the topic and value that are re-evaluated once for each element — exactly like the body of a For-Each loop, but collapsed into one node.

Use it instead of a For-Each + UNS Publish pair whenever you publish many records at once. A For-Each that publishes per item issues one synchronous write-ahead-log fsync per record; the batch node collapses all N writes into one commit. On large batches (thousands of records) this is typically two orders of magnitude faster.

The batch is all-or-nothing: if any record fails template evaluation, resolves to an empty topic, or is denied by authorization, the whole batch aborts before anything is written — you never get a partially-published namespace.

Node Handles

HandlePositionDescription
Input (in)LeftReceives data from the upstream node (often the array to publish).
Output (out)RightSends the batch commit summary and metadata to downstream nodes.

Evaluation Scope

The configuration form is organized into three sections by when each field is evaluated. Getting this right is the key to using the node correctly:

SectionFieldsEvaluated$item in scope?
1 · InputItemsOnce, at node entryNo — reference the upstream node by name, e.g. $node["Sample Readings"].payload
2 · Per-item templatesUNS Topic, ValueOnce per element in the resolved Items arrayYes — reference $item, $index, $key
3 · Batch metadataData SourceOnce, for the whole batchNo

When the Items expression resolves, the editor automatically takes row [0] as a sample so the Topic and Value fields can show live per-item previews — there is no separate "sample item" field to fill in.

Point Items at the array, not $input

Resolve the array by referencing the upstream node by name{{ $node["Sample Readings"].payload }} when a manual trigger carries the array, or {{ $node["Read Group"].results }} from a transform/read node. Avoid {{ $input }}: it is the raw array of upstream outputs, not your records array, so it won't iterate the way you expect.

Parameters

FieldUI ControlData TypeRequiredDefaultValidationDescription
ItemsExpression Field (multiline textarea with preview)arrayYes{{ $input }}Must resolve to an arrayExpression resolving to the array of records to publish. Each element becomes $item in the per-item templates. Evaluated once.
UNS TopicUNS Topic Selector (version dropdown + path input)stringYes""Must not resolve to empty per itemPer-item topic template, re-evaluated for each element — e.g. enterprise/site/{{ $item.name }}. The version prefix is auto-prepended if missing.
ValueExpression Field (multiline textarea with preview)anyYes{{ $item }}Must not be emptyPer-item value template. {{ $item }} publishes the whole row; {{ $item.payload }} picks a field.
Data SourceExpression Field (single-line input with preview)stringNo"" (auto-generated)Source attribution stamped on every record. Evaluated once at batch scope ($item not in scope). Defaults to pipeline:{pipelineName}:{pipelineId} if empty.
Source is batch-level

Unlike the topic and value, Data Source is evaluated once for the entire batch and shared by every record — $item is not available here. If you need a per-record source you must split the batch.

Settings

Description

A free-text area for documenting the node's purpose.

Execution Settings

SettingOptionsDefaultDescription
Timeout (seconds)1–600Pipeline defaultMaximum execution time for this node.
Retry on TimeoutPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry if the node times out.
Retry on FailPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry on failure. When Enabled, reveals Advanced Retry Configuration.
On ErrorPipeline Default / Stop Pipeline / Continue ExecutionPipeline DefaultBehavior when the node fails after all retries.

Advanced Retry Configuration (visible when Retry on Fail = Enabled)

FieldTypeDefaultRangeDescription
Max Attemptsnumber31–10Maximum retry attempts.
Initial Delay (ms)number1000100–30,000Wait before first retry.
Max Delay (ms)number1200001,000–300,000Upper bound for backoff delay.
Multipliernumber2.01.0–5.0Exponential backoff multiplier.
Jitter Factornumber0.10–0.5Random jitter.
Retry is all-or-nothing too

Because the batch commits atomically, a retry re-publishes the entire array, not just the failed records. Make downstream consumers tolerant of a record being delivered more than once, or keep batches idempotent.

Output Data Structure

On a successful commit, the node produces a summary of the batch (not the individual records):

{
"published": true,
"count": 3,
"distinctTopics": [
"mHv1.0/acme-corp/plant-1/press-01/temperature",
"mHv1.0/acme-corp/plant-1/press-01/pressure",
"mHv1.0/acme-corp/plant-1/press-02/temperature"
],
"source": "pipeline:Line-Ingest:abc-123",
"timestamp": "2026-06-11T14:15:00Z"
}
FieldTypeDescription
publishedbooleanAlways true on success.
countnumberNumber of records committed in the batch.
distinctTopicsarrayDeduped set of topics the batch wrote to. Publishing 5,000 records across 10 topics yields 10 entries here, not 5,000.
sourcestringThe source attribution recorded on every record.
timestampstringISO 8601 timestamp of when the batch was committed (UTC).
Empty array is a success, not an error

If the Items expression resolves to an empty array, the node completes successfully with published: true and count: 0 — nothing is written and the pipeline continues.

Referencing in Downstream Nodes

{{ $node["UNS Publish (Batch)"].count }}           → number of records published
{{ $node["UNS Publish (Batch)"].distinctTopics }} → the deduped topic set written to
{{ $node["UNS Publish (Batch)"].timestamp }} → when the batch committed

Validation Rules

RuleError Message
Node name is required"UNS Publish (Batch) node must have a name"
Items expression is required"Items expression is required"
Items must resolve to an array"items must be an array or expression, got …"
UNS topic is required"UNS topic is required"
Value is required"Value is required"
A record's topic must resolve to non-empty"record[N]: topic resolved to empty string"
A record may not be nil"record[N]: item is nil"

Usage Examples

Publish a Batch of Machine Readings

A Manual Trigger named Sample Readings provides an array of readings as its payload, each with its own machine and metric:

[
{ "machine": "press-01", "metric": "temperature", "value": 72.4 },
{ "machine": "press-01", "metric": "pressure", "value": 5.1 },
{ "machine": "press-02", "metric": "temperature", "value": 68.9 }
]
FieldValue
Items{{ $node["Sample Readings"].payload }}
UNS Topicacme-corp/plant-1/{{ $item.machine }}/{{ $item.metric }}
Value{{ $item.value }}
Data Source(empty — auto-generated)

Each reading is written to its own topic — mHv1.0/acme-corp/plant-1/press-01/temperature, .../press-01/pressure, .../press-02/temperature — in a single commit. The output reports count: 3 and three distinctTopics.

tip

This is exactly the wiring used by the bundled Demo_UNSPublishBatch pipeline. Open it, run the Sample Readings trigger, and inspect the node output to see count and distinctTopics for the batch.

Replace a For-Each + UNS Publish Loop

If you have a For-Each loop whose body is a single UNS Publish, collapse it into one batch node. The Items expression stays the same as the loop's Source Array; the loop body's Topic and Value templates move onto the batch node unchanged — they already reference $item.

For-Each + PublishUNS Publish (Batch)
Source Array: {{ $node["Read Group"].results }}Items: {{ $node["Read Group"].results }}
Publish Topic: plant/{{ $item.tag }}UNS Topic: plant/{{ $item.tag }}
Publish Value: {{ $item.value }}Value: {{ $item.value }}

The editor surfaces a hint inside the For-Each node when it detects this pattern. Keep the For-Each only if the loop body does extra per-item work the batch node can't express.

Publish Whole Rows Under a Static Topic

When every record goes to the same topic and you want to store the entire row:

FieldValue
Items{{ $node["Query"].rows }}
UNS Topicacme-corp/plant-1/audit/events
Value{{ $item }}
Data Sourceaudit-importer

Because the topic is a literal string (no $item reference), every record lands on the same topic and distinctTopics contains a single entry.


UNS Fetch Data

UNS Fetch Data node configuration

UNS Fetch Data Node

Overview

The UNS Fetch Data node retrieves the most recent data records stored in the UNS for a given topic. It is ideal for building dashboards, performing trend analysis, or feeding historical context into decision-making logic within a pipeline.

Node Handles

HandlePositionDescription
Input (in)LeftReceives data from the upstream node.
Output (out)RightSends the fetched records and metadata to downstream nodes.

Parameters

FieldUI ControlData TypeRequiredDefaultValidationDescription
UNS TopicUNS Topic Selector (version dropdown + path input with autocomplete)stringYes""Must not be empty after expression resolutionThe topic to fetch data from. Supports expressions.
LimitNumber inputnumberNo101–1,000 (clamped to 1,000 if exceeded)Number of most recent records to retrieve.

Settings

Description

A free-text area for documenting the node's purpose.

Execution Settings

SettingOptionsDefaultDescription
Timeout (seconds)1–600Pipeline defaultMaximum execution time for this node.
Retry on TimeoutPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry if the node times out.
Retry on FailPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry on failure. When Enabled, reveals Advanced Retry Configuration.
On ErrorPipeline Default / Stop Pipeline / Continue ExecutionPipeline DefaultBehavior when the node fails after all retries.

Advanced Retry Configuration (visible when Retry on Fail = Enabled)

FieldTypeDefaultRangeDescription
Max Attemptsnumber31–10Maximum retry attempts.
Initial Delay (ms)number1000100–30,000Wait before first retry.
Max Delay (ms)number1200001,000–300,000Upper bound for backoff delay.
Multipliernumber2.01.0–5.0Exponential backoff multiplier.
Jitter Factornumber0.10–0.5Random jitter.

Output Data Structure

The node returns an envelope containing the fetched records:

{
"records": [
{
"id": "rec-001",
"topic": "mHv1.0/enterprise/site/area/machine/temperature",
"value": { "temperature": 72.5, "unit": "F" },
"source": "pipeline:Temp-Monitor:abc-123",
"timestamp": "2026-02-11T14:10:00Z",
"retain": false
},
{
"id": "rec-002",
"topic": "mHv1.0/enterprise/site/area/machine/temperature",
"value": { "temperature": 73.1, "unit": "F" },
"source": "pipeline:Temp-Monitor:abc-123",
"timestamp": "2026-02-11T14:05:00Z",
"retain": false
}
],
"count": 2,
"topic": "mHv1.0/enterprise/site/area/machine/temperature",
"fetchMode": "recent"
}
note

The fetchMode field in the output is always "recent". Time-range based fetching is not currently available.

FieldTypeDescription
recordsarrayArray of data records matching the query.
records[].idstringUnique record identifier.
records[].topicstringThe topic the record belongs to.
records[].valueanyThe stored data value.
records[].sourcestringThe source that published the record.
records[].timestampstringISO 8601 timestamp of when the record was published.
records[].retainbooleanWhether this was a retained message.
countnumberNumber of records returned.
topicstringThe topic that was queried.
fetchModestringThe fetch mode used (currently always "recent").

Referencing in Downstream Nodes

{{ $node["UNS Fetch Data"].records }}        → the full records array
{{ $node["UNS Fetch Data"].records[0].value }} → the most recent record's value
{{ $node["UNS Fetch Data"].count }} → number of records returned
{{ $node["UNS Fetch Data"].fetchMode }} → "recent"

Validation Rules

RuleError Message
Node name is required"UNS Fetch Data node must have a name"
UNS topic is required"UNS topic is required"
Limit must be between 1 and 1,000"Limit must be between 1 and 1000"
Topic must resolve to non-empty string"topic resolved to empty string"

Usage Examples

Fetch Latest 5 Readings

FieldValue
UNS TopicmHv1.0/acme-corp/plant-1/assembly/robot-arm/temperature
Limit5

Downstream usage: {{ $node["UNS Fetch Data"].records }} to iterate over the readings in a For Each loop, or {{ $node["UNS Fetch Data"].records[0].value }} for the latest.

Fetch Maximum History for Trend Analysis

FieldValue
UNS TopicmHv1.0/acme-corp/plant-1/assembly/robot-arm/temperature
Limit1000

Downstream usage: Feed up to 1,000 recent records into a downstream calculation node for trend analysis or anomaly detection.

Dynamic Topic from Upstream Node

FieldValue
UNS Topic{{ $node["Set"].topic }}
Limit10

Downstream usage: The topic is dynamically determined by an upstream Set node, enabling reusable fetch logic across different data sources.


UNS Search Nodes

UNS Search Nodes configuration

UNS Search Nodes

Overview

The UNS Search Nodes node discovers topics in the Unified Namespace by keyword. It returns matching topic metadata with pagination support, making it useful for dynamic topic discovery, namespace exploration, and building guided selection flows.

Node Handles

HandlePositionDescription
Input (in)LeftReceives data from the upstream node.
Output (out)RightSends the search results to downstream nodes.

Parameters

FieldUI ControlData TypeRequiredDefaultValidationDescription
Search KeywordExpression Field (single-line input with preview)stringYes""Minimum 3 characters (unless it's an expression). Must not resolve to empty.Keyword to search for in UNS topic names. Supports expressions.
OffsetNumber inputnumberNo0Must be ≥ 0Number of results to skip for pagination.
LimitNumber inputnumberNo101–1,000 (clamped to 1,000 if exceeded)Maximum number of results to return.

Settings

Execution Settings

SettingOptionsDefaultDescription
Timeout (seconds)1–600Pipeline defaultMaximum execution time for this node.
Retry on TimeoutPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry if the node times out.
Retry on FailPipeline Default / Enabled / DisabledPipeline DefaultWhether to retry on failure. When Enabled, reveals Advanced Retry Configuration.
On ErrorPipeline Default / Stop Pipeline / Continue ExecutionPipeline DefaultBehavior when the node fails after all retries.

Advanced Retry Configuration (visible when Retry on Fail = Enabled)

FieldTypeDefaultRangeDescription
Max Attemptsnumber31–10Maximum retry attempts.
Initial Delay (ms)number1000100–30,000Wait before first retry.
Max Delay (ms)number1200001,000–300,000Upper bound for backoff delay.
Multipliernumber2.01.0–5.0Exponential backoff multiplier.
Jitter Factornumber0.10–0.5Random jitter.

Output Data Structure

{
"topics": [
{
"id": "topic-abc-123",
"name": "temperature",
"parentId": "node-xyz-789",
"parentName": "robot-arm",
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-02-11T14:10:00Z"
}
],
"total": 42,
"offset": 0,
"limit": 10,
"keyword": "temperature"
}
FieldTypeDescription
topicsarrayArray of matching topic metadata objects.
topics[].idstringUnique topic node identifier.
topics[].namestringTopic node name (the leaf segment of the topic path).
topics[].parentIdstringID of the parent node in the namespace tree.
topics[].parentNamestringName of the parent node.
topics[].createdAtstringISO 8601 timestamp of when the topic was created.
topics[].updatedAtstringISO 8601 timestamp of the last update.
totalnumberTotal number of matching results (across all pages).
offsetnumberThe offset used in this query.
limitnumberThe limit used in this query.
keywordstringThe keyword that was searched.

Referencing in Downstream Nodes

{{ $node["UNS Search Nodes"].topics }}          → the full topics array
{{ $node["UNS Search Nodes"].topics[0].name }} → name of the first match
{{ $node["UNS Search Nodes"].total }} → total matches found
{{ $node["UNS Search Nodes"].keyword }} → the search keyword used

Validation Rules

RuleError Message
Node name is required"UNS Search Nodes node must have a name"
Search keyword is required"Search keyword is required"
Keyword must be at least 3 characters (unless expression)"Search keyword must be at least 3 characters"
Offset must be non-negative"Offset must be a non-negative number"
Limit must be between 1 and 1,000"Limit must be between 1 and 1000"
Keyword must resolve to non-empty string"keyword resolved to empty string"

Usage Examples

Discover All Temperature Topics

FieldValue
Search Keywordtemperature
Offset0
Limit50

Downstream usage: {{ $node["UNS Search Nodes"].topics }} in a For Each loop to process each discovered temperature topic.

Paginated Search with Dynamic Keyword

FieldValue
Search Keyword{{ $trigger.payload.searchTerm }}
Offset{{ $trigger.payload.page * 20 }}
Limit20

Downstream usage: Build a searchable topic browser where the keyword and page come from a webhook trigger or manual input.

Namespace Audit

FieldValue
Search Keywordalarm
Offset0
Limit1000

Downstream usage: Discover all alarm-related topics in the namespace for an audit report. {{ $node["UNS Search Nodes"].total }} shows the full count.


Best Practices

Topic Naming Conventions

  • Follow the ISA-95 hierarchy: enterprise/site/area/line/cell/resource
  • Use lowercase, hyphen-separated segments: acme-corp/plant-1/assembly/robot-arm
  • Place measured values as leaf nodes: .../robot-arm/temperature, .../robot-arm/status
  • Keep topic paths stable — changing paths breaks downstream subscribers

Expression-Driven Topics

  • Use expressions like {{ $trigger._metadata.topic }} to build dynamic, reusable pipelines that work across multiple topics
  • Combine static prefixes with dynamic suffixes: mHv1.0/acme-corp/{{ $node["Set"].area }}/temperature
  • Always validate that expressions resolve to non-empty strings before publishing

Error Handling for UNS Nodes

  • Enable Retry on Fail for publish operations to handle transient UNS Manager unavailability
  • Use Continue Execution on error for fetch and search nodes in non-critical data paths
  • Use Stop Pipeline on error for publish nodes in critical data paths where data loss is unacceptable

Performance Considerations

  • Keep fetch Limit values as low as practical — fetching 1,000 records when you need 10 wastes resources
  • When using UNS Search in a loop, add pagination to avoid fetching all results at once