Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 23 additions & 20 deletions apps/docs/src/content/docs/integrations/chatwoot.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,26 @@ With all three set, an interactive session shows `chatwoot: on · support inbox

**`chatwoot_read`** (read-only):

| op | What it returns |
| --- | --- |
| `conversations` | the inbox. `status` is `open` (default), `pending`, `resolved`, `snoozed` or `all`; `assignee` is `me`, `unassigned` or `all`; plus `inbox` and `page`. Each row shows the customer, assignee, unread count, labels and the last message |
| `conversation` | one conversation `id` (the number in `#123`) with its messages in order: customer, agent, private notes and activity |
| `contacts` | people matching `query` (name, email or phone) |
| `contact` | one contact `id` with their attributes and conversations |
| `inboxes`, `agents`, `labels` | lookups for filtering and assigning |
| op | What it returns |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `conversations` | the inbox. `status` is `open` (default), `pending`, `resolved`, `snoozed` or `all`; `assignee` is `me`, `unassigned` or `all`; plus `inbox` and `page`. Each row shows the customer, assignee, unread count, labels and the last message |
| `conversation` | one conversation `id` (the number in `#123`) with its messages in order: customer, agent, private notes and activity |
| `contacts` | people matching `query` (name, email or phone) |
| `contact` | one contact `id` with their attributes and conversations |
| `inboxes`, `agents`, `labels` | lookups for filtering and assigning |

**`chatwoot_write`** on a conversation `id`:

| op | What it does |
| --- | --- |
| `reply` | sends `body` **to the customer, immediately** |
| `note` | adds a **private** note (`body`) that only agents see |
| `status` | sets `open`, `pending`, `resolved` or `snoozed` |
| `assign` | assigns to `"me"`, or an agent by id, name or email (a name that matches more than one agent is refused) |
| `label` | adds `labels`; existing labels are kept |
| op | What it does |
| --------- | -------------------------------------------------------------------------------------------------------- |
| `reply` | sends `body` **to the customer, immediately** |
| `note` | adds a **private** note (`body`) that only agents see |
| `status` | sets `open`, `pending`, `resolved` or `snoozed` |
| `assign` | assigns to `"me"`, or an agent by id, name or email (a name that matches more than one agent is refused) |
| `label` | adds `labels`; existing labels are kept |
| `unlabel` | removes `labels`; the rest are kept |

**`chatwoot_api`** covers everything else in the [Chatwoot API](https://developers.chatwoot.com/api-reference/introduction): create, update or delete contacts, start a conversation, canned responses, teams, custom attributes, macros, reports. It takes a `method`, a `path` relative to your account (`/contacts`, `/conversations/12/messages`) or an absolute API path (`/api/v1/profile`), and an optional JSON `body`. A `GET` counts as a read; every other method is a write, held back while planning or running unattended like `chatwoot_write`. The path can only reach your own instance: no other host, no `..`.

## Replies reach real people

Expand All @@ -58,12 +61,12 @@ For safety, tsforge never follows an HTTP redirect with your token. A token that

With [Twenty](/integrations/twenty/) connected too, the agent can look the customer up in the CRM while it reads their conversation, and log the outcome as a note on their person record.

| Setting / variable | Effect |
| --- | --- |
| `chatwootUrl` / `TSFORGE_CHATWOOT_URL` | your Chatwoot instance |
| `chatwootToken` / `TSFORGE_CHATWOOT_TOKEN` | your access token |
| `chatwootAccountId` / `TSFORGE_CHATWOOT_ACCOUNT_ID` | the account to work in |
| `TSFORGE_NO_CHATWOOT` | withhold the Chatwoot tools even when configured (`=1`) |
| Setting / variable | Effect |
| --------------------------------------------------- | ------------------------------------------------------- |
| `chatwootUrl` / `TSFORGE_CHATWOOT_URL` | your Chatwoot instance |
| `chatwootToken` / `TSFORGE_CHATWOOT_TOKEN` | your access token |
| `chatwootAccountId` / `TSFORGE_CHATWOOT_ACCOUNT_ID` | the account to work in |
| `TSFORGE_NO_CHATWOOT` | withhold the Chatwoot tools even when configured (`=1`) |

## Checking it against your instance

Expand Down
20 changes: 14 additions & 6 deletions apps/docs/src/content/docs/integrations/linear.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ The server **must be keyed exactly `linear`**. Once it connects, an interactive

## The tools

The agent has **all of Linear's MCP tools** (`mcp__linear__*`): everything a person can do in Linear through its API.

- **Issues**: `save_issue` creates an issue, or with an `id` updates any field: title, description, status, priority, assignee, labels, project, milestone, cycle, estimate, due date, parent, duplicate-of. Moving an issue to another project or team is an update.
- **Projects, milestones, labels, documents, status updates**: `save_project`, `save_milestone`, `save_issue_label`, `save_document` and `save_status_update` create and update them, and `list_*` / `get_*` find them.
- **What Linear itself doesn't offer**: there is no tool to delete an issue (cancel it, or mark it a duplicate of the original). Initiatives appear only if your Linear plan includes them.

On top of that, three shortcuts:

- **`linear_read`** (read-only): `issue` (one card by identifier like `ENG-123` — title, state, description, the **branch name** Linear generated, and links), `search`, `mine` (your assigned issues), and `comments`.
- **`linear_write`**: `create` (a new card with a `title` and the `team` to file it under, by key like `ENG`, name or id; returns its identifier and branch name) and `comment` (adds a comment to a card by its identifier). There is deliberately **no status op**: Linear moves the card itself when the linked PR opens and merges.
- **`linear_write`**: quick `create` (a `title` and the `team` to file it under, by key like `ENG`, name or id; returns its identifier and branch name) and `comment` (on a card by its identifier).
- **`linear_start`**: the one-step start — read a card by id and **check out the git branch** Linear made for it (creating it if needed). Edit as usual, then open a PR referencing the issue (e.g. `Fixes ENG-123`); Linear links the branch and transitions the card for you.

## Cards written for humans
Expand All @@ -36,11 +44,11 @@ The server **must be keyed exactly `linear`**. Once it connects, an interactive

## When they're active

Reads are available in every mode, including [plan mode](/cli/plan-mode/). Writes (`create`, `comment`, and `linear_start`'s checkout) follow capability-as-consent: allowed interactively, denied while planning or running unattended. See [Permissions & policy](/guardrails/policy/).
Reads (the shortcuts and every `get_`/`list_`/`search` tool) are available in every mode, including [plan mode](/cli/plan-mode/). Writes (every other Linear tool, and `linear_start`'s checkout) follow capability-as-consent: allowed interactively, denied while planning or running unattended. See [Permissions & policy](/guardrails/policy/).

| Variable | Default | Effect |
| --- | --- | --- |
| `TSFORGE_NO_LINEAR` | off | withhold the Linear tools even when the server is connected (`=1`) |
| `TSFORGE_LINEAR_RAW` | off | also advertise the raw `mcp__linear__*` tools alongside the curated verbs (`=1`) |
| Variable | Default | Effect |
| -------------------- | ------- | ------------------------------------------------------------------------ |
| `TSFORGE_NO_LINEAR` | off | withhold the Linear tools even when the server is connected (`=1`) |
| `TSFORGE_LINEAR_RAW` | on | `=0` hides the full `mcp__linear__*` toolset, leaving only the shortcuts |

→ [MCP servers](/integrations/mcp/) · [Git & GitHub](/integrations/git-github/) · [Environment variables](/reference/flags/)
4 changes: 3 additions & 1 deletion apps/docs/src/content/docs/integrations/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ On startup tsforge connects each server, lists its tools, and advertises them to

## Built-in integrations (Linear, Notion, Sentry, Twenty)

Some MCP servers get a **curated** treatment instead of raw passthrough. When you configure a server keyed **`linear`**, **`notion`**, **`sentry`** or **`twenty`**, tsforge offers a small set of purpose-built verbs (e.g. `linear_read`, `notion_read`, `sentry_read`) instead of that server's dozens of raw tools — so the model's tool list stays focused — and hides the raw `mcp__<server>__*` tools by default (re-expose them with the matching `TSFORGE_<NAME>_RAW=1`). These follow a **capability = consent** model: the server being connected is your consent, reads work in every mode, and writes are held back while planning or running unattended.
When you configure a server keyed **`linear`**, **`notion`**, **`sentry`** or **`twenty`**, the agent gets **that server's full toolset** (every `mcp__<server>__*` tool, with the server's own input schemas) plus a few purpose-built shortcuts on top (e.g. `linear_read`, `linear_start`, `twenty_read`). The shortcuts are conveniences, not a cap: anything the server can do, the agent can do.

Each raw call is classified by what it does. Look-ups (`get_…`, `list_…`, `search…`) are **reads**; everything else is a **write**, and an unknown verb is treated as a write. The same **capability = consent** model as the shortcuts applies: the server being connected is your consent, reads work in every mode including planning, and writes are held back while planning or running unattended. For a smaller tool list, `TSFORGE_<NAME>_RAW=0` hides a server's raw tools behind its shortcuts.

[GitHub](/integrations/git-github/) is first-class too, but via the `git`/`gh` binaries rather than MCP.

Expand Down
8 changes: 4 additions & 4 deletions apps/docs/src/content/docs/integrations/notion.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ Pages tsforge writes are for a human reader — the intent and the context, not

Reads are available in every mode, including [plan mode](/cli/plan-mode/). Writes follow capability-as-consent: allowed interactively, denied while planning or running unattended. See [Permissions & policy](/guardrails/policy/).

| Variable | Default | Effect |
| --- | --- | --- |
| `TSFORGE_NO_NOTION` | off | withhold the Notion tools even when the server is connected (`=1`) |
| `TSFORGE_NOTION_RAW` | off | also advertise the raw `mcp__notion__*` tools alongside the curated verbs (`=1`) |
| Variable | Default | Effect |
| -------------------- | ------- | ------------------------------------------------------------------------ |
| `TSFORGE_NO_NOTION` | off | withhold the Notion tools even when the server is connected (`=1`) |
| `TSFORGE_NOTION_RAW` | on | `=0` hides the full `mcp__notion__*` toolset, leaving only the shortcuts |

→ [MCP servers](/integrations/mcp/) · [Sentry](/integrations/sentry/) · [Environment variables](/reference/flags/)
8 changes: 4 additions & 4 deletions apps/docs/src/content/docs/integrations/sentry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ The server **must be keyed exactly `sentry`**. Once it connects, an interactive

Reads are available in every mode, including [plan mode](/cli/plan-mode/). The `resolve` write follows capability-as-consent: allowed interactively, denied while planning or running unattended. See [Permissions & policy](/guardrails/policy/).

| Variable | Default | Effect |
| --- | --- | --- |
| `TSFORGE_NO_SENTRY` | off | withhold the Sentry tools even when the server is connected (`=1`) |
| `TSFORGE_SENTRY_RAW` | off | also advertise the raw `mcp__sentry__*` tools alongside the curated verbs (`=1`) |
| Variable | Default | Effect |
| -------------------- | ------- | ------------------------------------------------------------------------ |
| `TSFORGE_NO_SENTRY` | off | withhold the Sentry tools even when the server is connected (`=1`) |
| `TSFORGE_SENTRY_RAW` | on | `=0` hides the full `mcp__sentry__*` toolset, leaving only the shortcuts |

→ [MCP servers](/integrations/mcp/) · [Linear](/integrations/linear/) · [Environment variables](/reference/flags/)
32 changes: 16 additions & 16 deletions apps/docs/src/content/docs/integrations/twenty.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,27 @@ Twenty's MCP server offers about 300 generated tools behind a catalog the model

**`twenty_read`** (read-only). `type` is `person`, `company`, `opportunity`, `task` or `note`.

| op | What it returns |
| --- | --- |
| `search` | records matching `query`: names and emails for people, name or domain for companies, titles for deals, tasks and notes |
| `list` | the most recently updated records (`limit`, default 10, max 50) |
| `record` | one record by `id`, with the notes and tasks attached to it |
| `pipeline` | opportunities counted and summed by stage |
| op | What it returns |
| ---------- | ---------------------------------------------------------------------------------------------------------------------- |
| `search` | records matching `query`: names and emails for people, name or domain for companies, titles for deals, tasks and notes |
| `list` | the most recently updated records (`limit`, default 10, max 50) |
| `record` | one record by `id`, with the notes and tasks attached to it |
| `pipeline` | opportunities counted and summed by stage |

Every row ends with the record's id in parentheses. That id is what `record`, `update`, `note` and `task` take.

**`twenty_write`**:

| op | What it does |
| --- | --- |
| op | What it does |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `create` | a person (`firstName`, `lastName`, `email`, `phone`, `jobTitle`, `companyId`), a company (`name`, `domain`) or an opportunity (`name`, `stage`, `amount` + `currency`, `closeDate`, `companyId`, `pointOfContactId`) |
| `update` | `type` + `id` + only the fields to change |
| `note` | `title` + `body` (markdown); add `type` + `id` to attach it to that person, company or deal |
| `task` | `title`, optional `body`, `dueAt`, `status` (`TODO`, `IN_PROGRESS`, `DONE`); `type` + `id` to attach it |
| `update` | `type` + `id` + only the fields to change |
| `note` | `title` + `body` (markdown); add `type` + `id` to attach it to that person, company or deal |
| `task` | `title`, optional `body`, `dueAt`, `status` (`TODO`, `IN_PROGRESS`, `DONE`); `type` + `id` to attach it |

Amounts are whole currency units (`5000` means 5,000). tsforge converts them to the micros Twenty stores. A new deal starts at stage `NEW` unless you pass one.

There is **no delete**. If a record needs to go, the agent tells you.
For everything else (deleting records, other objects, custom fields, filtered lists, workflows, dashboards, email), the agent also has **Twenty's full toolset**: it finds a tool with `mcp__twenty__get_tool_catalog`, learns its inputs with `learn_tools`, and runs it with `execute_tool`. Each `execute_tool` call counts as a read or a write by the tool it runs (`find_many_people` reads, `delete_one_company` writes). Deletes are soft: the record moves to Twenty's trash.

## Things worth knowing

Expand All @@ -63,10 +63,10 @@ There is **no delete**. If a record needs to go, the agent tells you.

Reads work in every mode, including [plan mode](/cli/plan-mode/). Writes follow capability as consent: allowed in an interactive session, held back while planning or running unattended. See [Permissions & policy](/guardrails/policy/).

| Variable | Default | Effect |
| --- | --- | --- |
| `TSFORGE_NO_TWENTY` | off | withhold the Twenty tools even when the server is connected (`=1`) |
| `TSFORGE_TWENTY_RAW` | off | also advertise Twenty's raw `mcp__twenty__*` meta-tools (`=1`) |
| Variable | Default | Effect |
| -------------------- | ------- | -------------------------------------------------------------------------- |
| `TSFORGE_NO_TWENTY` | off | withhold the Twenty tools even when the server is connected (`=1`) |
| `TSFORGE_TWENTY_RAW` | on | `=0` hides Twenty's raw `mcp__twenty__*` tools, leaving only the shortcuts |

## Checking it against your instance

Expand Down
Loading
Loading