Claude-code-plugins-plus-skills fireflies-core-workflow-a
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/fireflies-pack/skills/fireflies-core-workflow-a" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-fireflies-core-workflow-a && rm -rf "$T"
manifest:
plugins/saas-packs/fireflies-pack/skills/fireflies-core-workflow-a/SKILL.mdsource content
Fireflies.ai Core Workflow A -- Transcript Retrieval & Processing
Overview
Primary workflow for Fireflies.ai: fetch meeting transcripts via GraphQL, process speaker-diarized sentences, extract action items and summaries, and route meeting intelligence downstream.
Prerequisites
- Completed
setupfireflies-install-auth
set with Business+ plan for full accessFIREFLIES_API_KEY- At least one completed meeting in Fireflies
Instructions
Step 1: Build the GraphQL Client
// 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; }
Step 2: List Transcripts with Filters
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"], });
Step 3: Fetch Full Transcript with Sentences
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" });
Step 4: Process Meeting Intelligence
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, }; }
Step 5: Export Transcript as Text
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 Handling
| Error | Cause | Solution |
|---|---|---|
| Invalid API key | Regenerate in Fireflies dashboard |
Empty array | Transcript still processing | Check |
summary | Short meeting (<1 min) | Summary requires minimum content |
| Rate limit 429 | Over 60 req/min (Business) | Implement backoff per |
Missing | Free/Pro plan | Analytics requires Business+ plan |
Output
- Full transcript with speaker-diarized sentences and timestamps
- AI-generated summary, action items, and keywords
- Speaker analytics with talk time, word count, and sentiment
- Meeting intelligence object ready for downstream processing
Resources
Next Steps
For search, analytics, and AskFred, see
fireflies-core-workflow-b.