Trello's simplicity is its strength — and AI agents make it even more powerful. With its straightforward REST API and clear board/list/card model, Trello is one of the easiest project management tools to automate. AI agents can maintain your kanban flow, keep cards organized, and surface blockers without requiring complex setup.
For small teams, freelancers, and anyone who uses Trello to organize work across multiple projects, AI agent integration brings intelligence to the board without disrupting the familiar visual workflow.
What AI Agents Can Do With Trello Access#
Card Creation and Triage
- Create cards from emails, Slack messages, or text inputs with appropriate labels and due dates
- Route cards to the correct list based on content classification (Backlog vs. Urgent vs. Waiting)
- Add AI-generated checklists to complex cards to break down the work
- Detect potential duplicates before creating new cards
Board Maintenance
- Archive cards in Done lists older than a specified number of days
- Move stale In Progress cards back to Backlog with a comment explaining why
- Apply missing labels to untagged cards based on card content
- Generate weekly board health reports with WIP counts and bottleneck lists
Workflow Automation
- Create cards from templates for recurring project types (blog post workflow, bug report, client onboarding)
- Move cards automatically when checklists are fully completed
- Add comments to cards when external events occur (deployment successful, PR merged)
- Clone entire boards for new project kickoffs
Setting Up Trello API Access#
pip install py-trello langchain langchain-openai python-dotenv
Get credentials from trello.com/app-key:
export TRELLO_API_KEY="your-api-key"
export TRELLO_TOKEN="your-token"
Generate your token:
https://trello.com/1/authorize?expiration=never&scope=read,write&response_type=token&key=YOUR_API_KEY
Test your connection:
from trello import TrelloClient
import os
client = TrelloClient(
api_key=os.getenv("TRELLO_API_KEY"),
token=os.getenv("TRELLO_TOKEN")
)
boards = client.list_boards()
for board in boards:
print(f"Board: {board.name} (ID: {board.id})")
Option 1: No-Code with n8n#
Email-to-Trello Card Workflow#
- Email Trigger (Gmail/Outlook): Detect new emails matching a pattern (subject contains "TODO" or "Task:")
- OpenAI: "Extract from this email: task name, priority (high/medium/low), due date if mentioned, estimated effort"
- Trello node (n8n built-in): Create card in the appropriate list based on priority
- Trello: Add labels based on category
- Email: Send confirmation with Trello card link
n8n's Trello node handles authentication and card creation with simple field mapping — no custom code needed.
Option 2: LangChain with Python#
Build Trello Tools#
import os
import requests
from datetime import datetime, timedelta
from langchain.tools import tool
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("TRELLO_API_KEY")
TOKEN = os.getenv("TRELLO_TOKEN")
BASE_URL = "https://api.trello.com/1"
def trello_request(method: str, endpoint: str, **kwargs) -> dict:
"""Execute a Trello API request with authentication."""
params = kwargs.pop("params", {})
params.update({"key": API_KEY, "token": TOKEN})
response = requests.request(
method, f"{BASE_URL}/{endpoint}", params=params, **kwargs
)
response.raise_for_status()
return response.json()
@tool
def list_boards_and_lists() -> str:
"""List all Trello boards and their lists with IDs for reference."""
boards = trello_request("GET", "members/me/boards", params={"fields": "id,name,closed"})
result = []
for board in boards:
if board.get("closed"):
continue
lists = trello_request("GET", f"boards/{board['id']}/lists", params={"fields": "id,name,pos"})
result.append(f"\n{board['name']} (Board ID: {board['id']}):")
for lst in sorted(lists, key=lambda x: x.get("pos", 0)):
result.append(f" - {lst['name']} (List ID: {lst['id']})")
return "Your Trello boards:" + "\n".join(result) if result else "No active boards found"
@tool
def create_card(list_id: str, name: str, description: str = "",
due_days: int = None, label_ids: list = None) -> str:
"""
Create a new Trello card in a specific list.
due_days: days from today until due date (optional).
label_ids: list of label IDs to apply (optional).
"""
data = {"name": name, "desc": description, "idList": list_id}
if due_days is not None:
due_date = (datetime.now() + timedelta(days=due_days)).isoformat() + "Z"
data["due"] = due_date
if label_ids:
data["idLabels"] = ",".join(label_ids)
card = trello_request("POST", "cards", json=data)
return f"Card created: '{card['name']}' — {card.get('shortUrl', card['id'])}"
@tool
def move_card(card_id: str, target_list_id: str) -> str:
"""Move a Trello card to a different list (e.g., from 'In Progress' to 'Done')."""
card = trello_request("PUT", f"cards/{card_id}", json={"idList": target_list_id})
return f"Card '{card['name']}' moved to list {target_list_id}"
@tool
def add_checklist(card_id: str, checklist_name: str, items: list) -> str:
"""Add a checklist with items to a Trello card to track subtasks."""
checklist = trello_request("POST", "checklists", json={
"idCard": card_id,
"name": checklist_name
})
checklist_id = checklist["id"]
for item in items:
trello_request("POST", f"checklists/{checklist_id}/checkItems", json={"name": item})
return f"Checklist '{checklist_name}' added to card {card_id} with {len(items)} items"
@tool
def get_list_cards(list_id: str) -> str:
"""Get all open cards in a Trello list."""
cards = trello_request("GET", f"lists/{list_id}/cards", params={
"fields": "id,name,desc,due,labels,dateLastActivity",
"filter": "open"
})
if not cards:
return f"No open cards in list {list_id}"
result = [f"Cards in list ({len(cards)} open):"]
for card in cards:
due = card.get("due", "No due date")
if due and "T" in due:
due = datetime.fromisoformat(due.replace("Z", "+00:00")).strftime("%b %d")
labels = [l.get("name", l.get("color", "")) for l in card.get("labels", [])]
label_str = f" [{', '.join(labels)}]" if labels else ""
result.append(f" [{card['id'][-8:]}] {card['name']}{label_str} | Due: {due}")
return "\n".join(result)
@tool
def add_comment(card_id: str, comment: str) -> str:
"""Add a comment to a Trello card for updates or AI analysis notes."""
trello_request("POST", f"cards/{card_id}/actions/comments", json={"text": comment})
return f"Comment added to card {card_id}"
Kanban Management Agent#
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o", temperature=0.1)
tools = [list_boards_and_lists, create_card, move_card, add_checklist,
get_list_cards, add_comment]
prompt = ChatPromptTemplate.from_messages([
("system", """You are a kanban workflow assistant with access to Trello.
When creating cards:
1. List boards and lists first to find the right destination
2. Use clear, actionable card names (what to do, not what was done)
3. Add checklists for complex cards to break down the work
4. Set due dates when timing is mentioned
When reviewing boards:
1. Identify cards that have been in 'In Progress' for too long (stale WIP)
2. Check for cards missing labels or due dates
3. Provide specific recommendations, not just observations
Avoid moving cards unless explicitly instructed — just report what needs attention."""),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=6)
# Example: Triage a request
result = executor.invoke({
"input": "Create a Trello card for this task: 'Write Q1 board presentation for CEO - needs financial charts, product roadmap, and team headcount. Due in 5 days.' Add a checklist with subtasks."
})
print(result["output"])
Rate Limits and Best Practices#
| Trello API limit | Value |
|---|---|
| Per token rate | 100 req/10 seconds |
| Per API key rate | 300 req/10 seconds |
| Webhook delivery | Best-effort, 30s timeout |
Best practices:
- Cache board/list IDs: Fetch board and list IDs at agent startup and cache — they rarely change
- Use card short URLs: Card short URLs (card.shortUrl) are stable and human-friendly for notifications
- Limit card fetch fields: Use the
fieldsparameter to request only the card data you need, reducing response size - Archive, don't delete: Use PUT /cards/ with
{"closed": true}to archive cards — hard deletion is permanent and irreversible
Next Steps#
- AI Agents Asana Integration — More powerful project management for larger teams
- AI Agents Monday.com Integration — Flexible workflow boards with advanced columns
- AI Agents Slack Integration — Create Trello cards from Slack messages
- Build an AI Agent with LangChain — Complete agent framework tutorial