Around August 2017, the engineering tools team at Target was tasked to rewrite and rearchitect a few team chatbots that helped complete certain administrative and operational tasks. These bots were written using several different languages and frameworks that often got confusing and difficult to manage. For example, one of our bots was written in Hubot coffescript, which called a Node script, which triggered a Jenkins job. Another bot was written in Golang, which made calls to various APIs for gathering and relaying information. And another bot was written in Ruby using the Rubotnik framework to do various admin tasks.

Each bot was essentially written by its own engineer along with that engineer’s own technical preferences. Thus reworking and managing all these different bots in their own respective tech ecosystems only brought forth much burden to our engineers, i.e. picking up a new language(s) to work on one bot or the other, learning a particular bot’s framework, etc. So during the course of our efforts, we simply decided to scrap everything and head back to the drawing board. Long story short, we built our own enterprise chatbot framework: Flottbot.

During our investigation of what would make a good chatbot framework that would best suit our team’s needs, but also the needs of other teams across Target, we found that the following four properties were essential in a good framework:

  1. Portable - I want the ability to run my bot anywhere.
  2. Abstracted - I don’t want to have to learn a new language to get my bot running.
  3. Quick-Setup - I want to have functionality right out of the box.
  4. Plug-N-Play - I want to easily customize the functionality of my bot anytime.

What Is Flottbot? How Is It Different from Other Chatbot Frameworks?

Flottbot is a chatbot framework written in Go. But there’s a catch – you don’t need to know a lick of Go to use it! All of your bot’s configuration and logic are written in YAML files, or in scripts written in your favorite language. The word flott is a German word meaning “quick, speedy and smart.” Flottbot was designed in a way to run your bot fully functional on any chat application right out of the box.

Our philosophy behind Flottbot was to create a very simple, lightweight, language-and-chat-agnostic framework that would allow users to create bots that could interact with external APIs or custom scripts that essentially house their bots’ business logic. In our opinion, the more logic baked inside a bot itself, the harder it becomes to maintain and troubleshoot a bot. Therefore, we opted to pull any business-specific logic out. This, of course, potentially limits how or when a bot could respond, but it will gives users the freedom to externally fulfill a task however they want (i.e., via HTTP calls or script/binary execution, or both).

We also believed that a plug-and-play style architecture would provide the best experience for users in regards to customizing and extending (or removing) bot features. We also believed that this would easily allow other developers to add their own innersource, and now open source, contributions within the framework, such as supporting a new chat application bots could run on. For example, if your bot isn’t running on Discord, a remote package for Discord could be added to Flottbot with little effort while implementing similar functionality for the chat platform your bot currently runs on. We’ve seen that other chatbot frameworks only support a single remote chat application which tends to skew its codebase to that specific platform, thus making it difficult to extend to other platforms.

chatbot meme

Inspiration

We took out a lot of great concepts from other chatbot frameworks and projects that we liked. Here are some of them:

  • Hex: We adopted a lot of terminology and architecture from Hex(matching, rules, actions, scheduler, etc.), as well as great insights on golang libraries we might need to utilize in order to implement our own ideas.
  • Drone CI: We adopted the agnostic remote VCS architecture found in the opensource Drone CI project to easily add remote chat platforms that a bot could run on.
  • nlopes/slack & bwmarrin/discordgo: Both excellent golang libraries we use in our implementation to get our bots running on Slack and Discord, respectively.

What Can Flottbot Do out of the Box?

  • Monitor a channel, bot mentions, direct messages and match on certain user-defined keywords/patterns.
  • Send user-defined messages and create logs based on matched keywords/patterns.
  • Send HTTP calls to user-defined endpoints, and capture and interpret the returned payload for use in bot responses.
  • Execute scripts written by the bot owner, and capture and interpret the stdout and exit status of the script for use in bot responses.
  • Add reaction emojis to messages when the bot matches a keyword/pattern and modify that reaction when certain user-defined conditions are met through the bot actions.
  • Schedule actions to be taken and schedule messages to be sent to specific channels/rooms based on a user-defined cronspec.
  • Optionally start up an internal Prometheus metrics endpoint for querying information regarding bot-specific actions that were taken.
  • Optionally start up an HTTP server to listen for events rather than polling channel messages. This supports the push strategy of Slack’s Events API.
  • Optionally run in CLI Mode, where you interact with your chatbot entirely over CLI without a chat application behind it.
  • Limit which users/user groups can or can not trigger a rule (Flottbot’s ACL strategy).

Flottbot Walkthrough

Flottbot Anatomy

Bot

A bot’s configuration will be housed in the config/bot.yml file relative to where your bot is running.

Example bot.yml:

name: mybot
# chat applications
chat_application: slack

# Slack chat application specific fields.
#required
slack_token: ${SLACK_TOKEN}
# optional
slack_verification_token: ${SLACK_VERIFICATION_TOKEN}
slack_workspace_token: ${SLACK_WORKSPACE_TOKEN}

# system
cli: false
# true: enables usage of CLI mode.
# false: disables usage of CLI mode.

scheduler: false
# true: enables rule scheduling
# false: disables rule scheduling

debug: true
# true: enable logging to console
# false: disable logging to console

log_json: false
# true: logging will be in JSON format
# false: logging will be in plain text

metrics: false
# true:  enable metrics collection through prometheus
# false: disable metrics collection through prometheus

Rules

A rule is where you will define what you want your bot to respond to and what actions you want your bot to take when a rule is triggered. Rules are YAML files located in the config/rules/ directory, where each YAML file will be treated as a separate rule. Any string in your YAML file wrapped in ${} will either be parsed and interpreted to use an environment variable (set where the bot is run) OR be mapped/stored as a result of an action within the YAML file to be accessed later during the bot’s execution.

Example rule YAML file that will look for the word ‘hello’ and respond with ‘what’s up?’‘

# metadata
name: hello
active: true # activate rule

# trigger & arguments
respond: hello
args:
# no required args, as we're just looking for the match and nothing else.

# actions
actions: # this rule takes no actions, just collects and responds with whats laid out in the format_output section

# response
format_output: "what's up?" # message to send to your user when they say hello
direct_message_only: false # allow messaging inside channels
output_to_rooms: # this is an array of rooms/channels you want messages to be sent into.
  - mychannel # EDIT this (Slack channel you want the bot to listen & respond in)

#help
help_text: hello # help/usage text for the hello rule
include_in_help: true # see help_text in help message or if a rule isnt matched

Actions

Rules are generally composed of several actions that your bot will take when it is addressed or hears something you specify.

Example of an action section of a rule that will get a punchline and joke from a joke api.

actions:
  - name: joke http request
    type: GET
    url: https://08ad1pao69.execute-api.us-east-1.amazonaws.com/dev/random_joke
    auth:
    expose_json_fields:
      setup: '.setup'
      punchline: '.punchline'

Running Your Bot on Slack

To run your bot in Slack, run the following command from the directory where your config directory housing bot/rule configuration resides (make sure your Docker daemon is up and running).

docker run --rm --name mybot --env SLACK_TOKEN=$SLACK_TOKEN -v "$PWD"/config:/config target/flottbot:latest /flottbot

Future Enhancements

We are continually developing Flottbot and adding new features, but this will largely depend on customers and new users to drive its direction. Some thoughts that have been discussed on how to make Flottbot better are:

  • Add more remotes (Mattermost, Microsoft Teams, etc.); we would love to support more chat platforms with basic functionality.
  • Architect/refactor other areas of the codebase to be more chat-platform-agnostic.
  • Improve test coverage.
  • Reduce the cyclomatic complexity in our codebase.
  • Create a UI or some kind of scaffolding tool for creating new bots/rules.

Deep Dive Docs and Examples

Visit the Flottbot Docs github page for a deeper dive into Flottbot and tons of examples.

Contributors