--- name: fireflies-relanguage description: Fix a wrong-language Fireflies transcript on a meeting you don't own (can't hit Reprocess yourself) by re-uploading its audio under the correct language via the Fireflies API, recovering real speaker names into the result with transcript-speaker-fill, then deleting the duplicate meeting. Use when the user has a link to a Fireflies recording they aren't the host/owner of, the transcript is in the wrong language, and they want a corrected transcript without waiting for the owner to act or leaving a duplicate meeting behind. Trigger phrases: "I'm not the owner of this meeting", "can't reprocess this transcript", "fix this Fireflies transcript without the owner", "re-transcribe a shared meeting". --- # Fireflies relanguage skill ## Purpose Fireflies' own "Update Language + Reprocess" fix only works for the meeting's host/owner (see `guide.fireflies.ai` docs). If you were just sent a link to someone else's recording and it came out in the wrong language, you have no UI path to fix it and can't wait for the owner. This skill routes around that: pull the meeting's audio via the API, re-upload it as a **new** meeting under your own account with the correct language forced, recover the original's real speaker names into the new, correctly-transcribed text using the [[transcript-speaker-fill]](../transcript-speaker-fill/SKILL.md) skill, then delete the duplicate meeting the re-upload created. ## Before you start: real constraints, not hypothetical ones **This may simply not be possible on your account.** `audio_url`/`video_url` on a Fireflies transcript require a Pro+ plan, and it is undocumented whether they populate at all for a meeting merely *shared* with you rather than owned by you. [Michał's own wiki notes](/wiki/entities/fireflies-transcript-handling.md) record hitting exactly this wall before (no Pro seat → transcript download tooling broke). Step 1 below (`fetch`) is also the diagnostic: if it prints the "audio_url is null" warning, stop here — this workflow cannot proceed without one of the workarounds it suggests (a Pro+ seat's API key, the actual owner reprocessing it, or you manually downloading the audio via the web UI and hosting it at some public HTTPS URL yourself). **Every re-upload consumes real transcription quota/minutes** on the account whose API key you use, same as any other Fireflies upload — this isn't free just because it's automated. **Deleting a transcript is irreversible.** Don't run this on a meeting you actually might need to keep two copies of, and don't skip the confirmation gates below. Also worth knowing up front: the Fireflies API has thin rate limits (Free: 50 requests/day, Pro: 500/day, Business/Enterprise: 60/min) and `deleteTranscript` specifically is capped at 10/min. This workflow only needs a handful of calls plus some polling, but don't loop the `wait` step aggressively. ## Requirements - `FIREFLIES_API_KEY` set in the environment. Get one from the Fireflies web app under **Settings > API**. The script exits with this exact instruction if it's missing — don't hardcode the key anywhere. - The `transcript-speaker-fill` skill installed alongside this one (it is, in this repo) — this skill hands off the actual name-recovery merge to it rather than duplicating that logic. ## Workflow Resolve `` to this skill's own directory throughout. ### 1. Fetch the original (broken-language) transcript ```bash python3 "/scripts/fireflies_client.py" fetch --ref "" --out original.md ``` Accepts a bare transcript id or a full share link like `https://app.fireflies.ai/view/Some-Title::abcDEF123`. Writes `original.md` (real speaker names, garbled text — the shape `transcript-speaker-fill` expects for its "broken" input) and `original.md.meta.json` (id, title, `audio_url`, etc., needed by later steps). **Check the printed output for the audio_url warning before continuing.** If it's null, stop and follow the guidance it prints instead of proceeding to step 2 — do not attempt step 2 anyway "just to see." ### 2. Confirm the target language with the user Don't guess the correct language from context alone unless it's unambiguous (e.g. the user already told you). Ask if unclear. Use the language code Fireflies expects — check [Learn about Fireflies supported languages](https://guide.fireflies.ai/articles/2973706448-learn-about-fireflies-supported-languages) for the exact code if you're not sure it matches (e.g. `en`, `pl`, `es`). ### 3. Re-upload the audio under the correct language ```bash python3 "/scripts/fireflies_client.py" upload --meta original.md.meta.json --language ``` This calls `uploadAudio` with `custom_language` set, tagging the new meeting's title with `[relang:]` so it can be found unambiguously afterward (override with `--title` if you want a cleaner name, but then pass that exact same string to step 4). Note the exact title printed — you need it verbatim for the next step. ### 4. Wait for the re-upload to finish processing ```bash python3 "/scripts/fireflies_client.py" wait --title "" ``` Polls every 30s (default) up to 15 minutes (default) for a transcript with that exact title to appear with content. Long recordings can take longer — if it times out, just re-run `wait` again rather than assuming failure. Prints the new transcript's `id` once ready. ### 5. Fetch the new (correct-language) transcript ```bash python3 "/scripts/fireflies_client.py" fetch --ref "" --out new.md ``` This one should come back with correct text but generic `Speaker 1`, `Speaker 2`, ... labels (no calendar/roster context on a bare re-upload) — exactly the gap `transcript-speaker-fill` closes. ### 6. Recover real speaker names Hand off to the `transcript-speaker-fill` skill exactly per its own SKILL.md, using `original.md` and `new.md` as the two inputs — dry run first, present the resolution report, get the user's confirmation/manual overrides, then `--apply`. Do not skip its confirmation gate just because you're mid-pipeline; it's exactly as load-bearing here as when invoked standalone. Also pass `--recording-url "https://app.fireflies.ai/view/"` on every `fill_speakers.py` call in this handoff (both the dry-run and the `--apply` run) — the bare-id form of the URL works without needing to slug-encode the title, and gives the user a direct link to a recording they definitely have full access to (they own the re-uploaded meeting) right next to every label's example lines, for the spot-check `transcript-speaker-fill` asks them to do before confirming. Use the new transcript's id, not the original's — do this *before* step 8's cleanup, while that meeting (and its recording) still exists. ### 7. Ask where to save the corrected transcript Before touching the duplicate meeting, ask the user where the final `--apply`'d output (from step 6) should end up — don't default to leaving it in a scratch/temp location without asking. Common answers: a specific path they name, this project's own `tmp/` (if this skill is being run from inside a Cascade Knowledge Base repo like this one — gitignored, agent- managed), or `raw/inbox/` if they want it ingested into a wiki afterward. Move (don't copy) the file there once they've told you. ### 8. Delete the duplicate meeting — only after explicit confirmation Once the user has confirmed the merged transcript (from step 6) looks right and it's been saved wherever they wanted (step 7), delete the meeting the re-upload created (**not** the original — you don't own that one anyway, and couldn't delete it if you tried): ```bash python3 "/scripts/fireflies_client.py" delete --id --yes ``` The script refuses to run without `--yes`. Never pass `--yes` without the user having explicitly confirmed they're ready — this is irreversible and removes a real meeting from their Fireflies account. Show them the printed `{id, title, date, duration}` of what was deleted as final confirmation. ## Failure modes and what they mean - **`fetch` on the original prints the audio_url warning** — see "Before you start" above. This is the expected failure mode when the API key's account isn't Pro+, or when a merely-shared meeting doesn't expose audio via the API. Not a bug to work around silently. - **`upload` mutation succeeds (`success: true`) but `wait` never finds it** — the title match is exact-string, so a `--title` override that doesn't exactly match what you pass to `wait` will never resolve; double check you used the identical string in both commands. - **`wait` times out** — normal for long recordings. Re-run it; don't assume the upload failed. - **Rate limit errors (`too_many_requests`)** — the error message includes `retryAfter`; wait that long before retrying, especially on a Free-tier key (50 requests/day total). - **`delete` fails with `require_elevated_privilege`** — you're trying to delete a transcript you don't own (e.g. you accidentally passed the *original* id instead of the new one from step 4). Only the re-uploaded meeting is yours to delete. ## Edge cases - **Multiple speakers with a name-recovery gap** (new transcript has more distinct `Speaker N` labels than the original has real names) — this is `transcript-speaker-fill`'s "roster gap" warning, not something this skill's own steps can fix; it means someone's voice wasn't distinctly captured with a real name in the original either. - **Original meeting has `video_url` but not `audio_url`** — `upload` only accepts `--audio-url`; there's no video re-upload path here. If you truly only have video access, extract audio from it yourself first and host that as a public URL, then pass it via `--audio-url`. - **The user wants the corrected transcript ingested into this repo's wiki**, not just saved as a file — step 7 already asks where to save it; if the answer is "ingest it," save it to `raw/inbox/` there, then run the normal "Ingest" workflow from the root `CLAUDE.md` on it after step 8's cleanup (the duplicate meeting is Fireflies-side bookkeeping, unrelated to whether the wiki ingest has happened yet).