Skip to content

Crew tools

import { Aside } from ‘@astrojs/starlight/components’;

Grant tools when you call sdk.crew.define({ tools: { read: [...], write: [...] } }). The runtime only exposes what the owner enabled — artifact HTML cannot widen grants.

await sdk.crew.define({
instructions: '…',
tools: {
read: ['json_get', 'connection_query'],
write: ['json_set', 'notify_send'],
approval: { notify_send: 'always', json_set: 'whenPublic' },
limits: { connection_query: { maxCalls: 5, maxRows: 100 } },
},
});
Tool What it does
json_get Read a key from the artifact JSON store
table_query Query rows from an artifact table (filters, limits)
table_schema Inspect table column names and types
connection_query Query a workspace connection — REST or warehouse SQL
web_search Web lookup (when enabled for the workspace)

Query a workspace connection by name.

  • REST: query = "GET /endpoint/path"
  • Warehouse (BigQuery, Snowflake, …): query = SQL string; pass params.projectId for BigQuery

Returns rows into the crew conversation — best for aggregates and small result sets.

Runs as the artifact owner, including per_user connectors, so unattended crews can query BigQuery the same way the interactive data API does.

{
"connection": "team_bigquery",
"query": "SELECT region, SUM(revenue) AS revenue FROM analytics.daily GROUP BY 1",
"params": { "projectId": "my-gcp-project" }
}
Tool What it does
json_set Write or merge a value in the JSON store
materialize_query Run a connection query and save results without loading every row into the conversation
table_insert Insert rows into an artifact table
table_update Update rows by id or filter
comment_create Add a comment on the artifact
email_send Send email from the artifact
notify_send One-shot delivery to Slack, email, Discord, or webhook
scheduled_job_create Create a recurring scheduled job

Owner-scoped write to the artifact JSON store. Creates or replaces a key; optional path merges one field inside the key’s object.

Use for computed summaries, status flags, or narratives the page reads on next load.

Run a connection query and save results. Same target shapes as query_snapshot:

target.type Writes to
table sdk.table(name)
dataset sdk.dataset(name)
json sdk.json key name; optional path merges at a field inside the object
{
"connection": "team_bigquery",
"query": "SELECT * FROM `project.dataset.table` LIMIT 500",
"params": { "projectId": "my-gcp-project" },
"target": { "type": "json", "name": "snapshot", "path": "rows" }
}

Use query_snapshot jobs when SQL is stable. Use materialize_query when the agent should decide what to refresh interactively.

One-shot delivery via the shared destination layer. Pass a top-level message for the crew’s narrative — forwarded as customMessage. Slack mode: "both" attaches a dashboard screenshot and link alongside the message.

{
"destination": "slack",
"message": "*Daily summary*\nRevenue up 12% vs yesterday.",
"config": {
"connection": "team",
"channelId": "C0123456789",
"mode": "both"
},
"source": {
"connection": "warehouse",
"query": "SELECT … FROM metrics.daily_revenue …",
"asOf": "2026-06-22"
}
}

Pass source when delivering data-derived numbers — a compact attribution footer (_Source: … · as of …_ plus the one-line query) is appended so recipients can trace where the figures came from. See Data provenance.

See Slack integration for connection and channel setup.

Creates a recurring job (POST /v1/jobs under the hood). Config shapes match Scheduling jobs.

Policy When approval is required
never Execute immediately (owner already authorized the grant)
always Every call queues for owner approval
whenPublic Only when the artifact is publicly accessible
approval: {
notify_send: 'always',
table_insert: 'whenPublic',
}
const { approvals } = await sdk.crew.approvals.list('pending');
await sdk.crew.approvals.approve(approvals[0].id);

Per-tool caps in limits:

limits: {
connection_query: { maxCalls: 10, maxRows: 500 },
materialize_query: { maxCalls: 3 },
}