Skip to content

Commit 9ab6988

Browse files
Align the Slack app docs and metadata with the vetted apps (twentyhq#25235)
Brings the Slack app's documentation and marketplace metadata up to the standard the other first-party apps set. Split out of [twentyhq#25214](twentyhq#25214), which now carries only the vetted flag and the version bump. ## Docs `README.md` and `SETUP.md` were denser and differently shaped than the other apps': - README follows the Call Recorder / Last Contact / People Data Labs shape: pitch line, `What you get`, `Billing`, `Heads up`. The user-links and consent detail, which ran about twice the length of any other app's entire README, moved into the setup guide. - SETUP.md follows Call Recorder's, the only real setup guide among the vetted apps: admin framing with a Twenty Cloud note, `What you need to wire up` before any steps, a server variables table, and a troubleshooting table collecting failure modes that were previously inline asides scattered through the prose. - The server-URL placeholder now matches Call Recorder's form, in both the guide and the manifest. Every fact from the previous versions is preserved, just relocated. The roster sweep and unlinked-users list from twentyhq#25151 are folded into both files. ## Billing correction The README claimed the app was free and unmetered. It isn't. Logic function runs are billed per invocation plus runtime (`logic-function-billing.constant.ts`), and the `message.channels` / `message.groups` subscriptions deliver every message posted in a channel the bot belongs to. The resolver dispatches all of them to `slack-events-enqueue`, which runs in the customer's workspace and only then drops the irrelevant ones, so the invocation is already billed by the time the message is discarded. The section now states the rate, explains that messages the bot never answers still cost an invocation, and documents dropping the two subscriptions as the lever for anyone who only wants explicit mentions and DMs. The alternative was adding the app to `MARKETPLACE_BILLING_EXEMPT_UNIVERSAL_IDENTIFIERS` alongside Call Recorder and Last Contact. Documenting the real cost was the call here; happy to switch if the exemption is preferred. ## Metadata `websiteUrl` now points at the app folder rather than the generic app-development docs, since it is the only link from the marketplace detail page to the setup guide. Server-variable descriptions tightened, and `SLACK_WEBHOOK_SECRET` now says it covers interactivity requests too, which it did but wasn't documented. ## Slack's PKCE opt-in SETUP.md now says to leave it off, with the reason. Enabling it reclassifies the app as a public client (one-way, reversible only by Slack support) while `exchangeCodeForToken` sets `client_secret` unconditionally, and it stops a localhost redirect from requesting bot scopes. Note that dropping `client_secret` whenever `usePkce` is true would be the wrong fix: `usePkce` defaults to true for every provider and Linear already runs that flow against a confidential client, where sending both is correct. ## Merge order Contains the `im:write` manifest line from [twentyhq#25234](twentyhq#25234) so the rewritten scopes table is correct standalone. If twentyhq#25234 merges first the hunk is a no-op. Merge this before publishing 1.0.0 from twentyhq#25214 — the catalog reads `description` and `websiteUrl` from the published tarball, so a publish that predates this ships the old metadata. ## Test plan - [ ] Marketplace detail page shows the new description and a Website link to the app folder --- _Generated by [Claude Code](https://claude.ai/code/session_01FVj51vPJYMhvfkRoppynJW)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/25235?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
1 parent afc426b commit 9ab6988

5 files changed

Lines changed: 331 additions & 129 deletions

File tree

packages/twenty-apps/public/slack/README.md

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,20 @@
44

55
## ✨ What you get
66

7-
- **A CRM assistant in Slack**`@twenty how many open opportunities do we have?` or `@twenty create a company called ACME`. It answers in-thread, remembers the thread, and can read, create, update and soft-delete records
8-
- **Follow-ups without re-mentioning** — once it has replied in a thread you can keep talking to it for 24 hours; when that window lapses it privately nudges you to mention it again
7+
- **A CRM assistant in Slack**`@twenty how many open opportunities do we have?` or `@twenty create a company called ACME`. It answers in-thread and can read, create, update and soft-delete records
8+
- **Follow-ups without re-mentioning** — once it has replied in a thread you can keep talking to it, for 24 hours in a channel and indefinitely in a DM
9+
- **It acts as whoever tagged it** — Slack accounts are matched to workspace members, so the bot can never do more than the person asking
910
- **Slack steps for your workflows** — post, update or delete messages, send ephemerals, add reactions, list channels
1011

1112
## 🤖 The assistant
1213

13-
Mention the bot in a channel or DM it. It replies in the thread with your CRM data, using the recent conversation as context. Answers end with native thumbs up / thumbs down feedback buttons — except very long answers, which fall back to plain text without them — and ratings are stored on the matching Slack Assistant Request record in Twenty.
14+
Mention the bot in a channel or DM it. It replies in the thread with your CRM data, using the recent conversation as context. Short answers end with native thumbs up / thumbs down buttons, and the rating is stored on the matching Slack Assistant Request record in Twenty.
1415

15-
Out of the box the bot runs with the **Slack Assistant** role, which can read, create, update and soft-delete people, companies, opportunities, notes and tasks. Workspace members stay read-only and hard delete is off. Tighten the role in **Settings → Roles** if you want a narrower bot.
16+
A Slack account with no link to a workspace member runs with the **Slack Assistant** role, which can read, create, update and soft-delete people, companies, opportunities, notes and tasks. Workspace members stay read-only and hard delete is off. Tighten the role in **Settings → Roles** if you want a narrower bot.
1617

17-
**It acts as whoever tagged it.** The first time someone mentions the bot, their Slack profile email is matched against workspace members and the pair is stored as a **Slack User Link** record. The person who connects the Slack workspace is matched the same way right at connection time, and the rest of the Slack roster is swept for matching emails in the same pass, so most people are linked before anyone messages the bot. From then on the bot runs with that member's own permissions, so it can never do more than the person asking. Someone with no link gets the **Slack Assistant** role instead, exactly as before.
18+
Everyone else runs with their own permissions. Connecting the Slack workspace sweeps the roster and links every full member whose confirmed Slack email matches a workspace member; anyone the sweep missed is matched the first time they mention the bot. Each pair is stored as a **Slack User Link**. Guests and Slack Connect users are never matched automatically, so an admin links them by hand from the app's **Settings** tab, which also lists who the sweep skipped. See [SETUP.md](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/public/slack/SETUP.md) for how linking, consent and re-verification work.
1819

19-
A link matched on email is re-verified on every request: the bot rechecks that the Slack account's current verified email still points at the same member, and follows the live match rather than the stored record if they disagree. The record is an audit trail, not the source of truth.
20-
21-
Only members of the Slack workspace that installed the app are matched automatically. Guests and Slack Connect users from another Slack workspace are not, because their email is vouched for by someone other than your admin. For those cases a member with the roles permission can link them by hand from the **Slack user links** section of the app's **Settings** tab, or by asking the assistant to link a Slack user to a workspace member; either way the pair is stored with its source set to manual. The Settings section searches members by name so there is no need to paste a member ID, searches the Slack workspace by name or email the same way to pick the Slack account, and spells out next to the save button whether saving activates the link immediately or sends an approval request, so you never link or message the wrong account. It lists the existing links with their status, lets a member with the permission remove a link or resend a pending consent request, and shows a read-only view to anyone without the permission. A guest or Slack Connect user whose email is not in your workspace is linked by their Slack user ID instead; for a Slack Connect user, include their own Slack workspace's team ID so the link matches the messages they send.
22-
23-
The same section lists Slack users who have no link yet, so an admin can see who the automatic match skipped and finish the job in place: each row has its own member picker, spells out whether linking activates immediately or asks the person first, and saves without leaving the list. An **Auto-link by email** button reruns the roster sweep on demand, which covers workspaces that connected the app before the sweep existed and new hires who joined Slack after connection. The sweep only trusts a confirmed email on a full member of the installed workspace and never touches an existing link, so a declined or hand-made link is left alone.
24-
25-
**A matching email needs no approval.** Linking a Slack account to the workspace member with the same email is just the automatic match set up ahead of the person's first message, so it is stored as an email-matched link and is active immediately, with the same live re-verification automatic links get.
26-
27-
**Any other manual link asks the person first.** When you link someone who is in the installed Slack workspace to a member with a different email, the app sends them a direct message explaining that an admin wants the assistant to act with a workspace member's access, with **Approve** and **Decline** buttons. The link stays inactive (shown as _Awaiting consent_) until they approve, so the assistant never borrows someone's permissions without their say-so; a decline keeps it off. Guests and Slack Connect users from another workspace cannot be messaged this way, so their link is admin-set and active on save, labelled as such. A consented or admin-set manual link wins over email matching. Slack User Link records can only be written by the app itself, never directly through the API or the UI, so a manual link always reflects both an admin's decision and, where possible, the person's consent. Sending the consent request needs the `im:write` scope, so reconnect the Slack app after upgrading to grant it.
28-
29-
One Slack workspace answers into one Twenty workspace.
30-
31-
When the bot is added to a channel it introduces itself once, with a short message in the channel and the details (what to ask it, what it reads, and how permissions work) in a thread reply. It needs the `member_joined_channel` subscription, so leave that one off if you want the bot to arrive quietly.
20+
When the bot is added to a channel it introduces itself once, with a short message in the channel and the details in a thread reply.
3221

3322
## 🧰 The workflow steps
3423

@@ -45,10 +34,14 @@ Pick a **workspace shared** or **just for me** Slack connection; steps run with
4534

4635
## 💳 Billing
4736

48-
**Free** — the app itself costs no credits and is not metered.
37+
No per-seat or per-message charge, but the app's runs are metered like any other app's — **$0.0001 per logic function invocation**, plus runtime.
38+
39+
Every Slack event the bot is subscribed to costs an invocation, including messages it never answers: `message.channels` and `message.groups` deliver every message posted in the channels the bot belongs to, which is what makes un-mentioned thread follow-ups work. Drop those two subscriptions to limit the bot to explicit mentions and DMs. Each workflow step run costs an invocation too.
4940

50-
The assistant still runs on your workspace AI credits, billed on the model's token usage, so every mention or DM answered has an indirect cost. The workflow steps only call Slack and consume nothing.
41+
Answering costs AI credits on top, billed on the model's token usage — the whole prompt as well as the reply — so cost tracks the conversation context, the records the bot reads and the length of its answer.
5142

5243
## 📌 Heads up
5344

54-
You need to create a Slack app and connect it — see [SETUP.md](./SETUP.md). The assistant needs a few extra steps (signing secret and event subscriptions) on top of the base connection.
45+
- **You create the Slack app** — Twenty connects to a Slack app you own, so an admin has to create it and set its credentials before anyone can connect. The assistant needs a signing secret and event subscriptions on top. See [SETUP.md](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/public/slack/SETUP.md).
46+
- **One Slack workspace per Twenty workspace** — connecting claims that Slack team. Removing the last connection using it releases the claim, so another Twenty workspace can then connect the same team.
47+
- **Private channels need membership** — public channels are covered by `chat:write.public`; anywhere else, invite the bot.

0 commit comments

Comments
 (0)