This blog post guides you on how to rapidly develop a Slack Bolt app using Slack CLI and sandbox organizations/workspaces.
Slack's Developer Program
At TrailblazerDX held in San Francisco on March 6th, new valuable features for Slack app developers were announced:
https://slack.com/blog/developers/developer-program-launch
Utilizing Enterprise Grid sandboxes for local development simplifies your Bolt app development like never before! This article provides a guide on the minimum steps to get started.
What's exciting about this?
Prior to the Developer Program, developing Slack apps required the following steps:
- Accessing https://api.slack.com/apps to configure the app
- Installing the app being developed into the Slack workspace
- Specifying the obtained access token as an environment variable
- Finally launching the app
However, with the combination of the newly available Slack CLI and sandboxes by Developer Program, the process has become extremely simple. In fact, all you need to do are creating a sandbox, connecting the CLI to it, and then slack run
to start your app.
"... Wait, isn't Slack CLI only usable for the Deno thing?"
Yes, indeed, initially it was provided as a tool exclusively for Deno apps. However, from now on, it will also be available for Bolt app development too!
Now, let's get right to the point.
Create your first sandbox
First, access the developer portal:
https://api.slack.com/developer-program
If you haven't registered yet, create a new account first.
Provisioning a sandbox requires a workspace with a paid plan or registering a credit card, but there is no cost for creating a sandbox or testing the functionality of an app.
However, for executing custom workflow functions, excess usage beyond a certain free quota will be billed based on the number of workflow executions, in the same manner with the production environment. For more details, please refer to this help page.
Once you've set up your account, go ahead and create a sandbox. If everything goes well, you should see a screen similar to the one below.
What's Enterprise Grid?
By the way, you may not be familiar with Enterprise Grid, so let me provide a brief explanation about the "Org" within a sandbox.
In plans other than Enterprise Grid, which most people are familiar with, you can only use one workspace. However, Enterprise Grid has the concept of an "organization" above workspaces, allowing you to create multiple workspaces within an org.
Since the sandbox environment provided by the Developer Program is for Grid, the process involves creating an org first and then creating workspaces. At this point, it'd be enough if you understand this as "that's how it works."
For general information about Enterprise Grid, please refer to the following help page and official guides:
https://slack.com/help/articles/115005481226-Enterprise-Grid-launch-guide
Set up Slack CLI
Once you have provisioned a sandbox, the next step is to install Slack CLI. Please refer to the following page for installation instructions for each platform. You only need to complete the steps before running slack login
:
https://api.slack.com/automation/quickstart
After installing the slack
command, execute slack login
in your terminal. You should see a screen like this:
$ slack login
📋 Run the following slash command in any Slack channel or DM
This will open a modal with user permissions for you to approve
Once approved, a challege code will be generated in Slack
/slackauthticket MGIwNTczNzktYWQ5Y***********************************
? Enter challenge code
Copy the part /slackauthticket MGIwN....
, and execute it in the message composer in the Slack workspace you created earlier for the sandbox.
A modal dialog like the following will appear:
Press the "Confirm" button, and you will see the "Challenge Code" displayed as follows:
Copy that string and paste it into your terminal to complete the setup.
The result of this integration is saved in a file called $HOME/.slack/credentials.json
. If you want to revoke the authentication, you can run slack logout
comamnd.
OK, now you're all set!
Create a Python app
Let's start by connecting the simplest Python app to your sandbox org.
Set up Python venv and libraries
You can use Poetry or any other method you prefer, but set up your Python environment and install the necessary dependencies (just two!) as follows:
# Set up Python environment (you can use Poetry or any other tool)
python3 -m venv .venv
source .venv/bin/activate
# Install the necessary dependencies, just these two for now
pip install slack-bolt slack-cli-hooks
Place required files for CLI
For Slack CLI to work with Python, it expects at least the following files:
File name | Description |
---|---|
slack.json |
Configuration required for CLI to run locally |
manifest.json |
App settings (automatically synchronized with Slack when running slack run ) |
app.py |
Code to execute the app (file name can be changed) |
For slack.json
, save the following content as it is:
{
"hooks": {
"get-hooks": "python3 -m slack_cli_hooks.hooks.get_hooks"
}
}
Next is manifest.json
, which is a file that you can modify as needed. For this demo, please copy and paste it as is.
{
"display_information": {
"name": "Hello",
"description": "You can update this later",
"background_color": "#4361ba",
"long_description": ""
},
"features": {
"app_home": {
"home_tab_enabled": false,
"messages_tab_enabled": false,
"messages_tab_read_only_enabled": true
},
"bot_user": {
"display_name": "Hello Bot",
"always_online": true
},
"slash_commands": [
{
"command": "/hello-sandbox",
"description": "Say hello to sandbox",
"usage_hint": "",
"should_escape": true
}
]
},
"oauth_config": {
"scopes": {
"bot": ["commands"]
}
},
"settings": {
"interactivity": { "is_enabled": true },
"org_deploy_enabled": true,
"socket_mode_enabled": true
},
"outgoing_domains": []
}
Finally, place app.py
with the following content:
import os
import logging
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
logging.basicConfig(level=logging.DEBUG)
app = App(token=os.environ["SLACK_BOT_TOKEN"])
# Add your code here
if __name__ == "__main__":
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
Start your app
Now that the preparation is complete, please try launching the app with slack run
. If there are no apparent errors, then everything should be fine.
At this stage, the slash command /hello-sandbox
should already be available in your workspace. Please try executing it.
While you may encounter an error on the UI, in the terminal, you should see warnings similar to the following. These are suggestions provided by Bolt for Python to guide your implementation.
WARNING:slack_bolt.App:Unhandled request ({'type': None, 'command': '/hello-sandbox'})
---
[Suggestion] You can handle this type of event with the following listener function:
@app.command("/hello-sandbox")
def handle_some_command(ack, body, logger):
ack()
logger.info(body)
Let's add code to pass "Hello!" to ack()
method call. Please add this before the line if __name__ == "__main__":
.
@app.command("/hello-sandbox")
def handle_some_command(ack, body, logger):
ack("Hello!")
logger.info(body)
At the time of posting this article, Python CLI support does not have automatic code reloading. Please relaunch slack run
whenever you make changes to the code.
To avoid selecting the workspace every time, you might find it convenient to specify the displayed App ID like slack run -a A06P0E7LY48
.
With the updated code, you should not encounter execution errors on the UI, and the bot should respond with 'Hello!' 🎉
Create a Node.js app
Let's do the same thing with Node.js. There's no need to change manifest.json
. Modify slack.json
as follows:
{
"hooks": {
"get-hooks": "npx -q --no-install -p @slack/cli-hooks slack-cli-get-hooks",
"start": "npm start"
}
}
Let's add package.json
and app.js
as well.
npm init -y
npm i @slack/bolt
npm i --save-dev @slack/cli-hooks nodemon
Next, update the "scripts" in package.json
as follows. If you want a name other than npm start
, please name it in line with slack.json
.
"scripts": {
"start": "nodemon --watch '*.js' --exec node app.js"
},
Finally, save app.js
with the following content:
const { App, LogLevel } = require('@slack/bolt');
const app = new App({
socketMode: true,
token: process.env.SLACK_BOT_TOKEN,
appToken: process.env.SLACK_APP_TOKEN,
logLevel: LogLevel.DEBUG,
});
app.command("/hello-sandbox", async ({ ack }) => {
await ack("Hello!");
});
;(async () => {
await app.start();
console.log("⚡️ Bolt app is running!");
})();
Try launching it with slack run
. Is it working properly?
In this example, nodemon automatically detects file changes. Thus, you'll be able to smoothly develop without restarting the server each time.
Create a TypeScript + Node.js app
Lastly, let's set up the Node.js app in TypeScript.
First, add a tsconfig.json
file. The following is just an example, so feel free to adjust the details according to your preferences.
{
"compilerOptions": {
"target": "es2022",
"module": "commonjs",
"lib": ["es2022", "dom"],
"outDir": "lib",
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true
}
}
Next, install additional dependencies:
npm i --save-dev typescript ts-node @types/node
Then, update the command in package.json
to "start": "nodemon --watch 'src/**/*.ts' --exec \"ts-node\" src/app.ts"
.
Finally, save src/app.ts
with the following content:
import { App, LogLevel } from "@slack/bolt";
const app = new App({
socketMode: true,
token: process.env.SLACK_BOT_TOKEN,
appToken: process.env.SLACK_APP_TOKEN,
logLevel: LogLevel.DEBUG,
});
app.command("/hello-sandbox", async ({ ack }) => {
await ack("Hello!");
});
;(async () => {
await app.start();
console.log("⚡️ Bolt app is running!");
})();
If configured correctly, it should work similarly. Also, try changing the code and verifying that it gets reflected.
Benefits of using CLI + sandboxes
The real joy of using Slack CLI begins here.
No longer do you need to access https://api.slack.com/apps, make app configuration changes, reinstall, and go through that hassle.
Let's rewrite and save manifest.json
with the following content:
{
"display_information": {
"name": "Hello",
"description": "You can update this later",
"background_color": "#4361ba",
"long_description": ""
},
"features": {
"app_home": {
"home_tab_enabled": false,
"messages_tab_enabled": false,
"messages_tab_read_only_enabled": true
},
"bot_user": {
"display_name": "Hello Bot",
"always_online": true
}
},
"oauth_config": {
"scopes": {
"bot": ["commands", "chat:write", "app_mentions:read"]
}
},
"settings": {
"interactivity": { "is_enabled": true },
"event_subscriptions": {
"bot_events": ["app_mention"]
},
"org_deploy_enabled": true,
"socket_mode_enabled": true
},
"outgoing_domains": []
}
When you save the file, Slack CLI will automatically reflect these changes in the metadata managed by Slack's servers.
The slash command you were using earlier will disappear from the workspace, and instead, this app will be able to receive events, which can be delivered when a user mentions your app's bot.
Please add the following code to the src/app.ts
file that you added earlier. This change should also be automatically reflected by nodemon.
app.event("app_mention", async ({ say }) => {
await say("Hi!");
});
For testing, invite @Hello Bot (local)
to a channel and mention it. If you receive a response saying "Hi!", then it's successful! 🎉
Wrap up
You should now understand how easy it is to get started and develop smoothly.
For production, if you're using Socket Mode, it's a good idea to prepare a Dockerfile
for deployment (you won't need nodemon in that case).
For setting up manifest.json
, please refer to the following page. Note that if it's in YAML format, it won't be loaded with CLI integration, so be sure to specify it in JSON format.
https://api.slack.com/reference/manifests
You might wonder, "Can I use this with runtimes/languages other than Node.js or Python?" Technically, it's possible, but it might require a bit more effort to get it up and running. I hope to cover this in another article someday.
That's all for now!
Top comments (0)