> ## 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.

# Skills

> Connect external services, generate typed code, and control what the model can reach.

Integrations and skills are two sides of the same coin. An integration is a connected external service: your CRM, enrichment provider, messaging tool, or data warehouse. A skill is the declaration that hands an integration to your workflow. Connect once, generate typed code, then declare per job which skills the model can reach.

## Integrations: stored credentials

An integration is a connection to an external service. When you run `terse integrate` or connect through the Terse app, the platform stores your OAuth tokens or API keys securely. The integration itself is just an authenticated link to a service.

Terse supports two connection types:

| Type      | Flow                                                        | Examples                                                  |
| --------- | ----------------------------------------------------------- | --------------------------------------------------------- |
| **OAuth** | Opens your browser for authorization                        | GitHub, Slack, Gmail, Linear, Notion, Attio               |
| **Form**  | Prompts for API keys or account credentials in the terminal | Datadog, PostHog, Snowflake, LaunchDarkly, WorkOS, Apollo |

After connecting, run `terse generate` to turn your active integrations into typed code.

## Code generation: from credentials to code

`terse generate` reads your connected integrations and their resources (repos, channels, lists, teams, projects), then writes a typed SDK file for your project.

See the [Generated SDK](/core-concepts/generated-sdk) page for more detail.

## Skills vs. deterministic tools

This is the key distinction:

|                   | Skills (model access)                                       | Deterministic tools (code access)            |
| ----------------- | ----------------------------------------------------------- | -------------------------------------------- |
| **Who decides**   | The model chooses which tools to call                       | Your code calls tools directly               |
| **Controlled by** | `skills` array on `generateText` (or `TerseAgent.create()`) | `toolbox.*` (unfiltered)                     |
| **Scope**         | Only integrations declared as skills                        | `toolbox.*` covers any connected integration |
| **Token cost**    | Tokens consumed per call                                    | Zero LLM tokens                              |

`agent.tools.*` mirrors the `skills` allowlist: only integrations declared as skills appear on the agent's typed tool object. For unfiltered programmatic access to every connected integration, import `toolbox` from `./terse.generated` and call it directly, no agent needed.

This means you can be precise about the model's reach for a given job, while still calling any connected integration from your handler code through `toolbox`:

```ts theme={null}
import { generateText, createJob } from "terse-sdk"

import { AttioObject, Skills, SlackChannel, Triggers, toolbox } from "./terse.generated"

createJob({
    name: "weekly-digest",
    triggers: [Triggers.schedule.cron({ expression: "0 9 * * 1" })],
    onTrigger: async (event) => {
        // Agentic: model can only use Attio (the declared skill)
        const summary = await generateText({
            prompt: "Summarize this week's pipeline activity.",
            skills: [Skills.attio({ object: AttioObject.Deal })]
        })

        // Deterministic: toolbox is unfiltered, so Slack works even though it isn't a skill
        await toolbox.slack.sendMessage({
            channelId: SlackChannel.DealDesk.channelId,
            message: summary
        })
    }
})
```

## Skill configuration

Some skills accept configuration that scopes what the model sees or where it acts:

| Skill                | Configuration     | Effect                                             |
| -------------------- | ----------------- | -------------------------------------------------- |
| `Skills.attio()`     | `object`          | Scopes record reads and writes to one Attio object |
| `Skills.slack()`     | `channel`         | Targets a specific channel for messaging           |
| `Skills.github()`    | `repos`           | Scopes code access to specific repositories        |
| `Skills.linear()`    | `team`, `project` | Optionally scopes to a team and/or project         |
| `Skills.snowflake()` | None              | Read-only SQL queries against your warehouse       |
| `Skills.apollo()`    | None              | People/company enrichment and prospect search      |
| `Skills.web()`       | None              | Built-in web search, page extraction, and research |

Skills without configuration give the model access to the full integration surface.

## Where to go next

<CardGroup cols={2}>
  <Card title="Skills & tools reference" icon="wrench" href="/reference/skills">
    Full list of every skill and the tools it exposes.
  </Card>

  <Card title="Deterministic tool calls" icon="locate-fixed" href="/core-concepts/deterministic-tool-calls">
    Call tools directly from code without the LLM.
  </Card>
</CardGroup>
