From fireflies-pack
Fetches Fireflies.ai meeting transcripts via GraphQL, processes speaker-diarized sentences, extracts action items and summaries for intelligence pipelines.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin fireflies-packThis skill is limited to using the following tools:
Primary workflow for Fireflies.ai: fetch meeting transcripts via GraphQL, process speaker-diarized sentences, extract action items and summaries, and route meeting intelligence downstream.
Searches Fireflies.ai transcripts by keyword/date/participants, queries AskFred AI for meeting Q&A and threads, aggregates data for analytics reports.
Queries Fireflies.ai for meeting transcripts from Zoom, Teams, Google Meet; searches by keyword/date, extracts action items, and retrieves summaries.
Fetches speaker-attributed, timestamped meeting transcripts—full, paginated, or filtered by speaker/phrase—without leaking raw PII into storage. Use for specific quotes or targeted pulls from large transcripts.
Share bugs, ideas, or general feedback.
Primary workflow for Fireflies.ai: fetch meeting transcripts via GraphQL, process speaker-diarized sentences, extract action items and summaries, and route meeting intelligence downstream.
fireflies-install-auth setupFIREFLIES_API_KEY set with Business+ plan for full access// lib/fireflies.ts
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
export async function firefliesQuery<T = any>(
query: string,
variables?: Record<string, any>
): Promise<T> {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) {
const err = json.errors[0];
throw new Error(`Fireflies API error: ${err.message} (${err.code || "unknown"})`);
}
return json.data;
}
const LIST_TRANSCRIPTS = `
query ListTranscripts(
$limit: Int,
$mine: Boolean,
$fromDate: DateTime,
$toDate: DateTime,
$organizers: [String],
$participants: [String]
) {
transcripts(
limit: $limit
mine: $mine
fromDate: $fromDate
toDate: $toDate
organizers: $organizers
participants: $participants
) {
id title date duration
organizer_email participants
summary { overview action_items keywords }
}
}
`;
// Fetch this week's meetings for a specific organizer
const data = await firefliesQuery(LIST_TRANSCRIPTS, {
limit: 20,
fromDate: "2026-03-15T00:00:00Z",
organizers: ["alice@company.com"],
});
const GET_TRANSCRIPT = `
query GetTranscript($id: String!) {
transcript(id: $id) {
id title date duration
organizer_email
speakers { id name }
sentences {
index
speaker_name
speaker_id
text
raw_text
start_time
end_time
ai_filters {
task
question
sentiment
pricing
metric
date_and_time
}
}
summary {
overview
short_summary
bullet_gist
action_items
keywords
outline
topics_discussed
}
meeting_attendees { displayName email }
meeting_attendance { name join_time leave_time }
analytics {
sentiments { positive_pct negative_pct neutral_pct }
speakers {
name duration word_count
words_per_minute questions
longest_monologue filler_words
}
}
}
}
`;
const { transcript } = await firefliesQuery(GET_TRANSCRIPT, { id: "abc123" });
interface MeetingIntelligence {
id: string;
title: string;
attendees: string[];
actionItems: string[];
keyTopics: string[];
speakerBreakdown: { name: string; minutes: number; wordCount: number }[];
sentiment: { positive: number; negative: number; neutral: number };
questions: string[];
}
function processMeeting(transcript: any): MeetingIntelligence {
// Extract questions from AI filters
const questions = transcript.sentences
.filter((s: any) => s.ai_filters?.question)
.map((s: any) => `${s.speaker_name}: ${s.text}`);
return {
id: transcript.id,
title: transcript.title,
attendees: transcript.meeting_attendees?.map((a: any) => a.email) || [],
actionItems: transcript.summary?.action_items || [],
keyTopics: transcript.summary?.keywords || [],
speakerBreakdown: (transcript.analytics?.speakers || []).map((s: any) => ({
name: s.name,
minutes: Math.round(s.duration / 60),
wordCount: s.word_count,
})),
sentiment: {
positive: transcript.analytics?.sentiments?.positive_pct || 0,
negative: transcript.analytics?.sentiments?.negative_pct || 0,
neutral: transcript.analytics?.sentiments?.neutral_pct || 0,
},
questions,
};
}
function transcriptToText(transcript: any): string {
const lines: string[] = [
`# ${transcript.title}`,
`Date: ${transcript.date} | Duration: ${transcript.duration}min`,
`Speakers: ${transcript.speakers.map((s: any) => s.name).join(", ")}`,
"",
"## Summary",
transcript.summary?.overview || "(no summary)",
"",
"## Action Items",
...(transcript.summary?.action_items || []).map((a: string) => `- ${a}`),
"",
"## Transcript",
];
for (const s of transcript.sentences) {
const timestamp = formatTimestamp(s.start_time);
lines.push(`[${timestamp}] ${s.speaker_name}: ${s.text}`);
}
return lines.join("\n");
}
function formatTimestamp(seconds: number): string {
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
}
| Error | Cause | Solution |
|---|---|---|
auth_failed | Invalid API key | Regenerate in Fireflies dashboard |
Empty sentences array | Transcript still processing | Check meeting_info.summary_status |
null summary | Short meeting (<1 min) | Summary requires minimum content |
| Rate limit 429 | Over 60 req/min (Business) | Implement backoff per fireflies-rate-limits |
Missing analytics | Free/Pro plan | Analytics requires Business+ plan |
For search, analytics, and AskFred, see fireflies-core-workflow-b.