Evil Jacob: My Personal Slackbot

Slack is a really good interface for AI agents

  • it has good web/desktop/mobile apps
  • you can upload images, videos, audio, and other files
  • context can be organized into threads
  • you can either work directly with APIs or with any existing Slack integration

I’ve started building my own open source AI Slackbot named Evil Jacob and based on Vercel’s official Slackbot guide

You can check these guides for the Slack setup, this article will be about the the bot itself

The bot needs to be able to consume all webhooks coming from Slack in order to receive messages, then perform actions either immediately or in the future

What makes it an agent is “agency” — the ability to decide on its own what to do. That means we pass the event that occurred to an LLM and allow it to call sequences of tools to construct its response.

Choosing models

The Slackbot template I started with came with OpenAI as the main LLM and Exa for web search.

I don’t have an OpenAI account so I swapped it for Groq/Llama, but I had a really hard time getting the tool calls to work reliably. About half the time it would work, and the other half it would output text like <function=searchWeb which probably means I’m doing something wrong.

I switched to Anthropic and Claude as my main LLM and then everything worked well

Durability

There are two rules when building webhook based background job systems

  • webhooks are fraught with race conditions, assume you’ll be dealing with duplicates
  • background jobs can fail and need to be able to retry

The general structure is to take all message webhooks, create a unique ID out of channel:thread_ts, and add each to a redis backed queue.

Then we process the queue transactionally

  • if it’s a mention, add this thread ID to KV
  • if it’s a thread, check if the thread is in KV
  • process the job by passing to the LLM, and remove the job from the queue when it’s don

Vercel has an easy integration with Upstash that comes with a lot of this out of the box

  • Upstash Redis is simple KV
  • Upstash QStash is a simple queue
  • they also have a webhook endpoint that I might try for ingesting the slack events

Handling Responses

The agent needs to be able to reply either to its current conversation right now, or somewhere else later. We can add a tool call to write delayed or scheduled jobs back into the queue, which essentially lets the agent talk to itself.

A prompt like this

Reply here, send me a DM, and tag me from a new post in #general

Should trigger three tool calls for scheduling new responses

Every morning at 8am, look up a coffee shop in Toronto and DM me the address

Should trigger one tool call for a scheduled cron job in Upstash, that delivers the same request every day

Future Features

From here on out it’s just adding features as I want them

  • Pass images/files from messages to the bot
  • Read and write from my Google Calendar
  • Read my emails

It’s a bit of a pain switching back and forth from production endpoints in the Slack app to my local tunnel during development. I think I’ll end up making two Slack Apps, one for prod and one for dev. The prod one will check for the existence of the dev app, and refuse to accept jobs when it’s online.


What would your personal agent do?

6 Likes

I love idea and the detailed write up. Thanks @jacobparis :raising_hands:

I think my agent’s first job would be to protect me from those looks “evil jacob” is giving me :laughing: You’re too good with this.

But, I think mine would be to find complementing exercises for my weekly split. So, every Tuesday find improved or varied exercises than you suggested last Tuesday.

1 Like

This is really awesome!

2 Likes

Now I’m interested what the evil part is. Will it give you a list of pretty bad coffee places? :grinning_face_with_smiling_eyes:

1 Like

Very neat. Something I’ve been thinking about is ingesting all of my X/Reddit/whatever comments and trying to have an agent parse out “how I write” and put it into a system prompt. Then I could use a Slackbot to draft my first response to things.

2 Likes

I think Jacob named it after Evil Rabbit :laughing: