Skip to main content

Getting Started

ChatOps4s is a Scala library for building chat-ops workflows in Slack. It gives you a type-safe, minimal API for messages, buttons, slash commands, and modal forms — all over Socket Mode, so you don't need a public URL.

Installation

"org.business4s" %% "chatops4s-slack" % "chatops4s-slack-client / version"

You also need an sttp backend that supports WebSockets. For example, with fs2:

"com.softwaremill.sttp.client4" %% "fs2" % "4.0.9"

Define Your App

Write your handlers first. Here's an app with buttons and a slash command — you'll need a Slack workspace to run it, but write the code first:

for {
slack <- SlackGateway.create(backend)
approveBtn <- slack.registerButton[String] { click =>
slack.update(click.messageId, s"Approved by <@${click.userId}>").void
}
rejectBtn <- slack.registerButton[String] { click =>
slack.update(click.messageId, s"Rejected by <@${click.userId}>").void
}
_ <- slack.registerCommand[String]("deploy", "Deploy to production") { _ =>
slack
.send(
channel,
"Deploy v1.2.3?",
Seq(
approveBtn.render("Approve", "v1.2.3"),
rejectBtn.render("Reject", "v1.2.3"),
),
)
.as(CommandResponse.Silent)
}
_ <- slack.validateSetup("MyApp", "slack-manifest.yml")
_ <- slack.start(botToken, Some(appToken))
} yield ()

Set Up Your Slack App

The validateSetup call in the example above is doing the heavy lifting. On first run it:

  1. Generates a Slack app manifest from your registered handlers (the right OAuth scopes, event subscriptions, and slash commands are derived automatically)
  2. Writes it to a file (slack-manifest.yml)
  3. Prints a setup guide with a one-click URL that opens api.slack.com/apps with the manifest pre-filled

You never need to manually figure out which scopes or event subscriptions your app needs. On subsequent runs, validateSetup checks the manifest against the file on disk and fails with a diff if they diverge.

See App Management for the programmatic checkSetup alternative, custom manifest modification, and fully automated app management via the manifest API.

Run Your App

After creating your Slack app from the generated manifest, grab your tokens from the app settings page and run:

object SendMessage extends IOApp.Simple {

override def run: IO[Unit] =
HttpClientFs2Backend.resource[IO]().use { backend =>
for {
slack <- SlackGateway.create(backend)
_ <- slack.validateSetup("MyApp", "slack-manifest.yml")
_ <- slack.start(
SlackBotToken.unsafe(sys.env("SLACK_BOT_TOKEN")),
sys.env.get("SLACK_APP_TOKEN").map(SlackAppToken.unsafe),
)
} yield ()
}
}

The bot token (xoxb-) comes from OAuth & Permissions, and the app token (xapp-) from Basic Information > App-Level Tokens (with the connections:write scope).

What You Get

  • Simple APIsend, reply, update, delete, reactions, ephemeral messages
  • Typed buttons — handlers receive ButtonClick[T] with your value type
  • Typed commands — argument parsing derived from case classes
  • Modal formsderives FormDef turns a case class into a Slack modal with 15+ field types
  • Manifest generationvalidateSetup generates and checks your Slack app manifest automatically
  • Runtime-agnostic — built on sttp, works with any backend that supports WebSockets
  • Standalone Slack client — a type-safe, AI-generated Slack API client you can use independently

Next Steps