ARTICLE

FLORA: spreadsheet batch via MCP (20 parallel rows) vs Bubble catalog orchestration in BIAIG

Where to stop at FLORA MCP (20-row chunks, polling, run_id→SKU maps) and where to keep source of truth and batch identity in Bubble—without conflating batch IDs or double-billing after timeouts.

Context

The digest added another pin on the “external batch host before Bubble” map: FLORA spreadsheet batch via MCP, roughly 20 parallel rows per call. Same slot as Ideogram Batch (~500 prompt rows per upload) and Batch Banana (up to 1,000 CSV/TSV rows on Max)—same role, different scale, and MCP/agent entry instead of upload-only UX.

Public FLORA docs frame the MCP pattern as agent orchestration: export a sheet, one prompt template per row, submit with flora_create_generations (1–20 generations per call, parallel within the call). Larger jobs go in chunks of 20 within a stated ~20–500 asset range. Poll with flora_list_generations (up to 20 run_ids per call), cooldown max(15 s, 2 s × run count).

BIAIG has no verified public orchestration spec—biaig.com is placeholder-level. What follows is how I split layers in practice, aligned with Bubble Manual primitives and the editorial brief (internal Bubble-backed catalog), not invented product APIs.


Stop FLORA at the MCP generation layer

I keep on FLORA + agent/middleware only what the docs call generation + chunk polling:

  1. Parallelism and chunking — max 20 rows per flora_create_generations; I split the rest of the job explicitly. That is not a single 500/1,000-row upload like Ideogram or Batch Banana.
  2. Polling and partial retry — documented intervals for run_id lists. I have seen aggressive polling hit workspace rate limits (429/cooldown).
  3. run_id → row (e.g. SKU) — docs say this is the only stable link between a run and its source row. I persist the map outside the chat session—file, DB, Bubble job record, not in the agent’s head.
  4. Quote-before-run where the recipe requires it. I do not jump into create without understanding billing.

I do not make Bubble the live ledger of every MCP create. Too chatty, too much coupling. Bubble should hold job state and outcomes, not every intermediate call.


Keep source of truth in Bubble (BIAIG)

If BIAIG is your Bubble catalog, this is where catalog, SKU/variant, statuses (queued / generating / failed / ready), and final image URLs live:

  • Data API — CRUD on catalog and batch job records.
  • Workflow API — triggers from middleware after chunks complete or on poll ticks.
  • Schedule API Workflow on a list — native list iteration with optional interval spacing when part of orchestration sits in Bubble instead of the agent loop. A closer look: ChatGPT is not bulk-native: where.

I create one canonical batch_job_id in Bubble before the first flora_create_generations. MCP create has no idempotency key—that does not replace your job id.


Non-negotiable: no create idempotency

FLORA is clear: flora_create_generations has no idempotency key. Timeouts or dropped sessions plus re-firing rows without checking project history can double-bill. I would not trust luck on that.

I treat these as requirements:

  • Before resubmitting a row, check whether a run already exists in history.
  • Persist every (stable_row_key, chunk_index, run_id, create_timestamp).
  • Retry failed rows only (partial success is explicit in the recipe), not whole chunks blindly.

Optional skill / skill_run_id on generation calls is reporting attribution only, not deduplication. I do not use it as Bubble batch job identity.


Checklist: do not duplicate “batch id” semantics

Identifier Owner Role
Bubble batch_job_id Bubble/BIAIG One job per spreadsheet import; your idempotency boundary
FLORA run_id (many) FLORA One generation run; map to SKU/row key
Chunk index Your middleware Which rows of 20 were already submitted
skill_run_id FLORA reporting Attribution, not dedupe

Anti-pattern: calling one MCP chunk or one skill_run_id “the batch id” for the entire spreadsheet job.

MCP batch is orchestration across many create/poll calls—not a single batch object like the FLORA API/SDK CSV recipe.


When to leave the MCP “fire chunks of 20” recipe

FLORA’s API/SDK CSV recipe (Technique-per-row) documents idempotency keys, bounded concurrency (e.g. start CONCURRENCY = 4), and resumable reruns—closer to production than an agent loop alone.

How I frame the decision (no invented throughput claims):

  • ~20–500 assets, MCP already in the stack — MCP recipe + persisted maps + history checks.
  • Need FLORA-side idempotency and resumability — prefer API/SDK CSV, not MCP-only.
  • 500–1,000+ rows, minimal custom orchestration — compare Ideogram/Batch Banana hosted batches (different limits, plans, credits); FLORA MCP at 20/call means more explicit steps than one upload.

Writing results back to catalog

On completion: image URL → SKU/variant field in Bubble (Data API or Workflow API from middleware). The row key frozen at job start must match the run_id→row map. If SKU can change mid-batch, I pick one conflict policy (frozen export vs live catalog) before run start and stick to it.


Short workflow

  1. Stable export with SKU column (per FLORA guides).
  2. Bubble: create batch_job_id, status draft → running.
  3. Middleware/agent: chunks of 20 → create → persist run_ids → poll with cooldown rules.
  4. Update Bubble on complete/fail; targeted retries with history checks.
  5. Close job in Bubble; FLORA is no longer catalog source of truth.

Sources (public)

FLORA MCP batch recipe, runs/polling, generation tools; FLORA API batch-from-CSV; Ideogram Batch; Batch Banana Batch; Bubble Schedule API Workflow on a list and API terminology. BIAIG is editorial internal app context—not a verified public orchestration layer. Worth reading next: Fragmented bulk-tools niche: Apify spreadsheet.

Open questions: where the canonical row list lives during a run; exact BIAIG↔FLORA wiring without internal docs—left to your product spec.

← All articles