In the world of project management, Trello has long been a favorite for its simplicity and visual organization. But what if your Trello cards could talk back? What if a bot could analyze your card's details, look at your attachments, and provide intelligent updates or answers to your team's comments?
In this article, we'll explore how to integrate Google's Gemini 3.0 Flash model into Trello using Firebase Genkit.
Prerequisites
Before we dive in, make sure you have:
- Trello accounts (One bot account, one to issue requests from)
- A Google AI API Key
- Node.js installed
- Firebase/GCP account (for telemetry and deployment)
Setting up your Trello Power-Up
To interact with Trello's API, you'll need to create a Power-Up. This gives you the API Key and Token required for authentication.
- Go to the Trello Power-Up Admin.
- Create a new Power-Up for your workspace.
- Generate your API Key and Secret.
- Generate a Token to allow your app to act on behalf of your user.
Keep these credentials safe! You'll need them for your .env file.
Crafting the AI Logic with Firebase Genkit
Firebase Genkit simplifies building LLM-powered applications. We'll define a Flow that takes a Trello card ID and a comment, fetches all relevant data, and uses Gemini to generate a response.
Defining the Schema
First, we define a structured schema for our card data. This ensures Gemini receives consistent information, including checklists, comments, and even image attachments. It's possible to easily extend this schema for other details, like links to other projects, more cards etc.
export const TrelloRequestRequestInputSchema = z.object({
instructions: z.string().describe("User's instructions"),
attachments: z.array(z.object({
url: z.string(),
caption: z.string().optional(),
})),
details: z.string(),
comments: z.array(z.object({
person: z.string(),
text: z.string(),
timestamp: z.string(),
})),
checklists: z.array(z.object({
name: z.string(),
items: z.object({
itemName: z.string(),
completed: z.boolean(),
dueDate: z.string(),
}).array(),
})),
today: z.string(),
});
The Trello Flow
The core of our application is the trelloFlow. It fetches the card details using a helper function and then calls our prompt.
const trelloFlow = ai.defineFlow(
{
name: "trelloFlow",
inputSchema: z.object({
trelloCardId: z.string(),
trelloComment: z.string(),
}),
// ...
},
async (input) => {
const formattedCard = await getFormattedTrelloCard(
input.trelloCardId,
input.trelloComment
);
const output = await trelloPrompt({ inputData: formattedCard });
await trelloClient.cards.addCardComment({
id: input.trelloCardId,
text: output.output.responseText,
});
return { success: true, message: "Comment added successfully" };
}
);
Multi-modal Capabilities: Seeing Attachments
One of Gemini's greatest strengths is its ability to understand images. Our bot can "see" attachments on a Trello card. In trello_helper.ts, we fetch attachments and convert them to base64 data URLs, which Genkit can pass directly to the LLM.
const formattedAttachments = await Promise.all(
attachments.map(async (attachment) => {
const response = await fetch(attachment.url, {
headers: {
Authorization: `OAuth oauth_consumer_key="${env.TRELLO_API_KEY}", oauth_token="${env.TRELLO_API_TOKEN}"`,
},
});
const base64 = await response.arrayBuffer();
return {
url: `data:${attachment.mimeType};base64,${Buffer.from(base64).toString("base64")}`,
caption: attachment.name,
};
})
);
Designing the Prompt with Dot-Prompt
Genkit introduces the .prompt file format, which is incredibly powerful for keeping your AI logic clean and separate from your application code. In prompts/trello.prompt, the Gemini 3.0 Flash model was selected for its speed and native multi-modal support.
The prompt uses Handlebars-style templates to inject our structured card data. We loop over the different parts of the Trello card, but this can be used to inject other context as well.
Connecting Trello via Webhooks
To make the bot reactive, we use Trello Webhooks. Whenever a comment is added, Trello sends a POST request to our application.
Different Express middleware is used to intercept, verify and format the requests, before they reach Genkit.
Security
We implement a middleware to verify that incoming requests actually come from Trello using HMAC-SHA1 signatures.
export const trelloSignatureMiddleware = (req: RequestWithAuth, res: Response, next: NextFunction) => {
const signature = req.headers["x-trello-webhook"];
const secret = env.TRELLO_WEBHOOK_SECRET;
const callbackURL = env.TRELLO_CALLBACK_URL;
const body = req.rawBody ? req.rawBody.toString("utf8") : "";
const baseString = body + callbackURL;
const computedSignature = crypto
.createHmac("sha1", secret)
.update(baseString)
.digest("base64");
if (signature === computedSignature) {
next();
} else {
res.status(401).send("Unauthorized");
}
};
Registering the Webhook
Once your app is deployed (e.g., to Cloud Run), you need to tell Trello where to send its updates. Make sure to fill out your deployment URL into the .env file. I've included a handy script for this:
npx tsx src/register_webhook.ts
Output:
69457XXXXXXXXXXXXXXX
Registering webhook for https://genkit-trello-{PROJECT_ID}.europe-west1.run.app/trelloFlow with board ID: 6945713XXXXXXXXXXXXXX
Seeing it in Action
Once everything is set up, you can tag your bot in a Trello comment (e.g., @GeminiBot what's the status of this task?). The bot will analyze the entire card context and reply.
It can even track progress based on checklists and card descriptions!
Monitoring
If we deploy to GCP and have the Firebase project setup, in the Genkit part of the dashboard, we get important debug and overview information right away.

Conclusion
By combining Trello's structured project data with Gemini's reasoning capabilities and Firebase Genkit's orchestration, you can create a helpful Trello assistant. Whether it's summarizing long comment threads, analyzing attached designs, or providing quick status updates, there are many ways for this to be useful. The project is also just a MVP. Feel free to fork it and extend it to your use-cases.
Check out the full source code at GitHub!





Top comments (0)