ImprovementIntegrationsNew FeaturePlatform
Claude Opus 5.5 on Snowflake data planes
Claude Opus 5.5 (anthropic.claude-opus-5.5) now runs on Snowflake data planes through Snowflake Cortex, as well as on Bedrock data planes. You can use it for structured inference and agent conversations on either platform. It behaves the same on both: it ignores temperature and top_p, always thinks, and doesn’t accept a forced tool choice. Read more →MCP server: update and share Rosetta Stone attributes from an AI assistant
The Narrative MCP server has a newnarrative_attribute_update tool for changing a Rosetta Stone attribute your company owns. Pass the attribute’s id and any of display_name, description, type_definition, or collaborators. Fields you leave out keep their current values. Setting collaborators controls which companies can view the attribute and map datasets to it, so you can now share an attribute you created with narrative_attribute_create without leaving the assistant. The API still rejects type changes that would break data already mapped to the attribute, and an attribute’s name and tags stay fixed.To make sharing easier to review, narrative_attributes_describe and narrative_attributes_search now show an attribute’s owning company and its current collaborators when your company owns it. Reconnect your MCP client to pick up the new tool. Read more →APIBreaking ChangeBug FixDashboardData StudioImprovementIntegrationsNQLNew FeaturePlatformRosetta StoneWorkflows
Ask Rosetta generates retention policies again
Ask Rosetta on a dataset’s Retention tab once again turns a plain-language description into a retention policy. When it can’t build the policy you asked for, such as a Row TTL policy on an AWS data plane, it now tells you why instead of showing a generic error. See Configuring retention policies.Jobs on AWS data planes must resolve to a compute pool
On AWS data planes, Narrative now rejects a job that resolves to no compute pool with400 Bad Request and an error message that starts cannot enqueue job: no active compute pool available for data plane. Health check jobs are the only exception. Previously the platform accepted such a job, and it could stay Pending indefinitely. Snowflake data planes are unchanged.A job resolves its pool from the request, the dataset default, your company default, or the data plane default. Every newly registered company already has a default compute pool on the Narrative data plane, so most jobs are unaffected. See Compute pools.Cancel any job on Narrative’s data plane
POST /jobs/{job_id}/request-cancellation now accepts any job on Narrative’s data plane, including materialized view refreshes. Before, Narrative’s data plane accepted cancellation only for health check, model inference, model training and model delivery jobs, and rejected every other job type with 400 Bad Request. Snowflake data planes already accepted cancellation for any job and are unchanged. Other AWS data planes accept cancellation for the job types they run, which today is health checks only.Command palette: more objects, create commands, and recently viewed
The command palette now finds workflows, models, access rules, saved queries, and jobs as well as datasets. Search for an access rule or saved query by its display name or its NQL name, for a model by its name or display name, and for a job by its ID.You can also start something new from the palette. Commands such as New query, New audience, New lookalike audience, New model, and New dataset open the matching builder. New classifier and New label project appear when your selected data plane runs on Snowflake, and New dataset appears when you’re on Narrative’s data plane.With nothing typed, the palette now lists your Recently viewed objects below Recent commands, leaving out the one already on screen. Recently viewed objects are remembered in your browser, separately for each company you work as.CreateDatasetIfNotExists uses the workflow’s data plane
TheCreateDatasetIfNotExists workflow task now creates its dataset on the workflow’s data plane when the call doesn’t set dataPlaneId. Before, it always fell back to Narrative’s data plane, so a workflow running on a Snowflake data plane created its dataset on Narrative’s instead. Every other workflow task already ran on the workflow’s data plane by default.Dataset details: an Overview section and a details panel
Opening a dataset now lands on a new Overview section, with tiles for records, last ingestion, write mode and expiry, and a card for each of the dataset’s other sections that opens it. Every section is framed in its own titled card, and the Connections section shows each connection as a card.A details panel now sits beside every section, holding the dataset’s description, tags, behavior, identifiers, data plane, format and history. On a narrow window, the Details button opens it as a drawer. The Settings section is gone: you edit write mode, refresh schedule, retention, compute pool and extended stats from the panel’s Behavior rows instead. Links to the old Settings section open the Overview with the panel shown. Read more →Derived mappings from every source column
A dataset now gets a derived mapping from each stored mapping that a derivation rule can reach, instead of only one per attribute. Previously, a dataset with both an MD5 and a SHA-256 email column returnedhashed_email rows for only one of the two algorithms. NQL queries now return rows from both, and the mappings API lists a derived mapping for each. Routes that start from the same stored mapping still collapse to the cheapest one. See Attribute derivations.Edit your attributes in the app
You can now edit an attribute your company owns without going through the API. Choose Edit from the attribute’s menu on the Rosetta Stone Attributes listing or on its detail page. You can change its display name, description, type configuration, and who can view it or map to it.An attribute’s name, tags, and base type stay fixed. If the platform refuses a change, the panel keeps what you entered and tells you why. See the Attributes interface reference.Rename a data plane through the API
You can now change a data plane’s display name and description without recreating it, usingPATCH /data-planes/{data_plane_id}. Send only the fields you want to change: an omitted field keeps its current value, and "description": null clears the description. Only the company that owns a data plane can update it.Display names must now be non-empty and at most 64 characters, and descriptions at most 2048 characters, after surrounding whitespace is trimmed. This applies when creating a data plane as well, and a request that breaks either limit returns 400. Existing data planes with longer values still load as before.Data plane responses now include is_narrative, which is true for the shared data plane Narrative operates. Because owners can now rename their data planes, use this field rather than the display name to identify Narrative’s data plane. Learn about data planes →Fill with Rosetta on metadata forms
Forms that ask for a name, display name, description, and tags now have a Fill with Rosetta button. Rosetta writes those fields from what you’re creating: the query behind an access rule, view, dataset, or query template, or the configuration of a graph, match report, model, or audience. You can tell Rosetta anything it should know before it starts, but you don’t have to.Rosetta’s answer goes straight into the form, and nothing is saved until you save, so you can review and change every field first. Rosetta fills only the fields the form shows, and it writes a unique name only while that name can still be edited.Fill with Rosetta appears when you create or edit an access rule, create a materialized view or dataset, buy from the template catalog, and save a query template. It also appears when you finish building an identity graph, a match report, or an addressable graph, and in LLM Studio, Lookalike Studio, and Audience Studio.MCP server: marketplace explorer and chart views
The Data Collaboration MCP server adds two tools that open interactive views in MCP clients that render MCP Apps views.narrative_marketplace_explore takes a buyer’s question, such as “find data about males aged 18-24”, and the filters your assistant draws from it. It looks each filter up in the Rosetta Stone attribute catalog, then shows the access rules your company can see that expose all of those attributes, with each rule’s provider and CPM price. narrative_chart_show draws a chart or a dashboard from rows your assistant already has from earlier tool calls.Both tools also return a text summary, so clients that don’t render views still show the results. See the tool reference →Job webhooks carry Narrative’s data plane ID
Job webhook events for jobs on Narrative’s data plane now setdata_plane_id to its ID and include data_plane_name, the same as events for jobs on any other data plane. Before, these events carried a null data_plane_id and no data_plane_name. If your webhook handler treats a null data_plane_id as Narrative’s data plane, match on Narrative’s data plane ID as well, since events created before this change still carry null. The jobs API already returned the ID and is unchanged. See the event reference →POST /nql/run is retired, and taken view names are rejected
POST /nql/run has been removed as announced. Every call now returns 410 Gone with an Endpoint Retired problem body that links to the migration guide. Send statements to POST /v1/nql/execute instead; the request body is unchanged.CREATE MATERIALIZED VIEW through /v1/nql/execute now checks the view name before it starts a run. If a dataset with that name already exists, the request fails with 403 and a Table Already Exists error Previously the run succeeded and returned the existing dataset unchanged. The ExecuteNql workflow task behaves the same way: it now runs the statement as the new CreateMaterializedView task, which fails when the name is taken. To keep the old reuse-if-present behavior in a workflow, call CreateMaterializedViewIfNotExists directly. See Workflow orchestration.Boolean CASE expressions with LIKE, IN, or BETWEEN run on Spark data planes
Fixed an issue where some NQL queries failed on Spark data planes with[PARSE_SYNTAX_ERROR] Syntax error at or near 'IS'. The failure hit boolean CASE expressions whose conditions use LIKE, IN, BETWEEN, or IS NULL, such as CASE WHEN marital_status LIKE 'Married%' THEN TRUE WHEN marital_status IN ('Divorced', 'Separated') THEN FALSE END. NQL rewrites these into IS TRUE and IS NOT TRUE checks. The generated Spark SQL now wraps each predicate in parentheses before the check, so Spark parses the query and your materialized views and other jobs run as written.Struct comparisons and unions run on Spark data planes
NQL no longer adds its ownCAST to struct values when a query compares, joins, or unions struct columns that have the same fields, such as two structs that disagree only about which fields can be null. These added casts could make such queries fail on Spark data planes. Any CAST you write in the query is kept.Distinct rows in Query Builder
Query Builder in Data Studio now has a Distinct rows only switch under the query’s outputs. Turn it on to addDISTINCT to the generated query, so it returns each combination of output values once. When you fill a query template, the switch shows the template’s setting but can’t be changed.Rosetta AI Chat: charts and dashboards from your data
Rosetta AI Chat can now draw a chart in its answer. When a breakdown, comparison, distribution, or trend is clearer as a picture, such as counts by status or values over time, Rosetta gathers the records from your account and draws them without being asked. For a question that needs more than one view, it can build a dashboard of several charts, headline numbers, and tables.When more than one chart type suits the data, the chart’s header lets you switch between them. A single chart holds up to 500 rows, so for larger data Rosetta narrows or summarizes the records first.Dataset samples work with column names that start with a digit
Requesting a sample on a dataset now works when a column name starts with a digit. This can happen when a file is uploaded without a header row and a data value becomes the column name. Before this fix, the sample request failed right away and no job was created. Narrative now quotes these column names in the generated sample query.APIBreaking ChangeBug FixData StudioImprovementNQLNew FeaturePlatformRosetta Stone
Query policies on access rules
Access rules already let you decide who can query your data and on what terms. Query policies let you decide how they can query it. Should a partner see actual rows, or only counts? Should they see everything in the access rule, or only the records that match their own data? A query policy answers those questions, so you can share sensitive data such as email addresses without the raw values ever leaving your control.That opens up collaboration that wasn’t safe before: a partner can measure overlap with your audience, or count it by segment, without ever seeing who is in it. It also gives the marketplace a kind of listing no one else offers, where buyers pay to match and measure rather than to copy.Set up a query policy through the API, or ask your AI agent to configure it for you over the MCP server. Read the guide →NORMALIZE_EMAIL removes periods from Gmail addresses
NORMALIZE_EMAIL now removes the periods in the username of a Gmail address, as the function reference and the normalized_email attribute already described. [email protected] now returns [email protected] instead of [email protected]. Gmail ignores those periods, so both spellings reach the same mailbox and now normalize, and hash, the same way.The Gmail rules, removing periods and everything from a + to the @, now apply to exactly gmail.com and googlemail.com. googlemail.com addresses get them for the first time. Other domains that start with gmail, such as gmail.com.br, keep their periods and + tag, like every other address.normalized_email and the email hashes derived from raw_email change for the affected addresses. A materialized view or a stored hash computed with the old function won’t match a new one until you refresh it.Derived mappings now chain up to three rules
A dataset mapped only toraw_email now answers queries for sha256_hashed_email. Derived mapping resolution used to stop after one derivation rule. It now follows chains of up to three rules and picks the route with the lowest total cost. NQL queries, GET /mappings?source=derived, the derived mappings returned by POST /mappings, and the derivation graph endpoint all follow the longer chains. Each derived mapping’s provenance.derivation_path lists every rule applied. A chain stops at any attribute the dataset maps explicitly. Attributes past that point derive from the dataset’s own mapping, and get no derived mapping if that mapping is a cached_mapping. Read more →Bulk uploads run each statement on its own
A bulk upload in Data Studio now launches each statement in the file as its own workflow. A file of 200 statements starts 200 independent runs, so one failed statement no longer blocks the rest. Notifications shows how many failed, for example Failed · 3 of 200 failed.Apps API: patch a manifest and archive an app
Patch a manifest.PATCH /v2/apps/{app_slug}/manifest updates part of an app’s manifest, so you no longer need to replace the whole thing with PUT. The body is an RFC 7386 JSON merge patch: fields in the patch replace the stored ones, nested objects merge, arrays are replaced whole, and null removes a field. The patched manifest is validated the same way as a PUT, and nothing is stored if validation fails. A patch can’t change manifest_version. Send the body as application/merge-patch+json or application/json. Any other media type returns a 415.Archive an app. DELETE /v2/apps/{app_slug} archives an app you own and returns a 204. Every company’s active installations of the app are archived in the same transaction, and nothing is deleted. An archived app is hidden from every company, including its owner. It can’t be installed, updated, or given new credentials, and its slug stays taken. Any caller other than the owning company gets a 404, so the response doesn’t reveal which slugs exist.Agents read MCP structured tool results
Agent runs now pass an MCP tool’sstructuredContent to the model. Before, the model saw only a tool result’s content parts, so data a tool returned only in structuredContent never reached it. Narrative now adds structuredContent to the tool result as a JSON text part, unless a text part already holds the same JSON. Read about agent tools →Fixed: HTTP 500 on parenthesized queries with ORDER BY or LIMIT
CREATE MATERIALIZED VIEW ... AS (...) and EXPLAIN (...) no longer return an HTTP 500 when the parenthesized query contains ORDER BY or LIMIT. They now compile the same as the unwrapped query. Read more →Model inference jobs retry transient errors
A model inference job now retries its model call when the call times out, loses its connection, or gets a 408, 429 or 5xx response from the model provider. The job makes up to two more calls, 30 seconds and then 60 seconds apart. Before, one slow or failed call failed the job and ended any agent run waiting on it. Other errors, such as invalid requests, still fail the job at once.Each call can now run for up to 10 minutes, up from 5. A job that times out on every attempt can take about 31.5 minutes before it fails, so allow for that when you poll a job for its result.AI_EMBED replaces the EMBED_TEXT_* functions
NQL now generates text embeddings withAI_EMBED(model, text), which replaces the legacy EMBED_TEXT_* functions. On Snowflake data planes, NQL transpiles AI_EMBED to Snowflake’s AI_EMBED instead of the deprecated SNOWFLAKE.CORTEX.EMBED_TEXT_* functions, and returns the embedding as an array<double>. The model you pass sets the length of the embedding, such as 'e5-base-v2' for 768 dimensions or 'snowflake-arctic-embed-l-v2.0' for 1024. Update any queries that call EMBED_TEXT_* to use AI_EMBED. Read more →APIAudience StudioBreaking ChangeBug FixDashboardImprovementNew FeatureRosetta StoneWorkflows
More reliable webhook delivery
Webhook events no longer get stuck when a delivery is interrupted before Narrative records the result. Narrative now retries an interrupted delivery after 15 minutes, as long as the event has attempts left. Because a retried event can reach your endpoint more than once, use the envelopeid to discard duplicates. Read more →CreateWorkflowIfNotExists workflow task
The newCreateWorkflowIfNotExists task lets one workflow create another. You pass a complete workflow specification under with.workflow, and the task creates it on the parent workflow’s data plane. If no active workflow has that name yet, the task creates it and starts a run right away. If an active workflow with the same name already exists, the task returns it without starting a run, so reruns are safe. The output includes workflowId, created, and runId (null when the workflow already existed) for later tasks to reference. Read more →Dataset Changelog tab lists every snapshot
The Changelog tab on a dataset page lists every snapshot again, newest first. Previously it showed only the latest snapshot, so the rest of a dataset’s ingestion history was missing from the table. The total under the table now matches the snapshot count in the dataset’s header. Read more →Mapping editor shows every property and checks required ones
When you create a mapping, choosing an attribute now lists every property of that attribute with its expression box already open, so you can fill them in one pass instead of editing row by row. Nested object properties appear by their dotted path. Required properties are shown in bold with an asterisk, and a required property you leave empty is marked Required in place when you move away from it or try to save or test.A new mapping is checked against the dataset’s sample, so Save and Test now wait until the dataset has a sample with rows rather than failing after you’ve filled every expression in. If there is no sample yet, hover over the disabled buttons and click Request sample to generate one. Read more →Column suggestions in mapping expressions
When you edit a mapping expression in the mapping editor, the expression box now suggests columns from your dataset whose type matches the attribute property you’re mapping. Nested columns appear by their dotted path, such asuniqueId.value. Choosing a suggestion writes the column reference into the box, quoted where NQL requires it, and you can keep editing the expression from there. Type to narrow the list, or open the dropdown to see every matching column. Read more →Send images to Claude models in Model Inference
POST /model-inference/runs now accepts image content blocks, so Claude models can look at images alongside your text prompt. You can put an image in a user message or inside a tool_result. Each block uses the Anthropic image shape with base64 data and a media_type of image/jpeg, image/png, image/gif, or image/webp.Image input works with the Claude models on AWS data planes. OpenAI models and Snowflake data planes don’t accept images. A request can carry up to 20 images, and each image can be at most 512 KB once decoded. The API returns a 400 that names the problem when a request breaks one of these rules, puts an image in a system or assistant message, or targets a model without image input. Read more →My Audiences shows each audience’s current size
The size column on My Audiences now shows how many records an audience holds today. Previously it added up every snapshot still inside the dataset’s retention window, so an audience that had been rebuilt several times showed a multiple of its real size. Sorting by size now uses the corrected numbers too.Removed app profile store endpoints
Narrative removed the per-app profile store from the public API. The Trade Desk app was its only user. The store held JSON Schema-validated data saved against an app profile. The following endpoints are gone, along with their/v1/ aliases:GET /apps/{slug}/manifest/profile-store-schemaandGET /apps/{slug}/manifest/profile-store-schema/{schema_version_id}POST /apps/{slug}/manifest/profile-store-schemaGET /apps/{slug}/profile-store/{profile_id}andPUT /apps/{slug}/profile-store/{profile_id}GET /apps/{slug}/manifest/quick-setting/{profile_id}PUT /admin/apps/{app_id}/slug
quick_settings and the other app endpoints are unaffected.Rosetta AI Chat: chat sidebar, pinned chats, and a Chat objects pane
Rosetta AI Chat has a new layout that keeps your other conversations one click away.Chat sidebar. A sidebar on the left lists Pinned chats and All chats, and lets you create a new chat in the current tab or in a new one. Collapse it to a narrow toolbar whose buttons open the same options as menus, plus a Recent chats menu with your 10 latest conversations. The sidebar stays open or collapsed as you move between chats. Cmd-click or Ctrl-click a chat to open it in a new tab.Pinned chats. Pin a conversation from its row in the sidebar or from the chat header’s actions menu to keep it at the top of Pinned chats. Pins are saved in your browser, so they appear in every open chat tab.Chat objects pane. The charts, tables, datasets, and other objects Rosetta produces now collect in a Chat objects pane beside the conversation instead of a drawer that covers it. The pane opens automatically on wide screens, and you can show or hide it from the same menu. Each chat’s tab now shows the conversation’s name.Call any unversioned API endpoint under /v1/
Every unversioned Narrative API path now also answers under a /v1/ prefix. For example, /datasets and /v1/datasets are the same endpoint and return the same response. You can now spell out the version for every v1 endpoint in your integration. Existing unversioned paths keep working unchanged. The prefix does not apply to paths that already carry a version, such as /v2/queries, and /model-training has no alias because /v1/model-training is a separate endpoint. Read more →Webhook subscriptions reject non-public URLs
POST /webhooks now validates the subscription url before saving it. The URL must be absolute and use https. Narrative returns a 400 for reserved hostnames such as localhost or hosts ending in .local, .test, .example, or .invalid, and for IP addresses outside the public internet, such as loopback, private, and link-local ranges. Previously, Narrative stored these subscriptions even though they could never receive deliveries.App events sent through POST /apps/events are now delivered only to active subscriptions. Archived app webhook subscriptions no longer receive events. Read more →Bug FixDashboardImprovementIntegrationsNQLNew FeaturePlatformRosetta StoneWorkflows
Claude Sonnet 5.5 for Model Inference
You can now run structured inference with Claude Sonnet 5.5 (anthropic.claude-sonnet-5.5) on Bedrock data planes, through the Model Inference API, the RunModelInference workflow task, and agent conversations. It uses the same settings as Opus 5.5: it ignores temperature and top_p, always thinks, and doesn’t accept a forced tool choice. Snowflake Cortex support is coming. Read more →CreateDatasetIfNotExists workflow task
The newCreateDatasetIfNotExists task creates an empty dataset from inside a workflow. It takes the same schema as POST /datasets, plus an optional display name, description, tags, write mode, and data plane, and it waits until the dataset is active. It’s safe to rerun: if an active dataset with the same datasetName exists, it returns that dataset with created: false, and if an earlier run left it pending, it finishes it. The output includes datasetId for later tasks to reference. Narrative’s data plane and Snowflake data planes are supported. Read more →Command palette: jump to datasets and ask Rosetta
The command palette now searches more than commands:- Datasets — type a dataset’s display name or machine name to see up to eight matches from your selected data plane, and choose one to open it. When a dataset matches more closely than any command, the Datasets section comes first, so Enter opens it.
- Ask Rosetta — a row at the bottom of the results sends whatever you typed to Rosetta AI Chat. It opens a new chat with your question in the message box, ready to edit or send. A search that matches a command still runs that command on Enter.
Separate data plane and compute pool pickers
The context selector in the top navigation is now two pickers side by side, Dataplane and Compute Pool, so you can change the compute pool without reopening the data plane menu. Switching data planes moves you to the new plane’s default pool, and reapplying the current data plane leaves your pool alone. Read more →Connector pages prompt you to install the app
If your company hasn’t installed a connector’s app, its connector page now says so and offers an Install button, instead of a spinner that never stopped, a closing dialog, or an empty-looking list. Connector pages also now tell a failed list apart from an empty one: failures show the error and a Try again button, and empty tabs say what to set up next. Read more →Cached Mapping builder: Exact match off by default for large attributes
The built-in Exact match rule now starts off when the target attribute has more than 200 allowed values, because it adds one query branch per value. The Rules step explains why and how many branches it would add, and an Add button turns it back on. Attributes with 200 values or fewer still get the rule automatically.MCP tool errors now reach your AI assistant
The Narrative MCP server now returns invalid arguments and calls made before a company is selected as tool results withisError: true, instead of JSON-RPC errors that some clients hide from the model. Your assistant now sees the message and can fix its arguments or pick a company on its own. Calls to an unknown or hidden tool still fail as JSON-RPC errors, now with code -32602 instead of -32601. Read more →Edit panels stay open until your changes are saved
Bug fix: Side panels such as access rules, API keys, attributes, and taxonomies no longer close when you click Save before the save finishes, so a failed save now keeps your changes and shows the error instead of discarding them.Window functions accept Rosetta Stone attributes in PARTITION BY and ORDER BY
You can now partition or order a window function by a Rosetta Stone attribute property, such ast._rosetta_stone.attr.name. Before this fix, a query without a WHERE clause failed to compile with a ClassCastException. With a WHERE clause, the query ran on Spark but Snowflake rejected it as an invalid identifier. These queries now compile and return the correct rows on both data planes.Bug FixDashboardImprovementIntegrationsNew FeaturePlatformRosetta Stone
Map an attribute once, query it in every form
Map a column to one form of an attribute, such as a normalized email, and your derivation rules now carry it to every form that can be derived from it, such as a SHA-256 hash. You don’t add or maintain a mapping for each variant. NQL resolves those derived forms at query time, so a query forsha256_hashed_email works against a dataset that maps only normalized_email. Access rules don’t change: selling the source attribute doesn’t expose the derived one.You can also see this in the app. An attribute’s page shows which attributes it can be derived from and which it can produce, each marked Lossy or Imprecise where that applies. A dataset’s mappings list shows its derived mappings next to its stored ones, and View Provenance traces each one back to its source. For impact analysis, the /mappings API now filters by the dataset column a mapping reads, so you can see what depends on a field before you change it. Read more →Claude Opus 5.5 for Model Inference
Anthropic’s newest Opus model is now available for structured inference on Bedrock data planes, through the Model Inference API, theRunModelInference workflow task, and the model picker in the app. Use it for the enrichment and classification work where accuracy matters most. Snowflake Cortex support is coming. Opus 5.5 ignores temperature and top_p, and it doesn’t accept a forced tool choice in agent conversations. Read more →Onboard Reddit partners with a link
Bring a partner’s Reddit ad account onto Narrative without asking them to create a Narrative account. From the Reddit Connector’s new App Invites tab, send a link: the partner authorizes Reddit on their side, and a ready-to-use profile appears in your account. When a partner’s access expires, send an invite that refreshes it in place. Their ad accounts and connections stay as they are. Read more →See exactly what a job did
Every job now has its own details page. Open it with View Details from the Jobs table to see what the job did, how long it queued and ran, where it ran, and which workflow started it. If it failed, the error is at the top. The Raw JSON tab has the job’s full input and result.Clean up values before labeling in Label Studio
Label Studio projects can now build their labeling queue from an NQL expression. Trim, lowercase, or combine values before they are queued, so the same value never gets labeled twice under different spellings. The editor checks the expression as you type, and Run preview shows real values from your data before you create the project.AI agents get freshly redacted samples
A sample requested through the Narrative MCP server is now redacted in the same run that takes it, just like Update sample in the app. An AI assistant exploring your data sees masked sensitive values unless you explicitly asknarrative_datasets_describe for the raw rows with redacted=false. Requesting a sample now starts a workflow run that you poll, instead of returning a job id. Read more →App fixes and refinements
The tab bar’s ⋯ menu now lists every open page, with a search box once you have eight or more open, so you can jump straight to the page you want. On a dataset’s page, Created At and Last Data Ingested now show the correct day of the month, and the sample no longer disappears while an unrelated job runs on the same dataset.Archive pending Snowflake datasets
You can now archive a dataset on a Snowflake data plane while it’s still pending.Clearer attribute deletion
Delete is now disabled on attributes your company doesn’t own, and a refused delete now shows the reason instead of a generic error.MCP server: see derived mappings when you list and create mappings
AI assistants connected to the Narrative MCP server can now check which attributes a dataset already covers before mapping it. The newnarrative_mappings_list tool returns a dataset’s active stored and derived mappings together. You can exclude derived mappings with include_derived=false or filter to mappings that read specific columns with depends_on_dataset_fields. narrative_mapping_create now ends its result with the derived mappings the new mapping unlocked, so an assistant no longer creates by hand a mapping the platform already derives.Reconnect your MCP client to pick this up. Read more →Member TTL for Reddit audiences
New Reddit audiences can now drop members who stop appearing in your data. Set Member TTL (days) on a new audience that uses the Append write mode, and a member is removed once the dataset hasn’t delivered it for that many days, from 1 to 28. That suits rolling audiences such as “visited in the last 14 days”. Leave the field empty and members stay until an opt-out removes them. Choose Overwrite instead when each delivery is the complete audience: identifiers missing from the new delivery are removed from Reddit. Read more →APIBreaking ChangeBug FixComposable IdentityDashboardImprovementIntegrationsNew FeaturePlatformWorkflows
Query a dataset without rebuilding the select
Query, on a dataset’s page, now opens Data Studio on the Query Builder tab with a query that already selects that dataset’s own columns, so you can add filters or drop fields without naming the source again. It used to open an empty studio, and on a materialized view it opened the statement that defines the view rather than a query against it.Create access rule, on the dataset’s Access Rules tab, starts from that same query and arrives with Create access rule already chosen as the action to run.That tab now lists a dataset’s rules the way the Access Rules page does: the same sortable, searchable columns, the rule’s NQL unique name beside its price, the share type as a leading icon, and each name linking through to the rule itself. Editing a rule still happens on the Access Rules page.The datasets table no longer waits on access rules
My Data > Datasets used to stay behind its loading mask until the whole access-rule list had finished paging, which on an account with many access rules was routinely the slowest part of opening the page. The table now appears as soon as the datasets themselves arrive, and the access column and the access-type row icon fill in on their own once that list settles.Archiving all of a dataset’s access rules now takes effect on the page immediately. The row icon and the dataset’s actions menu used to go on offering rules that had already been archived until the page was reloaded.List derived mappings alongside stored ones
GET /mappings, GET /mappings/companies/{id}, GET /datasets, and GET /datasets/{id} now take a repeatable source filter (mapping_source on the dataset reads). Naming derived adds the virtual mappings your stored mappings imply through the derivation rules your company may use, so you can see that a mapping to raw_email unlocks normalized_email and sha256_hashed_email without composing them from /derivations by hand. Each derived row carries source: derived, no id (it is computed per request and cannot be fetched or mutated by id), and a provenance object naming the stored mapping it started from, its attribute, the ordered derivation ids applied, and the combined lossy and imprecise flags. Omitting the filter leaves responses unchanged apart from id no longer being listed as required on the mapping schema.Scope a graph build to the identifier types you choose
The Graph Builder’s Input Configuration step now lists the identifier types it found on the edges you selected, and you can build the graph on a subset of them. Unchecking a type keeps its edges out of the graph without touching the source datasets’ own Rosetta Stone mappings, so every other consumer of those datasets still sees that identifier — useful when a graph should resolve on hashed email alone, or should leave a noisy identifier out.Every type starts checked, which is the same as making no choice at all: a build you never narrowed is identical to one made before the selector existed, and Include all returns to that state. Read more →Open an installed app straight from the navigation rail
My stuff, in the navigation rail’s Marketplace menu, used to offer a single Apps row that took you to the list of everything your company had installed. It now names your apps individually: My Installed Apps opens onto All installed apps, which is the list as before, followed by one row per installed app that goes where launching it from the marketplace goes.Apps are listed alphabetically. An app that launches outside the platform has no row of its own and is still opened from the marketplace listing, and the menu stays as it was for a company with nothing installed.Long sessions and background tabs
A session set to run for longer than about four weeks used to end the moment the page loaded, signing you straight back out. Sessions are now held to their real expiry however far off it is, and the Session expiring warning arrives on schedule ahead of it rather than immediately.Opening the platform in a background tab no longer leaves it stuck on the loading screen. Start-up now finishes whether or not the tab is in front, so the platform is ready when you switch to it.Create-mapping response lists the derived mappings it unlocks
POST /mappings/companies/{company_id} now returns a derived_mappings array next to the created mapping’s fields. Each entry has the same shape a source: derived row from GET /mappings returns (no id, a provenance naming the source mapping and the derivation rules used), so a caller learns what the new mapping unlocked without a follow-up list call.The list is computed with the same resolver the list endpoint uses, over the dataset’s stored mappings, so an explicit mapping of a target attribute suppresses its derived row. The array is empty when the mapping’s attribute is not the source of any derivation rule, when the mapping was created pending, or when every target attribute already has an explicit mapping on the dataset.See Mapping types for the full response schema.MCP server: activate datasets from an AI assistant
The Narrative MCP server now exposes anarrative_dataset_activate tool, so an AI assistant can finish dataset setup without leaving the conversation. New datasets start inactive with status pending and Narrative does not ingest into them until they are activated; the same is true for the cache dataset that narrative_mapping_create produces for a cached_mapping. The tool wraps PUT /datasets/:id/activate, takes a single dataset_id, and returns the dataset id and its new status. Activation is one-time: the API rejects the call if the dataset is already active, does not exist, or is not accessible to the current company. Reconnect your MCP client to pick it up. Read more →MCP server: derived mappings in narrative_datasets_describe
When you include mappings in narrative_datasets_describe, the tool now returns the dataset’s stored mappings plus the derived mappings they imply so connected AI assistants see every attribute a dataset can serve, not just the ones an author mapped by hand. Each derived row is tagged source: derived, has no id (it is computed on the request from a stored mapping and a derivation rule, nothing is stored), and carries a provenance naming the source mapping, the derivation path, and whether the result is exact, lossy, or imprecise. A short note above the JSON block calls out how many rows are computed rather than stored. Fetching without mappings (or from tools that update a dataset) still returns only stored rows.Reconnect your MCP client to pick this up. Read more →MCP server: derivation rule tools
Three new MCP tools cover derivation rules end to end.narrative_derivations_list returns every rule the currently selected company can use, filtered by source or target attribute. narrative_derivations_describe fetches rules by id with each rule’s transformation JSON on by default. narrative_derivation_create adds a new rule; it is visible to and callable only by Narrative global admins, and both tools/list and tools/call treat it as unknown for anyone else.The read tools work on any user token — read:attribute_derivations is now included in the default user-token permission set — and POST /derivations now accepts a global admin’s user token without the admin grant, so MCP-issued tokens can create rules without extra configuration. Reconnect your MCP client to pick up the new tools. Read more →The navigation rail folds away on small screens
On a phone-sized screen the navigation rail no longer holds a permanent column against the left edge. It collapses into a menu button at the start of the top bar, and opening it slides the rail in over the page with everything it normally carries — Objects, Builder, Marketplace, Rosetta AI chat, and the Settings and Notifications controls at its foot. Choosing a destination closes it again, and the page gets the width back.Nothing changes at tablet width and above, where the rail stays where it has always been.Automatic sample redactions cover Rosetta Stone attributes
POST /v2/datasets/{dataset_id}/request-sample runs Narrative’s privacy model over the sampled rows and writes a redaction for the columns holding personal data. The model used to see only the top-level columns and skipped everything nested under _rosetta_stone, so a phone or email that lived on a mapped attribute came back unclassified and the stored sample kept showing it in the clear. The model now reads Rosetta Stone attributes alongside the source columns and only skips Narrative’s own bookkeeping fields (_nio_company_id, _nio_dataset_id, nio_last_modified_at, and other _nio_/nio_ prefixed columns), so a mapped attribute that holds personal data is masked in GET /datasets/{dataset_id}/sample/redacted the same way a top-level column would be. Read more →Negative and zero values in query value fields
Fixed two problems with the value fields that fill in a query’s literals, such as the placeholder controls on a saved query and the macro values in Prompt Studio.A minus sign typed into a whole-number or decimal field was stripped as you typed, so a negative value could not be entered at all. Minus signs are now accepted at the start of a number, and still rejected anywhere else in it.A value of0, false or an empty string was dropped when the field loaded, leaving it blank even though the value was stored. Those values now survive and appear as saved.Requesting a new sample now refreshes its redaction
Update sample in a dataset’s Actions menu now samples the dataset and runs Narrative’s privacy model over those rows in a single run, so the redaction that masks the sample is written against the rows it is masking rather than left to age against a sample it no longer describes.A dataset with no sample yet offers the same action on its empty sample card, as Request new sample, alongside a Refresh sample button that re-reads the sample already stored.If you maintain a redaction of your own through the API, requesting a new sample this way replaces it. To refresh the sample without touching the stored redaction, callPOST /datasets/{dataset_id}/request-sample instead.Auto-titled conversations from RunConversation
The RunConversation workflow task now auto-titles the conversation it creates, matching what happens when you start a conversation through the agents API. Right after the agent run is created, the task starts the rename as a detached child workflow and never waits on it, so a titling failure, a duplicate start, or a rename that outlives the task cannot fail the task itself.GET /datasets/{dataset_id}/sample is redacted by default
GET /datasets/{dataset_id}/sample now applies the dataset’s stored redaction before returning rows, masking every column the redaction names. Previously the plain sample endpoint always returned unmasked rows and only GET /datasets/{dataset_id}/sample/redacted was masked.A new redacted query parameter opts back into the previous behavior: pass redacted=false to get the unmasked sample. A dataset with no stored redaction returns the unmasked sample either way, so the default only changes what callers see once a redaction has been uploaded. GET /datasets/{dataset_id}/sample/redacted is unchanged and still requires a stored redaction.The endpoint now returns 400 when redacted is not a valid boolean, and reports both the size and redacted errors together when both are invalid rather than only the first. See Redacting dataset samples.Backing out of your first taxonomy folder
Choosing Create manually on a connector’s empty taxonomy page opens a dialog for your first folder. That dialog offered nothing a mouse could click to close it, and dismissing it left you on an empty taxonomy table with no way back to the starting screen and a Create manually button that did nothing on a second press.The dialog now carries a Cancel button on that first step, and cancelling returns you to the taxonomy start screen with the button working again.Reorder a connector taxonomy from the keyboard
Rearranging a taxonomy on the Yahoo DSP and The Trade Desk connectors needed a mouse. Any row you could drag can now be moved with the keyboard instead: focus it and hold Alt with an arrow key to move it up or down among its siblings, or in and out of the folder above it. A keyboard move can only land where a drag could, and a screen reader reads out where the row ended up.Dragging works as it did, and folders now keep the state you left them in: one you collapse stays collapsed after a change saves, while a folder you have just created opens on its own.Show unredacted values in a dataset sample
Wherever a dataset’s sample is shown in the app, the rows now arrive masked by the dataset’s stored sample redaction. A Show unredacted values switch below the table reloads the sample with the real values behind the mask.The switch starts off every time the sample is opened, so the masked rows are what you see first and revealing the underlying values is a deliberate step. A dataset with no stored redaction shows the same rows either way.APIBug FixComposable IdentityDashboardDeprecationImprovementIntegrationsNQLNew Feature
POST /nql/run will be removed on October 19, 2026
POST /nql/run has been deprecated since August 2026. On October 19, 2026 it stops answering and returns 404. Move your callers to POST /v1/nql/execute before then — the request body is unchanged, but you get a workflow and a run back instead of a job. See the deprecation notice for what differs, and the migration guide for the port.This is the first removal run under our API versioning and breaking change policies, both now published — what counts as a breaking change, how endpoint versions are numbered, and the notice you get before anything stops answering.Reddit Connector
The Reddit Connector is now in the marketplace under Apps — free, and it installs without an approval step. Its profiles are offered as a delivery destination everywhere the other connectors are: a dataset’s connections, Audience Studio, and Look-alike Studio. Create a profile and click Connect to Reddit to authorize it; a Reddit grant is member-scoped, so one authorization reaches every ad account that account can see. The Opt Out Configuration tab takes a dataset of opted-out users and removes their identifiers from every Reddit Custom Audience your company delivers to. Read more →A summary header on the dataset details page
Opening a dataset now starts with a summary header that stays put as you move between tabs: name, state, description and tags, all editable in place, plus chips for type, ID, region, query engine and file type, and tiles for record and file counts, last ingest, write mode, snapshot count and expiry. Schema is now the tab you land on. The Overview tab is gone — its editable settings moved to a new Settings tab at the end of the strip, along with lifecycle timestamps, file parsing options, and the extended-stats and data-expiration rows. Read more →Graph and match report builds run in the background
Build Graph in Graph Studio and Run Report in the match report builder now hand the run to the platform: you get a toast, and the outcome arrives in the Notifications inbox whether or not you stayed on the page. Leaving the builder or reloading no longer loses the run. Start Over is now its own button beside the run action, so you can clear the builder while a build is still going. A run that ends without a dataset now says which way it ended — failed, canceled, terminated, or still going.Two match report fixes come with it. KPI ratios now count identifiers the same way in numerator and denominator, so the figures beneath each card add up to the value on it — regenerate a report before comparing it with an older one. And a report no longer fails outright on an AWS EMR compute pool, where the Demographic & Behavioral Enrichment query used SQL the Spark analyzer rejects.Read more →Menus, tabs, and long lists
Dropdowns with thousands of options no longer stall when you open them. A searchable list shows up to 200 matching options at a time and says so under the last row —Showing 200 of 2,400. Type to narrow. — and the search still covers every option, not only the ones on screen.The tab bar’s overflow menu now leads with Close this tab, alongside Close all tabs and Close other tabs, and the tab strip announces that Delete or Backspace closes the focused tab — closing one tab used to mean clicking a ✕ that no keyboard could reach.Two menu fixes: clicking outside a menu, popover, select, autocomplete field or date picker now only closes it, instead of also activating whatever sat under the pointer; and moving from a menu row to the submenu it opens keeps both panels open, at every level of nesting.Query Builder’s field picker opens instantly on wide schemas
Query Builder’s field picker no longer stalls on sources with several thousand columns — it shows a first batch and adds more as you scroll. Your browser’s find-in-page only reaches the fields loaded so far, so use the picker’s own Search box, which still covers every field in the source. Read more →The Hugging Face Connector now says why a profile could not be created
Profile creation now names its cause — a token that does not authenticate, is not a user access token, or has no write access — instead of printing “Profile creation failed” twice. Read more →Bug FixComposable IdentityDashboardData StudioImprovementNew FeaturePlatform
The navigation redesign is complete
Navigation now lives entirely in the rail down the left edge. The rail replaced the old expanding sidebar, carrying everything it used to list behind four icons — Rosetta AI chat, Objects, Builder, and Marketplace — and the last two pieces have followed it there: the Settings menu has moved off the top bar to the foot of the rail, its contents unchanged, and a Notifications inbox now sits beside it. Every row still behaves like a real link, so cmd-click and middle-click open the destination in a new tab.That leaves the top bar to the things that describe your current session: your context selector, model picker, and account menu.A notifications inbox in the navigation rail
Work you hand to the platform no longer needs you to sit on the page while it finishes. A Notifications inbox now sits at the foot of the navigation rail, carrying a count of what you have not read and listing finished runs newest first, each with its outcome and how long ago it landed. Opening the panel clears the count.The tracking follows the run rather than the page: navigate away and the run is still watched, reload the browser and it is picked up where it left off. Label Studio’s Add Labels write, Data Studio queries, and bulk query uploads all report here. Records are kept for a day and cleared when you sign out.Addressable Graph Builder
Graph Studio has a new Addressable Graph Builder that turns a resolved identity graph into an audience source dataset — a table activation platforms can match against. A graph tells you which records belong to the same person; it does not tell you how to reach that person. This builder closes that gap.Pick the graph you want to make addressable, then enrich it: fold in datasets whose properties should travel alongside the identity as enrichment attributes, and choose which properties hold the identifiers that reach a person. Those identifiers are used for addressability only — they play no part in the graph-building logic that established identity in the first place. Identifiers are flagged as poor targeting dimensions so they don’t quietly widen the audience table without improving how you can segment it. From there, generate the addressable table and its companion audience table. Read more →Data Studio queries run in the background
Running a query in Data Studio no longer holds the page. The editor comes back as soon as the platform accepts your statement, so you can write the next query, switch tabs, move to another page, or reload the browser while it works, and the outcome reaches Notifications whether or not you were watching. The case this removes is the worst one: a hand-writtenCREATE MATERIALIZED VIEW over a large source, which used to sit behind a spinner covering the whole page for as long as the view took to build. While a run is in flight, Preview Results shows a placeholder; when it finishes you get a link to the new dataset, or the reason the run failed.Cancel now releases the page from the run rather than stopping it: the statement is already on the data plane, so it finishes and still reports to Notifications. Forecasts still wait inline, because the estimate is the point of asking and arrives in seconds.Bulk query uploads now run as a workflow
A bulk query upload in Data Studio is now kicked off as a single workflow rather than executed statement by statement while you wait. Every query in the file is still compiled one by one, and the ones that pass go into one workflow specification, in order, submitted as a single run. The upload panel comes back as soon as that run is accepted, saying how many queries went into it, and the outcome lands in Notifications whether or not you are still on the page.Label Studio shows which labels are unsaved, and says so before you leave
Picking a label in Label Studio stages it; only Add Labels writes it to the dataset. That distinction used to be invisible, and leaving the page discarded staged picks without a word. Now:- Staged picks are marked — a dashed outline and a pencil, with a tooltip reading “Not saved yet — click Add Labels to save this pick.” It reads differently from the tinted ring on an unconfirmed LLM suggestion.
- Leaving the page warns you, naming Add Labels as the control that saves them.
- Saving narrates itself — the button names the step it is on, Submitting… then Saving…, updating one notification in place rather than stacking one per stage, and the grid becomes interactive again as soon as the labels land.
Failed actions now report what actually went wrong
When an action failed, the platform frequently answered with a generic “please try again” while discarding the reason it had been given. Those messages now carry the cause through to the notification you see — across dataset and mapping actions, job cancellation, workflows and models, Label Studio, access rules, Rosetta Stone attributes, and the opt-out and profile settings on the Google DV360, PubMatic, Snapchat, TikTok, Trade Desk and Yahoo DSP connectors. Where a failure carries a diagnostic code, that code becomes the message heading with the explanation and suggested fix beneath it, the same treatment NQL execution errors already had.The context selector drops Database and Schema
Your execution context is now two settings rather than four. The Database and Schema columns are gone, and the pill in the top navigation reads out the data plane and compute pool alone. Neither column was ever selectable — both offered onlyDEFAULT, and the data plane resolved the database and schema for every operation regardless — so nothing about where your queries run has changed. Read more →Closing a tab now releases the memory it was holding
A page you opened used to stay in memory for the rest of the browser session whether or not its tab was still open, so ten tabs held over a hundred megabytes between them and closing all ten released none of it. Closing a tab now drops the page it was showing. Background tabs have also stopped polling at full rate — two of them could issue roughly eighty requests a minute between them — and polling now pauses when a tab is off screen and resumes when you return. What you are looking at refreshes exactly as before.The New Dataset form gets its name field right
Two fixes to the name field. It no longer shows Dataset name is required against a field nobody typed in — the message now appears only when you have typed a name and then cleared it. And a name another dataset already uses is now rejected against the field with Upload blocked, instead of succeeding quietly and leaving you with two datasets listed under the same name and a second whose unique name had been changed to avoid the clash. Names differing only by case count as a collision, and the helper text now reads The name your dataset is listed under. Must be unique.A comment above CREATE MATERIALIZED VIEW no longer changes how it runs
Data Studio now skips whitespace and comments when deciding whether to submit your NQL verbatim, so aCREATE MATERIALIZED VIEW or EXPLAIN written under a -- or /* */ comment is submitted as written rather than wrapped in a temporary one-day view with a 1,000-row limit — which meant the view you named was never created. A keyword now only counts at the start of the statement, so a query that merely mentions one further down keeps its full action bar.Bug FixComposable IdentityDashboardImprovementIntegrationsNew FeaturePlatformRosetta StoneWorkflows
RunConversation workflow task
Workflows can now ask an agent a question mid-pipeline. The task runs one turn against the model with the MCP servers you name, waits on a durable timer for the answer, and hands it to later tasks as structured output or prose. Learn more →Register Snowflake datasets programmatically
One of the most frequent requests from Snowflake customers: register a table or view as a Narrative dataset from your own account, in code, without launching the Native App’s Configuration screen. A new stored procedure does it from a worksheet, the Snowflake SQL API, or a scheduled task — so onboarding a dataset can be scripted and run from the pipeline that already builds the table. A new application role lets you delegate registration without handing over admin rights.The Configuration screen is unchanged and is still the simplest way to register your first dataset. This adds a route rather than replacing one. Learn more →A navigation rail replaces the sidebar
The platform’s navigation has moved into a rail down the left edge of every page, and the old expanding sidebar is gone. Four icons carry everything it used to list:- Rosetta AI chat opens a chat tab directly.
- Objects holds the things you already have — datasets, queries, reports, and access rules; attributes and normalized datasets; models and audiences; and jobs, workflows, and installed apps.
- Builder holds the studios you work in — Data Studio and Graph Studio, Audience Studio and Lookalike Studio, and the model studios, including Cached Mapping Studio.
- Marketplace browses data, apps, models, data plane providers, MCP servers, and skills, with your own models and apps one level in.
One model picker for every AI feature
The model picker in the top bar now chooses the model — and how hard it thinks — for every AI-powered action in the platform, not just for new Rosetta AI Chat conversations. The next message in a chat you already have open, a generated attribute or dataset description, an auto-labeling pass: all of them run on whatever the picker holds. The confirm button reads Apply, and the choice takes effect on the very next call.The picker also offers every model your data plane can run rather than three fixed tiers, listed strongest first. Switching data planes re-derives the list, and a model the new one cannot run gives way to that platform’s default without discarding your choice — switch back and your model returns. The Thinking column still appears only for models that accept a thinking level, so you can never pick a combination the run would reject.Because the model is now chosen in one place, the per-conversation model and thinking controls have been removed from the chat toolbar; the settings popover there still covers MCP servers and tools. In Label Studio, the auto-label panel lists models by name instead of by tier, so you choose exactly which models take part in a consensus pass.Opt-out configuration for TikTok, DV360, and PubMatic
The TikTok, Google Display & Video 360 (Customer Match), and PubMatic connector pages each have an Opt Out Configuration tab, matching the shape already used by Magnite, Yahoo DSP, and Snapchat. Connect an opt-out dataset without leaving the connector page.What a removal reaches differs by connector — TikTok covers every audience the profile delivers to, DV360 the Customer Match audiences under one account, and PubMatic every segment under the profile’s Data Provider ID. See the TikTok, Google DV360, and PubMatic references.Compute pool improvements
- Set your company’s own default. The data plane page now separates your company’s default pool from the one the plane’s owner set for everyone, and yours takes precedence. Setting it no longer requires owning the plane.
- Read the effective default from the API. Every compute pool in a response carries a
default_sourcenaming which level of the resolution chain made it the default. - Distinct capacity per fixed EMR tier.
x_smallthroughlargenow size their Spark containers explicitly, so each step up is a real one —mediumruns 3 executors instead of 1, andlargeruns 7 instead of 3, at the same cost.x_smallandsmalldrop to a single node. - Dataset detail names the pool. An archived pool, or one owned by someone else on a shared data plane, now shows its name instead of a raw identifier.
MCP tool improvements
- Compute pool defaults. The data plane tools render each pool’s
default_source, andnarrative_datasets_describereports a dataset’s own default pool — the one that actually wins for jobs against it. - Attribute derivation edges. The attribute tools render each attribute’s derivation edges, and now advise mapping a column to the attribute closest to the root of the graph, since one mapping there covers every derived variant.
- Job timings. The job tools return
dequeued_at,attempted_at,attempt_version, anddata_plane_id, and explain how to separate queue time from execution time.
Attribute derivation graph endpoint
GET /attributes/{name_or_id}/derivation-graph returns every derivation relationship around an attribute in one call — what it can be derived from, what can be derived from it, the rules connecting them, and each route’s cost and fidelity flags. A consumer deciding what to map can see that mapping an attribute’s canonical form unlocks its derived variants. Learn more →Match reports cover every identifier type the supplier holds
A Marketplace Match Report used to scan the supplier only for the identifier types you matched on, hiding the rest — including the mobile advertising IDs or compound identifiers that were the reason to evaluate that supplier. The supplier scan is now unfiltered, so the Enrichment card, the Identifier Type Summary, and the ID Enrichment and IDs Per Person KPIs cover everything the supplier holds for your matched people.Your match counts are unchanged, but both KPIs rise. Re-run an existing report to pick up the wider coverage. Learn more →Ranked, fuzzy search in the command palette
The command palette no longer needs the letters you type to sit next to each other.ds finds Data Studio, dstud finds it too, and spaces are ignored, so it makes no difference whether you type data studio or run the two words together.Results now come back ranked rather than in menu order. A match on a command’s name outranks a match on its description, letters matched at the start of a word count for more than ones landing mid-word, and the shorter of two equally good matches wins — so job puts Go to Jobs at the top instead of a longer destination that merely contains the same letters. Commands you run often, and recently, get a small lift on top of that, enough to separate the ones you use from the ones you never have without pushing a poor match above a good one. The Recent list is drawn from the same history.Destinations also answer to the words people actually type for them: nql or query editor for Data Studio, match reports for Reports, and ai or assistant for Rosetta AI Chat.Connecting an opt-out dataset now asks you to confirm
Connecting a dataset to a connector’s opt-out feed opts every identifier in it out of that connector, and the removal cannot be undone. That step now opens a confirmation naming the dataset and the connector before anything is created, so a dataset picked by mistake costs a click rather than an audience.The confirmation appears on the Opt Out Configuration tab of the Meta, Google DV360, Magnite, PubMatic, Snapchat, and TikTok connectors, and when you connect a dataset to a connector’s opt-out interface from the dataset itself.PubMatic profiles no longer ask for destination paths
Creating or editing a PubMatic profile no longer asks for a Delivery Destination or a Taxonomy Destination. Both paths were required before you could save, and neither is part of a profile any more — setting up PubMatic now needs only your Data Provider ID and your SFTP credentials.Label Studio shows the full text you are labeling
String is now the widest column and wraps onto as many lines as the row needs, and long options in the Label dropdown wrap rather than truncate — so values longer than a short phrase are finally readable.Failed inference jobs name the model
A failed inference job now names the model the run selected and links to its listing, where the catalog reports whether your installed data planes can run it. The previous message gave you a job id and a generic documentation link.Edit tags on a dataset’s detail page
The Tags row on a dataset’s detail page can now be edited in place: the field accepts what you type, and your tags save the way every other row on the page does. Tags the platform sets for itself sit beside the field as plain chips — visible, but not yours to remove.Enterprise login settings stay reachable for your whole session
If you sign in through Enterprise Login, Settings > Enterprise Login Settings no longer disappears part-way through your session. The platform now remembers that your session is an enterprise one for as long as you stay signed in, rather than inferring it from a shorter-lived login cookie, and it renews the enterprise login behind the page whenever you load the app or return to the tab.When that login has genuinely expired, the page says so and offers a Sign in again button that brings you back to where you were — instead of leaving the organization settings, member management, and SSO panels showing an error with no way forward. The page is also reachable only by the account that signed in through Enterprise Login.See SSO Configuration for the full administrator walkthrough.Heavy sessions no longer trip a request limit in the app
The app counted roughly 150 requests per five minutes per network address, so polling screens hit the ceiling on their own and everyone on an office network shared one budget. That limit is gone; API clients are still rate limited at the edge.Cached mappings are now scored in mapping evaluations
Cached mappings were left out of evaluations entirely, so a dataset that leaned on them looked far less covered than it was. They are now scored alongside value and object mappings. Learn more →Classifier Studio clears the builder once a training run is queued
Submitting a run used to leave the configuration on screen, so clicking Train Classifier again queued a duplicate. Classifier Studio now returns to its start view once a run is accepted, and clears nothing when the platform rejects one.Connections keep the profile you picked for the connector
Switching connectors without closing the configuration panel could save the connection against the profile belonging to the connector you started on. A connection is now always saved against the account you chose for it.Dataset file downloads no longer fail on Iceberg tables written with s3a:// paths
The internal S3 URI parser rejected the Hadoop s3a:// scheme that some Iceberg tables recorded their file locations with. It now treats s3://, s3a://, and s3n:// as the same object.APIBreaking ChangeBug FixComposable IdentityDashboardImprovementIntegrationsNew FeatureWorkflows
Sample redaction
A dataset’s sample can now carry a redaction: a record of which columns hold personal data, what kind of personal data each one holds, and how each one is masked. Narrative’s privacy model can produce that record for you, or you can write it yourself.Reading and writing a redaction
Four new endpoints put redactions on the public API.GET, PUT, and DELETE /datasets/{dataset_id}/redaction read, write, and delete the redaction, and GET /datasets/{dataset_id}/sample/redacted returns the sample with the redaction applied. Deleting a redaction leaves the underlying sample untouched.Seven masking strategies are available (keep_email_domain, keep_initials, keep_last_digits, keep_network_prefix, keep_two_decimal_places, keep_year, mask_everything) and nine personal-data categories (account_number, other, private_address, private_date, private_email, private_person, private_phone, private_url, secret). Both sets are closed — a redaction naming anything outside them is refused with a 400. A single redaction may name at most 20,480 columns. Customers may write redactions for their own datasets; only Narrative may record the model_version that produced a redaction. See Redacting dataset samples for the full walkthrough.Sampling and redacting in one request
POST /v2/datasets/{dataset_id}/request-sample samples a dataset and asks the privacy model to mark which columns hold personal data and how each should be masked, all in one call. The response is the created workflow and the id of its run. When the run completes, read the model’s decisions with GET /datasets/{dataset_id}/redaction and the masked rows with GET /datasets/{dataset_id}/sample/redacted.The /v2 route requires the caller’s own company to own the dataset — a data-plane collaborator gets a 404 — and it triggers a workflow that draws on the owner’s credit limit, so a company over its limit gets a 403. The v1 POST /datasets/{dataset_id}/request-sample endpoint is unchanged: it samples without redacting, admits collaborators, enqueues a job under the owner’s company, and spends no credit.Redacting from inside a workflow
The newGenerateSampleRedaction task runs the same classification from within a workflow. Chain it after CreateDatasetSample to keep a dataset’s redaction current whenever its sample is regenerated.Specify the target dataset by either datasetId or datasetName (exactly one). The dataset must already have a sample, and the model is shown at most 100 rows of it. The task replaces the stored redaction rather than merging with it, so any redaction previously uploaded through PUT /datasets/{dataset_id}/redaction is overwritten. Narrative’s own columns (_rosetta_stone and other reserved fields) are excluded from classification, so ingestion metadata is never flagged as personal data. The output carries datasetId, columnsExamined, columnsRedacted, and modelVersion — the redaction itself is written directly to the dataset and served by GET /datasets/{dataset_id}/redaction by the time the task returns.Configure Snapchat opt-outs from the connector page
The Snapchat Connector page now has an Opt Out Configuration tab, matching the shape already used by Magnite and Yahoo DSP. The tab lists the datasets currently feeding opt-outs into Snapchat and lets you connect a new one without leaving the connector page. Only datasets that carry a Snapchat-readable identifier column and aren’t already wired up are offered when you create a connection, and the connection binds to a Snapchat profile for bookkeeping — an opt-out names no ad account and no audience, and the connector resolves a token per segment at delivery time. See the Snapchat Connector reference for the full setup.Pick a Rosetta Chat model and thinking level from the top bar
The top navigation now includes a Rosetta Chat model picker. Open it and you get a two-column menu: choose a model on the left, and the right column shows only the thinking levels — Default, Off, Low, Medium, or High — that model actually offers. Unsupported model-and-thinking combinations never appear, so you can’t pick a setting the run will reject. Your top-bar choice sets what new Rosetta conversations start from; conversations already open keep the model and thinking level they were created with.Inside a conversation, the chat model bar picks up the same Thinking level control, and it only renders on models that support thinking. “Default” leaves the model’s own behavior alone, “Off” explicitly disables reasoning, and Low / Medium / High map to the provider’s effort levels. The setting rides each run, so you can dial reasoning up on a hard question and back down for the next turn without leaving the chat.Jump to any sidebar destination from the command palette
The command palette (⌘K / Ctrl+K) now offers a Go to… command for every destination in the side navigation, not just a hand-picked seven. Datasets, Models, Rosetta Chat, the studios, settings pages, and everything else the sidebar reaches are all searchable and reachable from the palette. Commands react to your context: switching the data plane from AWS to Snowflake makes Classifier Studio, Label Studio, and Cached Mapping Studio appear in the open palette without closing it or retyping your search. Where two destinations share a leaf label — for example Models under both My Models and Marketplace — the palette shows the full path so you can tell them apart.The four Graph Studio tab shortcuts (Graph Builder, Edge Builder, Match Report Builder, Addressable Graph Builder) and Create New Dataset are no longer in the palette while the underlying page-contributed command API is finished; they will return in a follow-up release.Label Studio: literal source input, and the target attribute picker renders again
The Source Input step of the Label Studio project builder now supports Literal mode alongside Fields mode. Pick Literal in the mode selector and enter a single string; every row queued for labeling will present that exact text as its source input, with no field selection, concatenation strategy, or preview cards to configure.Typing live-updates the draft: the value you enter is emitted as-is, and the underlying NQL expression is a single-quoted string literal with embedded single quotes doubled (matching the escaping convention used elsewhere in the platform). Backslashes pass through unchanged because NQL does not treat\ as an escape character. An empty literal is allowed and surfaces inline helper text so you know the field is intentionally blank. Switching away from Literal and back does not carry Fields-mode selections into the emitted source input.Separately, a regression introduced in v2026.8.16 that made creating a Label Studio project impossible is fixed. The Target attribute view rendered empty, so no attribute could be selected and the project could not be saved — the picker’s AttributeSelect component crashed during setup because a watch was registered before the groupedAttributeOptions value it read, hitting the temporal dead zone on first evaluation. The declaration order is fixed and the attribute list, allowed values panel, and Create project button work as before.MCP narrative_classifier_train tool
The MCP server now exposes classifier training as narrative_classifier_train. The tool submits a training run against a dataset that is materialized on a Snowflake data plane and returns the job id so the agent polls completion with narrative_jobs_describe. The trained model is saved to the Snowflake ML Registry in the data plane’s account.Arguments mirror POST /v1/model-training/train-classifier: a dataset_id, a label_column, a model_name, and a feature_inputs array. Each feature entry picks one of text, categorical, numeric, or embedding and takes its own tuning block. The model object picks the algorithm (defaults to logistic regression) from logistic_regression, random_forest, gradient_boosting, svm, or naive_bayes. Column references and every top-level key are validated against the dataset’s schema before the job is enqueued, so most malformed requests fail the tool call rather than the job. See narrative_classifier_train for the full parameter list.Stop an agent conversation from waiting on a handle
Agent conversations can now drop a claim on a handle without stopping the job behind it.POST /agents/conversations/{id}/waitables/{handle}/cancel wakes a run parked on that handle, tells it the handle reads stopped_waiting, and lets the turn finish normally, so the conversation is free to take its next turn immediately. The job the handle points at keeps running exactly as before — cancellation drops the wait, not the work. Cancelling the same handle twice returns the original cancelled_at, and a later wait_for on the dropped handle reads the abandoned claim rather than waiting again. See Waiting for Work to Finish for the full behavior.Attributes API: cooccurrence metadata hides private attributes
GET /attributes/{name_or_id} previously embedded each entry in metadata.attribute_cooccurrence as a full attribute record with no viewability check, so an unauthenticated caller could enumerate private attributes — owner company_id and collaborators included — through any public attribute’s cooccurrence list. The endpoint now filters the cooccurrence list by the same view permission as every other attribute read, so entries the caller cannot view no longer appear.Each surviving entry’s attribute field is also slimmed to a fixed shape (id, name, type, description, display_name, tags) for every caller, owners included. company_id and collaborators no longer appear anywhere under metadata.attribute_cooccurrence[].attribute. cooccurrence_pct values are unchanged. Update any consumer that reads owner fields from cooccurrence entries — fetch the attribute directly by id or name instead.OpenAPI spec corrections across Webhooks, Access Tokens, Attributes, and /whoami
Four public OpenAPI specs were out of step with what the services actually send and receive. All four are now accurate. No production behavior changed in any of them — the spec is the piece that moved — but anyone generating a client from these specs will see type changes. Regenerate your SDK client to pick up the corrections.Webhooks
The Webhook Event Reference now reflects the corrected shape:- Subscription responses use
snake_case. The fields formerly documented ascompanyId,jobIds,jobStates,jobTypes,createdAt, andupdatedAtarecompany_id,job_ids,job_states,job_types,created_at, andupdated_at. company_idandapp_idare integers, not strings.- The three job filters —
job_ids,job_states, andjob_types— are returned as objects of shape{ "values": [...] }, not bare arrays. Requests still take bare arrays. app_idandnameare first-class fields on the subscription response.- The
statesenum now includesscheduled. job_typesis an open string up to 255 characters, not a closed enum.expires_aton webhook subscriptions no longer claimsformat: date-time.
X-Narrative-Secret header holding the subscription’s secret, and the body follows a four-field envelope (id, created_at, type, data). Verify the header before processing the body and key your idempotency store on the envelope id.Access Tokens
- The
access_tokencredential now appears only on the response toPOST /access-tokens/tokens, where it is actually returned.GET,PUT, andLISTresponses no longer advertise a field they never send. The two shapes are now distinct components:CreatedAccessToken(which carries the credential) andAccessTokenMetadata(which does not). TheAccessTokenWithoutCredentialscomponent is removed. - Validation rules are now documented on the operations:
nameis 1 to 256 characters,admincannot be granted, andexpires_atmust be 1 to 365 whole days out. Expiry is stored with day granularity, so a token requested for 36 hours expires in 24.
/whoami
The /whoami spec carried a stale 21-value copy of the permission resource enum, so generated clients rejected 22 of the resources the endpoint actually returns. Both /whoami and /access-tokens now reference a single shared PermissionResource enum with all 50 values, and the two specs can no longer drift apart. Consumers who previously typed Permission.resource as a bare string will see it become a union of the 50 valid values.The spec also now types last_updated_at and last_updated_by as nullable on the /whoami response. An account that has never been updated sends both keys with a null value, and only created_by allowed a null before. The four field descriptions previously called these company timestamps; they describe the user account and now say so.Attributes
GET /attributes documents the Page envelope the endpoint returns, GET /attributes/references documents its {records} wrapper, POST /attributes documents its 201 response, and every operation documents its reachable 4xx codes. PUT /attributes/{name_or_id} is documented for the first time.The read operations declare optional bearer auth: a token decides per record whether the response uses the owned shape (with company_id and collaborators) or the shared shape (without them). Request schemas no longer promise defaults the decoder never applies — tags is required. Inclusion and exclusion collaborators send company_ids rather than companies, and self-references are written $this (the previously documented $self is rejected with 400).Context selector rebuilt for clarity on every screen
The workspace context selector in the top navigation has been rebuilt on the platform’s standard multi-level menu. The flyout now shows all four columns (data plane, compute pool, database, schema) at once instead of clipping the fourth, and the row you selected uses a distinct fill from the row under your pointer so the two are easy to tell apart on both light and dark surfaces. Rows are edge-to-edge and respond to the pointer instantly, the Cancel and Accept buttons are now filled instead of faint outlines against the dark panel, and the Narrative logo renders correctly on the pill and in the data plane column instead of appearing as a blank square.Below 1400px viewport width the selector no longer disappears from the top bar. It compacts to the data plane name and still opens the full four-column panel, so your query context stays visible and reachable at narrower window sizes.Changing your data plane no longer leaves a downstream column standing empty when its previous pick is gone: any single-choice column with nothing selected automatically takes its first row. The pill also refreshes correctly when you switch away from a data plane, so it never keeps showing the previous plane’s name.Settings menu in the top navigation
The platform’s settings destinations now live in a single Settings menu beside the user menu in the top nav, instead of being scattered through the sidebar. The menu carries five links under two headings: Data Planes and Sources under Infrastructure, and API Keys, Secret Sharing, and Enterprise Login Settings under Access. Enterprise Login Settings only appears for B2B companies. Jobs and Workflows stay in the sidebar, since they are operational views rather than settings. Each row behaves like a real link — cmd-click and middle-click open the destination in a new tab, and hovering previews the URL in the browser’s status bar.API key permissions drawer now offers every resource in the contract
The Settings > API Keys drawer built its permission matrix from a hand-written list that had drifted to 40 of the API contract’s 50 resources, so a key could not be scoped to the other ten and nothing on screen said so. Rows are now derived from the API’s own schema, and the drawer renders all 50 resources across five categories. Ten resources are newly selectable, includingattribute_derivations, internal_reports, and persistent_permissions. See the Permissions reference for the full list.Edge Builder emits bare attribute names for object-shaped attributes
Edge Builder was labeling object-shaped attributes with their property path, so a customer edge went out assha256_hashed_email.value while supplier edges carried sha256_hashed_email. Match reports join the two sides on exact string equality of that label, so the join matched nothing and the report showed a legitimate-looking 0% match rate. Edge Builder now writes the bare attribute name for every leaf you pick, and hydration recovers the specific leaf from the mapping’s target_id expression so existing edges load onto the right property.Mappings already saved with a .value label are not rewritten automatically. Re-save them through Edge Builder to restore matching against supplier edges.Classifier Studio trains on datasets without an ID column
Classifier Studio used to send id_column: "ID" on every train request, so the v1 train-classifier endpoint returned id_column 'ID' references column 'ID' which does not exist in the dataset and the submit failed with a 400 whenever the selected dataset had no literal ID column. Training now only sets id_column when the dataset’s schema actually contains an ID column, and omits the field otherwise, so Classifier Studio submits successfully against any Snowflake dataset regardless of its column names.Dialogs stay clickable when the page behind them is blocked
Dialogs and drawers now respond to clicks even when they are mounted inside a region that has disabled pointer events. The bug was easiest to hit in Data Studio: when a query failed, the “Something went wrong…” dialog appeared looking normal but its close button and buttons did nothing, because the dialog was a DOM descendant of the loading wrapper that setspointer-events: none on its contents. The fix restores interactivity on every TackleboxDialog and TackleboxDrawer in the dashboard, so any dialog opened over a busy or blocked region behaves correctly.APIBreaking ChangeBug FixComposable IdentityDashboardData StudioDeprecationImprovementIntegrationsNQLNew FeatureRosetta Stone
Agents can wait for long-running work
An agent asked to “run this and tell me when it’s done” used to have no way to wait: it re-checked the job’s status every turn and ran out of turns before the work finished. Agent Conversations now pause instead.- Waiting on Narrative work. The agent registers a job with
job_monitor, which hands back an opaque handle (wt_…) — a claim ticket for work that outlives the call that started it — then waits on up to 8 handles at once withwait_for, for up to 12 hours. The run is paused until the work finishes or the timeout passes, holding no compute and making no model calls in between, so a four-hour job costs no more to wait for than a four-second one. A failed job is a finished wait, not a failed run. Handles work only in the conversation they were issued in and last 24 hours. While a run is paused,live.messagesonGET /agents/runs/{id}shows what it’s waiting for. - Pausing between checks. For work Narrative cannot observe, such as a third-party ticket,
sleeppauses the run for 1 second to 1 hour as a durable timer that survives a restart, so the agent can re-check without hot-looping.sleep,job_monitor, andwait_forare always available on top ofmcp_servers[]andtools[], and their names are reserved. - One run at a time. Starting a run while another is still
pendingorrunningon the same conversation now returns 409 Run Already In Progress, naming the active run and what it’s waiting on — previously both runs started and the loser died at finalize withConcurrentConversationAppendafter paying for a workflow. Re-posting aclient_op_idyou’ve already used is still idempotent and returns that run’s row. max_iterationsnow defaults to 10 (was 3), since starting a job, taking a handle, and waiting on it are three iterations of the budget on their own. Existing conversations keep whatever value they were created with.
Conversions API Connectors for Pinterest, TikTok, PubMatic, and Yahoo
Following the Meta Conversions API Connector, you can now send conversion events — purchases, signups, leads, and more — to four more ad platforms for improved attribution and campaign optimization. Each is a second interface of the platform’s existing audience connector, so you can reuse the profiles and accounts you already have.- Pinterest — deliver web, app, and offline events per ad account via the
pinterest_conversion_eventattribute. View documentation → - TikTok — deliver offline events to TikTok Offline Event Sets via the
tiktok_conversion_eventattribute. View documentation → - PubMatic — deliver events per advertiser over SFTP following PubMatic’s conversion data contract, via the
pubmatic_conversion_eventattribute. View documentation → - Yahoo — deliver events per pixel to Yahoo DSP via the platform-neutral
conversion_eventattribute. View documentation →
Legacy subscription forecast API and job types removed
The legacy/data-shops/subscriptions forecast routes (cost-forecasts, forecasts, and the unauthenticated public/forecasts pair) have been removed, along with the forecast, forecast-internal, and costs job types they enqueued. These endpoints powered retired frontend flows and had no remaining callers. Use the NQL forecast path (nql-forecast via POST /nql/run) to estimate query cost and rows going forward.The nql-forecast job completion payload discriminator is now "nql-forecast" to match the job type. Data planes that still post "forecast" continue to work — both discriminators are accepted.Cached Mapping builder: built-in Exact match and a unified Models step
The Cached Mapping builder now shows the built-in identity rule every mapping already runs before its ML and LLM stages: a single Exact match rule in the Rules step that resolves any normalized input equal to one of the target attribute’s values straight to that value, with no model call. It’s on by default — remove it when you need every key to go through your models, and restore it from the warning banner the step shows once you do.The ML and LLM steps are now a single Models step. Pick classifiers and Cortex LLM models from one catalog, order them into a waterfall, and set a confidence threshold per stage — incompatible models are greyed out with a hint, and models with a partial-overlap warning stay selectable. A stage caches a value only when its model clears its threshold; a key no stage answers confidently caches as NULL rather than falling back to a nominated vocabulary member, since no member can honestly mean “we couldn’t tell.” Each stage’s threshold input appears as soon as the stage exists, so you can tune it off its 50% / 75% default even before a probe can run. A live Sample run scores every chosen model against up to 100 source keys so you can tune thresholds against real coverage — classifier thresholds are chosen automatically from where the classifier stops agreeing with the LLM, and hand edits stick until you resample. Between the Exact match rule and the optional Models step, attribute, source, and input expression are enough to build a valid mapping.Classifier training moves to v1, resolved by dataset id
Classifier training now goes through the newPOST /v1/model-training/train-classifier endpoint, which takes a dataset_id instead of a raw Snowflake table name and resolves the backing table server-side. Pass dataset_id, model_name, label_column, and feature_inputs (plus optional id_column, model, test_size, stratify, random_state, save_model, debug, model_version, and tags); the endpoint validates every column reference against the dataset’s schema before enqueuing the job and returns a job_id to poll. It only accepts datasets active on a Snowflake data plane and owned by the caller — non-Snowflake datasets and malformed identifiers return 400, datasets shared via data-plane collaboration return 403, and unknown datasets return 404.Classifier Studio now posts to this endpoint. The training job runs on whichever data plane owns the selected dataset, so the Data plane selector is gone from the Finalize step — a model name is the only remaining gate on Train Classifier. The two conditions v1 rejects at submission now surface at dataset selection instead: a non-Snowflake navigation data plane replaces the picker with a message pointing you at a Snowflake plane, and datasets with no backing table are disabled with an explanatory tooltip. Count Vectorizer is no longer offered as a feature type — choose Text (TF-IDF), Categorical, Numeric, or Embedding in the Classifier Studio feature configuration step.Derivations API
You can now create and manage attribute derivation rules through the new public/derivations endpoints. A derivation rule describes how the value of one Rosetta Stone attribute is computed from another, so a rule from raw_email to sha256_hashed_email might map its value property to SHA2(NORMALIZE_EMAIL($source.value), 256). Once a rule exists, queries can resolve the target attribute from the source without a stored mapping.The endpoints cover the full lifecycle: GET /derivations lists the rules your company can use, GET /derivations/{id} fetches a single rule, POST /derivations creates one, PATCH /derivations/{id} updates fields on an existing rule, and DELETE /derivations/{id} removes it. List results can be filtered with repeated source_attribute_id and target_attribute_id parameters, and the response includes every rule your company owns plus every rule shared with it through collaborators. Reads require a read grant on attribute_derivations; creating, updating, and deleting require an admin grant, and only the owning company can modify or delete a rule. A rule’s source_attribute_id and target_attribute_id are immutable once the rule exists.Every transformation is validated before the rule is written. Each expression is parsed, compiled against a synthetic single-column table built from the source attribute, and type-checked against the target attribute; every required target property must be covered, unknown properties are rejected, and each failure comes back as its own descriptive 400. cached_mapping is not accepted, since there is no stored dataset to substitute $source into. Expressions may use CURRENT_DATE, CURRENT_TIMESTAMP, and RAND, so a rule like birthdate to age in years is correct as of each query that resolves it. If a create or update closes a cycle in the derivation graph the rule is still written, and the create and update responses return a cyclic_derivation warning listing the attributes in the cycle (cycles up to six attributes, up to ten reported).See the Derivations API reference for the request and response shapes.Filter MCP job searches by workflow
narrative_jobs_search now accepts first-class workflow_id and workflow_run_id inputs, matching the Jobs API additions. Agents can list every job spawned by a workflow (or a single run) directly, instead of composing tag-string filters. narrative_jobs_describe also surfaces workflow_id and workflow_run_id in the metadata block when the underlying job carries them.The tool description for tags is corrected at the same time: multiple tags match any job carrying at least one of them, not all. Read more →Actionable error messages for Rosetta AI chat
Toast errors from Rosetta AI chat now lead with a stable code and a specific fix instead of a generic “Request failed” line. SevenAGENT_E001 through AGENT_E007 codes cover the failures the chat raises on its own: no data plane selected when sending a message or compressing a conversation, the platform connection not being ready, the auto-resume round cap being hit, and the summarizing chat that compresses a conversation failing or returning nothing. Each toast now reads the same as the equivalent dialog error, with the code as the title and the why plus fix as the body, so an AGENT_E001 toast points at the data plane switcher in the top bar just like NQL_E002 already does in Data Studio.Grouped multi-select filters on the dataset listing
The dataset listing’s Tags and Dataset Type filters are now grouped, multi-select menus. Tags are split into User Tags and System Tags on the real_nio_ boundary, so user-written tags that start with an underscore (like _debug_only) no longer get misfiled as system tags. Known system tags display their catalog label (for example, Materialized View, Audience) with the raw tag on hover, and shared prefix:value namespaces collapse under an expand row with a selected-count badge. You can now select multiple tags at once (OR semantics) and multiple dataset types, with tag selections still round-tripping through the ?tags= URL parameter.Single-statement NQL execution: ExecuteNql task, POST /v1/nql/execute, and the MCP tool
You can now run any NQL statement without knowing its kind in advance — useful when the statement is supplied dynamically, for example through ${$workflow.input.statement}. The new ExecuteNql workflow task, the new POST /v1/nql/execute endpoint, and the MCP server’s narrative_nql_execute tool all parse the nql you pass in and dispatch to the matching executor: EXPLAIN runs as ExecuteExplain, INSERT/UPDATE/DELETE run as ExecuteDml, and CREATE MATERIALIZED VIEW runs as CreateMaterializedViewIfNotExists. SELECT and MERGE are rejected (WORKFLOW.EXECUTE_NQL.STATEMENT_IS_NOT_SUPPORTED from the task, 400 from the endpoint).The ExecuteNql task returns a type field naming the task that actually ran and a payload field with its normal output, so downstream workflow steps can branch on the statement kind — see the Task Reference. The POST /v1/nql/execute endpoint wraps the same dispatch for one-off calls: send nql plus an optional data_plane_id, compute_pool_id, and create_as_view flag, and it creates and starts a one-task workflow immediately, returning the workflow plus a run_id you poll like any other run — unlike POST /nql/run, which returns a job document. See Executing NQL via the API and the migration guide if you have existing /nql/run callers.The MCP server exposes this same endpoint as narrative_nql_execute, returning the workflow and run id so you poll with narrative_workflow_runs_list(workflow_id=...) and find the enqueued job with narrative_jobs_search(workflow_run_id=...). The previous tool name, narrative_nql_run, still works and routes transparently to narrative_nql_execute — update your prompts and skills to call it directly.NQL UDFs work on AWS EMR compute pools
Fixed a bug where NQL queries that called anarrative_id_*, embed_text_*, or UID2 UDF failed during analysis on AWS EMR compute pools. The Spark application running the job never registered these UDFs, so the function name fell through to an external catalog lookup that failed with a permissions error. Compute pools now register the same UDFs as every other NQL executor before accepting work, so these queries run as expected.Bulk NQL runs attempt every query and log why each failure occurred
Fixed a bug in Data Studio’s bulk query upload where the run stopped at the first unexpected error and reported truncated counts as if the whole file had been processed — a 50-query file could come back “2 validated, 1 failed” with the remaining 47 never attempted. Every query is now attempted regardless of individual failures, and each failure entry inbulk-query-log.jsonl carries the response status, body, and a plain-language NQL_W001 diagnostic; the upload panel also returns to idle after a rejected run so a new file can be picked without a reload.Snapshot TTL retention drawer keeps recent snapshots
Fixed a bug in the dataset retention policy drawer where the time-based Snapshot TTL option emitted the wrong comparison, retaining only snapshots older than the configured interval and expiring everything younger — including the current snapshot. Because retention enforcement deletes the data files added by expired snapshots, affected datasets lost all data ingested within the interval on every retention run. The drawer now emitssnapshot_age <= interval, so time-based Snapshot TTL keeps snapshots newer than the interval as documented in configuring retention policies.Dataset Actions menu shows a busy state
Fixed a bug where the dataset Actions menu gave no feedback while a network-bound action (Update sample, Delete sample, Update statistics, Copy as Markdown) was running, so a second press could fire the same job multiple times. The button now spins and the menu disables until the request resolves, and on the datasets and audiences listings, the acting row’s ellipsis becomes a spinner while other rows stay usable.Match Report input scoped to the selected identifier types
Fixed a bug where the Marketplace Match Report builder’s step 1 customer scan included every identifier type in your source graph, not just the ones you picked at Match identifiers — unselected types showed a large input count and 0 matches, reading as a matching failure, and the same unfiltered scan understatedkpi_match_rate by dividing matches over ineligible identifiers. New reports now scope the Input panel, Identifier Type Summary, and Match Rate KPI to the selected types; re-run older reports to pick up the fix. See Building a marketplace match report.MCP attribute tools surface enum and items in schema output
Fixed a gap where narrative_attributes_describe, narrative_attributes_search, and narrative_attribute_create omitted a scalar attribute’s enum values and an array attribute’s items element type from their schema output. All three now include these fields — nested object attributes were unaffected, since their enum values already passed through the forwarded properties JSON. See the MCP server reference.Rosetta chat keeps the transcript when an inference run fails
Fixed a bug where a failed inference run in Rosetta AI chat wiped the pane down to a red “Inference Job Failed” box, losing the full transcript — and “New conversation” didn’t help, since the page instance was cached against the route path. The transcript now survives the failure with the error rendered inline, the composer stays usable for a follow-up, and “New conversation” opens a genuinely empty chat.Dataset picker row clicks respect disabled state
Clicking the blank area of a disabled row in the shared dataset picker no longer selects the dataset. Previously the row-blank click bypassed the same guard that disabled the row’s Select button, so a dataset the caller had marked ineligible could still be picked from anywhere else on the row. The fix applies wherever the picker is used, including Classifier Studio and Prompt Studio’s dataset create flow.APIBreaking ChangeBug FixDashboardImprovementIntegrationsNQLNew FeatureWorkflows
Cortex Code support in the MCP Configuration and skill Installation pickers
Data Collaboration listing detail pages and skill detail pages now offer Cortex Code (Snowflake’s CoCo CLI) alongside their existing harness options — Claude Code, Claude Cowork, Claude Desktop, ChatGPT, Codex, and the Narrative Conversations API on listings; theskills CLI and Claude Code on skills. Each picker preselects Cortex Code when the listing’s active data plane is Snowflake and falls back to the previous default otherwise, with no harness flicker while the data plane resolves. A manual pick sticks even if the data plane later changes.- MCP Configuration picker:
cortex mcp add -t http narrative-mcp https://mcp.narrative.io/mcp— the-t httpflag is required, since it defaults tostdioand would never reach the hosted URL. - Skill Installation picker:
/plugin install github:narrative-io/narrative-skills-marketplace/plugins/<plugin>#maininstalls the plugin a skill ships inside directly from GitHub, with no separate/plugin marketplace addstep. See Installing skills for the full picker walkthrough.
Secured the external MCP OAuth callback
GET /mcp-connections/callback no longer exchanges the authorization code. It now parks the code against its flow and 303s the browser to the Narrative app’s callback page, which finishes the connection by calling the new POST /mcp-connections/complete with the signed-in user’s own bearer. The exchange only runs when the bearer’s (company_id, user_id) matches the flow’s owner — a mismatch returns 404, so a state can no longer be used to capture another user’s token by luring them through the consent screen. See the MCP Connections reference for the updated lifecycle.The redirect from the callback carries only state on success and, on failure, an error whitelisted to RFC 6749 §4.1.2.1 codes plus invalid_state, unknown_state, and invalid_callback — an unrecognized code from the authorization server is reported as server_error rather than reflected.Filter jobs by workflow on the Jobs API
TheGET /jobs endpoint now accepts workflow_id and workflow_run_id query parameters, so you can list every job enqueued by a given workflow or a single run without scanning tags. Job responses also gain matching workflow_id and workflow_run_id fields, which are populated for jobs enqueued by a workflow and omitted otherwise. Read more →Removed deprecated Rosetta Stone API endpoints
The deprecated Rosetta Stone mapping-suggestion endpoints and their supporting job type have been removed from the public API. Calls to the following are now rejected:POST /datasets/{id}/suggest-mappings— the batch mapping-suggestion request against a dataset.- The
/rosetta-stone/label-datasetand/rosetta-stone/label-samplelabeling endpoints. - The
datasets_suggest_mappingsvalue in thejob_typesfilter forPOST /webhooks(webhook subscriptions).
datasets_suggest_mappings, remove that value — the enum no longer accepts it and requests including it will fail validation. The AI mapping-suggestion experience in the dashboard (Rosetta Stone → Normalized Datasets → Normalize → Start Analysis) is unaffected and continues to work through the current Rosetta Stone service. See Accepting AI Mapping Suggestions for the supported flow.Build and schedule a Cached Mapping from the studio
The Cached Mappings studio can now build a mapping end to end. A new Build Cache action creates the cached mapping, activates the backend-provisioned cache dataset, and submits a population workflow that runs the rules, ML, and LLM tiers as a single waterfall. A toast confirms the build and links straight to the running workflow. If anything after mapping creation fails, the mapping is rolled back so a half-provisioned cache never breaks attribute queries at compile time.A new Cache Refresh step picks the cadence the population workflow re-runs on. Schedules run in UTC, default to daily, and@predefined aliases are expanded to the 5-field cron form the workflow DSL accepts. Choosing “One-time” means the cache fills once at build and only re-runs when triggered manually. A refresh-spend card sums the LLM stages’ row caps and warns when the schedule is hourly or faster, since frequent runs with an LLM tier are the runaway-bill shape to avoid.Refreshes are incremental: the waterfall’s keys CTE anti-joins the cache dataset so only keys not yet cached enter a tier. A scheduled run picks up new keys and retries still-unresolved ones instead of re-billing the whole waterfall.Two smaller changes come with this release:- Rule matching is now case-insensitive. A rule for
labfires onLabandLABbecause rule arms compile toWHEN LOWER(input_0) = 'lab'. The rule editor still flags surrounding whitespace with a Trim all repair. - Narrative admins get a Preview Workflow action that renders the population workflow YAML before Build Cache runs, and if the draft is incomplete the dialog reports the reason.
cached_mapping schema.Exclude collaborators when configuring a compute pool
The compute pool create and edit drawers now offer Exclude alongside All companies, Only my company, and Include. You can grant a compute pool to everyone in the data plane except a named set of companies without dropping to the API. Opening an already-excluding pool in the edit drawer now preselects Exclude with its company list intact — previously the form silently coerced the exclusion back to “only my company” on save.The backend has enforced theexclusion collaborator variant since it shipped in July; this change surfaces it in the UI.Rebuilt S3 Connector settings page
The Amazon S3 Connector settings page has been rebuilt as a native part of the Narrative dashboard, replacing the embedded legacy experience. Existing/s3-connector/settings links keep working, and Launch from the marketplace now opens the profiles list directly.The new page tightens the profile create wizard with a three-step flow — profile info, bucket policy and ownership tag with a mandatory connection test, and file format — and translates the eight discriminated access-test error codes into actionable copy so you know exactly why a connection was rejected. Bucket policy and ownership tag fetches that fail now surface an inline error with a retry action instead of spinning indefinitely, and editing the bucket name no longer invalidates and re-mints the ownership tag on every keystroke.NQL query included in dataset markdown exports
The Copy as Markdown action on materialized-view datasets now includes the dataset’s NQL under a## NQL Query heading, as a fenced SQL block, in both the extended and full formats. The exported query is the reconstructed CREATE MATERIALIZED VIEW statement — the same query shown on the read-only NQL tab and opened by Open in Data Studio — so it runs as written. The concise format is unchanged, and the section is omitted for datasets that no query produced (uploads, subscription deliveries, and connector-fed datasets).Collaborator picker holds Include or Exclude until you choose companies
Choosing Include or Exclude in the collaborator picker before selecting any companies no longer snaps the control back to “All companies” or “Only my company”. The picker now holds the chosen type until you pick a company, switch to an unconstrained type, or the form loads a different collaborator. Clearing the last company from an existing Include or Exclude also keeps the type instead of jumping to another option.The fix applies everywhere the picker is used — access rules, query templates, query views, datasets, audiences, and compute pools.Dataset sample requests now honor the selected compute pool
Requesting a dataset sample from the dashboard previously posted an empty body toPOST /datasets/{dataset_id}/request-sample, so the compute pool picked in the context selector was ignored and the job fell back to the dataset’s or data plane’s default pool. The dashboard now sends the selected pool as compute_pool_id on the request, giving you control over what a sample costs and how long it takes. The fix applies everywhere a sample is triggered from the dashboard, including the dataset “Update sample” action, audience metrics, and match report pages. See Compute pools for how pool selection resolves against dataset and data plane defaults.Partial BETWEEN ranges in query templates now surface as a validation error
When you run a query template from the Data Studio catalog and fill in only one side of a BETWEEN range placeholder — the minimum but not the maximum, or vice versa — Data Studio now blocks execution with an inline NQL_E007 diagnostic explaining which bound is missing and how to clear it. Previously the unfilled bound was silently dropped during placeholder substitution, quietly changing the query you thought you were running. Leaving both bounds empty (skipping an optional range) and templates whose author hard-coded one bound (BETWEEN 5 AND {{max_age}}) are unaffected. Read more →Extended thinking for Model Inference and Agent Conversations
Model Inference and agent conversations can now ask the model to reason before it answers. Setinference_config.thinking on a Model Inference call, or thinking on a conversation’s defaults (at creation) or config_override (per run). The field takes one of three shapes: the bare string "disabled" (explicit off), { "type": "effort", "level": "low|medium|high" } for models that take an effort scale, or { "type": "budget", "budget_tokens": 4096 } for models that take a token budget — the floor is 1024 and the budget must be smaller than max_tokens, since thinking is spent from the same output budget as the answer. Omit the field on a Model Inference call to get the model’s own default behavior; in an agent conversation the platform fills in the model’s top default for you (effort: high, or a 1024-token budget on budget-only models).Support is per-model and per-data-plane, so the same setting can be accepted on one data plane and refused on another. A setting the target model does not accept returns a 400 rather than being silently downgraded: agent conversations reject the run with Thinking Setting Not Accepted, or Thinking Not Supported for models that are not offered thinking at all. Forcing a tool call — tool_choice of either any or specific_tool — cannot be combined with thinking, and a run that asks for both is refused as Thinking With Forced Tool Choice.Reasoning comes back on the assistant turn as reasoning content blocks — the working as words plus a provider signature, or a signature alone when the model withholds the text — or as redacted_reasoning blocks when the provider encrypts it. Both shapes can be replayed verbatim on a follow-up turn so the model continues exactly where it left off, or dropped if you only want the answer. When rendering a conversation, use each message’s final_answer_from field: it names the blocks that make up the reply, so a model narrating its working as ordinary text before answering does not show up as two messages.anthropic.claude-opus-5.0 supports extended thinking on Bedrock data planes. See Supported Models for per-model support, Running Model Inference for request examples, and Agent Conversations for the full content-block reference.ExecuteExplain workflow task
You can now forecast an NQL query from within a workflow using the newExecuteExplain task. The task runs an EXPLAIN statement without executing the underlying query, and outputs rows (estimated row count) and cost (estimated cost in micro-cents USD). Downstream tasks can read those values via export.as or ${…} expressions to gate expensive work — for example, only running ExecuteDml if the forecasted row count exceeds a threshold. See the task reference for parameters and an example.Previous Release Notes
Q3 2026
July 2026
Q2 2026
April – June 2026
Q1 2026
January – March 2026
Q4 2025
December 2025

