Project Info
Inspiration
We kept seeing people build iMessage bots—Jarvis-style assistants, AI agents, feedback collectors—but every setup was custom, messy, and not reusable. So we built Bluely: a plug-and-play iMessage bot framework focused on real-world utility, with AI-first integrations baked in.
What it does
Bluely is a Python SDK and framework that makes it dead simple to build iMessage bots. It abstracts away BlueBubbles' iMessage plumbing and gives devs a clean interface—like building Slack or Discord bots, but for iMessage. Our flagship bot helps early-stage founders automatically collect user feedback over iMessage, summarize it using AI, and triage it into actionable Linear issues.
How we built it
We used the BlueBubbles API to tap into iMessage, and built a Pythonic SDK on top with routing, message handling, and response templates. Then we integrated OpenAI for summarization and Linear’s API for issue creation. We built five bots using Bluely, including a therapy bot, a scheduling assistant, and a fact-checking agent—but our founder feedback bot is the one we’re most excited about.
Challenges we ran into
Apple doesn’t expose iMessage APIs, so getting stable and real-time access requires reverse engineering via BlueBubbles. Making the SDK general enough to support different bot types—but still easy to use—was a tricky balance. Integrating AI without losing control over hallucinations also required tuning.
Accomplishments we're proud of
Our flagship founder bot works. It receives iMessage feedback from users, uses GPT to summarize and categorize it, and files it directly to Linear with context. In less than 24 hours, we built multiple bots using Bluely—each one showcasing a different vertical—but this one made real product feedback effortless.
What we learned
iMessage is wildly underutilized in product workflows. The response rates are better, the UX is friendlier, and it’s where users already are. Founders shouldn’t have to forward texts, open Notion, or guess what users want—our bot handles all that with AI.
What's next
We’re open-sourcing Bluely with docs and templates for rapid bot building. We’ll expand integrations—Notion, Slack, Calendly, Supabase—and focus on AI-first bots that solve real pain points. The founder feedback bot is just the beginning. We want to power every conversational use case on the most engaging messaging platform in the world. Demo Link Pitch Live Demo
🤖 iMessage Bot Framework
A simple, flexible framework for building iMessage bots using BlueBubbles. Create powerful bots with just a few lines of Python!
✨ Features
- Simple API: Create bots with minimal code
- Flexible Patterns: Commands, regex, text matching, and more
- State Management: Built-in persistent storage
- Middleware Support: Add authentication, rate limiting, logging
- Production Ready: Built on FastAPI with proper error handling
- Extensible: Plugin system for advanced features
🚀 Quick Start
Installation
Install using pip:
pip install imessage-bot-framework
Or with Poetry:
poetry add imessage-bot-framework
Your First Bot
from imessage_bot_framework import Bot
# Create a bot
bot = Bot("My First Bot")
# Add a simple command
@bot.on_message
def hello_handler(message):
if message.text.startswith("!hello"):
return "Hello there! 👋"
# Start the bot
bot.run()
Set your environment variables:
export BLUEBUBBLES_SERVER_URL="http://localhost:1234"
export BLUEBUBBLES_PASSWORD="your_password"
Run your bot and send !hello in any iMessage chat!
📚 Examples
Command Bot with Arguments
from imessage_bot_framework import Bot
from imessage_bot_framework.decorators import command
bot = Bot("Calculator Bot")
@bot.on_message
@command("!calc")
def calculator(message, args):
try:
result = eval(args) # Don't do this in production!
return f"Result: {result}"
except:
return "Invalid calculation"
bot.run()
State Management
from imessage_bot_framework import Bot, State
from imessage_bot_framework.decorators import command
bot = Bot("Counter Bot")
state = State()
@bot.on_message
@command("!count")
def increment_counter(message):
count = state.increment(f"counter_{message.sender}")
return f"Your count: {count}"
@bot.on_message
@command("!reset")
def reset_counter(message):
state.set(f"counter_{message.sender}", 0)
return "Counter reset!"
bot.run()
Regex Patterns
from imessage_bot_framework import Bot
from imessage_bot_framework.decorators import regex
bot = Bot("Math Bot")
@bot.on_message
@regex(r"(\d+)\s*([+\-*/])\s*(\d+)")
def math_handler(message, a, op, b):
a, b = int(a), int(b)
if op == '+': return f"{a} + {b} = {a + b}"
if op == '-': return f"{a} - {b} = {a - b}"
if op == '*': return f"{a} * {b} = {a * b}"
if op == '/': return f"{a} / {b} = {a / b}" if b != 0 else "Cannot divide by zero!"
bot.run()
Middleware Example
from imessage_bot_framework import Bot
from imessage_bot_framework.decorators import command, rate_limit
bot = Bot("Protected Bot")
# Rate limiting middleware
@bot.use_middleware
def rate_limiter(message, next_handler):
# Simple rate limiting logic here
return next_handler(message)
# Authentication middleware
@bot.use_middleware
def auth_required(message, next_handler):
if message.sender not in ["allowed_user@example.com"]:
return "Access denied"
return next_handler(message)
@bot.on_message
@command("!secret")
def secret_command(message):
return "You have access to the secret!"
bot.run()
Chat Interaction
from imessage_bot_framework import Bot
bot = Bot("Chat Manager")
@bot.on_message
def chat_info(message):
if message.text == "!info":
participants = message.chat.get_participants()
recent_messages = message.chat.get_messages(limit=10)
return f"Chat has {len(participants)} participants and {len(recent_messages)} recent messages"
@bot.on_message
def broadcast(message):
if message.text.startswith("!broadcast ") and message.is_from_me:
msg = message.text[11:] # Remove "!broadcast "
# Send to multiple chats
bot.send_to_chat(msg, "chat-guid-1")
bot.send_to_chat(msg, "chat-guid-2")
return "Message broadcasted!"
bot.run()
🎯 Available Decorators
Pattern Matching
@command("!trigger")- Match command triggers@contains("text")- Match messages containing text@regex(r"pattern")- Match regex patterns
Access Control
@only_from_me()- Only respond to your messages@only_from_user("user@example.com")- Restrict to specific user@rate_limit(max_calls=5, window_seconds=60)- Rate limiting
🗄️ State Management
The framework includes a simple but powerful state system:
from imessage_bot_framework import State
state = State("my_bot_state.json")
# Basic operations
state.set("key", "value")
value = state.get("key", "default")
state.delete("key")
# Numeric operations
count = state.increment("counter")
state.increment("score", 10)
# List operations
state.append("items", "new_item")
# Conversation context
with state.conversation(user_id) as conv:
conv.set("name", "John")
conv.save({"age": 25, "city": "NYC"})
🛠️ CLI Tool
The framework includes a CLI tool to help you create new bots quickly:
Create a New Bot
# Install the framework
pip install imessage-bot-framework
# Create a new bot project
imessage-bot create "My Awesome Bot"
# Or specify a directory
imessage-bot create "My Bot" --directory ~/bots/
This creates a complete bot project with:
main.py- Your bot's main fileconfig.py- Configuration managementpyproject.toml- Poetry dependencies.env.example- Environment templateREADME.md- Project documentation
CLI Commands
imessage-bot create <name> # Create a new bot
imessage-bot version # Show framework version
Using the Generated Project
cd my-awesome-bot
poetry install
cp .env.example .env
# Edit .env with your BlueBubbles configuration
poetry run python main.py
🔧 Configuration
Set these environment variables:
# Required
BLUEBUBBLES_SERVER_URL=http://localhost:1234
BLUEBUBBLES_PASSWORD=your_password
# Optional
BOT_DEBUG=true
BOT_PORT=8000
Or configure programmatically:
bot = Bot("My Bot", port=8001, debug=True)
🏗️ Project Structure
my_bot/
├── main.py # Main bot file
├── config.py # Configuration management
├── pyproject.toml # Poetry dependencies
├── .env # Environment variables
├── .env.example # Environment template
├── README.md # Project documentation
└── bot_state.json # Persistent state (auto-created)
📡 Deployment
Local Development
# With Poetry
poetry run python main.py
# Or with pip
python main.py
Production with Docker
FROM python:3.11-slim
# Install Poetry
RUN pip install poetry
WORKDIR /app
# Copy Poetry files
COPY pyproject.toml poetry.lock* ./
# Configure Poetry and install dependencies
RUN poetry config virtualenvs.create false \
&& poetry install --no-dev
COPY . .
CMD ["python", "main.py"]
Environment Variables for Production
BLUEBUBBLES_SERVER_URL=https://your-bluebubbles-server.com
BLUEBUBBLES_PASSWORD=your_secure_password
🔌 Extending with Plugins
Create custom plugins:
# plugins/openai_plugin.py
import openai
class OpenAIPlugin:
def __init__(self, api_key):
self.client = openai.OpenAI(api_key=api_key)
def chat_completion(self, prompt):
response = self.client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
# Use in your bot
from plugins.openai_plugin import OpenAIPlugin
bot = Bot("AI Bot")
ai = OpenAIPlugin(api_key="your-key")
@bot.on_message
@command("!ai")
def ai_chat(message, prompt):
response = ai.chat_completion(prompt)
return response
bot.run()
# Add to pyproject.toml:
# [tool.poetry.dependencies]
# openai = "^1.0.0"
🐛 Debugging
Enable debug mode:
bot = Bot("Debug Bot", debug=True)
Or set environment variable:
export BOT_DEBUG=true
This will show detailed logs of webhook processing, message handling, and errors.
📖 API Reference
Bot Class
class Bot:
def __init__(self, name: str = "Bot", port: int = 8000, debug: bool = False)
def on_message(self, handler: Callable) -> Callable
def use_middleware(self, middleware: Callable) -> Callable
def send_to_chat(self, text: str, chat_guid: str) -> bool
def run(self, host: str = "127.0.0.1") -> None
Message Class
class Message:
text: str # Message content
sender: str # Sender identifier
chat_guid: str # Chat GUID
is_from_me: bool # True if sent by bot owner
timestamp: datetime # Message timestamp
def reply(self, text: str) -> bool
def send_to_chat(self, text: str, chat_guid: str = None) -> bool
@property
def chat(self) -> Chat # Get Chat object
Chat Class
class Chat:
guid: str # Chat GUID
def send(self, text: str) -> bool
def get_messages(self, limit: int = 50) -> List[Dict]
def get_participants(self) -> List[str]
State Class
class State:
def get(self, key: str, default: Any = None) -> Any
def set(self, key: str, value: Any) -> None
def delete(self, key: str) -> None
def increment(self, key: str, amount: int = 1) -> int
def append(self, key: str, value: Any) -> None
def conversation(self, user_id: str) -> ConversationContext
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built on top of BlueBubbles for iMessage integration
- Powered by FastAPI for the web framework
- Inspired by modern bot frameworks like Discord.py and Telegram Bot API
Ready to build your first iMessage bot? Check out our examples directory for more inspiration!
Analysis
View
Metric
- 9
- 5
- 2
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- FastAPIIn code
- OpenAIIn code
- PythonIn code
3 of 3 appear in the indexed code.
AI coding agents
No AI coding agent signals were found in this repository.
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
554 KB
Source files
80
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
shrey150/imessage-bots
96 files · 4.1 MB · @ c896a8d
Structure
Application logic
68 files · 71%Domain rules, services and shared utilities.
+2 more
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Python72%
- Markdown28%
- YAML0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
pyproject.toml
pypi · 15- fastapi
- pydantic
- requests
- uvicorn
- +11 more
imessage-bots/src/bots/feedback-bot/pyproject.toml
pypi · 11- fastapi
- openai
- pydantic
- python-dotenv
- requests
- uvicorn
- +5 more
imessage-bots/src/bots/meeting-scheduler/pyproject.toml
pypi · 11- fastapi
- google-api-python-client
- google-auth-httplib2
- google-auth-oauthlib
- openai
- pydantic
- python-dateutil
- python-dotenv
- python-multipart
- requests
- uvicorn
imessage-bots/src/bots/meeting-scheduler/requirements.txt
pypi · 11- fastapi[standard]
- google-api-python-client
- google-auth-httplib2
- google-auth-oauthlib
- openai
- pydantic
- python-dateutil
- python-dotenv
- python-multipart
- requests
- uvicorn[standard]
imessage-bots/src/bots/lover-bot/pyproject.toml
pypi · 10- fastapi
- imessage-bot-framework
- openai
- pydantic
- python-dotenv
- requests
- uvicorn
- +3 more
imessage-bots/src/bots/recap-bot/pyproject.toml
pypi · 9- fastapi
- openai
- pydantic
- python-dotenv
- requests
- uvicorn
- +3 more
imessage-bots/src/bots/resume-roast/pyproject.toml
pypi · 8- beautifulsoup4
- fastapi[standard]
- openai
- pydantic
- python-dotenv
- python-multipart
- requests
- uvicorn[standard]
imessage-bots/src/bots/resume-roast/requirements.txt
pypi · 8- beautifulsoup4
- fastapi
- openai
- pydantic
- python-dotenv
- python-multipart
- requests
- uvicorn[standard]
imessage-bots/src/bots/gork-bot/pyproject.toml
pypi · 7- fastapi
- openai
- pydantic
- python-dotenv
- python-multipart
- requests
- uvicorn
imessage-bots/src/bots/recap-bot/requirements.txt
pypi · 6- fastapi
- openai
- pydantic
- python-dotenv
- requests
- uvicorn
imessage-bots/src/bots/lover-bot-sdk/pyproject.toml
pypi · 5- imessage-bot-framework
- openai
- python-dotenv
- +2 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.