Per-Row Dynamic Metadata Filters in Agentic Table
4 min read
Configure Agentic Table column search filters that resolve per row at run time, so different sheets (or rows) can search different slices of the knowledge base from a single shared pipeline config.
The problem this solves
An Agentic Table space shares one pipeline config across every sheet in the space. The search filter (search_config.metadata_filter) therefore lives at the space level: one space = one static filter. If several sheets in the same space each need to search a different slice of the knowledge base — for example "only documents valid as of this sheet's cutoff date" — a static filter cannot express it, especially when sheets are created programmatically via API.
Per-row dynamic metadata filters fix this by letting the filter reference a token instead of a hardcoded value. The token is resolved from the metadata of the row being processed, at run time.
How it works
The filter references a token instead of a hardcoded value, and the token is resolved from the row's metadata at run time. Walking through it with one running example — "only search documents valid as of this sheet's cutoff date":
1. Write a token in the filter. In the column's metadata_filter, put a <row.metadata.KEY> token in the value field instead of a literal value:
"metadata_filter": {
"path": ["validAsOf"],
"operator": "greaterThanOrEqual",
"value": "<row.metadata.cutoff_date>"
}2. Set the value as metadata. Set cutoff_date as sheet metadata (applies to the whole sheet) or row metadata (per row), via the sheet-creation UI or the metadata API:
cutoff_date = 2026-01-01T00:00:00Z3. Sheet metadata materializes onto rows. When a row is created, the sheet's metadata is copied onto it; whenever sheet metadata changes, node-chat re-syncs it to every row. Row metadata is therefore the ground truth at processing time.
4. Token resolves at time of search. When a cell is processed, the Agentic Table logic replaces <row.metadata.KEY> in the filter with the current row's metadata value, then runs the search with the resolved filter:
"value": "<row.metadata.cutoff_date>" → "value": "2026-01-01T00:00:00Z"Because sheet metadata is automatically copied to every row, setting a value once per sheet covers the per-sheet use case for free. You only use row metadata directly when you want to override individual rows.
Configuration
1. Space pipeline config (once)
In the space's search_config, reference the token in the filter value:
"search_config": {
"scope_ids": ["scope_xxxx"],
"metadata_filter": {
"path": ["validAsOf"],
"operator": "greaterThanOrEqual",
"value": "<row.metadata.cutoff_date>"
}
}More filter shapes you can use in metadata_filter:
Static value (no token) — a literal value passes through unchanged:
"metadata_filter": {
"path": ["validAsOf"],
"operator": "greaterThanOrEqual",
"value": "2026-01-01T00:00:00Z"
}Nested and / or with tokens — tokens resolve anywhere in the UniqueQL structure, so you can mix tokenized and static conditions:
"metadata_filter": {
"and": [
{
"path": ["validAsOf"],
"operator": "greaterThanOrEqual",
"value": "<row.metadata.cutoff_date>"
},
{
"path": ["fund"],
"operator": "equals",
"value": "<row.metadata.fund_id>"
}
]
}2. Per sheet
Set the sheet metadata key referenced by the token. However it is set, node-chat materializes it onto every row of the sheet. There are two ways to do this:
Option A — Sheet-creation UI
When creating a sheet in the Agentic Table, set the sheet metadata (e.g. cutoff_date) in the sheet-creation flow. This is the simplest path for users creating sheets manually and requires no API access.
Option B — API
For programmatic / bulk sheet creation, set the metadata via the existing createMagicTableSheetMetadata / createAndDeleteManyMagicTableSheetMetadata mutations. No new API surface is required.
cutoff_date = 2026-01-01T00:00:00Z3. Per row (optional override)
To make a single row search a different slice, override that row's metadata via the row-metadata API (for example a different cutoff_date per fund or per question). All other rows continue to use the value inherited from the sheet.
Applying metadata changes: re-run the row
The <row.metadata.KEY> token is resolved only when a row is processed, not when metadata is saved. Adding or changing metadata (sheet or row) persists immediately to the database but does not re-execute the search on existing cells on its own.
After changing metadata that a filter token depends on, the user must Re-run Row for the new value to take effect. Existing answers are not recalculated automatically.
Ways to trigger a re-run (all re-fetch the row's metadata and re-resolve the token before searching):
UI — row context menu → Re-run Row.
GraphQL —
rerunDueDiligence(dueDiligenceId, rowOrder).Public API —
POST /magic-table/:tableId/row/:rowOrder/rerun.
Re-run operates on the whole row; there is no single-cell re-run. Setting metadata before the row is first processed needs no extra step — the token resolves on that initial run.
Token reference
Token | Resolved from | Granularity |
|---|---|---|
| The current row's metadata (inherited from sheet metadata, or overridden per row) | Per row (and therefore per sheet) |
This token composes with the platform's existing Smart Rules variables (<T-N>/<T+N>, <userMetadata.KEY>, <toolParameters.KEY>). On the subagent path the platform tokens still resolve afterwards.
Value handling and formats
Dates are normalized to
YYYY-MM-DDTHH:MM:SSZ. BothYYYY-MM-DDand full ISO 8601 inputs are accepted.Fail-open on missing/invalid values. If the referenced metadata key is missing or its value cannot be parsed, that filter statement is dropped and a warning is logged. The search runs as if the condition were not there — this avoids silently returning zero results for the cell.
Static filters are untouched. Filters with no tokens pass through unchanged.
Nested logic is supported. Tokens are resolved throughout the UniqueQL structure, including nested
and/orstatement lists.
Column type coverage
Token resolution is wired into both Agentic Table column paths:
Custom columns — the resolved filter is merged before the
exclude_content_ids/scope_idsAND-merge.Subagent columns — the resolved filter is AND-merged into
scope_rules.
Worked example: per-sheet cutoff date
Space config uses
"value": "<row.metadata.cutoff_date>"with operatorgreaterThanOrEqualon pathvalidAsOf.Sheet A sets
cutoff_date = 2026-06-30; Sheet B setscutoff_date = 2026-12-31(via the sheet-creation UI or the API).Cells in Sheet A only cite documents valid on/after 2026-06-30; cells in Sheet B use the later cutoff — from the same space and the same pipeline config.
To special-case one question, override
cutoff_dateon just that row, then re-run the row; only that row's citations shift.
Out of scope
<row.COLUMN_NAME>tokens that read cell values (free-text date parsing from row cells).<T-N>relative-date enrichment for column-level filters.