You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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. -->
Copy file name to clipboardExpand all lines: packages/twenty-apps/public/slack/README.md
+14-21Lines changed: 14 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,31 +4,20 @@
4
4
5
5
## ✨ What you get
6
6
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
9
10
-**Slack steps for your workflows** — post, update or delete messages, send ephemerals, add reactions, list channels
10
11
11
12
## 🤖 The assistant
12
13
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.
14
15
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.
16
17
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.
18
19
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.
32
21
33
22
## 🧰 The workflow steps
34
23
@@ -45,10 +34,14 @@ Pick a **workspace shared** or **just for me** Slack connection; steps run with
45
34
46
35
## 💳 Billing
47
36
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.
49
40
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.
51
42
52
43
## 📌 Heads up
53
44
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