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 } },
},
});
ToolWhat it does
json_getRead a key from the artifact JSON store
table_queryQuery rows from an artifact table (filters, limits)
table_schemaInspect table column names and types
connection_queryQuery a workspace connection — REST or warehouse SQL
web_searchWeb 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" }
}
ToolWhat it does
json_setWrite or merge a value in the JSON store
materialize_queryRun a connection query and save results without loading every row into the conversation
table_insertInsert rows into an artifact table
table_updateUpdate rows by id or filter
comment_createAdd a comment on the artifact
email_sendSend email from the artifact
notify_sendOne-shot delivery to Slack, email, Discord, or webhook
scheduled_job_createCreate 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.typeWrites to
tablesdk.table(name)
datasetsdk.dataset(name)
jsonsdk.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.

PolicyWhen approval is required
neverExecute immediately (owner already authorized the grant)
alwaysEvery call queues for owner approval
whenPublicOnly 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 },
}