Dataset Tools — MCP Tool Reference¶
Dataset tools implement the Bundle-scoped medallion data pipeline: a Bundle binds a Project, Questionnaire, and Campaign subset to one linear Bronze → Silver → Gold chain (see Bundle Tools for lifecycle operations). These tools extract survey responses into a Bundle's Bronze, derive its Silver (open-end coding, then post-stratification weighting on the coded case base), refine into Gold, and export in multiple formats. Quality is a Bundle concern, not a dataset one — see the quality tools in the Bundle Tools Reference.
Every dataset tool is Bundle-scoped
create_bronze_dataset and create_gold_dataset take a bundle_id, not a free-form questionnaire/campaign/source selection — the Bundle already carries that selection. Weighting a dataset other than a Bundle's own Bronze isn't offered by any tool.
Running the whole chain in one call
create_bronze_dataset → code_open_ends → create_gold_dataset is also available as a single run_bundle_pipeline call, which runs those same three tools and hands back a task_id to poll with get_task_status. Call the stages individually when you want to inspect the Bronze or review the coded dimensions before deriving further.
list_datasets¶
List datasets with optional filters.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
stage |
string |
No | — | Filter by stage: "bronze", "silver", or "gold" |
source_type |
string |
No | — | Filter: "campaign", "project", "upload", "weighted", or "refined" |
campaign_id |
string |
No | — | Filter by campaign ID |
limit |
integer |
No | 100 |
Maximum results to return |
Returns: { items: [...], count, limit }
get_dataset¶
Get a dataset's identity, lineage, metrics and status. This is the tool every pipeline step says to poll, so it is bounded — the response does not grow with the questionnaire.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
dataset_id |
string |
Yes | — | Dataset UUID |
Returns: id, name, description, stage, source_type, source_dataset_ids, bundle_id, campaign_id, questionnaire_id, strategy_id, row_count, column_count, has_weights, weight_column, weighted_at, weighting_method, weighting_config, quality_score, processing_status, processing_error, data_path, created_at, invalid_cells.
processing_error is the reason a stage ended in error — the derive's own coding_produced_no_columns: refusal, for example. It is null on every other status. Read it whenever processing_status is error: without it a poll can see that a stage failed and not why.
processing_error always carries the failure kind before the colon. A reason that names only identifiers, units, columns or a threshold comes back whole. A weighting refusal keeps the factor and column it names, but not the column values it quotes, because those can be respondent data. The Silver stage page in Balansor shows that reason in full. get_bundle_quality reports a failed stage's reason the same way, and so does get_task_status for a run_bundle_pipeline run that stopped at Silver.
weighting_config is the derive's record of what it did:
- the factors it weighted on, with their targets and adjustments;
- the convergence figures;
- how many rows the completeness threshold and the volunteer exclusion removed;
- which open-ended units it attempted, coded and lost, with the kind of each loss.
The column schema is not here — read it with get_dataset_schema. It is the one unbounded field a dataset carries (89 KB of a 90 KB response on a 192-column Silver), so a poll spent tens of thousands of tokens re-reading an unchanging schema to see a 7-byte status string.
invalid_cells is {column: count} for the cells the extraction could not read as the type their column stores and therefore stored as blank — a Radio item holding prose, say. {} means the extraction checked and found none; null means the dataset predates the check. A blank written this way is otherwise indistinguishable from a respondent's skip, so read it before drawing conclusions about missingness.
get_dataset_schema¶
Get a dataset's column schema: per column its dtype, the item_id, item_title and control_type it came from, its labels map (code → caption), and its roster/indicator provenance.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
dataset_id |
string |
Yes | — | Dataset UUID |
columns |
string[] |
No | — | Column names to return; omit for every column |
detail |
boolean |
No | true |
false returns column_index — each column's name and control_type — instead of column_schema |
Returns: { dataset_id, stage, column_count, column_schema, returned, unknown_columns }, with column_index ({ name: control_type }, null for row metadata) in place of column_schema when detail is false.
Two row-metadata columns describe how far each Survey got: _reached counts the items the respondent was shown (the one on screen included), and _completeness is the share of those they answered (answered ÷ reached). The Bundle's completeness threshold reads _completeness.
A Bronze also returns custom_attribute_keys: the respondent custom attributes it was extracted with, each one a column of the dataset (_custom_<key>). Only attributes that a Sampling Strategy factor or a Calibration Target of the Bundle names are extracted, so read this list before targeting an attribute: a key outside it is not in the dataset until a re-extract (create_bronze_dataset). An empty list means nothing was named. The field is absent for Silver and Gold, and for a Bronze extracted before keys were recorded; re-extract that one before weighting on an attribute.
column_count is the dataset's own, so with a columns filter it is larger than returned and the gap tells you how much of the schema you have not seen. A name you pass that the dataset does not have comes back in unknown_columns rather than being dropped, so a typo is distinguishable from a column the stage genuinely lacks.
On a real instrument, read it in two steps. A 293-column schema is ~134 KB, larger than most agent tool-result budgets. Call with detail: false first — the same 293 columns come back as a ~7 KB index — then pass the few names you need as columns for their full entries. Two moments need this tool at all: choosing Calibration Targets (which column, and what its labels map calls each code) and composing a Gold operations catalog (which columns exist to rename, remove or reorder). GET /api/v1/datasets/<id> is the other door and carries the whole schema — REST is the lane for large results.
create_bronze_dataset¶
Extract a Bundle's Bronze dataset. The Bundle already carries the questionnaire and its campaign subset — there is no free-form questionnaire/campaign selection at this tool. Previews are refused unconditionally, so no argument can fold a design-time test walk into the base. Re-running attaches the fresh Bronze to the Bundle chain and cascade-invalidates a downstream Silver/Gold (they become stale, not deleted — their recipes survive for a one-click re-derive).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | The Bundle whose Bronze to (re)extract |
include_demographics |
boolean |
No | true |
Include respondent demographic columns and the custom attributes the Bundle names |
Returns: { dataset_id, bundle_id, stage: "bronze", ... } with the extraction report, including invalid_cells (see get_dataset, which is where to read it on any later turn), custom_attribute_keys (the custom attributes written as columns) and empty_custom_attribute_keys (those among them no surveyed respondent carries, which is how a misspelt attribute name shows up).
Which respondent attributes are extracted. Age, gender and location are written for every row. A custom attribute is written only when a Sampling Strategy factor or a Calibration Target of the Bundle names it; every other key on the respondent record stays out of the dataset. A named attribute no respondent carries still gets a column, left empty. Naming a new attribute after an extraction therefore needs another create_bronze_dataset before a derive can weight on it.
include_demographics: false is refused when the Bundle names a custom attribute, with {"error": "named_attributes_require_enrichment", "detail": "..."} naming the attributes. A named attribute is written only together with the demographic columns, and a Bronze without it could never be weighted on it. Extract with the default instead.
code_open_ends (alias: derive_silver)¶
Derive a Bundle's Silver: code open-ended text into one labelled categorical column per selected dimension, then rake (post-stratification weighting) over the coded case base. This is the only tool that produces a Silver dataset, and it always sources the Bundle's own ready Bronze — weighting any other dataset is not offered by any tool.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | The Bundle whose Bronze to derive into Silver |
Returns: { silver_dataset_id, status: "processing", job_id } — the derive runs in the background. Poll get_dataset(dataset_id=silver_dataset_id) until processing_status is ready or error.
Coding runs over the units the Bundle's coding selection names — set it with set_coding_selection (see Bundle tools) — and, within each, over the dimensions a researcher selected in Balansor; a unit the analyst classified nominal is coded by exact value instead, with no model call and no dimension review. A selected unit that is unclassified or classified identifier stops the derive with coding_selection_unresolvable naming it. When nothing is selected, coding is skipped and weighting runs directly on the Bronze data; that is an ordinary outcome, not an error. A selected unit whose dimensions nobody has reviewed produces no coded column and the derive still succeeds — check awaiting_review on get_bundle_coding before treating the result as complete. A derive is refused when a Calibration Target names a coded column whose dimension (weighting_factor_dimension_deselected) or whose whole unit (weighting_factor_deselected) the Bundle no longer selects — re-select it or drop the factor. A derive is also refused with weighting_attributes_not_extracted when it would weight on a respondent custom attribute the Bronze was not extracted with (see below). derive_silver is registered as a second tool name for the same operation — agent prose that says "derive silver" and prose that says "code open ends" both resolve to it.
A derive that codes nothing ends error, not ready. One unit that cannot be coded is left uncoded and the rest still code, but if every unit the derive attempted produced no column, the Silver reaches processing_status: "error" with processing_error reading coding_produced_no_columns: followed by each unit key and why it yielded nothing. Treat it as terminal — a re-run meets the same units and produces the same nothing, so fix the cause (re-extract a Bronze whose text columns are missing, or repair the codebook in Balansor) before deriving again. This is distinct from an unreachable embedding backend, which the job retries on its own before any error is written.
Weighting on a custom attribute the Bronze does not hold is refused, by name. The code is weighting_attributes_not_extracted and the detail names each attribute and its column. It arrives one of two ways, depending on the Calibration Targets:
- When the targets are the whole weighting set (
use_strategy_factorsisfalse, which is the case afterset_calibration_targets(factors=[...])or once a researcher has opened the Silver page), the tool itself answers{"error": "weighting_attributes_not_extracted", "detail": "..."}and no job starts. - When the targets still follow the Sampling Strategy, the tool returns
processingand the Silver endserrorbefore any coding, withprocessing_erroropeningweighting_attributes_not_extracted:.
Either way the fix is the same: run create_bronze_dataset again, then derive. If no respondent of the Bundle carries an attribute by that name, the name is wrong; correct it in the Calibration Targets or the Sampling Strategy, since a re-extract would only add an empty column. Compare the Bronze's custom_attribute_keys (get_dataset_schema) with the attributes you intend to weight on to see this coming. An attribute the Strategy names without weighting on it never blocks a derive; its factor reads as not measurable in get_bundle_quality until a re-extract.
Coding before weighting
Askalot codes open-ended answers into labelled categorical columns first, then weights once over the finished coded case base — this deliberately differs from a "weight first" workflow. A coded dimension becomes available as a weighting variable in the same derive.
create_gold_dataset¶
Refine a Bundle's ready Silver into its Gold. Always sources the Bundle's own Silver; replaces any prior Gold in the chain.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | The Bundle whose Silver to refine |
name |
string |
No | — | Name for Gold dataset. Defaults to "{bundle_name} — Gold" |
operations |
object[] |
No | — | The Gold recipe for this call. Omit it to build from the Bundle's stored recipe (the layout saved on the Gold page; read it with get_bundle). Passing it overrides the stored recipe for this call only; nothing is stored |
With no operations (none passed and none stored) the Gold is a copy of the Silver. With operations, the Gold differs from the Silver only by what they say: every column not removed is kept, in the Silver file's order, with its full schema entry (question text, value labels).
The operations recipe¶
An ordered list of rows. A row names columns of the Silver file — never a name a rename introduces. The one exception is a reorder entry, which may also name a column the recipe adds. get_dataset_schema lists the columns the Silver's schema names: answers, coded dimensions and weights. The Silver file also holds columns it does not list: row-metadata columns (such as _survey_id and _response_timing) and enrichment columns, the respondent attributes extraction added (_demographic_*, _custom_*). They are kept in the Gold like any other column, and a recipe may address them by name too.
op |
Fields | Effect |
|---|---|---|
rename |
column, to |
Serve column under the name to. The last rename of one column wins |
remove |
column |
Leave column out of the Gold |
alias |
column, to |
Serve column once more, under the name to. One row per extra name; a column may have several. column must itself be served |
reorder |
order (list of names) |
The named columns come first, in this order; every column order omits follows in its default position. An entry is a Silver column, an alias's to or a computed name, each at most once. It never drops a column. Only the last reorder row takes effect |
compute |
name, kind, plus the kind's fields |
Add a column called name |
Default positions, for every column order does not name: the Silver columns in the Silver file's order, then the aliases in recipe order, then the computed columns in recipe order. To put an alias or a computed column between two Silver columns, name it in order together with the columns before it.
compute kinds:
kind |
Fields | Effect |
|---|---|---|
arithmetic |
left, operator ("+", "-", "*", "/"), right |
An operation between two columns, each cell read as a number. A cell that is not a number, and a division by zero, give an empty value |
recode |
column, buckets (list of [min, max, label]) |
Each bucket maps the values from min to max, inclusive, to label; each cell is read as a number. A cell that is not a number, or that no bucket holds, gives an empty value. min and max are finite numbers with min not above max; label is non-empty text |
concat |
columns (list), separator (text) |
Join the columns in order |
formula is reserved for a future release and is refused by name, both as an op and as a kind.
Rules the recipe must satisfy:
- What a compute reads. Computes run on the whole Silver, before any column is renamed or removed. An input is a Silver column (served, renamed or removed alike) or the
nameof acomputerow earlier in the list, never an alias. Where a computed column sits in the file does not change what it may read. - Alias and computed names. An alias's
toand a computednamemust differ from every Silver column name, removed ones included. - An alias needs its column. An
aliasof a column the recipe removes is refused: to serve a column under one new name only,renameit. - New names. A name the recipe makes (a
renametarget, an alias or a computedname) may not be blank and may not start or end with whitespace. - Output names. The names the Gold ends up with are each served column under its final name, plus every alias and every computed name. A name the recipe makes must differ from every other output name ignoring letter case:
Scoreandscorecollide. Two Silver columns the recipe leaves under their own names are never refused, even when they differ only by letter case; that is the Silver's own naming. - At least one column. A recipe that removes every Silver column and computes none is refused.
- The weight column. The Gold's weights are the Silver's weight column: renamed, it stays the weight column under its new name; removed, the Gold carries no weights, even when another column is renamed to its old name. An alias of the weight column is a second copy of its values and is never the Gold's weight column.
rename,remove,aliasandreorderrows may come in any order among themselves. Order matters amongcomputerows, and amongaliasrows only for their default position.
[
{"op": "rename", "column": "age", "to": "Age"},
{"op": "remove", "column": "_response_timing"},
{"op": "alias", "column": "age", "to": "age_at_interview"},
{"op": "reorder", "order": ["_survey_id", "age", "age_band"]},
{"op": "compute", "name": "age_band", "kind": "recode", "column": "age",
"buckets": [[18, 34, "18-34"], [35, 54, "35-54"], [55, 120, "55+"]]}
]
Returns: { gold_dataset_id, name, stage: "gold", bundle_id, row_count, column_count, skipped }
skipped lists the recipe entries the build set aside because the Silver does not have their column, each as { "op": "remove" | "reorder", "column": "<name>" }. A recipe can outlive the Silver it was written for: a remove or a reorder entry naming a column the Silver no longer has is skipped and reported here rather than refused. It is an empty list when nothing was skipped.
Refusals (each { "error": "<code>", "detail": "..." }; no Gold is published):
error |
When |
|---|---|
silver_not_ready |
The Bundle has no ready Silver, its file cannot be read, or the Silver changed while the Gold was building. Derive the Silver, then call again |
invalid_operations |
The recipe breaks a rule above, checked before any build: an unknown or reserved op or kind, a missing field, a blank or padded new name, a malformed bucket (a bound that is not a finite number, or min above max), a name listed twice in one reorder, a rename or an alias of a column the Silver lacks, an alias of a removed column, a compute input that is neither a Silver column nor an earlier computed name, an alias or computed name equal to a Silver column, a name the recipe makes that differs from another output name only by letter case, or a recipe that leaves no column. detail names each column involved |
build_failed |
The recipe passed the checks and a computation could not be carried out on the data. detail carries the reason |
layout_changed |
Only when building from the stored recipe: the recipe was saved again (on the Gold page) while this Gold was building. The built Gold is discarded and the Bundle's earlier Gold, built from the recipe before that save, is no longer ready; call again |
gold_superseded |
A concurrent build replaced this Gold; call again |
Stage validation: The Bundle's Silver must be ready; a missing or non-ready Silver returns an error rather than falling back to Bronze.
export_dataset¶
Export a dataset in the specified format.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
dataset_id |
string |
Yes | — | Dataset UUID |
format |
string |
No | "csv" |
Export format: "csv", "xlsx", "spss", "parquet", "rds", or "json" |
Returns: { dataset_id, format, download_url, rows, columns, file_size_bytes }. The exported file is never returned inline — download_url is a short-lived link (expires a few minutes after minting) that lets you fetch the file directly over HTTPS with no further authentication; it can be reused any number of times until it expires. Request a fresh export if the link has expired.
Export Formats¶
| Format | Extension | Description |
|---|---|---|
csv |
.csv |
Universal format for most tools |
xlsx |
.xlsx |
Excel with summary and schema sheets |
spss |
.sav |
SPSS with variable and value labels |
parquet |
.parquet |
Columnar format with full metadata (Snappy compression) |
rds |
.rds |
R — categoricals arrive as factors, value labels as factor levels |
json |
.json |
One document: {dataset, column_schema, rows}. Rows keep the stored answer codes; each column's value labels are in column_schema. Missing values are null |
delete_dataset¶
Delete a dataset and optionally its data file.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
dataset_id |
string |
Yes | — | Dataset UUID |
delete_file |
boolean |
No | false |
Also delete the Parquet data file |
Returns: { deleted: true, dataset_id, dataset_info: { name, stage, row_count, data_path }, file_deleted }
Error Handling¶
Stage Validation¶
The Bundle pipeline enforces stage progression and readiness — a stage can't be skipped or exported while stale:
| Operation | Requirement | Error |
|---|---|---|
code_open_ends / derive_silver |
Bundle's Bronze must be ready |
{"error": "bronze_not_ready", "detail": "Extract a ready Bronze first"} |
code_open_ends / derive_silver |
The Bronze must be of the current extraction schema version | {"error": "bronze_schema_stale", "detail": "..."}. Re-extract Bronze (create_bronze_dataset), then derive |
code_open_ends / derive_silver |
Every custom attribute the derive weights on must have been extracted into the Bronze | {"error": "weighting_attributes_not_extracted", "detail": "..."}, naming the attributes. Re-extract Bronze, then derive |
create_bronze_dataset |
include_demographics must stay true when the Bundle names a custom attribute |
{"error": "named_attributes_require_enrichment", "detail": "..."}, naming the attributes |
create_gold_dataset |
Bundle's Silver must be ready |
{"error": "silver_not_ready", "detail": "Derive a ready Silver first"} |
create_gold_dataset |
The recipe must be valid for the Silver's columns | {"error": "invalid_operations", "detail": "..."}, naming the rows and columns. See create_gold_dataset |
export_dataset |
Dataset must be ready (not processing/invalidated/error) |
{"error": "not_ready", "detail": "Dataset is '{status}', not ready — re-derive the stage before exporting."} |
export_dataset |
A Silver's coded questions must all be reviewed: a question awaiting dimension review has no coded column yet | {"error": "coding_awaiting_review", "detail": "..."}, naming the questions. Review the dimensions in Balansor, re-derive, then export |
export_dataset |
The dataset's data file must exist | {"error": "file_missing", "detail": "The dataset's data file is missing — re-derive the stage."} |
Common Errors¶
| Scenario | Response |
|---|---|
| Dataset not found | {"error": "Dataset {id} not found"} |
| Bundle not found | {"error": "not_found", "detail": "Bundle {id} not found"} |
| Strategy not found | {"error": "Sampling strategy {id} not found"} |
| No data file | {"error": "Dataset {id} has no data file"} |
| Invalid export format | {"error": "Invalid format. Allowed: csv, xlsx, spss, parquet, rds, json"} |
| No completed surveys | {"error": "no_completed_surveys", "detail": "..."} — widen the campaign selection or wait for more completions |
| Bundle selects no campaign | {"error": "no_campaigns_selected", "detail": "..."} — a Bundle's measurement base is the surveys of the campaigns it selects; assign at least one |
| Extraction could not write the dataset | {"error": "extraction_failed", "column": "q_x", "detail": "..."} — one column holds values that cannot be unified into a single type. The offending value is deliberately omitted (it is a respondent's answer); inspect that column's raw values, correct the source responses, and re-extract |