Skip to main content
Context as Code is the idea. The generated SDK is the artifact. Running terse generate writes a typed bundle to your project: src/terse.generated.ts (the entry point) plus a src/terse.generated/ folder with one file per integration and kind. Every trigger, skill, deterministic tool wrapper, and real workspace resource (channels, repos, objects, owners) is exported as a typed value. Your workflows import from it. Your coding agent reads it. The compiler enforces it.
The generated files are deterministic, overwritten on every terse generate, and committed alongside your workflows. Do not hand-edit them.

How the bundle is laid out

src/terse.generated.ts is the only file your code imports from — it re-exports everything. The folder next to it splits the declarations by integration and kind, so a reader (human or agent) opens only what the workflow at hand touches:
The header of the root file carries three things an agent needs before writing any job code:
  • the list of every integration currently available in Terse (connected or not),
  • a summary of the platform primitives from terse-sdk (createJob, generateText, durability operations, waitForInput, state, secrets), so job code never requires spelunking the package,
  • a line-numbered index of every tool, trigger, and resource in the folder — e.g. toolbox.slack.sendMessage() with the exact file and line of both the method and its params type. Line numbers are exact as of the last terse generate.

What the bundle contains

Each file is generated from a real integration you’ve connected. Here’s a trimmed snapshot of what you’d see after connecting Slack, GitHub, and Attio.

Resource constants

Every workspace resource is exported as a typed constant. No UUIDs in your workflow code, no runtime lookups. Resources live in each integration’s tools file, next to the tool methods that take them.
src/terse.generated/slack.tools.ts (and github.tools.ts, attio.schemas.ts)

Trigger builders and skills

Triggers and skills are exposed under two umbrella namespaces, with each integration as a nested key. The factories are defined in each integration’s triggers file and composed in the root. Parameters take resource constants, not strings.
src/terse.generated.ts (composed from terse.generated/*.triggers.ts)

Deterministic tool wrappers

Every connected integration also generates typed wrappers on agent.tools.*, with the exact parameter and return types of each tool. Use them when you know what to do and don’t want to burn tokens letting a model decide. agent.tools.* is gated at runtime by the agent’s skills: only integrations declared in skills are populated on agent.tools (the others are undefined). The TypeScript surface includes every connected integration, so the safety net here is “you’ll get a clear runtime error if you reach for a skill you didn’t declare.” The same file also exports toolbox: identical typed namespaces, but callable without a TerseAgent and not filtered by skills. Prefer toolbox for workflows that are purely deterministic.
src/terse.generated.ts (composed from terse.generated/*.tools.ts)

What you write against it

Because every resource, trigger, skill, and tool is an export, your workflow code reads like a description of your business, not a scavenger hunt through admin UIs.
src/index.ts
No channel IDs. No repository numbers. No list UUIDs. The only strings you write are your own content.

Why humans love it

Before the generated SDK, shipping a workflow meant context switching between your editor, your CRM admin, your Slack workspace, and GitHub settings to collect IDs. After it, SlackChannel.DealDesk replaces "C08XYZ1234" and Repos.TerseAI.Terse replaces a repository ID you’d otherwise dig out of a URL. Your editor lists every connected channel, object, and repo inline; hover for the real name. When #deal-desk is renamed in Slack, the next terse generate rewrites the constant and your code keeps working against SlackChannel.DealDesk. PRs read like English: AttioObject.Deal, not "obj_f1e3c0b2…".

Why coding agents love it even more

The generated SDK is the difference between an agent that guesses and an agent that knows. This is where the compounding wins live:
  • Cursor, Claude Code, Windsurf, and Codex see every real channel, repo, and list as an exported symbol; they pick the one that exists instead of asking which channel to post to.
  • Agents are notoriously bad at preserving long opaque strings across tool calls. With resource constants, there’s nothing to copy.
  • If an agent invents SlackChannel.SalesTeam or Repos.TerseAI.Website, the TypeScript language server in your editor flags it immediately, and any tsc --noEmit step in your own CI catches it before push. A fabricated resource never lands.
  • agent.tools.slack.sendMessage requires message plus either channelId or slackUserId (or both; channelId wins). The signature is enforced, so an agent can’t accidentally pass channel_name or forget message.
  • Point your coding assistant at src/terse.generated.ts and it instantly has a complete map of the integrations, resources, and tools available in your workspace — plus a line-numbered index into the terse.generated/ folder, so it reads only the files the workflow needs instead of one giant dump. No documentation gap.
  • The root header also summarizes the terse-sdk platform primitives (createJob, generateText, durability operations, waitForInput, state, secrets), so an agent never has to dig through the package’s dist to learn the job-authoring API.
The net effect: coding agents ship working workflows on the first try, without a human looping through “here’s the channel ID, here’s the list ID, here’s the repo name” every time.

How it stays in sync

terse generate is idempotent and safe to re-run. Typical triggers for regenerating:
1

You connect a new integration

Run terse integrate or connect from the Terse app, then terse generate to pick up new trigger builders, skills, and tool wrappers.
2

Workspace resources change

A new Slack channel, a new Attio list, a renamed repo. Re-run terse generate and commit the updated file.
Because the file is committed to your repo, git history gives you a full audit trail of how your workspace has changed over time.

Where to go next

Context as Code

The philosophy behind compiling your workspace into typed code.

Skills & integrations

How the generated skills and triggers fit into a workflow.

Deterministic tool calls

Use toolbox or agent.tools.* to call integrations directly, no LLM in the loop.

TypeScript SDK reference

Full reference for the runtime types the generated file imports from.