The Power of Gemini inside Trello: Building an LLM Assistant with Firebase Genkit

Published: (December 21, 2025 at 11:51 AM EST)
5 min read
Source: Dev.to

Source: Dev.to

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 a card’s details, look at its 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 the following:

  • A Trello account (one bot account, one regular account to issue requests from) – Trello
  • A Google AI API Key – Google AI Studio
  • Node.js installed – Node.js download
  • A Firebase / GCP account for telemetry and deployment – Firebase

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.

  1. Go to the Trello Power‑Up Admin.

  2. Click “Create a new Power‑Up” for your workspace.

    Create a new Power‑Up screen

  3. Generate your API Key and Secret.

    API Key & Secret screen

  4. Generate a Token to allow your app to act on behalf of your user.

    Token generation screen

  5. (Optional) Verify the credentials on the “Token” page.

    Token verification screen

Keep these credentials safe! You’ll need them in 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 (checklists, comments, image attachments, etc.). The schema can be extended to include links to other projects, additional cards, and more.

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, calls the prompt, and posts the LLM’s response back to Trello as a comment.

const trelloFlow = ai.defineFlow(
  {
    name: "trelloFlow",
    inputSchema: z.object({
      trelloCardId: z.string(),
      trelloComment: z.string(),
    }),
    // …additional metadata if needed
  },
  async (input) => {
    // 1️⃣ Retrieve and format the card data
    const formattedCard = await getFormattedTrelloCard(
      input.trelloCardId,
      input.trelloComment
    );

    // 2️⃣ Generate a response with Gemini
    const output = await trelloPrompt({ inputData: formattedCard });

    // 3️⃣ Post the response as a comment on the card
    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. In trello_helper.ts we fetch attachments, convert them to base64 data URLs, and pass them 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 arrayBuffer = await response.arrayBuffer();
    const base64 = Buffer.from(arrayBuffer).toString("base64");

    return {
      url: `data:${attachment.mimeType};base64,${base64}`,
      caption: attachment.name,
    };
  })
);

Designing the Prompt with Dot‑Prompt

Genkit introduces the .prompt file format, which keeps AI logic clean and separate from application code. In prompts/trello.prompt we select the Gemini 3.0 Flash model 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 the same pattern can be reused to inject any additional context you need.

(The actual prompt file is omitted here for brevity, but it follows the standard .prompt syntax with sections for system instructions, user input, and variable interpolation.)

With the pieces above—Power‑Up credentials, a Genkit Flow, multi‑modal attachment handling, and a clean .prompt—you now have a fully functional bot that can “talk” to your Trello cards using Gemini 3.0 Flash. Deploy the code to Firebase Functions (or any Node.js environment), set the required environment variables, and watch your cards become conversational collaborators.

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. Fill out your deployment URL in the .env file. A handy script is provided:

npx tsx src/register_webhook.ts

Sample output

69457XXXXXXXXXXXXXXX
Registering webhook for https://genkit-trello-{PROJECT_ID}.europe-west1.run.app/trelloFlow with board ID: 6945713XXXXXXXXXXXXXX

Seeing it in Action

After 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.

Conversation example

It can even track progress based on checklists and card descriptions!

Conversation progress

Monitoring

If you deploy to GCP and have the Firebase project set up, the Genkit part of the dashboard provides important debug and overview information right away.

Firebase Genkit dashboard

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 an MVP—feel free to fork it and extend it to your use‑cases.

Check out the full source code on GitHub:

Back to Blog

Related posts

Read more »