Skip to main content
Stories turn a chat analysis into a persistent, shareable document with live charts, tables, and narrative text. You can revisit it, refine it, and distribute it to your team.

Creating a Story

Stories are created directly from a chat conversation. Simply ask the agent to write one:
“Write a story about our new user growth since the last release.” “Create a story summarizing MRR trends over the past quarter.”
The agent will:
  1. Run the relevant queries against your data.
  2. Compose a structured document with narrative text, charts, and tables embedded inline.
  3. Open the story in a side panel next to the chat thread.
Story example with charts

Editing a Story

Once a story is open in the side panel, click the pencil icon to switch to edit mode. The editor is Notion-style: every block (text, chart, table) can be dragged and reordered using the grip handle on the left. You can edit text in rich markdown, rearrange sections, and remove blocks you don’t need. When you’re done, click Save: this creates a new version of the story. To discard your changes, click Cancel.

Renaming a story

The story owner can rename a story from its title in the header, without opening the editor. Click the title, type a new one, and the change is saved in place. The new title propagates everywhere the story is referenced - other story pages and the chat cards that link to it - and the story’s link stays the same, so shared URLs keep working.

Arranging charts into a grid

Charts and tables don’t have to stack one per row. In edit mode, each chart and table has a drag handle next to its edit pencil:
  • Move a block by dragging its handle anywhere in the story.
  • Put blocks side by side by dropping one beside another - they form a row. Drop a third into an existing row to add it.
  • Resize by dragging the divider between two charts in a row. Widths snap to clean fractions (halves, thirds, quarters), and charts in a row line up at the same height with aligned baselines. Labels and legends adapt as columns get narrower.
The agent can also build multi-chart grids with uneven widths directly when it composes a story.

Selecting multiple blocks

To move several blocks at once, select them first:
  • Cmd/Ctrl-click a block to toggle it in the selection.
  • Shift-click to select a range.
  • Esc, or a plain click, clears the selection.
Selected blocks are highlighted. Drag the handle on any selected block to move the whole selection together, keeping their order. This works with non-contiguous selections and with charts, tables, and whole grids. Press Backspace to delete exactly what you have selected - the highlighted blocks and grid columns, and nothing else. Removing one chart from a row leaves the rest of the row intact rather than wiping the whole row.

Tabs

A story can be split into tabs so one report can hold several views without becoming a long scroll. Tabs are written with <tabs> markup:
In edit mode, use the pencil button to add, rename, reorder, and delete tabs. Editing is tab-aware: you edit one tab at a time, and saving writes all tabs as a single new version. Stories without tabs are unchanged. You can ask the agent for tabs in plain English (“split this into an overview tab and a per-region tab”), and the Add to story action drops a chart into the tab you’re currently viewing. When a tabbed story is exported to PDF or HTML, the tabs are flattened into sequential titled sections so nothing is hidden in the static file.

Filters

Interactive filters are a beta feature and are off by default. Enable them on your deployment by setting BETA_STORY_FILTERS_ENABLED=true. Until then, the filter controls and the agent’s filter tooling are hidden.
Filters let a reader change what a story shows without editing it - pick a country, a date range, or a search term from a filter bar at the top of the story, and the charts and tables re-run their queries against the new selection. It turns one story into a self-serve view over your data. You usually don’t write the markup by hand: ask the agent (“add a country filter and a date-range filter to this story”) and it declares the filters and rewires the queries for you. The mechanics below are useful for understanding and reviewing what it produces.

Declaring a filter

A filter is declared with a <filter /> tag. Four types are available: For select and multi_select, give the options either from your data or as a fixed list:
When options come from table+column and your project has more than one database, add database_id so nao loads the options from the right connection.

Wiring a filter into SQL

A chart or table query opts into a filter with a {% filter <id> %} ... {% endfilter %} block, and drops the selected value in with {{ filters.<id>.sql }}:
  • {{ filters.<id>.sql }} expands to the selected value(s), safely quoted.
  • For date_range, the single {{ filters.<id>.sql }} already expands to 'start' AND 'end', so pair it with BETWEEN - don’t reach for .start, .end, or .value.
  • When a filter has no selection, its whole {% filter %} block is stripped before the query runs, so the query still works with nothing selected. Changing a selection re-renders and re-executes the affected charts and tables, and the same applies on live-story refreshes.
If the agent writes an invalid filter template, it comes back as a template warning to fix before the story is saved.

Versions

Every time you save a story, nao creates a new version. Use the version navigator in the story header (v1 / v2 / ...) to browse previous versions.
  • ← / → arrows step through versions.
  • When viewing an older version, a Restore button lets you roll back to that version (creating a new version from it).
Recipients who receive a shared link always see the latest version automatically.

Editing Charts

After a chart is generated, you can tweak its configuration without re-running the query. In a chat thread: click the pencil icon next to the chart’s download button. This opens an edit dialog where you can change:
  • Chart title
  • Chart type (bar, line, area, pie, etc.)
  • X-axis key and type
  • Per-series settings: data key, label, and color
Click Save to persist the changes. The updated chart config is written back to the database, and any cached chart image (used for Slack/Teams/WhatsApp previews) is regenerated on next request. In a story: hover over any chart block and click the pencil icon in the top-right corner. The same edit dialog opens. Saving creates a new story version with the updated chart tag, following the same versioning flow as text edits. Chart editing is only available to the chat or story owner. The edit button is hidden while the agent is running, on archived stories, in shared/read-only views, and when viewing older story versions.

Editing the Story Code

The story side panel has a Code view that shows the raw markdown behind the story. This view is now editable: you can modify text, chart tags, table tags, and grid blocks directly. The editor validates your changes in real-time:
  • Missing required chart attributes (query_id, chart_type, x_axis_key)
  • Invalid chart type or axis type values
  • Malformed or empty series definitions
  • Missing query_id on table blocks
  • Unterminated or unclosed tags
  • Out-of-range cols on grid blocks
Validation errors appear as red markers in the editor and a banner above it. The Save button is disabled until all errors are resolved. Press Cmd+S (or Ctrl+S) as a shortcut to save. Saving creates a new story version, just like editing in the visual editor. The code view is read-only on shared stories.

Adding a Chart from the Thread

When the agent produces a chart in the chat thread, you can embed it directly into a story:
  1. Open the story side panel.
  2. Ask the agent to add the chart: “Add this chart to the story.”
The chart is embedded as a live block: it renders with the same query data and can be repositioned in the editor like any other block.

Sharing a Story

Click the share icon in the story header to open sharing settings. You can share with:

Entire project

All members of your nao project can view the story via the shared link.

Specific people

Search by name or email and select individual team members.
Clicking Share & copy link copies the URL to your clipboard. Recipients open the story in their browser: they always see the latest version. Notify people The share dialog has a Notify people toggle that sends recipients an email letting them know about the story. It is off by default, so sharing is silent unless you turn it on. The same toggle is available when sharing a chat. The toggle only appears when SMTP is configured on your deployment. Without SMTP, no notification email is sent. Managing an existing share Once a story is shared, the share icon turns green. Click it again to:
  • Copy link - grab the URL again.
  • Update access - add or remove specific people (for specific-person shares).
  • Unshare - revoke access and disable the link entirely.

Sharing, forking, and text selection

Once a chat or story is shared, recipients can branch from it or ask targeted follow-ups without breaking the original. The same selection-based “Ask” flow also works on your own (non-shared) chats and stories. Continue chat On a shared chat, Continue chat opens a new forked chat that contains the full shared history. Each click creates a fresh fork, so the original conversation is never modified. The fork copies the messages only: stories that belong to the origin chat are not duplicated into your Stories library. Discuss story On a shared story, Discuss story opens a new chat with the story embedded at the top in editable form, ready to be questioned or refined. Ask about a selection Select any text inside a chat or a story and an Ask button appears above the selection. Clicking it opens an inline frame where you can quote the selection and ask a follow-up about that specific passage:
  • The quoted text shows up as a pending citation in the input until you send the question, so you can see exactly what the agent will see.
  • Once sent, the answer keeps a Go to original selection link that jumps back to the exact passage in the source chat or story.
  • The frame leaves a small persistent indicator when collapsed so you can reopen it later.
Selection-based asks work in four places:
  • Your own chats
  • Your own stories
  • Shared chats and stories you have received
  • The admin Chats replay view (asking about a past chat for debugging or follow-up)
All “Continue chat”, “Discuss story”, and “Ask” actions create new conversations under the current user’s account, so the original content stays untouched.

Exporting stories

Stories can be exported to PDF or HTML from the download button in the story header. Export works on your own stories and on shared stories, and you can pick any existing version from the version navigator before exporting. PDF
  • A4 page size, formatted for printing.
  • Charts are rendered as vector SVG so they stay sharp at any zoom level.
  • Tables are included up to 10 rows per table to keep the document readable; longer tables are truncated in the PDF (the full dataset is still available in the HTML export and in the live story).
HTML
  • Self-contained single file: no external assets, works offline.
  • Interactive chart tooltips are preserved, so recipients can hover data points in their browser.
  • Styled for print, so File -> Print in the browser produces a clean printed copy without separate theming.
Use PDF when you need a fixed-layout report to attach to an email or a doc. Use HTML when you want the story to stay interactive and portable.

Live Stories

By default, a story is a snapshot: charts and tables freeze the data that was returned when the story was created. Live stories keep the story connected to the underlying queries so the numbers refresh on a schedule (or on demand) without anyone having to rebuild the report.

Enabling live mode

  1. Open the story in the side panel.
  2. Click the settings icon in the story header.
  3. Toggle Live mode on.
  4. Pick a refresh strategy (see below).
  5. Save.
A green Live badge appears in the story header once it’s enabled, along with a “last refreshed” timestamp. Anyone who opens the shared link sees the most recently refreshed version.

Refresh strategies

When live mode is on, choose how freshness should work:
  • Manual refresh only - the story keeps its last refreshed values until someone clicks the refresh button in the header.
  • No cache (always fresh) - queries re-run every time the story is opened. Best for low-volume stories where you always want live numbers; avoid on expensive queries.
  • Scheduled refresh presets - every 5 minutes, hourly, daily, weekly, or monthly.
  • Custom schedule - type a schedule in plain English (e.g. “every weekday at 8am”, “first Monday of the month”) and nao converts it to cron, or paste a raw cron expression directly.
Each refresh re-runs every query block in the story against your connected warehouse, then updates the cached results that recipients see.

Refreshing the narrative

For live stories, you can also enable Regenerate the narrative in the same settings panel. When turned on, nao rewrites the text blocks with the updated numbers while keeping the layout intact:
  • Section titles stay in place.
  • Charts and tables stay embedded in the same positions.
  • Only the prose around them is rewritten so the commentary matches the new data.
This is what turns a live story into a real recurring report - the agent doesn’t just refresh the numbers, it explains them.

Access and refresh on shared stories

Live refresh respects the same access rules as the share itself:
  • For project-wide shares, any project member can trigger a manual refresh.
  • For specific-people shares, only the people on the access list can refresh.
  • Scheduled refreshes always run with the story owner’s permissions, so the data the recipients see is the data the owner is allowed to query.
If a query underlying a live story starts failing (schema change, permissions, etc.), the story keeps showing the last successful refresh and surfaces an error indicator in the header so you can investigate.

Stories Library

The Stories Library is your central hub for all stories. Access it by clicking Stories in the left sidebar. Stories Library The library is a folder explorer: it lists the folders in the current location, then the stories inside it. Stories you created and stories shared with you appear together, each card showing its author and last update. From the toolbar you can switch between a grid view (thumbnail cards) and a list view, search by title, and jump to archived items with See archives (Back to stories returns to the main view). Sort pills above the list order the current folder by Name, Owner, or Updated. Click the active pill again to reverse the direction. Your view and sort choices are remembered.

Folders

Organize stories into folders to keep the library tidy:
  • Create one with New folder in the explorer.
  • Each folder card has a menu with Modify (rename), Move to…, Archive, and Delete. Archived folders offer Restore folder.
  • Folders can be nested. Navigate down with a click and back up with the breadcrumb at the top of the explorer.
  • Drag and drop stories and folders onto another folder, or onto a breadcrumb level, to move them.

Pinned and Favorites

Two sections at the top of the library promote the items you reach for most. Each one is collapsible and only appears when it has content:
  • Favorites - favorite any story or folder for yourself. Favorites are per-user, so only you see yours.
  • Pinned - pinned stories surface at the top for everyone with access. Pinning is admin-only and applies to shared stories.

Bulk actions

Click Select in the toolbar to enter selection mode, then tick multiple stories and folders. A bar appears at the bottom with the number selected and the action available in the current view: Archive in the main library, Restore when browsing archives. Up to 100 stories and 100 folders can be handled in one action. Leave selection mode with Cancel.

Who can change what

Renaming, moving, archiving, and deleting a story or a folder is restricted to its owner and to project admins. Other members can open, favorite, and search items shared with them, but not reorganize them.

Usage analytics

Open Analytics from the story header menu to see who viewed, downloaded, forked, or favorited a story, and when it was last refreshed. See Asset analytics for the full breakdown.