Skip to content

Slack app manifest

Every field of the Slack app manifest Chickpea installs, with the scopes, events, and URLs it declares and what each one is used for.

Updated View as Markdown

The Slack app manifest is the single JSON document that declares the Slack app a Chickpea deployment installs: its identity, its permission scopes, the events Slack sends it, and the URLs Slack calls. Where a channel grant decides which Agent may answer inside Slack, the manifest decides what the Slack app may ask Slack for at all. This page lists every field of that manifest, the 20 bot scopes and 3 user scopes with the code path behind each, the 11 bot events, and the settings that are deliberately off.

Source of truth: slack-app-manifest.json at the repository root. It is generated by canonicalSlackAppManifestJson() in src/slack/app-manifest.ts, and tests/slack-app-manifest.test.ts asserts the committed file is byte-identical to that builder’s output. Editing the JSON without editing the builder fails the test.

Quick reference

Field group Value
App name and bot display name Chickpea, both
Description A self-hosted, model-agnostic AI agent for Slack.
Background color #bd5732
Bot token scopes 20
User token scopes 3 (openid, profile, email)
Redirect URLs 2, under /auth/slack/
Events request URL /channels/slack/events
Bot events 11
Interactivity request URL /channels/slack/interactions
Socket Mode, org deploy, token rotation, Slack MCP all false

Where the manifest applies

The manifest describes the customer-owned app created in the Use your own Slack app lane. Admin builds a Slack deep link from it: the committed placeholder origin https://chickpea.example is replaced with the deployment’s own origin before the link is handed to Slack, so no URL is ever copied by hand. Over a plain HTTP origin, which Slack rejects anyway, only the Events request URL is substituted.

The scope list is wider than one lane. REQUIRED_SLACK_BOT_SCOPES in src/slack/scopes.ts is read directly from the committed manifest and is the authority for every bot installation, so the same 20 scopes are requested and verified whichever lane a deployment uses. The Add to Slack lane installs Chickpea’s shared app instead of this manifest, and the deployment reaches Slack through a fixed allowlist of 33 gateway operations rather than with a token of its own.

Display information

Field Value
name Chickpea, at most 35 characters
description A self-hosted, model-agnostic AI agent for Slack.
background_color #bd5732

The builder accepts a different app name and bot display name for a deployment that needs one. The description and background color are fixed.

App features

Feature Value What it enables
app_home.home_tab_enabled true The App Home directory that lists an operator’s available Agents
app_home.messages_tab_enabled true Direct messages to an Agent from the Messages tab
app_home.messages_tab_read_only_enabled false The Messages tab accepts input
bot_user.display_name Chickpea, at most 80 characters The installed bot’s name
bot_user.always_online true The bot never shows as away
agent_view.agent_description Same string as the app description Slack’s agent view header
agent_view.suggested_prompts 3 entries Starter prompts: Summarize supplied text, Investigate a question, Plan a task

Bot token scopes

Twenty scopes, in manifest order. Each line names the Slack API method or event that requires it.

Scope Why Chickpea needs it
app_mentions:read Receives the app_mention event, the mention that addresses an Agent handle in a channel.
assistant:write Drives the Slack agent view through assistant.threads.setStatus, setTitle, and setSuggestedPrompts.
channels:history Reads public channel context with conversations.history and conversations.replies.
channels:join Calls conversations.join when an Agent is published to a public channel the app has not joined.
channels:read Resolves public channel facts with conversations.info, conversations.list, and conversations.members.
chat:write Posts and edits replies: chat.postMessage, chat.postEphemeral, chat.update, chat.delete, and the three chat.*Stream calls.
chat:write.customize Posts each reply under that Agent’s own username and icon_url instead of one shared bot identity.
files:read Reads an attachment’s bytes by file id before normalization and analysis.
files:write Uploads files an Agent produces, with files.uploadV2.
groups:history The same context reads inside private channels, where message.groups arrives.
groups:read The same channel facts for private channels.
im:history Reads direct message context for a DM turn.
im:write Opens a DM with conversations.open to deliver a schedule result or a management receipt.
mpim:read Identifies group DMs, so a turn is classified mpim rather than as a channel.
reactions:read Receives reaction_added and reads the reacted message with reactions.get.
reactions:write Adds and clears reactions with reactions.add and reactions.remove.
users:read Reads users.info and users.list for display names and account class: deleted, bot, guest, or foreign.
usergroups:read Lists user groups with usergroups.list to find the group behind an Agent handle.
usergroups:write Creates, renames, disables, and re-enables the user group that is an Agent handle, with usergroups.create, update, disable, and enable.
users:read.email Adds profile.email to users.info. The address is stored as a member contact detail, never as an identity key.

User token scopes

Three scopes, requested only during Slack OIDC sign-in and never used to call the Slack Web API. Slack OIDC is the only human sign-in. No passwords.

Scope Why Chickpea needs it
openid Issues the ID token that proves a Slack workspace and user identity to Admin.
profile Supplies the display name on the openid.connect.userInfo response.
email Supplies the email claim on the same response.

Redirect URLs

Two, both on the deployment’s own origin.

Path Purpose
/auth/slack/install/callback Completes the bot installation OAuth exchange.
/auth/slack/oidc/callback Completes a Slack OIDC sign-in.

Event subscriptions

The request URL is /channels/slack/events on the deployment origin. Eleven bot events are subscribed.

Event What it does
app_context_changed Accepted and ignored. No handler runs.
app_home_opened Publishes the App Home Agent directory to the user who opened it.
app_mention The primary trigger. Routes the turn to the Agent whose handle was mentioned.
member_joined_channel Greets the channel when the app itself joins a channel that has an active grant. On by default, disabled with SLACK_TAG_WELCOME_ON_JOIN=false.
message.channels Public channel messages. In every channel, a top-level message that mentions no one is dropped before any model is involved.
message.groups The same for private channels.
message.im Direct messages to the app.
reaction_added May start a turn from a reaction, using the reacted message as the thread root.
app_uninstalled Marks the stored workspace installation revoked.
tokens_revoked Marks the stored workspace installation revoked.
user_change Suspends a member’s stored authority when Slack reports that account deleted or converted to a bot.

Interactivity

interactivity.is_enabled is true and its request URL is /channels/slack/interactions. The only interaction the app handles is the App Home button that starts a private thread with a chosen Agent, action id chickpea.agent.start.

Settings that are off

Setting Value Consequence
socket_mode_enabled false Slack delivers events over HTTPS to the request URL. No app-level token exists.
org_deploy_enabled false The app installs into one workspace, not an Enterprise Grid org.
token_rotation_enabled false The bot token does not expire and is not refreshed.
is_mcp_enabled false Slack’s own MCP surface is not exposed by this app.

One deployment currently serves one Slack workspace.

What is compared when a manifest is validated

validateSlackAppManifest compares a reduced contract rather than the whole document, so cosmetic drift in an exported manifest is tolerated and a capability change is not. The compared fields are the app name, the bot display name, the redirect URLs, the sorted user scopes, the sorted bot scopes, the events request URL, the sorted bot events, whether the App Home tab is enabled, whether interactivity is enabled, the interactivity request URL, and pkce_enabled, which Slack materializes as false when it is omitted. A mismatch raises Slack app manifest does not match the expected callbacks, scopes, or events.

Recovery has a narrower check. validateSlackAppManifestUrlRepair overwrites the two redirect URLs, the events request URL, and the interactivity request URL with the expected values before comparing, so a deployment that moved to a new origin may repair its own URLs and nothing else.

Scope enforcement

The granted scopes on a live token are checked against the manifest at three points.

  • On install. An OAuth exchange missing a manifest scope fails with missing_scopes. An exchange that returns a scope absent from the manifest fails with unexpected_scopes.
  • On verification. A missing scope raises Reinstall this Slack app to grant the required permissions: followed by the missing scope names. When the response carries no scope header at all, verification raises Slack did not return the installed permission scopes.
  • On health. An installation with a missing scope reports needs_reauthorization with the action label Reinstall Chickpea in Slack. When Slack omits the scope header, the status is unverifiable rather than healthy.
Navigation

Type to search…

↑↓ navigate↵ selectEsc close