Otto Docs
Integrations

Slack Integration

Otto operates as a full Slack bot, allowing your team to assign tasks, receive results, ask follow-up questions, upload files, schedule work, and set reminders -- all without leaving Slack.

Otto operates as a full Slack bot, allowing your team to assign tasks, receive results, ask follow-up questions, upload files, schedule work, and set reminders -- all without leaving Slack.


What Otto Can Do in Slack

  • Receive tasks via @mentions or the /otto slash command
  • Reply in threads with progress updates and final results
  • Send direct messages when it needs human input or wants to deliver results
  • Upload files (documents, reports, spreadsheets) directly into Slack threads
  • Schedule tasks to run at a future time
  • Set reminders for yourself or teammates, including recurring reminders
  • Auto-onboard when invited to a new channel, syncing members and learning context
  • Track membership as users join or leave channels

Setup

Otto ships an App Manifest that pre-configures all scopes, events, slash commands, and interactivity in one step.

1. Create the Slack App from the Manifest

  1. Go to api.slack.com/apps and click Create New AppFrom an app manifest.
  2. Select your workspace.
  3. Paste the contents of slack-manifest.yaml from the Otto repo root.
  4. Review the configuration and click Create.

2. Set Your Backend URL

The manifest uses YOUR_OTTO_URL as a placeholder. After creating the app, replace it with your actual Otto backend URL in three places:

  • Event Subscriptions → Request URL: https://your-domain.com/slack/dm_response
  • Interactivity & Shortcuts → Request URL: https://your-domain.com/slack/interactive
  • Slash Commands/otto Request URL: https://your-domain.com/slack/command

3. Install the App

Click Install to Workspace under OAuth & Permissions. After authorization, copy:

  • The Bot User OAuth Token (starts with xoxb-) from OAuth & Permissions
  • The Signing Secret from Basic Information

What the Manifest Configures

The manifest sets up everything Otto needs automatically. For reference, here is what it includes.

Bot Token Scopes (21 scopes)

Messaging & Actions:

ScopePurpose
chat:writeSend messages and thread replies as @Otto
chat:write.publicSend messages to channels Otto hasn't been invited to
im:writeStart and send direct messages to users
mpim:writeStart and send group direct messages
channels:joinJoin public channels in the workspace
files:writeUpload, edit, and delete files (reports, documents, etc.)
reactions:writeAdd emoji reactions (used for status indicators like eyes, checkmark)
commandsRegister the /otto slash command

Reading Messages & History:

ScopePurpose
app_mentions:readView messages that @mention Otto
channels:historyRead message history in public channels Otto is in
groups:historyRead message history in private channels Otto is in
im:historyRead direct message history with Otto
mpim:historyRead group direct message history

Channel & User Info:

ScopePurpose
channels:readList public channels and their metadata
groups:readList private channels Otto has been invited to
im:readView basic info about direct message conversations
mpim:readView basic info about group direct message conversations
files:readAccess files shared in channels and conversations
users:readDiscover workspace members and map them to Otto users
users:read.emailMap Slack users to Otto users by email address
users.profile:readView profile details (display name, avatar) for richer user context

Event Subscriptions

EventTrigger
app_mentionSomeone @mentions Otto in a channel
message.imSomeone sends Otto a DM
member_joined_channelOtto or a user joins a channel (triggers auto-onboarding)
member_left_channelA user leaves a channel Otto is in
channel_deletedA channel Otto was in is deleted

Slash Command

  • /otto — Assign a task to Otto from any channel

Interactivity

Enabled for the "Stop Reminders" button and other interactive features.


Manual Setup (Without Manifest)

If you prefer to configure the Slack app manually instead of using the manifest, follow these steps.

1. Create a Slack App

  1. Go to api.slack.com/apps and click Create New App.
  2. Choose From scratch, give it a name (e.g., "Otto"), and select your workspace.

2. Configure Bot Token Scopes

Under OAuth & Permissions, add all the bot token scopes listed in the Bot Token Scopes section above.

3. Enable Events

Under Event Subscriptions, enable events and set the request URL to:

https://your-domain.com/slack/dm_response

Subscribe to the bot events listed in the Event Subscriptions section above.

4. Create a Slash Command

Under Slash Commands, create a new command:

  • Command: /otto
  • Request URL: https://your-domain.com/slack/command
  • Short Description: Assign a task to Otto
  • Usage Hint: [describe your task]

5. Enable Interactive Components

Under Interactivity & Shortcuts, enable interactivity and set the request URL to:

https://your-domain.com/slack/interactive

This enables the "Stop Reminders" button and other interactive features.

6. Install the App

Click Install to Workspace under OAuth & Permissions. After authorization, copy the Bot User OAuth Token (xoxb-) and Signing Secret (from Basic Information).


Configuration

Set the following environment variables in your Otto backend:

VariableRequiredDescription
SLACK_MCP_XOXB_TOKENYesBot User OAuth Token (xoxb-...). This is the primary token used for all Slack API calls.
SLACK_SIGNING_SECRETYesSigning secret from your Slack app's Basic Information page. Used to verify incoming requests are from Slack.
SLACK_BOT_USER_IDNoThe bot's Slack user ID. Used to detect self-mentions and avoid loops. If not set, Otto attempts to detect it automatically.

Example .env configuration:

SLACK_MCP_XOXB_TOKEN=xoxb-1234567890-1234567890123-abcdefghijklmnopqrstuvwx
SLACK_SIGNING_SECRET=abc123def456ghi789jkl012mno345pq

There are also legacy token variables (SLACK_BOT_TOKEN, SLACK_MCP_XOXC_TOKEN, SLACK_MCP_XOXD_TOKEN) that appear in Docker Compose files. For new installations, only SLACK_MCP_XOXB_TOKEN and SLACK_SIGNING_SECRET are needed.


Usage Patterns

Mentioning Otto in a Channel

Type @Otto followed by your task in any channel where Otto has been invited:

@Otto write a summary of our Q4 sales numbers

Otto replies in a thread with progress updates and the final result.

Using the Slash Command

Use /otto from any channel:

/otto draft a follow-up email to the client about the proposal

Otto acknowledges the command immediately and posts results when finished.

Direct Messages

Send Otto a DM for private tasks:

Research competitor pricing for our enterprise tier

Responding to Questions

When Otto needs clarification during a task, it sends a DM or thread reply with its question. Simply reply in the same thread or DM to continue.

File Uploads

Share a file in a DM or alongside an @mention. Otto downloads the file to your sandbox and creates a task to process it:

@Otto summarize this document
[attached: quarterly-report.pdf]

Scheduling and Reminders

Scheduled Tasks

Schedule a task to run at a future time:

@Otto schedule "generate the weekly report" in 2 hours
@Otto schedule "check deployment status" in 30 minutes

Supported time expressions:

  • Relative: in X hours, in X minutes, in X days, in X weeks
  • Absolute: at 3pm, on tomorrow

One-Time Reminders

Set a reminder for yourself or a teammate:

@Otto remind me to review the PR in 1 hour
@Otto remind @alice to submit her timesheet in 2 hours

Reminders send up to 3 follow-up notifications at hourly intervals until stopped.

Recurring Reminders

Create repeating reminders:

@Otto remind me to check the logs every day
@Otto remind @bob to run standup every weekday

Recurring reminders run on a cron schedule until manually stopped.

Stopping Reminders

Every reminder notification includes a Stop Reminders button in Slack. Clicking it cancels the reminder and notifies the person who created it.


Channel Auto-Onboarding

When you invite Otto to a new Slack channel:

  1. Otto syncs all channel members into its user database.
  2. An onboarding task runs automatically to learn about the channel's context (by reading recent message history).
  3. A project record is created so future tasks in that channel carry project-scoped context and memory.

This means Otto understands the context of each channel it participates in and can draw on that knowledge when working on tasks.


Request Verification

Otto verifies every incoming Slack request using HMAC SHA256 signature verification:

  1. Slack sends the request body, a timestamp, and a signature header (X-Slack-Signature).
  2. Otto computes its own signature using the SLACK_SIGNING_SECRET.
  3. The request is rejected if the signatures do not match or the timestamp is older than 5 minutes (replay attack protection).

If SLACK_SIGNING_SECRET is not configured, signature verification is skipped with a warning. This is not recommended for production.


Troubleshooting

Otto does not respond to @mentions

  • Verify that SLACK_MCP_XOXB_TOKEN is set and valid. Check the health endpoint at GET /slack/health -- it reports whether the bot token is configured.
  • Confirm that the app_mention event is subscribed under Event Subscriptions.
  • Make sure Otto's event request URL is reachable from Slack's servers.

Slash command returns an error

  • The /otto slash command must point to your backend's /slack/command endpoint.
  • Verify that SLACK_SIGNING_SECRET matches the value in your Slack app's Basic Information page.
  • Slack requires a response within 3 seconds. If your backend is slow to start, the command may time out.

Files are not being processed

  • Ensure the files:read scope is granted.
  • Check that storage quota has not been exceeded (STORAGE_QUOTA_GB environment variable).

Members are not syncing

  • The users:read and users:read.email scopes are required for member discovery.
  • Run a manual sync from the Onboarding page in the web UI (Team & Behavior tab, "Sync from Slack" button).

Otto replies to its own messages

  • Set SLACK_BOT_USER_ID to the bot's Slack user ID so it can filter out its own messages.

Reminders are not firing

  • The scheduler service runs as an ARQ cron job that checks for due tasks every minute. Confirm your ARQ worker is running.
  • Verify that REDIS_URL is set and Redis is reachable.