home / skills / jeremylongshore / claude-code-plugins-plus-skills / twinmind-local-dev-loop

This skill helps set up a productive local TwinMind development loop for API integration, testing calls, and building meeting automation.

npx playbooks add skill jeremylongshore/claude-code-plugins-plus-skills --skill twinmind-local-dev-loop

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.7 KB
---
name: twinmind-local-dev-loop
description: |
  Set up local development workflow with TwinMind API integration.
  Use when building applications that integrate TwinMind transcription,
  testing API calls locally, or developing meeting automation tools.
  Trigger with phrases like "twinmind dev setup", "twinmind local development",
  "twinmind API testing", "build with twinmind".
allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(pip:*), Bash(curl:*)
version: 1.0.0
license: MIT
author: Jeremy Longshore <[email protected]>
---

# TwinMind Local Dev Loop

## Overview
Configure a productive local development environment for TwinMind API integration.

## Prerequisites
- TwinMind Pro or Enterprise account (API access)
- Node.js 18+ or Python 3.10+
- API key from TwinMind dashboard
- Local development environment

## Instructions

### Step 1: Project Setup

```bash
# Create project directory
mkdir twinmind-integration && cd twinmind-integration

# Initialize Node.js project
npm init -y

# Install dependencies
npm install dotenv axios zod typescript ts-node @types/node

# Initialize TypeScript
npx tsc --init
```

### Step 2: Configure Environment

```bash
# Create environment file
cat > .env << 'EOF'
TWINMIND_API_KEY=your-api-key-here
TWINMIND_API_URL=https://api.twinmind.com/v1
TWINMIND_WEBHOOK_SECRET=your-webhook-secret
NODE_ENV=development
EOF

# Add to .gitignore
echo ".env" >> .gitignore
echo "node_modules" >> .gitignore
```

### Step 3: Create TwinMind Client

```typescript
// src/twinmind/client.ts
import axios, { AxiosInstance } from 'axios';
import { z } from 'zod';

// Response schemas
const TranscriptSchema = z.object({
  id: z.string(),
  text: z.string(),
  duration_seconds: z.number(),
  language: z.string(),
  speakers: z.array(z.object({
    id: z.string(),
    name: z.string().optional(),
    segments: z.array(z.object({
      start: z.number(),
      end: z.number(),
      text: z.string(),
      confidence: z.number(),
    })),
  })),
  created_at: z.string(),
});

const SummarySchema = z.object({
  id: z.string(),
  transcript_id: z.string(),
  summary: z.string(),
  action_items: z.array(z.object({
    text: z.string(),
    assignee: z.string().optional(),
    due_date: z.string().optional(),
  })),
  key_points: z.array(z.string()),
});

export type Transcript = z.infer<typeof TranscriptSchema>;
export type Summary = z.infer<typeof SummarySchema>;

export class TwinMindClient {
  private client: AxiosInstance;

  constructor(apiKey: string, baseUrl?: string) {
    this.client = axios.create({
      baseURL: baseUrl || 'https://api.twinmind.com/v1',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
      },
      timeout: 30000,
    });
  }

  async healthCheck(): Promise<boolean> {
    const response = await this.client.get('/health');
    return response.status === 200;
  }

  async transcribe(audioUrl: string, options?: {
    language?: string;
    diarization?: boolean;
    model?: 'ear-3' | 'ear-2';
  }): Promise<Transcript> {
    const response = await this.client.post('/transcribe', {
      audio_url: audioUrl,
      language: options?.language || 'auto',
      diarization: options?.diarization ?? true,
      model: options?.model || 'ear-3',
    });
    return TranscriptSchema.parse(response.data);
  }

  async summarize(transcriptId: string): Promise<Summary> {
    const response = await this.client.post('/summarize', {
      transcript_id: transcriptId,
    });
    return SummarySchema.parse(response.data);
  }

  async search(query: string, options?: {
    limit?: number;
    date_from?: string;
    date_to?: string;
  }): Promise<Transcript[]> {
    const response = await this.client.get('/search', {
      params: {
        q: query,
        limit: options?.limit || 10,
        date_from: options?.date_from,
        date_to: options?.date_to,
      },
    });
    return z.array(TranscriptSchema).parse(response.data.results);
  }
}
```

### Step 4: Create Dev Runner Script

```typescript
// src/dev.ts
import 'dotenv/config';
import { TwinMindClient } from './twinmind/client';

async function main() {
  const client = new TwinMindClient(process.env.TWINMIND_API_KEY!);

  // Health check
  console.log('Checking TwinMind API health...');
  const healthy = await client.healthCheck();
  console.log(`API Status: ${healthy ? 'Healthy' : 'Unhealthy'}`);

  // Example: Transcribe audio file
  // const transcript = await client.transcribe('https://example.com/meeting.mp3');
  // console.log('Transcript:', transcript);

  // Example: Generate summary
  // const summary = await client.summarize(transcript.id);
  // console.log('Summary:', summary);

  // Example: Search memory vault
  // const results = await client.search('budget review');
  // console.log('Search results:', results);
}

main().catch(console.error);
```

### Step 5: Configure Dev Scripts

```json
// package.json scripts
{
  "scripts": {
    "dev": "ts-node src/dev.ts",
    "build": "tsc",
    "test": "jest",
    "lint": "eslint src/**/*.ts",
    "typecheck": "tsc --noEmit"
  }
}
```

### Step 6: Create Test Fixtures

```typescript
// tests/fixtures/mock-responses.ts
export const mockTranscript = {
  id: 'tr_test_123',
  text: 'Welcome to the meeting. Today we discuss the project timeline.',
  duration_seconds: 45,
  language: 'en',
  speakers: [
    {
      id: 'spk_1',
      name: 'Host',
      segments: [
        {
          start: 0,
          end: 5.2,
          text: 'Welcome to the meeting.',
          confidence: 0.97,
        },
        {
          start: 5.5,
          end: 12.1,
          text: 'Today we discuss the project timeline.',
          confidence: 0.95,
        },
      ],
    },
  ],
  created_at: '2025-01-15T10:00:00Z',
};

export const mockSummary = {
  id: 'sum_test_456',
  transcript_id: 'tr_test_123',
  summary: 'Brief meeting to discuss project timeline and milestones.',
  action_items: [
    {
      text: 'Review timeline document',
      assignee: 'John',
      due_date: '2025-01-20',
    },
  ],
  key_points: [
    'Project kickoff confirmed',
    'Timeline review scheduled',
  ],
};
```

### Step 7: Run Development Loop

```bash
# Start development
npm run dev

# Watch mode (requires nodemon)
npm install -D nodemon
npx nodemon --exec ts-node src/dev.ts

# Run with debug logging
DEBUG=twinmind:* npm run dev
```

## Output
- Project structure with TypeScript configuration
- TwinMind client with type-safe schemas
- Environment configuration
- Development scripts
- Test fixtures for offline development

## Error Handling

| Error | Cause | Solution |
|-------|-------|----------|
| API key missing | .env not loaded | Check dotenv import |
| Connection refused | Wrong API URL | Verify TWINMIND_API_URL |
| Rate limited | Too many requests | Add delay between calls |
| Schema validation failed | API response changed | Update Zod schemas |
| Timeout | Large audio file | Increase timeout value |

## Project Structure

```
twinmind-integration/
├── src/
│   ├── twinmind/
│   │   ├── client.ts       # API client
│   │   ├── types.ts        # TypeScript types
│   │   └── errors.ts       # Error classes
│   ├── services/
│   │   └── meeting.ts      # Business logic
│   └── dev.ts              # Development entry
├── tests/
│   ├── fixtures/
│   │   └── mock-responses.ts
│   └── twinmind.test.ts
├── .env                    # Environment (gitignored)
├── .env.example            # Template
├── package.json
└── tsconfig.json
```

## Resources
- [TwinMind API Documentation](https://twinmind.com/docs/api)
- [Ear-3 Model Specification](https://twinmind.com/ear-3)
- [Zod Documentation](https://zod.dev/)

## Next Steps
Apply patterns in `twinmind-sdk-patterns` for production-ready code.

Overview

This skill sets up a reproducible local development loop for integrating the TwinMind transcription API into applications. It provides a TypeScript client, environment configuration, dev runner, test fixtures, and scripts to run and iterate quickly. The goal is to make building, testing, and debugging TwinMind-powered meeting automation and transcription features fast and safe locally.

How this skill works

The skill scaffolds a small TypeScript project, installs runtime and dev dependencies, and creates a TwinMind client wrapper with Zod schemas for type-safe responses. It reads credentials from a .env file, exposes health check, transcribe, summarize, and search methods, and includes a dev script to run sample flows. Mock fixtures and test scripts let you run the loop offline and validate behavior before hitting the real API.

When to use it

  • Building or prototyping meeting transcription and summary features
  • Testing TwinMind API calls locally without shipping secrets
  • Creating meeting automation that uses transcripts, summaries, and action items
  • Setting up CI-friendly type-safe integration tests
  • Developing voice-enabled features that need diarization or search over transcripts

Best practices

  • Store API keys in .env and add that file to .gitignore; use .env.example for templates
  • Validate API responses with Zod schemas and update schemas when the API changes
  • Use mock fixtures for unit tests to avoid hitting rate limits or incurring costs
  • Run health checks and implement exponential backoff for rate-limited endpoints
  • Keep long-running uploads or large audio handling off the main request thread and increase timeouts when necessary

Example use cases

  • Prototype a meeting recap tool that transcribes calls and generates action items
  • Run local tests for a memory vault search across past transcripts
  • Integrate diarized transcripts into a CRM to tag speakers and assign follow-ups
  • Build a scheduled job that summarizes daily meetings and posts summaries to Slack
  • Develop a customer support QA flow that searches past call transcripts for keywords

FAQ

What do I need before starting?

A TwinMind Pro/Enterprise account with an API key, Node.js 18+ or Python 3.10+, and a local dev environment.

How do I avoid leaking my API key?

Keep keys in .env, add .env to .gitignore, and use environment variables or secrets manager in CI and production.

Can I run the loop without network access?

Yes — use the included mock fixtures and unit tests to simulate transcripts and summaries offline.