Skip to content
Changelog

Report a bug

Context Reference

Type calls a subscription method with two arguments: ctx and event. This page lists every property and method of ctx. For event, see the Events reference.

src/main.ts
import type {
AutomationContext,
RecurringEvent,
} from "@type-dot-com/sdk/automations";
export default class {
daily(ctx: AutomationContext, event: RecurringEvent) {
return ctx.setOutput({ ranAt: event.scheduledAt });
}
}

The type of ctx is AutomationContext. Import it from @type-dot-com/sdk/automations.

  • Methods that call Type return ResultAsync<T, TypeApiError> from neverthrow. They do not throw. Check isErr() before you use the value.
  • A run can send at most 128 requests to Type. This count includes tool calls, reads, writes, messages, data reads, and searches.
  • At most 8 requests can be in progress at the same time. Await calls, or limit Promise.all to small groups.
  • Each response to a request can be at most 2 MiB. Ask for smaller pages if a response is larger.
  • Each request body can be at most 1 MiB.
  • Type does not retry a request automatically. If a write times out, the write can still be complete. Read the destination before you try again.
  • console.log does nothing. Use ctx.setOutput() or action logs to see values in run history.

See Limits for all limits.

MemberTypeUse it to
ctx.identityAutomationExecutionIdentityRead the IDs of this automation, run, and event.
ctx.checkpoint{ value, version } | nullRead the state that the last successful run saved.
ctx.saveCheckpoint()(value) => Result<void>Save state for the next run.
ctx.setOutput()(value) => Result<void>Show a result in run history.
ctx.setSummary()(text) => Result<void>Show one sentence about what the run did.
ctx.setVisualization()(value) => Result<void>Save a report of the results. Needs reports to be on.
ctx.toolsTool clientFind and call integration tools and sandbox commands.
ctx.readRead clientRead tool data, API data, saved data, and search results.
ctx.writeWrite clientChange data in a connected app, or post in a Space.
ctx.agentAgent clientGive work that needs judgment to the managed agent.
ctx.action()Action loggerRecord an important step in run history.
ctx.mutativeAction()Action loggerRecord a step that changes data.
ctx.jevAutomationJevResult | nullRead answers to AI questions about the event.
ctx.signalAbortSignalStop work when the run deadline comes.

Read-only IDs for the current run.

FieldTypeMeaning
organizationIdstringThe workspace that owns the automation.
automationIdstringThe automation.
revisionIdstringThe saved code revision that runs now.
runIdstringThis run.
subscriptionIdstringThe subscription key, which is also the method name.
eventIdstringThe event that started this run.
purpose"live" | "test" | "repair"Why Type started the run.
phase"subscription" | "inspect" | "execute"The run phase. Methods always get "execute".

These IDs are information only. Type does not use them to give access. Type checks access with a short-lived token for each run.

The state that the last successful run of this subscription saved. The value is null before the first successful save.

interface AutomationCheckpoint {
readonly value: JsonValue;
readonly version: string;
}
  • Each subscription has its own checkpoint. Two subscriptions in the same automation do not share it.
  • The checkpoint stays when you deploy new code, if the subscription key stays the same.
  • If you rename a subscription key, the new key starts with no checkpoint.
saveCheckpoint(value: JsonValue): Result<void, TypeApiError>

Saves value as the next checkpoint for this subscription.

  • The value must be JSON.
  • Type saves the checkpoint only when the method succeeds. If the run fails, the old checkpoint stays.
  • If you call it more than one time, the last value is saved.
  • The call is synchronous. It returns a Result, not a ResultAsync.
  • If the value is not JSON, the run fails, even if your code ignores the error.
setOutput(value: JsonValue): Result<void, TypeApiError>

Sets the result that run history shows for this run. It does not post a message and does not start a conversation.

  • The value must be JSON. Keep it small. All results of a run must fit in 2 MiB of JSON together: the output, checkpoint, report, handoffs, and action logs. Type does not cut a large result. It fails the run.
  • If you call it more than one time, the last value is kept.
  • Fixtures compare expectedOutput with this value.
  • A common pattern is return ctx.setOutput({ ... }) at the end of the method.
setSummary(value: string): Result<void, TypeApiError>

Sets one plain sentence that says what this run did. An example is “Two tickets arrived; one is about billing.” Type shows it as the headline of the run in run history, and under the report.

  • The text must be 1 to 300 characters after Type trims spaces. Otherwise the run fails.
  • Describe the change, not the steps of the code.
  • Do not set a summary for a run that did nothing.
setVisualization(value: JsonValue): Result<void, TypeApiError>

Saves a report for the automation, for example a chart, a table, or metric cards. The report shows on the automation page. The value is a json-render spec: { root, elements, state }.

  • Set a report only when it helps people understand the results. Do not save a placeholder.
  • null, or no call, keeps the current report. ctx.setOutput() never makes a report.
  • The report shares the 2 MiB result limit.
  • If the report is not valid, Type keeps the earlier report and records a warning. The run still succeeds.
  • Test and repair runs do not change the live report.
  • Saving a report does not send it anywhere.
  • Limits: charts have at most 500 points and 12 series. A report has at most 200 elements after Type expands repeats.

The integration tool client. Type checks the automation’s access on every call.

MethodReturnsUse it to
services(options?){ services }List the services that the automation can use.
find({ service, organizationIntegrationId?, includeRelatedConnections? }, options?)Tool listGet tool names and input schemas for a service.
call(call, options?)ToolResultCall a tool and get the raw result.
callWithSchema(call, schema, options?)ToolResult with parsed structuredContentCall a tool and parse its structured result.

A call object has these fields:

interface ToolCall {
service: string; // for example "slack" or "managed-sandbox"
name: string; // the tool name from find()
arguments?: Record<string, JsonValue>;
organizationIntegrationId?: string; // the connection ID, "orgint_..."
rawSlug?: string;
}

A ToolResult has this shape:

interface ToolResult {
content: Array<{ type: string; text?: string }>;
structuredContent?: unknown;
isError?: boolean;
}

Sandbox commands use ctx.tools.call with service: "managed-sandbox". They need an automationEffectKey option. See Run Commands in the Sandbox.

Reads data. Use ctx.read only for operations that do not change data.

call<S extends z.ZodType>(call: ToolCall, schema: S, options?: RequestOptions): ResultAsync<z.output<S>, TypeApiError>

Calls a tool, then parses its structuredContent with your Zod schema. It returns the parsed value.

  • It fails if the tool returns isError: true.
  • It fails if structuredContent does not match the schema.
  • JSON text in content[].text is not structuredContent. For tools that return only text, use ctx.tools.call.
request<S extends z.ZodType>(request: IntegrationRequest, schema: S, options?: RequestOptions): ResultAsync<z.output<S>, TypeApiError>

Sends an HTTP request to a Custom API connection. Type adds the credentials. Your code never sees them. It parses the response body with your schema and returns the parsed value.

interface IntegrationRequest {
organizationIntegrationId: string;
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
path: string; // relative to the connection's base URL
query?: Record<string, string | number | boolean>;
headers?: Record<string, string>;
body?: JsonValue;
}

It fails if the response is not successful, if Type truncated the response, or if the body does not match the schema.

Reads saved data for this automation.

MethodReturns
read(key, scope?, options?){ found: true, key, value, version, updatedAt } or { found: false, key, version: null }
list({ after?, limit? }, options?){ items: [{ key, version, updatedAt }], nextCursor }

Automation code cannot write saved data. Use checkpoints for state between runs.

Searches the Type workspace.

MethodUse it to
workspace(query, options?)Search people, Spaces, docs, apps, files, threads, and messages.
messages({ query?, channelIds?, limit?, from?, to? }, options?)Search messages, with optional channel and date filters.

Changes data. Each method needs an effectKey.

interface AutomationMutationOptions {
effectKey: string; // stable for the same logical change, across retries and runs
signal?: AbortSignal;
timeoutMs?: number;
}
MethodUse it to
call(call, schema, { effectKey })Call a tool that changes data, then parse its structuredContent.
request(request, schema, { effectKey })Send an HTTP request that changes data to a Custom API connection, then parse the body.
sendMessage({ channelId, content, parentMessageId? }, { effectKey })Post a message in the automation’s Space. Set channelId to the Space ID (ch_...). Set parentMessageId to reply in a thread. Returns { messageId }.

Only live runs get real writes. In a test, Type gives your code the responses from your fixtures.

Gives work to the managed agent after your method succeeds. The deployment must use mode: "code_with_optional_agent". In mode: "code", these calls fail the run.

run(input: {
effectKey: string; // 1 to 500 characters
instructions: string; // 1 to 10,000 characters
context?: JsonValue; // evidence for the AI; default null
tools?: Array<{ service: string; name: string; organizationIntegrationId: string; rawSlug?: string }>; // at most 16
}): ResultAsync<void, TypeApiError>

Stages a handoff. Type starts the AI only after the method succeeds. Type gives the AI the full source event. Use context for more evidence.

evaluate(input: {
effectKey: string;
instructions: string;
context?: JsonValue;
tools?: AgentTool[];
evaluation: {
question: string; // 1 to 2,000 characters
criteria: {
skip: string; // 1 to 2,000 characters
invoke_agent: string; // 1 to 2,000 characters
};
};
}): ResultAsync<void, TypeApiError>

Stages a handoff that Type evaluates first. After the method succeeds, Type asks a model if the work needs the AI.

  • If the model answers skip with a confidence of 0.8 or more, no AI starts.
  • In all other cases, the AI starts. This includes a low-confidence answer, a failed evaluation, and a workspace with no evaluation model.

evaluate is not a synchronous classifier: your code does not get the answer. To get answers in code, use AI questions in a matcher.

Rules for both methods:

  • A run can stage at most 100 handoffs.
  • If you stage the same effectKey with the same input two times, Type keeps one handoff.
  • If you stage the same effectKey with different input, the run fails.
  • A staged handoff is not a delivered message. If the method fails, Type starts no handoffs.

See Hand Off Work to a Managed Agent.

type Action = <T>(
run: () => Result<T, TypeApiError> | ResultAsync<T, TypeApiError>,
before: { id: string; message: string; data?: JsonValue },
after: (result: T) => { message: string; data?: JsonValue },
) => ResultAsync<T, TypeApiError>;

Records an important step in run history. Type saves the before log, runs run, then saves the after log.

  • Use mutativeAction for steps that change data. Use action for other important steps.
  • id must be unique in the run, and 1 to 200 characters. It must not start or end with a space.
  • message must be 1 to 2,000 characters. Each log must fit in 8 KiB.
  • A run can record at most 100 actions.
  • If run fails, Type records a failed step and returns the error.
  • If Type cannot save the after log, the call fails with “Do not repeat the action”. The step itself can be complete.

Action logs do not retry, and they do not undo earlier changes. ctx.destructiveAction is an old name for ctx.mutativeAction. Do not use it in new code.

const created = await ctx.mutativeAction(
() => ctx.write.call(createIssue, issueSchema, { effectKey: `issue:${event.id}` }),
{ id: "create-issue", message: `Create an issue for ${event.id}` },
(issue) => ({ message: `Created issue ${issue.id}`, data: { id: issue.id } }),
);
if (created.isErr()) return err(created.error);

Answers to the AI questions that the subscription’s matcher asked about this event. The value is null when the matcher asks no questions.

interface AutomationJevResult {
model: string;
answers: Record<string, JevAnswer>; // keyed by your question IDs
}

Each answer has the type of its question: noul (a probability from 0 to 1), choice, or score. See Filter Events with AI Questions.

An AbortSignal that aborts when the run deadline comes. Pass it to long operations as the signal option.

A subscription method can return:

  • nothing, or a Promise of nothing,
  • ok(undefined) or err(error) from neverthrow,
  • a ResultAsync<void, TypeApiError>.

Return err(error) to fail the run. Do not throw. If the method throws, the run also fails, but the error is less clear.

import { TypeApiError } from "@type-dot-com/sdk";
import { err } from "neverthrow";
return err(new TypeApiError("The order has no ID", "invalid_response"));