[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F99RW2FQ91W2M9MSVB4SAB":3,"skill-same:01M6F99RW2FQ91W2M9MSVB4SAB":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":51,"commitSha":52,"skillDirectory":53,"forksCount":54,"repositoryHtmlUrl":55,"repositoryHomepageUrl":6,"ownerHtmlUrl":56,"ownerBlogUrl":57,"ownerDescription":58,"updatedAt":59,"install":60,"resources":73},"01M6F99RW2FQ91W2M9MSVB4SAB","speak-reference-architecture",null,"Implement Speak reference architecture with best-practice project layout for language learning apps.\nUse when designing new Speak integrations, reviewing project structure,\nor establishing architecture standards for language learning applications.\nTrigger with phrases like \"speak architecture\", \"speak best practices\",\n\"speak project structure\", \"how to organize speak\", \"speak layout\".","Dicklesworthstone\u002Fpi_agent_rust","Dicklesworthstone","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F35050222?v=4","01M6CG26AR942CSVMN1M5E3DSE","Jeff Emanuel","01M6CG26EPP71PSHW1VDS71121",1979,"MIT","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fspeak-pack\u002Fskills\u002Fspeak-reference-architecture\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"architecture","speak reference architecture","speak","reference","new","project structure","when","for","how to","apps","trigger","io","layout","project","structure","organize","language learning","standards","read","integrations","learning","how","applications","2026-11-10 10:12:30",false,"---\nname: speak-reference-architecture\ndescription: |\n  Implement Speak reference architecture with best-practice project layout for language learning apps.\n  Use when designing new Speak integrations, reviewing project structure,\n  or establishing architecture standards for language learning applications.\n  Trigger with phrases like \"speak architecture\", \"speak best practices\",\n  \"speak project structure\", \"how to organize speak\", \"speak layout\".\nallowed-tools: Read, Grep\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\n---\n\n# Speak Reference Architecture\n\n## Overview\nProduction-ready architecture patterns for Speak language learning integrations.\n\n## Prerequisites\n- Understanding of layered architecture\n- Speak SDK knowledge\n- TypeScript project setup\n- Testing framework configured\n\n## Project Structure\n\n```\nmy-speak-app\u002F\n├── src\u002F\n│   ├── speak\u002F\n│   │   ├── client.ts           # Singleton client wrapper\n│   │   ├── config.ts           # Environment configuration\n│   │   ├── types.ts            # TypeScript types\n│   │   ├── errors.ts           # Custom error classes\n│   │   └── handlers\u002F\n│   │       ├── webhooks.ts     # Webhook handlers\n│   │       └── events.ts       # Event processing\n│   ├── lessons\u002F\n│   │   ├── session.ts          # Session management\n│   │   ├── conversation.ts     # Conversation practice\n│   │   ├── pronunciation.ts    # Pronunciation training\n│   │   └── vocabulary.ts       # Vocabulary exercises\n│   ├── speech\u002F\n│   │   ├── recognizer.ts       # Speech recognition wrapper\n│   │   ├── scorer.ts           # Pronunciation scoring\n│   │   └── audio.ts            # Audio processing utilities\n│   ├── progress\u002F\n│   │   ├── tracker.ts          # Progress tracking\n│   │   ├── streaks.ts          # Streak management\n│   │   └── achievements.ts     # Gamification\n│   ├── services\u002F\n│   │   └── speak\u002F\n│   │       ├── index.ts        # Service facade\n│   │       ├── sync.ts         # Data synchronization\n│   │       └── cache.ts        # Caching layer\n│   ├── api\u002F\n│   │   └── speak\u002F\n│   │       ├── lessons.ts      # Lesson endpoints\n│   │       ├── progress.ts     # Progress endpoints\n│   │       └── webhook.ts      # Webhook endpoint\n│   └── jobs\u002F\n│       └── speak\u002F\n│           ├── sync.ts         # Background sync job\n│           └── notifications.ts # Reminder notifications\n├── tests\u002F\n│   ├── unit\u002F\n│   │   └── speak\u002F\n│   ├── integration\u002F\n│   │   └── speak\u002F\n│   └── fixtures\u002F\n│       └── audio\u002F              # Test audio files\n├── config\u002F\n│   ├── speak.development.json\n│   ├── speak.staging.json\n│   └── speak.production.json\n└── docs\u002F\n    └── speak\u002F\n        ├── SETUP.md\n        └── RUNBOOK.md\n```\n\n## Layer Architecture\n\n```\n┌─────────────────────────────────────────┐\n│             API Layer                    │\n│   (Controllers, Routes, Webhooks)        │\n├─────────────────────────────────────────┤\n│           Lesson Layer                   │\n│  (Conversation, Pronunciation, Vocab)    │\n├─────────────────────────────────────────┤\n│          Speech Layer                    │\n│   (Recognition, Scoring, Audio)          │\n├─────────────────────────────────────────┤\n│          Speak SDK Layer                 │\n│   (Client, Types, Error Handling)        │\n├─────────────────────────────────────────┤\n│         Infrastructure Layer             │\n│    (Cache, Queue, Storage, Monitoring)   │\n└─────────────────────────────────────────┘\n```\n\n## Key Components\n\n### Step 1: Client Wrapper\n```typescript\n\u002F\u002F src\u002Fspeak\u002Fclient.ts\nimport { SpeakClient as SDKClient } from '@speak\u002Flanguage-sdk';\n\nexport class SpeakService {\n  private client: SDKClient;\n  private cache: Cache;\n  private monitor: Monitor;\n\n  constructor(config: SpeakConfig) {\n    this.client = new SDKClient({\n      apiKey: config.apiKey,\n      appId: config.appId,\n    });\n    this.cache = new Cache(config.cacheOptions);\n    this.monitor = new Monitor('speak');\n  }\n\n  get tutor() {\n    return {\n      startSession: (config: SessionConfig) =>\n        this.monitor.track('tutor.startSession', () =>\n          this.client.tutor.startSession(config)\n        ),\n      getPrompt: (sessionId: string) =>\n        this.monitor.track('tutor.getPrompt', () =>\n          this.client.tutor.getPrompt(sessionId)\n        ),\n    };\n  }\n\n  get speech() {\n    return {\n      recognize: (audio: ArrayBuffer) =>\n        this.monitor.track('speech.recognize', () =>\n          this.client.speech.recognize(audio)\n        ),\n      score: (audio: ArrayBuffer, text: string) =>\n        this.monitor.track('speech.score', () =>\n          this.client.speech.score({ audio, expectedText: text })\n        ),\n    };\n  }\n\n  get vocabulary() {\n    return {\n      lookup: (word: string, language: string) =>\n        this.cache.getOrFetch(`vocab:${language}:${word}`, () =>\n          this.client.vocabulary.lookup(word, language)\n        ),\n    };\n  }\n}\n```\n\n### Step 2: Error Boundary\n```typescript\n\u002F\u002F src\u002Fspeak\u002Ferrors.ts\nexport class SpeakServiceError extends Error {\n  constructor(\n    message: string,\n    public readonly code: string,\n    public readonly retryable: boolean,\n    public readonly originalError?: Error\n  ) {\n    super(message);\n    this.name = 'SpeakServiceError';\n  }\n\n  static fromSDKError(error: unknown): SpeakServiceError {\n    if (error instanceof RateLimitError) {\n      return new SpeakServiceError(\n        'Rate limit exceeded',\n        'RATE_LIMITED',\n        true,\n        error\n      );\n    }\n    if (error instanceof AuthError) {\n      return new SpeakServiceError(\n        'Authentication failed',\n        'AUTH_ERROR',\n        false,\n        error\n      );\n    }\n    if (error instanceof AudioError) {\n      return new SpeakServiceError(\n        'Audio processing failed',\n        'AUDIO_ERROR',\n        true,\n        error\n      );\n    }\n    return new SpeakServiceError(\n      error instanceof Error ? error.message : 'Unknown error',\n      'UNKNOWN',\n      true\n    );\n  }\n}\n```\n\n### Step 3: Lesson Session Manager\n```typescript\n\u002F\u002F src\u002Flessons\u002Fsession.ts\ninterface ActiveSession {\n  id: string;\n  userId: string;\n  language: string;\n  topic: string;\n  startedAt: Date;\n  exchanges: number;\n}\n\nexport class LessonSessionManager {\n  private sessions: Map\u003Cstring, ActiveSession> = new Map();\n  private speakService: SpeakService;\n\n  constructor(speakService: SpeakService) {\n    this.speakService = speakService;\n  }\n\n  async startSession(userId: string, config: LessonConfig): Promise\u003CSession> {\n    \u002F\u002F End existing session if any\n    await this.endSession(userId);\n\n    const session = await this.speakService.tutor.startSession({\n      language: config.language,\n      topic: config.topic,\n      difficulty: config.difficulty,\n    });\n\n    this.sessions.set(userId, {\n      id: session.id,\n      userId,\n      language: config.language,\n      topic: config.topic,\n      startedAt: new Date(),\n      exchanges: 0,\n    });\n\n    \u002F\u002F Track session start\n    await analytics.track('lesson_started', {\n      userId,\n      sessionId: session.id,\n      ...config,\n    });\n\n    return session;\n  }\n\n  getActiveSession(userId: string): ActiveSession | null {\n    return this.sessions.get(userId) || null;\n  }\n\n  async endSession(userId: string): Promise\u003CSessionSummary | null> {\n    const active = this.sessions.get(userId);\n    if (!active) return null;\n\n    const summary = await this.speakService.tutor.endSession(active.id);\n    this.sessions.delete(userId);\n\n    \u002F\u002F Track session end\n    await analytics.track('lesson_completed', {\n      userId,\n      sessionId: active.id,\n      duration: Date.now() - active.startedAt.getTime(),\n      exchanges: active.exchanges,\n    });\n\n    return summary;\n  }\n}\n```\n\n### Step 4: Health Check\n```typescript\n\u002F\u002F src\u002Fspeak\u002Fhealth.ts\ninterface SpeakHealthStatus {\n  status: 'healthy' | 'degraded' | 'unhealthy';\n  latencyMs: number;\n  services: {\n    api: boolean;\n    speech: boolean;\n    tutor: boolean;\n  };\n}\n\nexport async function checkSpeakHealth(): Promise\u003CSpeakHealthStatus> {\n  const start = Date.now();\n  const services = { api: false, speech: false, tutor: false };\n\n  try {\n    \u002F\u002F Check API\n    await speakService.health.check();\n    services.api = true;\n\n    \u002F\u002F Check speech recognition (with minimal audio)\n    services.speech = await testSpeechRecognition();\n\n    \u002F\u002F Check tutor availability\n    services.tutor = await testTutorAvailability();\n\n    return {\n      status: Object.values(services).every(Boolean) ? 'healthy' : 'degraded',\n      latencyMs: Date.now() - start,\n      services,\n    };\n  } catch (error) {\n    return {\n      status: 'unhealthy',\n      latencyMs: Date.now() - start,\n      services,\n    };\n  }\n}\n```\n\n## Data Flow Diagram\n\n```\nUser Interaction\n     │\n     ▼\n┌─────────────┐\n│   Web\u002FApp   │\n│   Client    │\n└──────┬──────┘\n       │ Audio + Text\n       ▼\n┌─────────────┐    ┌─────────────┐\n│   API       │───▶│   Cache     │\n│   Gateway   │    │   (Redis)   │\n└──────┬──────┘    └─────────────┘\n       │\n       ▼\n┌─────────────┐    ┌─────────────┐\n│   Lesson    │───▶│   Audio     │\n│   Service   │    │   Storage   │\n└──────┬──────┘    └─────────────┘\n       │\n       ▼\n┌─────────────┐\n│   Speak     │\n│   SDK       │\n└──────┬──────┘\n       │\n       ▼\n┌─────────────┐\n│   Speak     │\n│   API       │\n└─────────────┘\n```\n\n## Configuration Management\n\n```typescript\n\u002F\u002F config\u002Fspeak.ts\nexport interface SpeakConfig {\n  apiKey: string;\n  appId: string;\n  environment: 'development' | 'staging' | 'production';\n  defaultLanguage: string;\n  supportedLanguages: string[];\n  cache: {\n    enabled: boolean;\n    ttlSeconds: number;\n  };\n  audio: {\n    maxDuration: number;\n    format: 'wav' | 'mp3';\n    sampleRate: number;\n  };\n}\n\nexport function loadSpeakConfig(): SpeakConfig {\n  const env = process.env.NODE_ENV || 'development';\n  const baseConfig = require('.\u002Fspeak.base.json');\n  const envConfig = require(`.\u002Fspeak.${env}.json`);\n\n  return {\n    ...baseConfig,\n    ...envConfig,\n    apiKey: process.env.SPEAK_API_KEY!,\n    appId: process.env.SPEAK_APP_ID!,\n    environment: env as SpeakConfig['environment'],\n  };\n}\n```\n\n## Output\n- Structured project layout\n- Client wrapper with caching\n- Error boundary implemented\n- Health checks configured\n- Session management\n\n## Error Handling\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Circular dependencies | Wrong layering | Separate concerns by layer |\n| Config not loading | Wrong paths | Verify config file locations |\n| Type errors | Missing types | Add Speak types |\n| Test isolation | Shared state | Use dependency injection |\n\n## Examples\n\n### Quick Setup Script\n```bash\n# Create reference structure\nmkdir -p src\u002Fspeak\u002F{handlers}\nmkdir -p src\u002Flessons src\u002Fspeech src\u002Fprogress\nmkdir -p src\u002Fservices\u002Fspeak src\u002Fapi\u002Fspeak src\u002Fjobs\u002Fspeak\nmkdir -p tests\u002F{unit,integration,fixtures}\u002Fspeak\nmkdir -p config docs\u002Fspeak\n\ntouch src\u002Fspeak\u002F{client,config,types,errors}.ts\ntouch src\u002Flessons\u002F{session,conversation,pronunciation,vocabulary}.ts\ntouch src\u002Fspeech\u002F{recognizer,scorer,audio}.ts\n```\n\n## Resources\n- [Speak SDK Documentation](https:\u002F\u002Fdeveloper.speak.com\u002Fsdk)\n- [Speak Best Practices](https:\u002F\u002Fdeveloper.speak.com\u002Fdocs\u002Fbest-practices)\n- [Clean Architecture](https:\u002F\u002Fblog.cleancoder.com\u002Funcle-bob\u002F2012\u002F08\u002F13\u002Fthe-clean-architecture.html)\n\n## Flagship Skills\nFor multi-environment setup, see `speak-multi-env-setup`.\n","# Speak Reference Architecture\n\n## Overview\nProduction-ready architecture patterns for Speak language learning integrations.\n\n## Prerequisites\n- Understanding of layered architecture\n- Speak SDK knowledge\n- TypeScript project setup\n- Testing framework configured\n\n## Project Structure\n\n```\nmy-speak-app\u002F\n├── src\u002F\n│   ├── speak\u002F\n│   │   ├── client.ts           # Singleton client wrapper\n│   │   ├── config.ts           # Environment configuration\n│   │   ├── types.ts            # TypeScript types\n│   │   ├── errors.ts           # Custom error classes\n│   │   └── handlers\u002F\n│   │       ├── webhooks.ts     # Webhook handlers\n│   │       └── events.ts       # Event processing\n│   ├── lessons\u002F\n│   │   ├── session.ts          # Session management\n│   │   ├── conversation.ts     # Conversation practice\n│   │   ├── pronunciation.ts    # Pronunciation training\n│   │   └── vocabulary.ts       # Vocabulary exercises\n│   ├── speech\u002F\n│   │   ├── recognizer.ts       # Speech recognition wrapper\n│   │   ├── scorer.ts           # Pronunciation scoring\n│   │   └── audio.ts            # Audio processing utilities\n│   ├── progress\u002F\n│   │   ├── tracker.ts          # Progress tracking\n│   │   ├── streaks.ts          # Streak management\n│   │   └── achievements.ts     # Gamification\n│   ├── services\u002F\n│   │   └── speak\u002F\n│   │       ├── index.ts        # Service facade\n│   │       ├── sync.ts         # Data synchronization\n│   │       └── cache.ts        # Caching layer\n│   ├── api\u002F\n│   │   └── speak\u002F\n│   │       ├── lessons.ts      # Lesson endpoints\n│   │       ├── progress.ts     # Progress endpoints\n│   │       └── webhook.ts      # Webhook endpoint\n│   └── jobs\u002F\n│       └── speak\u002F\n│           ├── sync.ts         # Background sync job\n│           └── notifications.ts # Reminder notifications\n├── tests\u002F\n│   ├── unit\u002F\n│   │   └── speak\u002F\n│   ├── integration\u002F\n│   │   └── speak\u002F\n│   └── fixtures\u002F\n│       └── audio\u002F              # Test audio files\n├── config\u002F\n│   ├── speak.development.json\n│   ├── speak.staging.json\n│   └── speak.production.json\n└── docs\u002F\n    └── speak\u002F\n        ├── SETUP.md\n        └── RUNBOOK.md\n```\n\n## Layer Architecture\n\n```\n┌─────────────────────────────────────────┐\n│             API Layer                    │\n│   (Controllers, Routes, Webhooks)        │\n├─────────────────────────────────────────┤\n│           Lesson Layer                   │\n│  (Conversation, Pronunciation, Vocab)    │\n├─────────────────────────────────────────┤\n│          Speech Layer                    │\n│   (Recognition, Scoring, Audio)          │\n├─────────────────────────────────────────┤\n│          Speak SDK Layer                 │\n│   (Client, Types, Error Handling)        │\n├─────────────────────────────────────────┤\n│         Infrastructure Layer             │\n│    (Cache, Queue, Storage, Monitoring)   │\n└─────────────────────────────────────────┘\n```\n\n## Key Components\n\n### Step 1: Client Wrapper\n```typescript\n\u002F\u002F src\u002Fspeak\u002Fclient.ts\nimport { SpeakClient as SDKClient } from '@speak\u002Flanguage-sdk';\n\nexport class SpeakService {\n  private client: SDKClient;\n  private cache: Cache;\n  private monitor: Monitor;\n\n  constructor(config: SpeakConfig) {\n    this.client = new SDKClient({\n      apiKey: config.apiKey,\n      appId: config.appId,\n    });\n    this.cache = new Cache(config.cacheOptions);\n    this.monitor = new Monitor('speak');\n  }\n\n  get tutor() {\n    return {\n      startSession: (config: SessionConfig) =>\n        this.monitor.track('tutor.startSession', () =>\n          this.client.tutor.startSession(config)\n        ),\n      getPrompt: (sessionId: string) =>\n        this.monitor.track('tutor.getPrompt', () =>\n          this.client.tutor.getPrompt(sessionId)\n        ),\n    };\n  }\n\n  get speech() {\n    return {\n      recognize: (audio: ArrayBuffer) =>\n        this.monitor.track('speech.recognize', () =>\n          this.client.speech.recognize(audio)\n        ),\n      score: (audio: ArrayBuffer, text: string) =>\n        this.monitor.track('speech.score', () =>\n          this.client.speech.score({ audio, expectedText: text })\n        ),\n    };\n  }\n\n  get vocabulary() {\n    return {\n      lookup: (word: string, language: string) =>\n        this.cache.getOrFetch(`vocab:${language}:${word}`, () =>\n          this.client.vocabulary.lookup(word, language)\n        ),\n    };\n  }\n}\n```\n\n### Step 2: Error Boundary\n```typescript\n\u002F\u002F src\u002Fspeak\u002Ferrors.ts\nexport class SpeakServiceError extends Error {\n  constructor(\n    message: string,\n    public readonly code: string,\n    public readonly retryable: boolean,\n    public readonly originalError?: Error\n  ) {\n    super(message);\n    this.name = 'SpeakServiceError';\n  }\n\n  static fromSDKError(error: unknown): SpeakServiceError {\n    if (error instanceof RateLimitError) {\n      return new SpeakServiceError(\n        'Rate limit exceeded',\n        'RATE_LIMITED',\n        true,\n        error\n      );\n    }\n    if (error instanceof AuthError) {\n      return new SpeakServiceError(\n        'Authentication failed',\n        'AUTH_ERROR',\n        false,\n        error\n      );\n    }\n    if (error instanceof AudioError) {\n      return new SpeakServiceError(\n        'Audio processing failed',\n        'AUDIO_ERROR',\n        true,\n        error\n      );\n    }\n    return new SpeakServiceError(\n      error instanceof Error ? error.message : 'Unknown error',\n      'UNKNOWN',\n      true\n    );\n  }\n}\n```\n\n### Step 3: Lesson Session Manager\n```typescript\n\u002F\u002F src\u002Flessons\u002Fsession.ts\ninterface ActiveSession {\n  id: string;\n  userId: string;\n  language: string;\n  topic: string;\n  startedAt: Date;\n  exchanges: number;\n}\n\nexport class LessonSessionManager {\n  private sessions: Map\u003Cstring, ActiveSession> = new Map();\n  private speakService: SpeakService;\n\n  constructor(speakService: SpeakService) {\n    this.speakService = speakService;\n  }\n\n  async startSession(userId: string, config: LessonConfig): Promise\u003CSession> {\n    \u002F\u002F End existing session if any\n    await this.endSession(userId);\n\n    const session = await this.speakService.tutor.startSession({\n      language: config.language,\n      topic: config.topic,\n      difficulty: config.difficulty,\n    });\n\n    this.sessions.set(userId, {\n      id: session.id,\n      userId,\n      language: config.language,\n      topic: config.topic,\n      startedAt: new Date(),\n      exchanges: 0,\n    });\n\n    \u002F\u002F Track session start\n    await analytics.track('lesson_started', {\n      userId,\n      sessionId: session.id,\n      ...config,\n    });\n\n    return session;\n  }\n\n  getActiveSession(userId: string): ActiveSession | null {\n    return this.sessions.get(userId) || null;\n  }\n\n  async endSession(userId: string): Promise\u003CSessionSummary | null> {\n    const active = this.sessions.get(userId);\n    if (!active) return null;\n\n    const summary = await this.speakService.tutor.endSession(active.id);\n    this.sessions.delete(userId);\n\n    \u002F\u002F Track session end\n    await analytics.track('lesson_completed', {\n      userId,\n      sessionId: active.id,\n      duration: Date.now() - active.startedAt.getTime(),\n      exchanges: active.exchanges,\n    });\n\n    return summary;\n  }\n}\n```\n\n### Step 4: Health Check\n```typescript\n\u002F\u002F src\u002Fspeak\u002Fhealth.ts\ninterface SpeakHealthStatus {\n  status: 'healthy' | 'degraded' | 'unhealthy';\n  latencyMs: number;\n  services: {\n    api: boolean;\n    speech: boolean;\n    tutor: boolean;\n  };\n}\n\nexport async function checkSpeakHealth(): Promise\u003CSpeakHealthStatus> {\n  const start = Date.now();\n  const services = { api: false, speech: false, tutor: false };\n\n  try {\n    \u002F\u002F Check API\n    await speakService.health.check();\n    services.api = true;\n\n    \u002F\u002F Check speech recognition (with minimal audio)\n    services.speech = await testSpeechRecognition();\n\n    \u002F\u002F Check tutor availability\n    services.tutor = await testTutorAvailability();\n\n    return {\n      status: Object.values(services).every(Boolean) ? 'healthy' : 'degraded',\n      latencyMs: Date.now() - start,\n      services,\n    };\n  } catch (error) {\n    return {\n      status: 'unhealthy',\n      latencyMs: Date.now() - start,\n      services,\n    };\n  }\n}\n```\n\n## Data Flow Diagram\n\n```\nUser Interaction\n     │\n     ▼\n┌─────────────┐\n│   Web\u002FApp   │\n│   Client    │\n└──────┬──────┘\n       │ Audio + Text\n       ▼\n┌─────────────┐    ┌─────────────┐\n│   API       │───▶│   Cache     │\n│   Gateway   │    │   (Redis)   │\n└──────┬──────┘    └─────────────┘\n       │\n       ▼\n┌─────────────┐    ┌─────────────┐\n│   Lesson    │───▶│   Audio     │\n│   Service   │    │   Storage   │\n└──────┬──────┘    └─────────────┘\n       │\n       ▼\n┌─────────────┐\n│   Speak     │\n│   SDK       │\n└──────┬──────┘\n       │\n       ▼\n┌─────────────┐\n│   Speak     │\n│   API       │\n└─────────────┘\n```\n\n## Configuration Management\n\n```typescript\n\u002F\u002F config\u002Fspeak.ts\nexport interface SpeakConfig {\n  apiKey: string;\n  appId: string;\n  environment: 'development' | 'staging' | 'production';\n  defaultLanguage: string;\n  supportedLanguages: string[];\n  cache: {\n    enabled: boolean;\n    ttlSeconds: number;\n  };\n  audio: {\n    maxDuration: number;\n    format: 'wav' | 'mp3';\n    sampleRate: number;\n  };\n}\n\nexport function loadSpeakConfig(): SpeakConfig {\n  const env = process.env.NODE_ENV || 'development';\n  const baseConfig = require('.\u002Fspeak.base.json');\n  const envConfig = require(`.\u002Fspeak.${env}.json`);\n\n  return {\n    ...baseConfig,\n    ...envConfig,\n    apiKey: process.env.SPEAK_API_KEY!,\n    appId: process.env.SPEAK_APP_ID!,\n    environment: env as SpeakConfig['environment'],\n  };\n}\n```\n\n## Output\n- Structured project layout\n- Client wrapper with caching\n- Error boundary implemented\n- Health checks configured\n- Session management\n\n## Error Handling\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Circular dependencies | Wrong layering | Separate concerns by layer |\n| Config not loading | Wrong paths | Verify config file locations |\n| Type errors | Missing types | Add Speak types |\n| Test isolation | Shared state | Use dependency injection |\n\n## Examples\n\n### Quick Setup Script\n```bash\n# Create reference structure\nmkdir -p src\u002Fspeak\u002F{handlers}\nmkdir -p src\u002Flessons src\u002Fspeech src\u002Fprogress\nmkdir -p src\u002Fservices\u002Fspeak src\u002Fapi\u002Fspeak src\u002Fjobs\u002Fspeak\nmkdir -p tests\u002F{unit,integration,fixtures}\u002Fspeak\nmkdir -p config docs\u002Fspeak\n\ntouch src\u002Fspeak\u002F{client,config,types,errors}.ts\ntouch src\u002Flessons\u002F{session,conversation,pronunciation,vocabulary}.ts\ntouch src\u002Fspeech\u002F{recognizer,scorer,audio}.ts\n```\n\n## Resources\n- [Speak SDK Documentation](https:\u002F\u002Fdeveloper.speak.com\u002Fsdk)\n- [Speak Best Practices](https:\u002F\u002Fdeveloper.speak.com\u002Fdocs\u002Fbest-practices)\n- [Clean Architecture](https:\u002F\u002Fblog.cleancoder.com\u002Funcle-bob\u002F2012\u002F08\u002F13\u002Fthe-clean-architecture.html)\n\n## Flagship Skills\nFor multi-environment setup, see `speak-multi-env-setup`.\n",{"name":5,"author":47,"license":15,"version":48,"description":49,"allowed-tools":50},"Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Implement Speak reference architecture with best-practice project layout for language learning apps.\nUse when designing new Speak integrations, reviewing project structure,\nor establishing architecture standards for language learning applications.\nTrigger with phrases like \"speak architecture\", \"speak best practices\",\n\"speak project structure\", \"how to organize speak\", \"speak layout\".\n","Read, Grep","main","90b50ed0778745a80fd5bfb13b1843d45b9e82f7","tests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fspeak-pack\u002Fskills\u002Fspeak-reference-architecture",231,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust","https:\u002F\u002Fgithub.com\u002FDicklesworthstone","https:\u002F\u002Fwww.jeffreyemanuel.com\u002F","Building in NY","2026-11-11 01:23:40",{"source":8,"skillName":5,"commands":61,"prompt":71,"zipAvailable":72},[62,65,68],{"tool":63,"command":64},"npx","npx skills add Dicklesworthstone\u002Fpi_agent_rust --skill speak-reference-architecture",{"tool":66,"command":67},"bunx","bunx skills add Dicklesworthstone\u002Fpi_agent_rust --skill speak-reference-architecture",{"tool":69,"command":70},"pnpm","pnpm dlx skills add Dicklesworthstone\u002Fpi_agent_rust --skill speak-reference-architecture","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fspeak-pack\u002Fskills\u002Fspeak-reference-architecture\u002FSKILL.md",true,[],[75,115,139,165,190,212],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":80,"sourceHtmlUrl":81,"categories":82,"keywords":88,"publishedAt":42},"01M6FEGPPK0ZTKCCM0R3E3KS33","web-artifacts-builder","Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn\u002Fui). Use for complex artifacts requiring state management, routing, or shadcn\u002Fui components - not for simple single-file HTML\u002FJSX artifacts.","Apache-2.0","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FSKILL.md",[83],{"categoryNo":84,"categoryName":85,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,26,113,114],"web artifacts builder","web","artifacts","artifacts builder","builder","frontend","css","components","react","component","routing","state management","state","shadcn","file","ui","Tools","Tailwind","use","html","single-file","simple","ui components","multi","jsx","suite",{"skillNo":116,"name":117,"nameZh":6,"description":118,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":119,"sourceHtmlUrl":120,"categories":121,"keywords":126,"publishedAt":42},"01M6FEE9VTK1W4GY21AKREJXRG","webapp-testing","Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FSKILL.md",[122,125],{"categoryNo":123,"categoryName":124,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":84,"categoryName":85,"taxonomyType":86,"taxonomyTypeDesc":87},[127,128,129,94,130,131,90,132,133,134,104,135,41,136,137,138,26],"testing","webapp testing","webapp","screenshots","playwright","debugging","toolkit","browser","logs","behavior","local","with",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":143,"sourceHtmlUrl":144,"categories":145,"keywords":146,"publishedAt":42},"01M6FE20F7ZTQBFWKF4MPJ2SBX","neuropixels-analysis","Neuropixels neural recording analysis. Load SpikeGLX\u002FOpenEphys data, preprocess, motion correction, Kilosort4 spike sorting, quality metrics, Allen\u002FIBL curation, AI-assisted visual analysis, for Neuropixels 1.0\u002F2.0 extracellular electrophysiology. Use when working with neural recordings, spike sorting, extracellular electrophysiology, or when the user mentions Neuropixels, SpikeGLX, Open Ephys, Kilosort, quality metrics, or unit curation.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Fneuropixels-analysis\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fscientific\u002Fneuropixels-analysis\u002FSKILL.md",[],[147,148,149,150,151,152,153,154,107,155,156,157,158,159,160,161,138,162,163,164,26,25],"analysis","neuropixels analysis","spike","metrics","data","open","quality","user","recordings","Neural","motion","visual","quality metrics","unit","sorting","curation","recording","load",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":169,"sourceHtmlUrl":170,"categories":171,"keywords":175,"publishedAt":42},"01M6FDP0PDK6F1GGX395C7625Z","skill-creator","Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fskill-creator\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fskill-creator\u002FSKILL.md",[172],{"categoryNo":173,"categoryName":174,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000023","Skill与智能体开发",[176,177,178,179,180,181,182,183,38,184,185,186,187,188,138,26,189,25,23],"skill creator","creator","workflows","create","update","capabilities","knowledge","tool","specialized","guide","new skill","existing skill","users","Existing",{"skillNo":191,"name":192,"nameZh":6,"description":193,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":194,"sourceHtmlUrl":195,"categories":196,"keywords":198,"publishedAt":42},"01M6FDM8Y7VK7NYG9SM7QPA3PW","notebooklm","Use this skill to query your Google NotebookLM notebooks directly from Claude Code for source-grounded, citation-backed answers from Gemini. Browser automation, library management, persistent auth. Drastically reduced hallucinations through document-only responses.","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fnotebooklm\u002FLICENSE","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fnotebooklm\u002FSKILL.md",[197],{"categoryNo":173,"categoryName":174,"taxonomyType":86,"taxonomyTypeDesc":87},[192,199,200,201,202,203,204,134,205,206,107,207,208,209,210,26,211],"google","browser automation","gemini","automation","auth","code","library","management","only","document","query","Citation","source",{"skillNo":213,"name":214,"nameZh":6,"description":215,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":216,"sourceHtmlUrl":217,"categories":218,"keywords":225,"publishedAt":42},"01M6FDHPXE10J3XGTCH5HBHS1M","slack-gif-creator","Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like \"make me a GIF of X doing Y for Slack.\"","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fenterprise-communication\u002Fslack-gif-creator\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Ftemplates-davila7\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fenterprise-communication\u002Fslack-gif-creator\u002FSKILL.md",[219,222],{"categoryNo":220,"categoryName":221,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":223,"categoryName":224,"taxonomyType":86,"taxonomyTypeDesc":87},"01JBSEEDCAT000000000000016","图像与多媒体",[226,227,228,177,229,105,230,231,182,107,232,188,233,234,235,26,236,25],"slack gif creator","slack","gif","validation","constraints","Animation","me","make","Utilities","concepts","request"]