Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.useterse.ai/llms.txt

Use this file to discover all available pages before exploring further.

Think of it as infrastructure as code, scoped to your workspace. terse generate reads your connected integrations and writes a single typed file: every channel, repo, list, and owner becomes a constant your workflow code imports by name. Your coding agent (Cursor, Claude Code, Windsurf) reads the same file and sees the full surface as autocompletions and types.

The problem it solves

Without a generated SDK, both humans and agents rediscover the workspace on every job. At runtime, the code looks like this:
const lists = await attio.lists.list()
const newDeals = lists.find(list => list.name === "New deals")

const channels = await slack.conversations.list()
const dealDesk = channels.find(channel => channel.name === "deal-desk")

if (!newDeals || !dealDesk) {
    throw new Error("Workspace context drifted")
}
This adds latency, costs tokens, and breaks silently when someone renames a channel. At build time, the cost is worse. A coding agent writing this job has no idea what is actually connected. It guesses at channel names, hallucinates list IDs, and produces code you correct by hand. No autocomplete, no type check, no signal to the agent that #deal-desk is real and #sales-team is not.

How it works

Compile the workspace once, then write against the compiled file. Resource IDs land as typed constants. Each integration exposes a namespace of trigger builders and a skill() constructor. Tool wrappers attach to agent.tools.* with full parameter and return types.
import { generateText, createJob } from "terse-sdk"

import { Attio, AttioList, Slack, SlackChannel } from "./terse.generated"

createJob({
    name: "new-deal-enrichment",
    triggers: [Attio.onRecordCreated({ list: AttioList.Pipeline.NewDeals })],
    onTrigger: async event => {
        await generateText({
            prompt: `Enrich this new deal and alert the deal desk. ${event.formatForAgentRunner()}`,
            skills: [Attio.skill({ lists: [AttioList.Pipeline.NewDeals] }), Slack.skill({ channel: SlackChannel.DealDesk })]
        })
    }
})
No runtime discovery. No hardcoded IDs. If an agent or a human references a resource that doesn’t exist in your workspace, the TypeScript compiler rejects it and terse deploy refuses to ship.

Where to go next

Generated SDK

The anatomy of terse.generated.ts, with samples of every export.

Hosting & Deployment

What terse deploy actually does, from ZIP upload to pre-warmed sandbox.

Quickstart

Get a workflow live in under 10 minutes.