Get today's tasks in Slack
If I have a personal assistant, I'd love the person to message me my todo list for the day, ordered by priority, in Slack. For now, I'll build an AI agent to do that instead.
Scenario
For this demo, we will show how to build an AI agent that can get the tasks due today from Todoist and message us on Slack.
Specifically, our AI agent will:
- Get the tasks due today from Todoist
- Message us on Slack
To complete this task, our AI agent is equipped with tools to:
Even though we are using Todoist and Slack in this example, you can also use a research tool to send news in Slack or use an email tool to send yourself your tasks.
Setup
To get started, we first set the following environment variables in our .env
file:
TODOIST_API_TOKEN
: The API key of your Todoist account (see below)SLACK_WEBHOOKS
: The channels and respective webhook URLs for the AI agent to post in (see below)<COMPANY>_API_KEY
: The API key of the model you want to use
Todoist API key
To get your Todoist API key:
- Click on your profile icon in the top-left corner
- Select "Settings"
- Click on "Integrations"
- Click on "Developer"
- Copy the API token and save it as an environment variable
Slack webhooks setup
We will need to set up a Slack webhook so that our AI agent can send messages to our Slack workspace securely. To do that:
- Sign up to the Slack Developer Program
- Under "Your Apps", click on "Create New App" (Either "From manifest" or "From scratch" is fine.)
- Under "Features", click on "Incoming Webhooks"
- Toggle "Activate Incoming Webhooks" to "On"
- Scroll down and click on "Add New Webhook to Workspace"
- Select the channel you want your AI agent to post to (If you are not seeing any channels, you may need to refresh the page as the channels may take a few minutes to show up.)
- Copy the newly created webhook and save it as an environment variable
- Repeat this for as many channels as you want your AI agent to post to
You must format your SLACK_WEBHOOKs
environment variable as a strictly valid JSON-encoded object:
SLACK_WEBHOOKS='{"general": "<WEBHOOK_TO_GENERAL_CHANNEL>", "random": "<WEBHOOK_TO_RANDOM_CHANNEL>"}'
The AI agent will then be able to only post messages to only these channels. It won't have the permission to read messages in your Slack workspace.
Scripts
Some APIs and frameworks (e.g. Gemini, LangGraph, and LlamaIndex agent) automatically execute tool calls, which make the code much simpler. For the rest, we will need to add a while
loop so that the agent will keep working on the next step until the task is completed.
From my experiments, Gemini 2.0 Flash prefers to ask questions instead of using the tools to find the information it needs. You can either specify in the system prompt to use tools or try Gemini 2.5 Pro, which is much better at using tools.
import os
import anthropic
from dotenv import load_dotenv
import stores
# Load environment variables
load_dotenv()
# Load tools and set the required environment variables
index = stores.Index(
["silanthro/todoist", "silanthro/slack"],
env_var={
"silanthro/todoist": {
"TODOIST_API_TOKEN": os.environ["TODOIST_API_TOKEN"],
},
"silanthro/slack": {
"SLACK_WEBHOOKS": os.environ["SLACK_WEBHOOKS"],
},
},
)
# Initialize Anthropic client and messages
client = anthropic.Anthropic()
messages = [
{
"role": "user",
"content": "Let me know my tasks and their priority for today in bullet points in Slack #general",
}
]
# Run agent loop
while True:
# Get the response from the model
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=messages,
# Pass tools
tools=index.format_tools("anthropic"),
)
# Check if all blocks contain only text, which indicates task completion for this example
blocks = response.content
if all(block.type == "text" for block in blocks):
print(f"Assistant response: {blocks[0].text}\n")
break # End the agent loop
# Otherwise, process the response, which could include both text and tool use
for block in blocks:
if block.type == "text" and block.text:
print(f"Assistant response: {block.text}\n")
# Append the assistant's response as context
messages.append({"role": "assistant", "content": block.text})
elif block.type == "tool_use":
name = block.name
args = block.input
# Execute tool call
print(f"Executing tool call: {name}({args})\n")
output = index.execute(name, args)
print(f"Tool output: {output}\n")
# Append the assistant's tool call message as context
messages.append(
{
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": block.id,
"name": block.name,
"input": block.input,
}
],
}
)
# Append the tool result message as context
messages.append(
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": block.id,
"content": str(output),
}
],
}
)
In the folder where you have this script, you can run the AI agent with the command:
python get-tasks-in-slack.py
The AI agent will get the tasks due today from Todoist and message you on Slack.
To make this AI agent even more useful, you can set up a cron job to run this script every morning and get a daily task brief in your Slack.
If you have any questions, let us know on GitHub.