Skip to main content

Slack Runtime

AgentFlow can run a dedicated Slack agent from Slack messages, app mentions, and Slack Assistant threads. The HTTP API owns installation and tenant-admin controls; a separate Socket Mode worker keeps the Slack connection open and dispatches events into the AgentFlow runtime.

Deployment Shape

Run Slack in two pieces:
ProcessResponsibility
FastAPI web serviceTenant-admin Slack settings, OAuth install URL/exchange, installation records, user links, and health checks
Slack Socket Mode workerReceives Slack events, acks each envelope, deduplicates events, resolves the tenant installation, and runs AgentFlow turns
Start one Socket Mode worker per tenant/app-token pairing:
SLACK_TENANT_ID=acme \
SLACK_APP_TOKEN=xapp-... \
uv run python scripts/run_slack_socket_worker.py
TENANT can be used instead of SLACK_TENANT_ID. The worker enters that tenant database with tenant_context() before recording event receipts, looking up installations, resolving thread bindings, and running turns.

Configuration

Set these values on the API service:
SLACK_CLIENT_ID=1234567890.1234567890
SLACK_CLIENT_SECRET=your-slack-client-secret
SLACK_SIGNING_SECRET=your-slack-signing-secret
SLACK_REDIRECT_URI=https://app.example.com/settings/integrations/slack/callback
SLACK_DEFAULT_AGENT_REF=SlackAgent
SLACK_BOT_SCOPES=app_mentions:read,assistant:write,channels:read,chat:write,files:read,groups:read,im:history,im:read,im:write,mpim:read,usergroups:read,users:read,users:read.email
SLACK_USER_SCOPES=
Set these on the Socket Mode worker:
SLACK_APP_TOKEN=xapp-your-app-level-token
SLACK_SOCKET_MODE_ENABLED=true
SLACK_SOCKET_MODE_CONCURRENCY=8
SLACK_TENANT_ID=acme
SLACK_SOCKET_MODE_ENABLED is reported by admin settings and health endpoints. The standalone worker still requires SLACK_APP_TOKEN; SLACK_SOCKET_MODE_CONCURRENCY limits concurrent event processing inside the worker. Optional runtime limits:
SettingPurpose
SLACK_EVENT_MAX_AGE_SECONDSMaximum accepted Slack event age for runtime guards
SLACK_FILE_MAX_BYTESMaximum Slack file size to ingest as an AgentFlow attachment
SLACK_BROAD_MENTION_POLICYBroad mention handling policy

Admin API

Tenant admins manage Slack through /api/v1/admin/slack/*:
EndpointPurpose
GET /api/v1/admin/slack/settingsShow configured client/app-token state and default agent
GET /api/v1/admin/slack/healthCheck config readiness and enabled installation counts
GET /api/v1/admin/slack/oauth/install-urlBuild a Slack OAuth installation URL
POST /api/v1/admin/slack/oauth/exchangeExchange an OAuth code and persist the installation
GET /api/v1/admin/slack/installationsList workspace installations
GET /api/v1/admin/slack/installations/{slack_team_id}Retrieve one workspace installation
PUT /api/v1/admin/slack/installations/{slack_team_id}Save an installation manually
PATCH /api/v1/admin/slack/installations/{slack_team_id}Enable or disable an installation
DELETE /api/v1/admin/slack/installations/{slack_team_id}Revoke an installation
GET /api/v1/admin/slack/user-linksList Slack-user to AgentFlow-user links
POST /api/v1/admin/slack/user-linksUpsert a Slack-user link
All routes require tenant-admin permission. Installations store encrypted bot and optional user tokens. User links map a Slack user ID to an AgentFlow auth0_user_id; unmapped Slack users receive a Slack notice asking an admin to link their profile.

Supported Slack Events

The Socket Mode worker handles these Slack routes:
Slack routeAgentFlow behavior
message.imDirect message to the app becomes a SlackAgent turn
app_mentionMentioning the app in a channel starts or continues a thread-bound conversation
assistant_thread_startedStarts a Slack Assistant thread
assistant_thread_context_changedContinues a Slack Assistant thread with updated context
block_actions with slack_regenerateRe-runs an interrupted Slack turn
Bot-authored messages, changed/deleted messages, joins, leaves, and unsupported events are ignored so the app does not loop on itself.

Thread Binding And Context

Each Slack thread maps to one AgentFlow conversation through a deterministic origin id:
slack:{team_id}:{channel_id}:{thread_ts}
On the first eligible event in a Slack thread, AgentFlow creates or claims the conversation and stores a Slack thread binding. Later events in the same thread reuse that conversation. The resolved user receives an editor grant with grant source slack_thread, so the same conversation remains available through normal conversation APIs. Slack turns pass Slack context into the runtime as:
  • origin_type: Slack thread origin type
  • origin_id: deterministic Slack thread id
  • origin_metadata: route, team, channel, thread timestamp, message timestamp, user id, bot id, event id, and file ids
  • context_refs: Slack channel, thread, user, and file references for registered entity resolvers
  • session_context.slack: normalized Slack routing metadata
If the Slack message contains files, the handler downloads and ingests each allowed file as an AgentFlow attachment before running the agent. If ingestion fails, the app replies in Slack with a file-read failure notice and does not start the turn.

Streaming And Failures

AgentFlow streams the SlackAgent response into Slack through a coalescing sink. If the turn fails before any response text is posted, Slack gets a short internal-error message. If the failure happens after partial output, AgentFlow finalizes the partial Slack message best-effort and posts an interrupted notice with a Regenerate button. Clicking Regenerate:
  1. Acks the Slack action immediately.
  2. Resolves the clicked Slack user through the same installation and user-link checks.
  3. Verifies the target user conversation part still belongs to the thread and has not already been replaced.
  4. Re-runs the turn with a fresh Slack message id and regenerate_after_user_part_id.
  5. Updates the notice to a button-less regenerating or failure message.
If the target thread is no longer linked, the target user part has already been replaced, or the clicking user is not linked, the app posts a clear Slack notice instead of double-running the turn.