BakedBrie docs

Recipe: Slack intake and approvals

Three pieces, each usable on its own:

  • Intake: a top-level message from a person in a chosen channel becomes one card, with its attached files. Replies go to that message's thread.
  • Review posts: when a draft needs a review, BakedBrie posts it to Slack with Approve and Request changes buttons, then updates the message after a decision.
  • Approvals: a Slack user who is linked to a BakedBrie member decides the review as that member. Board access, the named reviewer and "the maker cannot approve" apply exactly as in the app.

Reviews need a work folder on the board (set_work_folder). This page uses your own Slack app. When Add to Slack is on, see the Add to Slack variant instead.

Create the Slack app (the person does this)

  1. At https://api.slack.com/apps, create an app in your Slack workspace.
  2. Under OAuth and Permissions, add these bot token scopes: chat:write, files:write, files:read, channels:history, groups:history, users:read.
  3. Install the app to the workspace. Copy the Bot User OAuth Token (xoxb-...) into the SLACK_BOT_TOKEN environment variable.
  4. Under Basic Information, App Credentials, copy the Signing Secret into the SLACK_SIGNING_SECRET environment variable.
  5. In the channel, type /invite @<your app name>.

Event Subscriptions and Interactivity are turned on after the prompt runs, because they need the URL BakedBrie creates.

The prompt

Run it with a Full control token from a workspace owner or admin: Slack approvals count only when an owner or admin set the endpoint's signing secret, and only they can link approvers.

Fill in {{BOARD_NAME}}, {{START_COLUMN}}, {{SLACK_CHANNEL_ID}} (starts with C, or G for an older private channel), {{SLACK_TEAM_ID}} (starts with T), and for each approver their Slack member id and BakedBrie user id.

In BakedBrie, connect the board "{{BOARD_NAME}}" to Slack channel {{SLACK_CHANNEL_ID}} in Slack workspace {{SLACK_TEAM_ID}}. Use only the BakedBrie MCP tools. Start with whoami and stop if inbound, api_workflow, destinations or secrets is off.

For each secret, call prepare_secret with the kind, purpose and environment variable I give, run the command it returns in my shell exactly as given (one command per shell call), then pass the drop_id. Never ask me to paste a secret and never print one.

1. Find the board with list_boards and its columns with read_board.
2. Slack destination: prepare_secret kind slack, purpose destination, env_var SLACK_BOT_TOKEN. Create an API destination with manage_destination: action create, preset slack, name "Slack {{BOARD_NAME}}", slack {"channel_id": "{{SLACK_CHANNEL_ID}}", "team_id": "{{SLACK_TEAM_ID}}"}, credential {"drop_id": "<the drop id>"}.
3. Review posts: with manage_board_hooks action set, send review_requested and review_decided to that destination with their default actions. If I want delivery and publish notices in the thread too, also set delivered and published.
4. Intake: prepare_secret kind inbound_signing, purpose connection, env_var SLACK_SIGNING_SECRET. Create an inbound endpoint with manage_inbound_endpoint: action create, preset slack, name "Slack {{BOARD_NAME}} intake", board_id, start_stage_id the {{START_COLUMN}} column, slack {"channel_ids": ["{{SLACK_CHANNEL_ID}}"], "team_id": "{{SLACK_TEAM_ID}}"}, signing_secret {"drop_id": "<the drop id>"}, fetch_destination_id and reply_destination_id both the Slack destination from step 2.
5. Approvers: for each approver I list, call manage_member_mapping action set with provider slack, external_user_id their Slack member id, team_id {{SLACK_TEAM_ID}} and user_id their BakedBrie user id. Link nobody else.
   Approvers: {{APPROVER_SLACK_ID_1}} = {{APPROVER_USER_ID_1}}
6. Read back manage_inbound_endpoint list, manage_board_hooks list and manage_member_mapping list. Reply with the endpoint's url (for Event Subscriptions) and the same url followed by /actions (for Interactivity), the hooks, and the links.

After it runs (the person does this)

  1. In the Slack app, Event Subscriptions: turn it on, paste the endpoint url as the Request URL (Slack checks it right away), and subscribe to the bot event message.channels, plus message.groups for a private channel.
  2. Interactivity and Shortcuts: turn it on and paste the url followed by /actions.
  3. Make sure each approver can open the board in BakedBrie (invite them in the app; invitations are human only).
  4. Post a test message in the channel. A card should appear in the start column.

No BakedBrie user id for an approver? Link them in the app instead: Settings, Members, Slack approvals lets an owner or admin pick the member from a list.

What happens in Slack

  • Messages from bots, thread replies and other channels never become cards. Every request must carry a valid Slack signature; unsigned, stale or replayed requests create nothing.
  • Attached files are downloaded with the bot token into the card and the work folder's Inbox/. The agent run waits until they land.
  • A click is refused with a private note when:
    • the Slack user is not linked (NOT_MAPPED),
    • the linked member cannot open the board (NO_BOARD_ACCESS),
    • the member made the draft (MAKER_CANNOT_APPROVE), or
    • the board has a named reviewer and it is someone else (NOT_NAMED_REVIEWER).
  • Request changes sends the card back for another round; a note given with it goes to the next run.

Changing it later

  • Disable intake: manage_inbound_endpoint action disable. Re-enable: action update with enabled: true.
  • Rotate the signing secret: a new drop, then manage_inbound_endpoint action update with signing_secret.
  • Remove an approver: manage_member_mapping action list, then action remove with the mapping_id.
  • Stop review posts: manage_board_hooks action clear with the event.
  • More boards on the same Slack app: give each board its own Slack destination and hooks. A Slack app has one Interactivity URL, so keep the first endpoint's /actions URL there: clicks on another board's review message are decided there too, as long as the linked member can decide reviews on that board. A signing secret backs one endpoint, so messages that should become cards on a second board need a second Slack app (or Add to Slack, where one install feeds any number of boards).
  • Archiving a board turns off its inbound endpoints and hooks.

View as Markdown