do block calls a supported task. This reference documents every available task, its parameters, output schema, and usage examples.
For how tasks fit into the overall workflow specification, see Workflow Specification Syntax.
Supported tasks
CreateMaterializedViewIfNotExists
Task that creates a materialized view if it does not already exist. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
nql | string | Yes | An NQL CREATE MATERIALIZED VIEW statement. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
createAsView | boolean | No | When true, the statement creates a view over the query rather than a materialized table, so reads run the query instead of returning stored rows. Applies only to CREATE MATERIALIZED VIEW statements, and is not compatible with MERGE, DELTA, CHUNKING_STRATEGY, or PARTITIONED_BY. Defaults to false. |
| Field | Type | Always present | Description |
|---|---|---|---|
datasetId | integer | No | The ID of the created or existing dataset. |
created | boolean | No | Whether the materialized view was newly created by this task. |
snapshotId | integer or null | No | The Iceberg snapshot ID of the initial refresh. Non-null only when created is true. |
recalculationId | string or null | No | The recalculation ID, if applicable. Non-null only when created is true. |
rowStats | object or null | No | Row-level statistics produced by a refresh. ## Platform behavior - Snowflake dataplanes populate this object with real counts. - AWS dataplanes return null — row-level statistics are not yet produced for materialized-view refreshes on AWS. |
document:
dsl: 1.0.0
namespace: analytics
name: create-active-users-view
version: 1.0.0
do:
- createView:
call: CreateMaterializedViewIfNotExists
with:
nql: CREATE MATERIALIZED VIEW active_users AS SELECT user_id, email, last_login FROM company_data.users WHERE is_active = true
RefreshMaterializedView
Task that triggers a refresh of an existing materialized view. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
datasetId | integer | No | The numeric id of an existing dataset. |
datasetName | string | No | The name of a dataset. Must contain only alphanumeric characters and underscores, with a maximum length of 256 characters. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
deltaBoundsOverrides | string | No | Overrides the lower bound used to read each delta source during this refresh. When omitted, delta bounds are computed automatically from the dataset’s tracked state. - { type: for_all, value: <ISO-8601 timestamp> } applies that one lower bound to every currently-tracked delta source. - { type: for_all, value: null } clears the tracked bounds, forcing a full reprocess of every source. - The whole field may instead be a ${…} jq expression that resolves to either of the above forms (or to null). |
| Field | Type | Always present | Description |
|---|---|---|---|
datasetId | integer | No | The ID of the refreshed dataset. |
snapshotId | integer | No | The new Iceberg snapshot ID after the refresh. |
recalculationId | string or null | No | The recalculation ID, if applicable. |
rowStats | object or null | No | Row-level statistics produced by a refresh. ## Platform behavior - Snowflake dataplanes populate this object with real counts. - AWS dataplanes return null — row-level statistics are not yet produced for materialized-view refreshes on AWS. |
document:
dsl: 1.0.0
namespace: analytics
name: refresh-active-users
version: 1.0.0
do:
- refreshView:
call: RefreshMaterializedView
with:
datasetName: active_users
ExecuteDml
Task that executes a DML statement on a dataset. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
nql | string | Yes | An NQL DML statement. Supports INSERT, UPDATE, and DELETE. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
| Field | Type | Always present | Description |
|---|---|---|---|
affectedRows | integer | Yes | Total rows affected by the DML statement (insert + update + delete). |
insertedRows | integer | Yes | Rows inserted by the DML statement. |
updatedRows | integer | Yes | Rows updated by the DML statement. |
deletedRows | integer | Yes | Rows deleted by the DML statement. |
document:
dsl: 1.0.0
namespace: etl
name: insert-audit-record
version: 1.0.0
do:
- insertAudit:
call: ExecuteDml
with:
nql: INSERT INTO company_data.audit_log (action, timestamp) VALUES ('manual_run', CURRENT_TIMESTAMP)
ExecuteExplain
Task that runs an NQLEXPLAIN query and returns the forecast row count and cost.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
nql | string | Yes | An NQL EXPLAIN statement. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
| Field | Type | Always present | Description |
|---|---|---|---|
rows | integer | Yes | Estimated number of rows the query would return. |
cost | integer | Yes | Estimated cost of the query, in micro-cents USD. |
document:
dsl: 1.0.0
namespace: etl
name: forecast-before-run
version: 1.0.0
do:
- forecast:
call: ExecuteExplain
with:
nql: EXPLAIN SELECT e.email.address FROM narrative.rosetta_stone e WHERE e._price_cpm_usd <= 1.00
export:
as: '$context + { rows: .rows, cost: .cost }'
ExecuteNql
Task that runs any NQL statement. The statement is parsed to work out what kind it is, then run by the task that handles that kind, and the result says which one ran. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
nql | string | Yes | Any NQL statement: EXPLAIN, INSERT, UPDATE, DELETE, or CREATE MATERIALIZED VIEW. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
createAsView | boolean | No | When true, the statement creates a view over the query rather than a materialized table, so reads run the query instead of returning stored rows. Applies only to CREATE MATERIALIZED VIEW statements, and is not compatible with MERGE, DELTA, CHUNKING_STRATEGY, or PARTITIONED_BY. Defaults to false. |
| Field | Type | Always present | Description |
|---|---|---|---|
type | string | Yes | The task that ran the statement. Tells you which shape payload has. |
payload | string | Yes | The output of the task named by type. |
document:
dsl: 1.0.0
namespace: etl
name: run-any-nql
version: 1.0.0
do:
- run:
call: ExecuteNql
with:
nql: ${$workflow.input.statement}
export:
as: '$context + { ranAs: .type, result: .payload }'
RunModelInference
Task that runs a model inference job. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
model | enum (anthropic.claude-haiku-4.5, anthropic.claude-sonnet-4.5, anthropic.claude-sonnet-4.6, anthropic.claude-sonnet-5.0, anthropic.claude-opus-4.5, anthropic.claude-opus-4.6, anthropic.claude-opus-4.7, anthropic.claude-opus-4.8, anthropic.claude-opus-5.0, openai.gpt-oss-120b, openai.gpt-4.1, openai.o4-mini) | Yes | The narrative model ID to use for inference. |
messages | array | Yes | A list of messages to send to the model. |
inferenceConfig | object | Yes | Configuration for the model inference. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
| Field | Type | Always present | Description |
|---|---|---|---|
structuredOutput | object | No | The structured output from the model, conforming to the provided outputFormatSchema. |
usage | object | No | Token usage information. |
document:
dsl: 1.0.0
namespace: ml
name: classify-records
version: 1.0.0
do:
- classify:
call: RunModelInference
with:
model: anthropic.claude-sonnet-4.5
messages:
- role: user
text: 'Classify the following record as spam or not spam: ...'
inferenceConfig:
outputFormatSchema:
type: object
properties:
classification:
type: string
enum:
- spam
- not_spam
required:
- classification
RunConversation
Task that asks an agent a question and waits for its answer. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | What to ask the agent. As everywhere in the DSL, a ${…} expression substitutes only when it is the whole value, so a prompt that mixes prose with context has to wrap the lot and interpolate inside it: '${ "Row stats: \($context.refreshed.rowStats). Anything odd?" }'. Inside the expression, $context holds what earlier tasks exported and . is the previous task’s own output. |
systemPrompt | string | No | Standing instructions for the agent, separate from the question. |
model | enum (anthropic.claude-haiku-4.5, anthropic.claude-sonnet-4.5, anthropic.claude-sonnet-4.6, anthropic.claude-sonnet-5.0, anthropic.claude-opus-4.5, anthropic.claude-opus-4.6, anthropic.claude-opus-4.7, anthropic.claude-opus-4.8, anthropic.claude-opus-5.0, openai.gpt-oss-120b, openai.gpt-4.1, openai.o4-mini) | No | The narrative model ID the agent runs on. Defaults to the model configured for the environment. |
mcpServers | array | No | Servers whose tools the agent may call. Each entry names either the Narrative platform server (narrative: true) or another server by url — one or the other, never both. alias prefixes every tool the server offers ({alias}-{tool}) so two servers can expose the same tool name. It is 1-8 letters or digits and has to start with a letter — short because the prefix eats into the length a tool name may have, and without dashes or underscores because those would make {alias}-{tool} ambiguous to split apart again. |
outputFormatSchema | object | No | A JSON Schema the agent’s answer must conform to. When set, the answer arrives as structuredOutput; when absent, the agent answers in prose and finalText carries it. |
maxIterations | integer | No | How many times the agent may think and call tools before it must answer. Defaults to 10. |
maxTokens | integer | No | Token ceiling for a single call to the model, not for the run as a whole. |
temperature | number | No | How much the model varies its wording. Lower is steadier; a task whose answer feeds a later step usually wants it low. |
thinking | string | No | What to ask the model to do about reasoning. disabled turns it off; an object asks for an effort level or a token budget. Models differ in which they accept. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
timeoutSeconds | integer | No | How long the task waits for the answer. Defaults to an hour, with a twelve-hour ceiling. On timeout the task fails and the agent run is left running — it is not cancelled. |
| Field | Type | Always present | Description |
|---|---|---|---|
conversationId | string | No | The conversation the agent ran in. Use it to read the transcript. |
runId | string | No | The agent run that produced this answer. |
status | string | No | The run’s terminal status. |
finalText | string | No | The agent’s answer in prose. Absent when an outputFormatSchema was set. |
structuredOutput | object | No | The agent’s answer, conforming to the outputFormatSchema. Absent when none was set. |
iterationsUsed | integer | No | How many times the agent thought or called a tool before answering. |
usage | object | No | Token usage across the whole run. |
document:
dsl: 1.0.0
namespace: ops
name: review-refresh
version: 1.0.0
do:
- refresh:
call: RefreshMaterializedView
with:
datasetName: customer_360
export:
as: '$context + { refreshed: . }'
- review:
call: RunConversation
with:
prompt: '${ "Row stats: \($context.refreshed.rowStats). Flag anything anomalous." }'
mcpServers:
- alias: nio
narrative: true
outputFormatSchema:
type: object
properties:
findings:
type: string
required:
- findings
export:
as: '$context + { review: .structuredOutput }'
LabelConnectedComponents
Task that runs bipartite label propagation for cross-system customer identity resolution. Finds connected components in a customer identity graph by linking customer IDs across platforms via shared identifiers. Parameters:| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
edgeDataset | string | Yes | — | Name of the dataset that holds the raw edge table. |
outputDataset | string | Yes | — | Name of the dataset that will hold the resolved connected components result. |
maxDegreeThreshold | integer | No | 100 | Maximum number of connections a single vertex can have before it is excluded as a “supernode.” Prevents a single overly-connected identifier from incorrectly merging thousands of unrelated customers. |
maxComponentSize | integer | No | 100 | Maximum number of members allowed in a single resolved component. Prevents runaway merges that would create implausibly large identity groups. |
maxIterations | integer | No | 10 | Upper bound on how many times the label propagation loop can run before stopping, even if not fully converged. Safety valve against infinite loops. |
convergenceThreshold | number | No | 0.000001 | Stop label propagation when the fraction of vertices that changed label in an iteration drops below this value. Must be in the range [0, 1]. |
sourceIdCol | string | Yes | — | Column name in the edge table containing the customer ID. |
sourceSystemCol | string | Yes | — | Column name identifying which platform the customer ID came from. |
bridgeKeyCol | string | Yes | — | Column name for the shared identifier value. |
bridgeKeyTypeCol | string | Yes | — | Column name for the type/category of the shared identifier. |
firstPartySources | array | No | [] | Ordered list of first-party platform identifiers. Order determines priority when selecting the representative component ID. |
thirdPartySources | array | No | [] | List of third-party platform identifiers. |
exclusiveAttributeCols | array | No | [] | Edge-table columns whose values are exclusive to one identity (e.g. an SSN token column). After label propagation converges, any component containing two or more distinct non-null values of any listed column is split so that each resulting component agrees on every listed column. Records without a value follow their edges into whichever fragment they are still connected to (ties resolved deterministically by minimum label). Empty by default (no splitting). |
computePoolId | string | No | — | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
| Field | Type | Always present | Description |
|---|---|---|---|
datasetId | integer | Yes | The ID of the dataset. |
document:
dsl: 1.0.0
namespace: identity
name: resolve-connected-components
version: 1.0.0
do:
- resolveIdentities:
call: LabelConnectedComponents
with:
edgeDataset: edge_table
outputDataset: connected_components_result
maxDegreeThreshold: 500
maxComponentSize: 10000
maxIterations: 50
sourceIdCol: customer_id
sourceSystemCol: source_system
bridgeKeyCol: bridge_key
bridgeKeyTypeCol: bridge_key_type
firstPartySources:
- AFTERPAY
- CASHAPP
- SQUARE
thirdPartySources:
- EXPERIAN
- ACXIOM
computePoolId: 11111111-1111-1111-1111-111111111111
CreateRosettaStoneMappingsIfNotExist
Task that creates Rosetta Stone attribute mappings for a dataset. Parameters:| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
datasetId | integer | No | — | The numeric id of an existing dataset. |
datasetName | string | No | — | The name of a dataset. Must contain only alphanumeric characters and underscores, with a maximum length of 256 characters. |
mappings | array | Yes | — | A list of mapping definitions to create. |
allowPartial | boolean | No | true | When true, individual mapping failures don’t prevent other valid mappings from being created. When false, any single failure causes the entire operation to fail. |
| Field | Type | Always present | Description |
|---|---|---|---|
createdMappings | array | Yes | Mappings that were successfully created. |
failedMappings | array | Yes | Mappings that failed to create. |
conflictMappings | array | Yes | Mappings skipped because an identical mapping already exists. |
document:
dsl: 1.0.0
namespace: etl
name: map-identity-seed
version: 1.0.0
do:
- mapToRosettaStone:
call: CreateRosettaStoneMappingsIfNotExist
with:
datasetName: identity_seed
mappings:
- attributeId: 92
mapping:
type: object_mapping
propertyMappings:
- path: value
expression: SHA2(NORMALIZE_EMAIL(email), 256)
- path: type
expression: '''sha256_email'''
- attributeId: 50
mapping:
type: value_mapping
expression: country_code
- attributeId: 73
mapping:
type: cached_mapping
inputExpressions:
- device_id
CreateDatasetSample
Task that generates a sample for a dataset. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
datasetId | integer | No | The numeric id of an existing dataset. |
datasetName | string | No | The name of a dataset. Must contain only alphanumeric characters and underscores, with a maximum length of 256 characters. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
| Field | Type | Always present | Description |
|---|---|---|---|
datasetId | integer | Yes | The id of the dataset whose sample was generated. |
rowCount | integer | Yes | The number of rows captured in the sample. |
document:
dsl: 1.0.0
namespace: analytics
name: create-dataset-sample-after-refresh
version: 1.0.0
do:
- refreshView:
call: RefreshMaterializedView
with:
datasetName: active_users
- createDatasetSample:
call: CreateDatasetSample
with:
datasetName: active_users
RecalculateStatistics
Task that triggers a recalculation of a dataset’s column statistics and waits for it to complete. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
datasetId | integer | No | The numeric id of an existing dataset. |
datasetName | string | No | The name of a dataset. Must contain only alphanumeric characters and underscores, with a maximum length of 256 characters. |
computePoolId | string | No | The compute pool ID to use for running the task. When omitted, the resolution depends on whether the task operates on an existing dataset: - If it does (e.g. RefreshMaterializedView, ExecuteDml, CreateDatasetSample), the dataset’s default compute pool is used; if the dataset has no default, the dataplane’s default compute pool is used. - If it does not (e.g. CreateMaterializedViewIfNotExists, where the dataset is being created, or RunModelInference, which is not tied to a dataset), the dataplane’s default compute pool is used directly. |
document:
dsl: 1.0.0
namespace: analytics
name: recalculate-statistics-after-load
version: 1.0.0
do:
- loadData:
call: ExecuteDml
with:
nql: INSERT INTO company_data.active_users (user_id, email) SELECT user_id, email FROM company_data.users WHERE is_active = true
- recalculateStats:
call: RecalculateStatistics
with:
datasetName: active_users
GenerateSampleRedaction
Task that has Narrative’s privacy model classify a dataset’s sample and write the dataset’s redaction, waiting for the model to finish. Parameters:| Parameter | Type | Required | Description |
|---|---|---|---|
datasetId | integer | No | The numeric id of an existing dataset. |
datasetName | string | No | The name of a dataset. Must contain only alphanumeric characters and underscores, with a maximum length of 256 characters. |
| Field | Type | Always present | Description |
|---|---|---|---|
datasetId | integer | Yes | The id of the dataset whose redaction was written. |
columnsExamined | integer | Yes | The number of leaf fields the model was shown, which is not the dataset’s column count. A nested column contributes one per leaf field inside it, and a column that is null or blank in every sampled row contributes none. |
columnsRedacted | integer | Yes | The number of those fields the model decided hold personal data. |
modelVersion | string | Yes | The version of the privacy model that made the decision. |
document:
dsl: 1.0.0
namespace: analytics
name: redact-sample-after-sampling
version: 1.0.0
do:
- createDatasetSample:
call: CreateDatasetSample
with:
datasetName: active_users
- redactSample:
call: GenerateSampleRedaction
with:
datasetId: ${.datasetId}
Related content
Workflow Specification Syntax
Full specification format for document, schedule, and task blocks
Automating Multi-Step Pipelines
Step-by-step guide to creating and running workflows
Materialized Views
How materialized views work
Workflows API
REST API endpoints for managing workflows

