Skip to content
sandadocs

MCP tool reference

Every tool sanda's MCP server offers, with the scope it needs, its parameters and what it does. Generated from the tool definitions the server runs.

This is every tool sanda's MCP server can offer an assistant. The names, titles, scopes and parameters below are read from the same tool definitions the server runs, so they cannot drift from what a client sees.

How a credential is offered tools

tools/list returns the tools this credential may use, not every tool. A tool is left off the list, and refused if called anyway, when any of these is true:

  • The credential does not hold the scope. Each tool needs one scope. A wider scope includes a narrower one, so a credential holding sql:write also gets everything sql:run and query:run give. See scopes.
  • The edition does not include it. The sanda search tools (search_documents and every tool needing search:manage) are on Standard and Enterprise.
  • The person behind it is no longer allowed. A privileged scope is honoured only while the person who granted it is an owner or admin.
  • The workspace is closed. Then only the tools that read remain: asking questions, looking up the docs and seeing connections.

action_status is offered only to a credential that holds a scope one of the held tools needs. See permissions and approvals.

A token created with no extra switches is offered search_fluid, describe_table, run_query, search_documents and search_docs.

Reading an entry

Each entry starts with the tool's name (the string a client sends), then a row of markers: the tool's title, what kind of tool it is, the scope it needs and, where it applies, the editions that include it. The kind comes from the tool's annotations, which a client can use to skip a confirmation prompt or add one:

  • Read only means the tool changes nothing, so calling it again is safe.
  • Writes means the tool changes something.
  • Destructive means the tool can remove or overwrite something, such as taking tables off the map, dropping a view or committing SQL.

The parameter table lists every top-level parameter with its type, whether it is required, and what it means. Where a parameter is an object or a list, its fields are described in the parameter's own text or in the entry's notes.

Limits every tool shares

Limit Value
Rows or hits returned by run_query, run_sql and search_documents At most 50
Rows returned by execute_sql 50 by default, at most 500
Rows loaded or added in one load_rows or append_rows call 10,000
Request body 1,000,000 bytes
Time a tool holds a call open when it builds or runs something 55 seconds. A longer job belongs on a schedule
Time a run_query or run_sql statement may run 20 seconds
Held actions a workspace may have waiting 50

A tool that cannot answer returns a sentence and isError: true rather than a failure, for example that two tables would fan out or that a column does not exist. An assistant is expected to read it and try again differently.

Resources

sanda also serves two resources for clients that read them. Both need fluid:read, like search_fluid. A credential without it is listed no resources, and reading one is refused the way a tool is, with a step-up challenge for a connected app:

Resource What it holds
becca://fluid/brief The one-page map of the workspace: its tables and the names of every metric, dimension, filter and category. Read this first
becca://fluid/context Everything in full: every column, expression, sample value and join. Large, so prefer the brief plus tool calls

cherry and MCP

cherry, the console's own agent, uses most of these tools too, under the signed-in person's role and the capabilities switched on under Settings · cherry. It is not offered execute_sql, set_intake, append_rows or the tools that manage sanda search, and action_status is for MCP credentials alone. cherry also has tools of its own for building reports, which are never served over MCP. See cherry.

Read the fluid and your data

Find what the workspace has modelled, look closely at a table, ask a question and search the text inside rows.

search_fluid

Search the fluidRead onlyfluid:read

Finds what the workspace has modelled: metrics, dimensions, named filters, tables and columns. An assistant calls it before using any name it has not already seen in the workspace brief or an earlier answer, because a metric found here is the definition the business agreed on.

Parameter Type Required Description
query string No A word or fragment to match against names, synonyms, descriptions, definitions and column names. Leave it empty to list everything.
kind string, one of all, metrics, dimensions, filters, tables, columns No Narrows the search to one kind of thing: all (the default), metrics, dimensions, filters, tables or columns.

The answer is text, one line per match. A search that finds nothing says so, which is an answer: try a synonym before concluding the question cannot be asked.

describe_table

Describe a tableRead onlyfluid:read

Describes one table in full: every column with its type, the grain, the primary key, the time column, the metrics and dimensions measured on it and every join it can follow. An assistant calls it before it names a column.

Parameter Type Required Description
table string Yes The table's business name, its schema-qualified relation or its identifier, for example order details, mapping.order_details or order_details. Case and separators do not matter.

A table that is not on the map is not found, and the answer names the closest tables that are.

run_query

Run a composed queryRead onlyquery:run

Answers a question with rows. The assistant names what it wants by reference (metrics, dimensions, filters, conditions) and sanda composes the SQL, resolves the joins and runs it, so a number means what the workspace says it means. This is the tool for almost every question.

Parameter Type Required Description
metrics array of strings No Metric names from search_fluid. These are the numbers the business has defined.
dimensions array of strings No Dimension names to break the numbers down by.
granularity string, one of day, week, month, quarter, year No How coarsely to group a time dimension: day, week, month, quarter or year. Empty means one row per underlying value.
columns array of objects No Raw columns for questions no metric covers, each as a fully-qualified schema.table.column and an aggregate (sum, avg, min, max, count, count_distinct, or empty to list the value). A well-behaved assistant says when it has leaned on one, because the answer rests on a column name rather than an agreed definition.
filters array of strings No Named filter names from search_fluid: conditions the workspace has already agreed on.
conditions array of objects No Extra narrowing for this question only. Each condition has a field (a dimension name or a fully-qualified column), an op, a list of values and an optional named period in relative. Operators are the same ones the console's filters use.
order_by array of objects No How to sort, first entry first, as by (a metric, dimension or column already in the query) and direction (asc or desc). Left out, a number broken down by a label comes back largest first and a time series in time order.
limit integer No How many rows to return. The default and the maximum are both 50.

Operators and named periods are listed in filters. The schema marks every key of a condition as required, so send all four: use an empty list for values and an empty string for relative when they do not apply. relative is only for in_range and names a period such as last_month; sanda resolves it in UTC and states the window it used.

JSON
{
  "metrics": ["net revenue"],
  "dimensions": ["region", "issue date"],
  "granularity": "month",
  "conditions": [
    { "field": "issue date", "op": "in_range", "values": [], "relative": "last_6_months" }
  ],
  "limit": 10
}

The answer is text: a table of rows, the window any named period resolved to, and the SQL sanda composed. Metrics measured on different tables can be asked for together, and each is counted on its own table, so revenue beside order count counts every order once. Each metric keeps its own condition. Two tables that would fan out if joined come back as a sentence explaining the refusal, not as a wrong number. A column whose name looks like it holds a secret is never returned.

search_documents

Search the text inside the rowsRead onlyquery:runStandard · Enterprise

Finds rows by what their text says, for questions about wording rather than about a number, such as which invoices mention water damage. It searches meaning and words together and answers with rows and never a total.

Parameter Type Required Description
query string Yes What to look for, in words. A phrase or a sentence works better than a keyword, because meaning is half of how this searches.
service string No Which search service to search, by name. Leave it out when the workspace has only one.
k integer No How many rows to return. The default is 10 and the maximum is 50.
filters array of objects No Narrows the search by a service's attribute columns, each as column, op (eq, neq, in, contains, gt, gte, lt, lte) and value. Only columns the service declares as attributes can be filtered.

Every hit carries the value of its table's key column. To turn hits into a number, take those keys and call run_query with a condition on them.

This is a question of the data, so it needs only query:run, and it is offered to any client holding that scope on an edition with sanda search (Standard and Enterprise). If the workspace has no search service yet, a call answers that there is nothing to search. Managing services is a separate, privileged scope (search:manage).

run_sql

Run SQL you wroteRead onlysql:run

Runs one read-only SELECT the assistant wrote itself. It is the fallback for a question run_query cannot express, such as a window function or a cohort. It bypasses the workspace's own definitions, so the number is the assistant's rather than the business's.

Parameter Type Required Description
sql string Yes One PostgreSQL SELECT (a leading WITH is fine). No semicolon, no comments, no DDL or DML. Every relation must be one describe_table listed.
why string Yes One sentence naming what run_query could not express. It is required, and a client is expected to show it to the person beside the answer.

Runs through the reader role inside a read-only transaction, returns at most 50 rows and stops after 20 seconds. A column whose name looks like a credential or an identity number is refused, whatever the statement calls it.

A default integration token does not see this tool at all: it is listed only for credentials granted sql:run. cherry is offered it only when its sql capability is switched on under Settings · cherry.

search_docs

Search the sanda docsRead onlyfluid:read

Searches sanda's own documentation at docs.sanda-os.com.au for how the product works and how to do something in it. An assistant calls it for a question about sanda, never for a question about your data, and gives you the link it used.

Parameter Type Required Description
query string Yes What to look for, in a few words, for example connect xero, incremental sync or invite a member.
limit integer No How many sections to return, from 1 to 5. The default is 3.

The answer is text: for each match, the page and section title, the address of the section, and the section's own words. A search that finds nothing says so and points at the docs site.

This reads public pages and nothing of the workspace's data, so it needs only fluid:read, and a call is never held for approval. It makes no model call, so it costs nothing on the AI limit. cherry uses it too, to answer how-to questions with a link.

See and refresh the workspace

Check which connections and warehouses exist, how fresh and how full they are, and start a sync.

list_connections

List connectionsRead onlyworkspace:read

Lists every data connection in the workspace: the system it pulls from, its health, when it last synced, how many rows it has landed, its schedule and where it lands. An assistant uses it to answer whether the data is fresh.

Takes no parameters.

Never returns a credential.

connection_status

One connection, in detailRead onlyworkspace:read

Shows one connection's last ten runs with status, rows, duration and any error text, and the dataset its rows became. While a sync is running it also reports the stage, rows read so far, the average rate and each stream's state.

Parameter Type Required Description
connection string Yes The connection's name or id, from list_connections.

list_warehouses

List warehousesRead onlyworkspace:read

Lists each warehouse with its storage against its limit, compute, table and row counts, and whether ingest is paused. An assistant uses it before a large load to check how much room is left.

Takes no parameters.

Never returns a connection string.

sync_now

Start a syncWritesworkspace:manage

Starts one connection's sync now instead of waiting for its schedule. The rows land in the background, and connection_status shows how far the run has got.

Parameter Type Required Description
connection string Yes The connection's name or id, from list_connections.

A sync reads from the source system and lands rows in the warehouse, so it costs compute like any other sync. This is the only tool that drives a connection.

Write the semantic fluid

Put landed tables on the map, define metrics, dimensions, filters and relationships, and review what sanda proposed. Definitions go live at once.

list_warehouse_tables

List tables in the warehouseRead onlyfluid:write

Lists every table that has landed in the warehouse, with its columns, a row estimate and whether it is already on the semantic map. This is the raw layer describe_table cannot see, and the first step before import_tables.

Parameter Type Required Description
only string No One schema-qualified relation to describe on its own, for example raw.xero__invoices. Leave it empty to list them all.

import_tables

Put warehouse tables on the mapWritesfluid:write

Puts landed tables on the semantic map so the fluid can query them. sanda reads each table's shape, publishes a view over the columns chosen and files it under its connector's dataset, then reports the kind, key and time column it guessed and the joins it drew.

Parameter Type Required Description
relations array of strings Yes Schema-qualified relations to add, for example raw.xero__invoices, from list_warehouse_tables. Up to 60 at a time.
columns object No Optional. For each relation, the column names to keep. The key and time columns are always kept. Leave a relation out to take every column.
kinds object No Optional. For each relation, fact or dimension, when the caller already knows. A fact records things that happened (orders, invoices) and a dimension records things that are (products, customers). This overrides sanda's guess.
relationships string, one of infer, none No infer (the default) draws joins that the column names assert, such as a column named exactly like another table's key. none draws none. Ambiguous matches are reported and never drawn.

Importing a table that is already on the map refreshes it and does not duplicate it. Nothing here changes the rows in the warehouse.

set_table_kind

Mark a table as a fact or a dimensionWritesfluid:write

Says whether a table on the map is a fact or a dimension. Getting this right is what stops a query summing a price list. An assistant calls it after import_tables when sanda's guess was wrong.

Parameter Type Required Description
table string Yes The table as the fluid names it, its relation or its identifier. Case and separators do not matter.
kind string, one of fact, dimension Yes fact or dimension.

retire_tables

Take tables off the mapDestructivefluid:write

Takes tables off the semantic map. The rows in the warehouse are untouched, but every metric, dimension, filter and relationship written against those tables goes with them.

Parameter Type Required Description
tables array of strings Yes Business names, relations or identifiers, as import_tables named them.

Destructive to the model, not to the data. A well-behaved assistant reads the table names back to the person before calling it. cherry always asks first, whatever its mode.

define

Define something in the fluidWritesfluid:write

Creates or replaces one definition in the fluid, live at once: a metric, dimension, filter, relationship, alias, category or dataset, or a statement of what a table already on the map means.

Parameter Type Required Description
kind string, one of metric, dimension, filter, relationship, alias, category, dataset, table Yes What to define: metric, dimension, filter, relationship, alias, category, dataset or table.
definition object Yes The fields for that kind, as an object. Each kind's fields are listed in the notes below.

A definition with the same name replaces the old one, and names are matched without regard to case. The reply names the table the definition landed on and says if an expression uses a column that table does not have.

Kind Fields
metric name, table, expression (one SQL fragment over that table's own columns, for example sum(total_ex_gst)), and optionally aggregation (sum, avg, count, count_distinct, min, max, ratio, custom), filters, unit, format (currency, percent, integer, decimal, duration), description, synonyms
dimension name, column (as schema.table.column), and optionally kind (categorical, time, geo, boolean, numeric), description, synonyms
filter name, table, expression (a named WHERE condition), optionally description
relationship left_column, right_column, key (the business name of the shared identity), optionally left_cardinality, right_cardinality (one or many), description
alias column, term, optionally description
category name, optionally description
dataset name, optionally description
table table, and any of description, grain, primary_key, time_column, kind, name. Only the fields given change
JSON
{
  "kind": "metric",
  "definition": {
    "name": "net revenue",
    "table": "invoices",
    "expression": "sum(total_ex_gst)",
    "format": "currency",
    "synonyms": ["turnover"]
  }
}

list_proposals

List proposals awaiting reviewRead onlyfluid:write

Lists everything sanda's own learning pass has proposed and nobody has signed off: tables, metrics, dimensions, filters and relationships. Proposals are invisible to queries until they are accepted.

Takes no parameters.

review_proposal

Accept or reject a proposalWritesfluid:write

Accepts or rejects one proposal. An accept may carry corrections, so a nearly right proposal is one call. A relationship is decided on both sides together.

Parameter Type Required Description
kind string, one of metric, dimension, filter, mapping, table, category, dataset, glue Yes What is being reviewed: metric, dimension, filter, mapping, table, category, dataset or glue.
id string Yes The proposal's id, from list_proposals.
action string, one of accept, reject Yes accept or reject.
edits object No Optional corrections applied when accepting, in the same shape define takes for that kind.

Accept a relationship's tables before the relationship.

delete_definition

Delete a definitionDestructivefluid:write

Removes one metric, dimension, filter, mapping, category, dataset or glue definition from the fluid for good. Redefining with define is better than deleting and recreating, because a delete loses the definition's history.

Parameter Type Required Description
kind string, one of metric, dimension, filter, mapping, category, dataset, glue Yes What to remove: metric, dimension, filter, mapping, category, dataset or glue. Use retire_tables for a table.
id string Yes The definition's id.

cherry always asks first, whatever its mode.

Load and change warehouse data

Land tables of an agent's own rows, add rows to tables opened for intake, and run one committed SQL statement of its own.

load_rows

Load rows into the warehouseWriteswarehouse:write

Lands a table of an agent's own rows in the warehouse as raw.csv__<table>, through the same loader and storage limit a sync uses. Typical uses are a forecast it computed or a lookup it was given. It cannot touch a table a sync landed.

Parameter Type Required Description
table string Yes A short name. It becomes raw.csv__<name>, lower-cased with underscores.
columns array of objects Yes The columns in order, each with a name and an optional type (text, bigint, integer, numeric, boolean, date, timestamptz or jsonb). Leave the type empty to infer it from the values. Up to 250 columns.
rows array of anys Yes The rows, each either a list of values in column order or an object keyed by column name. Empty cells are null. Up to 10,000 rows per call.
mode string, one of replace, append No replace (the default) swaps the table for the new rows, in their new shape, and keeps the views built on it. It is refused, naming the view, when one of your own views reads a column the new rows drop or retype. append adds to it and must match its columns.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.
import boolean No When true, also puts the table on the semantic map so run_query can reach it.
intake boolean No When true, also opens the table for intake, so credentials holding warehouse:append may add rows to it.

Send rows: [] with declared types to create an empty table. For more than 10,000 rows, append in batches.

JSON
{
  "table": "sales forecast",
  "columns": [{ "name": "month", "type": "date" }, { "name": "forecast", "type": "numeric" }],
  "rows": [["2026-10-01", 125000], ["2026-11-01", 131500]],
  "import": true
}

set_intake

Open or close a table for intakeWriteswarehouse:write

Opens a hand-loaded table for intake, or closes it. While a table is open, credentials holding warehouse:append may add rows to it and do nothing else. Closing leaves the rows and the map as they are.

Parameter Type Required Description
table string Yes The table as load_rows named it. dad habits, csv__dad_habits and raw.csv__dad_habits are one table.
open boolean Yes true opens the table, false closes it.
note string No Optional. What the table is for, shown beside it in the Intake tables panel of Settings · Integrations.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

The shape for a log a person keeps by talking to an assistant: land the table once with load_rows, open it here, then give the person a credential holding only warehouse:append. Not offered to cherry.

append_rows

Add rows to an intake tableWriteswarehouse:append

Adds rows to a table an owner or admin has opened for intake. It only ever appends: it cannot create, replace or delete a table, and a table that is not open refuses.

Parameter Type Required Description
table string Yes The table, as it was opened for intake.
columns array of strings No Only when rows are lists: the column names in the order the values come.
rows array of anys Yes The rows, each an object keyed by column name or a list in columns order. Send an empty list to be told the table's columns and types. Up to 10,000 rows per call.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

Send dates as YYYY-MM-DD, numbers as numbers and booleans as true or false, and leave a field null when the value is not known: the warehouse refuses a value a column cannot hold. If the same day is told twice, append a second row and let the workspace's model decide which counts.

This is the one write any member may grant, because its reach is only the tables an owner or admin has opened. Not offered to cherry.

JSON
{
  "table": "daily log",
  "rows": [{ "day": "2026-09-30", "steps": 8200, "note": "Long walk" }]
}

execute_sql

Run and commit SQL you wroteDestructivesql:write

Runs one SQL statement the agent wrote on a warehouse, as the warehouse's builder role, and commits it. The builder reads every landing table and writes only in the derived schema. This is the SQL shell held by a machine, and there is no undo.

Parameter Type Required Description
sql string Yes Exactly one PostgreSQL statement. Semicolons inside a string are fine and a second statement is refused. Qualify every relation with its schema (raw., derived. or mapping.).
why string Yes One sentence on what the statement is for. It is required and is kept in the audit trail beside the statement.
mode string, one of write, read No write (the default) runs and commits the statement. read runs it inside a read-only transaction the database enforces, for looking before deciding.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.
rows integer No How many rows to return from a statement that returns rows. The default is 50 and the maximum is 500.

A sync's landing tables, a published mapping view, the search indexes and sanda's own bookkeeping are out of reach whatever the statement says. A statement that changes rows answers with its command tag and the number of rows touched.

When the workspace asks for approval before an agent acts, a write-mode call is held for an owner or admin and does not run until one approves it. A read call is never held. See permissions and approvals. Not offered to cherry.

Views and procedures

Define, build and tune views, materialized views and procedures in the derived schema of a warehouse.

list_sources

List what a view may be built onRead onlywarehouse:model

Lists every relation in a warehouse that a view may be built on, with columns and types: landing tables, derived objects already defined, and the mapping tables. It is read as the role that would own the view, so it lists exactly what a CREATE will accept.

Parameter Type Required Description
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

A published mapping.* view is not listed and cannot be built on. Build on the table behind it.

list_views

List derived views and proceduresRead onlywarehouse:model

Lists every view, materialized view and procedure the workspace has defined in a warehouse's derived schema: its definition, its version, when a materialized view was last built and whether it is on the semantic map.

Parameter Type Required Description
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

create_view

Define a view or materialized viewWriteswarehouse:model

Defines a view in the derived schema from one SELECT over anything list_sources names. A materialized view stores its result and is built now, on the workspace's compute. The view goes on the semantic map in the same call unless told not to.

Parameter Type Required Description
name string Yes A lowercase identifier. It becomes derived.<name>.
sql string Yes One SELECT (or WITH ... SELECT) over the relations list_sources names, by schema-qualified name. One statement, no semicolons, no comments.
materialized boolean No When true, stores the rows and rebuilds them on refresh, instead of computing on every read.
unique_key array of strings No Materialized views only: the columns that identify one row, so a refresh can run without blocking readers.
description string No What the view is for, in a sentence.
replace boolean No When true, redefines derived.<name> if it already exists.
publish boolean No Whether to put the view on the semantic map. The default is true.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

A materialized view's build runs on the workspace's compute and is billed to it, which is why the scope that allows this is privileged. See usage.

refresh_view

Rebuild a materialized viewWriteswarehouse:model

Rebuilds one materialized view now and reports how long it ran and what it cost. An assistant calls it after the tables behind the view have synced.

Parameter Type Required Description
name string Yes The materialized view's name, from list_views.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

Runs for up to 55 seconds inside the call. A build that needs longer, up to 14 minutes, belongs on a schedule.

drop_view

Drop a derived objectDestructivewarehouse:model

Drops one view, materialized view or procedure from the derived schema, taking it off the semantic map first. It is refused while another derived view reads it, because sanda never cascades. The definition stays in the history and the rows do not.

Parameter Type Required Description
name string Yes The object's name, from list_views.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

When the workspace asks for approval before an agent acts, this call is held for an owner or admin. See permissions and approvals. cherry always asks first, whatever its mode.

create_procedure

Define a procedureWriteswarehouse:model

Defines a procedure in the derived schema: a multi-step transform in plpgsql or SQL that builds, merges or reshapes derived tables, with COMMIT allowed between steps. It runs as the warehouse's builder role.

Parameter Type Required Description
name string Yes A lowercase identifier. It becomes derived.<name>.
body string Yes The procedure body: the plpgsql block, or the SQL statements.
args string No The arguments as name type, name type, for example since date, region text. Empty for none. Types are text, integer, bigint, numeric, boolean, date, timestamptz, timestamp, interval, jsonb and uuid.
language string, one of plpgsql, sql No plpgsql or sql.
description string No What the procedure does, in a sentence.
replace boolean No When true, redefines derived.<name> if it already exists.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

The builder role may read landing tables, derived objects and the mapping tables, and may create and write only in derived. It cannot write a row anywhere else, whatever the body says. Run it with call_procedure.

call_procedure

Run a procedureWriteswarehouse:model

Runs one procedure now, with its arguments in declared order, and reports how long it ran and what it cost.

Parameter Type Required Description
name string Yes The procedure's name, from list_views.
args array of anys No Argument values in declared order. Leave it out for a procedure with none.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

Runs for up to 55 seconds inside the call. A run that needs longer belongs on a schedule.

warehouse_advice

What is slowing this warehouse downRead onlywarehouse:model

Reads a warehouse's own statistics and says what is slowing it down or costing it storage: a missing index, a table autovacuum has fallen behind on, stale statistics after a sync, an unused index, storage a rewrite would give back, or a table large enough to partition. It writes nothing.

Parameter Type Required Description
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

Each finding carries an id, the figures behind it and the statement sanda would run. A finding with no statement is one sanda will not act on, and it says why. Pass the ids you want acted on to optimise_warehouse.

optimise_warehouse

Apply what the advice foundWriteswarehouse:model

Runs the findings you name by id from warehouse_advice: a vacuum, an analyse, an index created or dropped. sanda re-reads the warehouse first and runs only findings that are still current. It never runs SQL you send it.

Parameter Type Required Description
ids array of strings Yes Finding ids from warehouse_advice, for example vacuum:raw.xero__invoices. Up to eight at a time.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

Each statement runs on the workspace's compute, is recorded on the run ledger and is billed as the seconds it takes. A finding that would lock a table against readers says so in the advice, so read it before sending its id.

Schedules

Run views and procedures on a clock or after a sync, and read what each run did and cost.

list_schedules

List schedulesRead onlywarehouse:model

Lists every task graph in a warehouse: its steps, its cadence, whether it is paused or has suspended itself after failures, when it next runs and how its last run went.

Parameter Type Required Description
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

create_schedule

Schedule a task graphWriteswarehouse:model

Defines a task graph: an ordered list of steps on the warehouse, each a materialized view to refresh or a procedure to call, and when it runs. Steps run in order, and a step is skipped when the one before it failed.

Parameter Type Required Description
name string Yes A name for the graph, for example nightly rebuild.
tasks array of objects Yes The steps in order, from one to 20. Each is { "refresh": "view_name" } or { "call": "procedure_name", "args": [ ... ] }, with an optional step name.
cron string No A five-field cron expression evaluated in UTC. sanda's scheduler runs on a 15 minute grid, so the minute field must be 0, 15, 30 or 45. Leave it out for a graph that runs only after a sync or by hand.
timezone string No The zone the cron was written for, kept for display. Evaluation is always UTC.
after_sync string No A connection, by name or id. The graph runs each time that connection lands rows, which is usually the better trigger. It may be combined with cron.
suspend_after_failures integer No Pause the graph after this many failures in a row, from 1 to 100. The default is 3 and 0 never pauses.
description string No What the graph is for, in a sentence.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

One run has at most 14 minutes, and every run is billed as the seconds its statements executed.

JSON
{
  "name": "nightly rebuild",
  "tasks": [{ "refresh": "revenue_by_month" }, { "call": "close_month", "args": ["2026-09-01"] }],
  "cron": "0 18 * * 1-5"
}

That cron is weekdays at 18:00 UTC.

run_now

Run a task graph nowWriteswarehouse:model

Queues one task graph to run now rather than waiting for its schedule. Because the scheduler runs on a 15 minute grid, it starts at the next quarter hour. A graph already queued or running is not queued again.

Parameter Type Required Description
name string Yes The graph's name, from list_schedules.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

pause_schedule

Pause or resume a task graphWriteswarehouse:model

Pauses a task graph so nothing fires it (not its schedule, not a sync landing, not run_now), or resumes one that is paused or has suspended itself. Resuming resets its failure count.

Parameter Type Required Description
name string Yes The graph's name, from list_schedules.
resume boolean No true to resume. Leave it out or set it to false to pause.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

run_history

Run historyRead onlywarehouse:model

Shows what ran and what it cost: the recent runs of one task graph with each step's outcome and seconds, or the versions, builds and calls of one derived view or procedure.

Parameter Type Required Description
schedule string No A task graph, by name, to see its runs.
view string No A derived object, by name, to see its versions and runs. Give one of schedule or view.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

Create, change, build and remove search services over tables on the map, and estimate what indexing costs first.

list_search_services

List search servicesRead onlysearch:manageStandard · Enterprise

Lists every sanda search service in a warehouse: the table and columns it indexes, how many rows and how large the index is, when it last built and what that cost. It also says whether sanda search is switched on for the workspace at all.

Parameter Type Required Description
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

The search tools are available on Standard and Enterprise. Not offered to cherry.

describe_search_service

Describe a search serviceRead onlysearch:manageStandard · Enterprise

Describes one search service in full: its definition and state, every build with the rows it embedded and what it cost, and every version its definition has had. An assistant uses it to find out why a service is broken.

Parameter Type Required Description
name string Yes The service, by name.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

estimate_search_build

Estimate what indexing would costRead onlysearch:manageStandard · Enterprise

Estimates what indexing a table would cost before anything is created: rows, tokens, dollars and how that compares with the workspace's daily AI limit.

Parameter Type Required Description
source string Yes The table on the map, as mapping.<table>.
text_columns array of strings Yes The columns whose text would be indexed.
key_column string No The column that identifies a row.
model string No The embedding model to use. Leave it out for sanda's default.
chunk_chars integer No How much text one indexed piece holds.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

create_search_service refuses without confirm: true when a build would use more than half a day's AI limit. This is how to know that in advance.

create_search_service

Create a search serviceWritessearch:manageStandard · Enterprise

Indexes the text of a table so it can be searched by meaning as well as by words. The first build sends the text of the columns named to an embedding model outside Australia and is charged against the workspace's daily AI limit.

Parameter Type Required Description
name string Yes A lowercase name for the service. It becomes a table in the warehouse.
source string Yes A table on the semantic map, as mapping.<table>. A view in the derived layer must be published to the map first.
key_column string No The column that identifies a row. It must be unique and never empty, because a hit is only useful if it can be joined back to a metric.
text_columns array of strings Yes The columns whose text is indexed. At least one.
attribute_columns array of strings No Columns kept beside the text as filters, such as status, region or a date. They are not indexed as text.
model string No The embedding model to use. Leave it out for sanda's default.
chunk_chars integer No How much text one indexed piece holds. The default is 1200 characters.
fts_config string, one of simple, english No Word matching: simple, or english, which stems words and drops common stop words.
after_sync string No A connection, by name or id. The service rebuilds each time it lands rows, which is usually the right trigger.
cron string No A five-field UTC cron on the quarter hour (minute 0, 15, 30 or 45), for a service rebuilt on a clock instead. With neither trigger the service is rebuilt when asked.
timezone string No The zone the cron was written for, kept for display. Evaluation is always UTC.
description string No What the service is for, in a sentence.
confirm boolean No Set to true to go ahead when the estimated cost is a large share of the day's AI limit.
replace boolean No Set to true to replace a service of the same name, rebuilding it from scratch.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

sanda search must be switched on by a workspace owner in the console before this works. An agent holding the scope cannot switch it on, because it is a decision about where a business's data may be processed. A column whose name says it holds a secret is refused outright. Not offered to cherry.

update_search_service

Change a search serviceWritessearch:manageStandard · Enterprise

Redefines a search service or changes when it rebuilds. Changing the model, text columns, chunk size, word matching, key or source rebuilds the whole index at the cost of a first build. Changing only the attribute columns, description or cadence costs nothing.

Parameter Type Required Description
name string Yes The service to change, by name.
source string No A new source table on the map.
key_column string No A new key column.
text_columns array of strings No The new list of columns to index.
attribute_columns array of strings No The new list of filter columns.
model string No A different embedding model.
chunk_chars integer No A new chunk size.
fts_config string, one of simple, english No simple or english.
after_sync string No A connection, by name or id. Null clears it.
cron string No A five-field UTC cron on the quarter hour. Null clears the schedule.
timezone string No The zone the cron was written for, kept for display.
description string No A new description.
enabled boolean No false pauses rebuilding. Searches keep working on what is already indexed.
suspend_after_failures integer No Pause rebuilding after this many failures in a row.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

A well-behaved assistant tells the person before it rebuilds a large table. Not offered to cherry.

build_search_service

Index a search service nowWritessearch:manageStandard · Enterprise

Queues an index build now instead of waiting for the service's own trigger. Only rows whose text changed since the last build are sent to the model, so it is cheap on an unchanged table.

Parameter Type Required Description
name string Yes The service, by name.
full boolean No When true, discards the index and rebuilds every row. It costs what the first build cost.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

This only queues the build. sanda's scheduler runs on a 15 minute grid, and indexing then runs in slices across as many ticks as it takes. Use run_search_build to spend the call indexing now. Not offered to cherry.

run_search_build

Index a search service now, inside this callWritessearch:manageStandard · Enterprise

Queues a build and then spends up to 55 seconds of the call indexing it, so a small index finishes inside the call. It reports what it read, embedded and cost.

Parameter Type Required Description
name string Yes The service, by name.
full boolean No When true, rebuilds every row and not only what changed.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

An index too large for one call keeps its place and says there is more to do: call again to carry it on, or leave it to the scheduler. This builds an index and does not query one. Use search_documents for that. Not offered to cherry.

drop_search_service

Remove a search serviceDestructivesearch:manageStandard · Enterprise

Removes a search service and deletes its index from the warehouse. Searches against it stop at once, and rebuilding it later costs a full first build. The definition and every build it ran stay on record.

Parameter Type Required Description
name string Yes The service to remove, by name.
warehouse string No Which warehouse, by name or id, when the workspace has more than one.

When the workspace asks for approval before an agent acts, this call is held for an owner or admin. See permissions and approvals. Not offered to cherry.

Email reports

Schedule, change, pause, send and remove report deliveries.

list_deliveries

List report deliveriesRead onlyreports:deliver

Lists every report delivery: the report it sends, its cadence, who it goes to, whether it is paused, when it next goes and how its last run went, with each delivery's id. It also names the reports that have no delivery.

Parameter Type Required Description
report string No Only this report's deliveries, by name or id.

Reading deliveries needs the same scope as creating them, because the list is who receives what.

create_delivery

Schedule a report deliveryWritesreports:deliver

Emails a report on a schedule. At each firing sanda asks every block on the report again and sends the answers to the recipients. Email only: Slack and webhook deliveries are set up on the Report schedules page, because their address is a secret.

Parameter Type Required Description
report string Yes The report to send, by name or id.
recipients array of strings Yes Email addresses, up to 25.
cron string Yes A five-field cron on the quarter hour (minute 0, 15, 30 or 45), for example 0 8 * * 1 for Mondays at 8.
timezone string No An IANA zone the cron is local to, for example Australia/Sydney. It stays on local time across daylight saving. Leave it out and the cron is UTC.
note string No A closing note for the email, up to 500 characters.

A workspace may limit which email domains a delivery can go to, and the answer says so when a recipient is outside them. To send a report once, create the delivery, send it with send_delivery, then pause it with pause_delivery.

When the workspace asks for approval before an agent acts, a call naming a recipient outside the domains its members use is held for an owner or admin, because a report emailed to someone cannot be recalled. See permissions and approvals. cherry always asks before an email, whatever its mode.

JSON
{
  "report": "Board pack",
  "recipients": ["cfo@example.com.au"],
  "cron": "0 8 * * 1",
  "timezone": "Australia/Sydney"
}

update_delivery

Change a report deliveryWritesreports:deliver

Changes who a delivery goes to, its closing note or when it goes. recipients is the whole new list, so to add someone pass the current recipients with them, and to remove someone leave them out.

Parameter Type Required Description
report string No The report the delivery sends, by name or id.
delivery string No The delivery's id, from list_deliveries, when the report has more than one.
recipients array of strings No The whole new list of email addresses.
cron string No A new five-field cron on the quarter hour. It stays on the delivery's own clock unless timezone names another.
timezone string No The IANA zone a new cron is local to. Leave it out to keep the delivery's own.
note string No A new closing note. An empty string removes it.

Held for approval on the same terms as create_delivery when a recipient is outside the domains the workspace's members use.

send_delivery

Send a report delivery nowWritesreports:deliver

Sends a delivery now, to its recipients, instead of waiting for its schedule. It goes out within a minute or two.

Parameter Type Required Description
report string No The report the delivery sends, by name or id.
delivery string No The delivery's id, when the report has more than one.

A paused delivery can still be sent by hand. cherry always asks first, whatever its mode.

pause_delivery

Pause or resume a report deliveryWritesreports:deliver

Pauses a delivery so its schedule stops sending it, or resumes a paused one. A resumed delivery next goes at its next firing from now.

Parameter Type Required Description
report string No The report the delivery sends, by name or id.
delivery string No The delivery's id, when the report has more than one.
resume boolean No true to resume. Leave it out or set it to false to pause.

delete_delivery

Remove a report deliveryDestructivereports:deliver

Removes a delivery. The report stays, and the record of every run it made stays on the timeline. Only the schedule and its recipients go.

Parameter Type Required Description
report string No The report the delivery sends, by name or id.
delivery string No The delivery's id, when the report has more than one.

pause_delivery is the way to stop one for a while. cherry always asks first, whatever its mode.

Approvals

Find out what happened to an action the workspace held for a person to approve.

action_status

Check an action waiting for approvalRead onlyany held scope

Reports what happened to an action the workspace held for approval: still waiting, declined, expired, or approved and what the tool answered when it ran. With no id it lists this credential's ten most recent actions.

Parameter Type Required Description
id string No The id the held call answered with. Leave it out to list recent actions.

A credential sees only its own actions. The tool is listed only for credentials that hold a scope a held tool needs (sql:write, warehouse:model, search:manage or reports:deliver), because a credential that can only ask questions never has anything waiting. It is read-only, and it is never held itself.

A well-behaved assistant never tells a person a held action is done until this says it ran. See permissions and approvals.

Something unclear or out of date? Tell us, and we will fix the page.