| name | twinmind-core-workflow-a |
| description | Execute TwinMind primary workflow: Meeting transcription and summary generation.
Use when implementing meeting capture, building transcription features,
or automating meeting documentation.
Trigger with phrases like "twinmind transcription workflow",
"meeting transcription", "capture meeting with twinmind".
|
| allowed-tools | Read, Write, Edit, Bash(npm:*), Grep |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
TwinMind Core Workflow A: Meeting Transcription & Summary
Overview
Primary workflow for capturing meetings, generating transcripts, and creating AI summaries.
Prerequisites
- Completed
twinmind-install-auth setup
- TwinMind Pro/Enterprise for API access
- Valid API credentials configured
- Audio source available (live or file)
Instructions
Step 1: Initialize Meeting Capture
import { getTwinMindClient } from '../twinmind/client';
import { Transcript, Summary } from '../twinmind/types';
interface MeetingOptions {
title?: string;
calendarEventId?: string;
language?: string;
enableDiarization?: boolean;
}
export class MeetingCapture {
private client = getTwinMindClient();
async startLiveCapture(options: MeetingOptions = {}): Promise<string> {
const response = await this.client.post('/meetings/live/start', {
title: options.title || `Meeting ${new Date().toISOString()}`,
calendar_event_id: options.calendarEventId,
language: options.language || 'auto',
diarization: options.enableDiarization ?? true,
model: ,
});
response..;
}
(: ): <> {
response = ..();
response..;
}
(: , : = {}): <> {
response = ..(, {
: audioUrl,
: options.,
: options. || ,
: options. ?? ,
: ,
});
.(response..);
}
(: , maxWaitMs = ): <> {
startTime = .();
pollIntervalMs = ;
(.() - startTime < maxWaitMs) {
response = ..();
(response.. === ) {
response.;
}
(response.. === ) {
();
}
( (r, pollIntervalMs));
}
();
}
}
Step 2: Generate AI Summary
export interface SummaryOptions {
format?: 'brief' | 'detailed' | 'bullet-points';
includeActionItems?: boolean;
includeKeyPoints?: boolean;
maxLength?: number;
}
export class SummaryGenerator {
private client = getTwinMindClient();
async generateSummary(
transcriptId: string,
options: SummaryOptions = {}
): Promise<Summary> {
const response = await this.client.post('/summarize', {
transcript_id: transcriptId,
format: options.format || 'detailed',
include_action_items: options.includeActionItems ?? true,
include_key_points: options.includeKeyPoints ?? true,
max_length: options.maxLength || 500,
});
return response.data;
}
async generateFollowUpEmail(: ): <> {
response = ..(, {
: transcriptId,
});
response..;
}
(: ): <> {
response = ..(, {
: transcriptId,
: ,
});
response..;
}
}
Step 3: Handle Speaker Identification
export interface Speaker {
id: string;
name?: string;
email?: string;
speakingTime: number;
segments: number;
}
export class SpeakerManager {
async identifySpeakers(transcript: Transcript, attendees?: string[]): Promise<Speaker[]> {
const speakers = new Map<string, Speaker>();
for (const segment of transcript.segments) {
const speakerId = segment.speaker_id || 'unknown';
const existing = speakers.get(speakerId);
if (existing) {
existing.speakingTime += segment.end - segment.start;
existing.segments += 1;
} else {
speakers.set(speakerId, {
id: speakerId,
speakingTime: segment.end - segment.,
: ,
});
}
}
(attendees && attendees. > ) {
matched = .(
.(speakers.()),
attendees
);
matched;
}
.(speakers.());
}
(: [], : []): <[]> {
client = ();
response = client.(, {
: speakers.( s.),
attendees,
});
speakers.( ({
...speaker,
: response..[idx]?.,
: response..[idx]?.,
}));
}
}
Step 4: Complete Workflow Orchestration
import { MeetingCapture } from './meeting-capture';
import { SummaryGenerator } from './summary-generation';
import { SpeakerManager } from './speaker-handling';
export interface MeetingResult {
transcriptId: string;
transcript: Transcript;
summary: Summary;
speakers: Speaker[];
followUpEmail?: string;
meetingNotes?: string;
}
export async function processMeeting(
audioUrl: string,
options: {
title?: string;
attendees?: string[];
generateEmail?: boolean;
generateNotes?: boolean;
} = {}
): Promise<MeetingResult> {
const capture = new MeetingCapture();
const summaryGen = new SummaryGenerator();
const speakerMgr = new SpeakerManager();
.();
transcript = capture.(audioUrl, {
: options.,
: ,
});
.();
.();
[summary, speakers] = .([
summaryGen.(transcript., {
: ,
: ,
: ,
}),
speakerMgr.(transcript, options.),
]);
: = {
: transcript.,
transcript,
summary,
speakers,
};
(options.) {
result. = summaryGen.(transcript.);
}
(options.) {
result. = summaryGen.(transcript.);
}
result;
}
() {
result = (
,
{
: ,
: [, ],
: ,
: ,
}
);
.();
.();
.();
.();
}
Output
- Complete meeting transcript with timestamps
- Speaker-labeled segments
- AI-generated summary
- Extracted action items with assignees
- Optional follow-up email draft
- Optional formatted meeting notes
Example console output:
Starting transcription...
Transcription complete: tr_abc123
Generating summary and identifying speakers...
Meeting processed successfully!
Summary: Daily standup covering sprint progress and blockers...
Action Items: 3
Speakers: Alice, Bob, Charlie
Error Handling
| Error | Cause | Solution |
|---|
| Transcription timeout | Large audio file | Increase maxWaitMs or use async callback |
| Speaker match failed | No calendar data | Provide attendees list manually |
| Summary generation failed | Transcript too short | Ensure minimum 30s of audio |
| Audio format unsupported | Wrong codec | Convert to MP3/WAV/M4A |
| Rate limit exceeded | Too many requests | Implement queue-based processing |
Audio Format Support
| Format | Extension | Supported | Notes |
|---|
| MP3 | .mp3 | Yes | Recommended |
| WAV | .wav | Yes | Best quality |
| M4A | .m4a | Yes | iOS recordings |
| WebM | .webm | Yes | Browser recordings |
| OGG | .ogg | Yes | Open format |
| FLAC | .flac | Yes | Lossless |
Resources
Next Steps
For action item extraction and follow-up automation, see twinmind-core-workflow-b.