Snapshots

Slack is the one connector that writes, and it needs no review

Settled
  • It posts cards and jams a team picks, and thread replies return to the jam.
  • Public since 16 Oct; any workspace can install it with no Slack review.
  • Slack never counts as evidence for a Play, and reads only the workspace and channel.
  • Anyone in the channel can press Approve; Param chose to keep it.
  • The manifest now says plays, but a push to Slack is not recorded.
16 Octmade public
Your call

Who may press Approve?

Integrations and ecosystem · 18.4

Slack

DraftLast checked 2026-10-26Owner Param

Answer

Slack is the one connector that writes: the Brew Slack app posts the cards and jams a team chooses to send, brings thread replies and Approve back into the jam, needs no Slack review, and is never evidence for a Play.

Today

The app

Fact Value Source
App Brew, A0C98G07J1M, in the joinsquareup workspace, built from docs/slack-app-manifest.json with the Slack CLI through tools/slack-app.mjs create or update memory brew-real-connectors
Keys SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_SIGNING_SECRET in Secret Manager; the connector switches on when the first two are set brew/connectors/slack.js:5-6, 11 brew/docs/connectors-approvals.md:15
Distribution Public since 16 Oct: any workspace can install it; no review needed memory brew-real-connectors brew/connectors/slack.js:5
Slack Marketplace listing Parked; Slack does not require it brew/docs/connectors-approvals.md:36
Bot scopes chat:write, chat:write.public, incoming-webhook, channels:join, channels:read, groups:read, channels:history, groups:history, users:read, users:read.email, team:read brew/connectors/slack.js:12 brew/docs/slack-app-manifest.json
Bot events message.channels, message.groups, app_uninstalled, tokens_revoked brew/docs/slack-app-manifest.json
Redirects /connect/slack/callback on brew. and feed. brew/docs/slack-app-manifest.json
Manifest copy Since 26 Oct says "marketing plays" and "We read a brand's own store"; the app name and the bot are still Brew, left as is until the name is picked. Not yet pushed to Slack in any source we read brew/docs/slack-app-manifest.json:4-10 brew commit ca2bc7b
Messages Slack refusals and replies say we and us, and the name in Invite @Brew comes from PRODUCT_NAME brew/connectors/slack.js:7, 32-34 brew/slack-routes.js:49-51

What happens

  1. The brand signs in with Continue with Slack and picks a channel on Slack's own screen; Brew joins that channel itself, because Slack only sends a bot replies from channels it is in brew/connectors/slack.js:1-3, 50-52.
  2. Share to Slack and Take it to Slack post for real, with an Approve button memory brew-real-connectors.
  3. Thread replies land in the jam and fold into the brief; what is written in the jam is mirrored to the thread memory brew-real-connectors.
  4. Each thread message is sorted by one cheap call: chatter folds into the brief; a change or any paid image or video becomes a proposal with Make it and Not now, run once on a yes; @Brew applies a text change at once memory brew-real-connectors brew/slack-routes.js:37-39.
  5. Approve moves the jam to Ready; the button must come from the workspace the brand connected, on the jam's own post brew/slack-routes.js:45-51.
  6. Slack's read is the workspace and channel only: no cards, no ledger rows brew/connectors/slack.js:3-4, 58-62.

Events and the relay

  • Slack sends one app's events to one address: feed.joinsquareup.com/slack/events and /slack/actions brew/docs/slack-app-manifest.json.
  • Every request is checked against the signing secret, at most 5 minutes old, and answered within Slack's 3 seconds brew/connectors/slack.js:23-29 brew/slack-routes.js:1-6.
  • Production handles workspaces connected to its brands and relays any other to staging byte for byte, with the signature headers, so staging checks it the same way; staging never relays; a forged request is never relayed brew/slack-routes.js:19-26, 81, 90 brew/test/slack-relay.test.js brew/tools/prod-env.sh:9.
  • Retried events are skipped for an hour by event id brew/slack-routes.js:29-30.
  • A brand at home on one site gets no Slack from the other brew/docs/production.md:21.

Known limits

Limit Source
Approve can be pressed by anyone in the channel; Param said keep it memory brew-go-live-2026-10-17
A real Approve click in the Slack interface was checked only by a signed replay memory brew-real-connectors
A brand connected before channels:join existed needs /invite @Brew memory brew-real-connectors
apps.manifest.update does not verify the events URL; press Retry on the app's Event Subscriptions page, then Save memory brew-real-connectors
The demo site stays simulated memory brew-real-connectors

Tomorrow

Item Version Tag
Post only where the team sends it, replies only from Brew's own threads v1 Stays
Manifest and messages say plays, done on origin/main v1 Stays
App name and bot follow the chosen name v1 Changes
Approve limited to the brand's team members v1 Changes, if Param reverses his call
Weekly digest posted to the channel v1 Stays
Scheduled posts to Slack after a yes v2 New

Rows that change v1 or add v2 are proposals for Param, not decisions.

How we do it

  1. Change the app only through the manifest, then push it:
node tools/slack-app.mjs update

memory brew-real-connectors

  1. After any events URL change, open the app's Event Subscriptions page, press Retry, then Save memory brew-real-connectors.
  2. Test on Cozy in a test channel; never post into a design partner's workspace to test memory brew-live-stores.
  3. When Slack refuses, show its plain words from why(), such as invite @Brew to the channel brew/connectors/slack.js:31-34.

Numbers

Metric Definition Where measured
Connected workspaces Slack connections in state live connections on production, Proposed
Replies into jams Thread replies taken per week Server log [slack] … a reply from, Proposed
Approvals from Slack Approve presses that moved a jam to Ready Server log, Proposed
Relayed events Events production passed to staging Server log [slack] relayed, Proposed

Open

  1. List the app in the Slack Marketplace? Proposal: no until the name is picked; the listing would carry the old name.
  2. Who may press Approve? Param chose anyone in the channel on 17 Oct. Proposal: keep it, and record who pressed it in the jam as it does now.
  3. The manifest now says plays, and still names the app Brew. Proposal: push the new description with tools/slack-app.mjs update now, and rename the app in one more update once the name is picked.
Sources
  • brew origin/main d6154b3: connectors/slack.js:1-64; slack-routes.js:1-51, 81, 90; docs/slack-app-manifest.json; docs/connectors-approvals.md:15, 36; docs/production.md:21, 119-123; tools/prod-env.sh:9; SCOPE.md:14; test/slack-relay.test.js
  • memory brew-real-connectors, brew-go-live-2026-10-17, brew-live-stores
  • handbook content/engineering/connectors.md, read for consistency

Source file content/integrations-and-ecosystem/slack.md · For agents: Markdown · JSON