Skillshub deepgram-multi-env-setup
install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/jeremylongshore/claude-code-plugins-plus-skills/deepgram-multi-env-setup" ~/.claude/skills/comeonoliver-skillshub-deepgram-multi-env-setup && rm -rf "$T"
manifest:
skills/jeremylongshore/claude-code-plugins-plus-skills/deepgram-multi-env-setup/SKILL.mdsource content
Deepgram Multi-Environment Setup
Overview
Configure isolated Deepgram environments for development, staging, and production. Each environment uses a separate Deepgram project, scoped API keys, environment-specific model selection, and validated configuration. Includes typed config, client factory, Docker Compose profiles, and Kubernetes overlays.
Environment Strategy
| Setting | Development | Staging | Production |
|---|---|---|---|
| Model | (fast, cheap) | | |
| Concurrency | 5 | 20 | 100 |
| Diarization | Off | On | On |
| PII Redaction | Off | On | On |
| Callback URL | localhost:3000 | staging.example.com | api.example.com |
| Key Rotation | Manual | Monthly | 90-day auto |
Instructions
Step 1: Typed Environment Configuration
interface DeepgramEnvConfig { apiKey: string; projectId: string; model: 'base' | 'nova-2' | 'nova-3'; maxConcurrency: number; features: { diarize: boolean; smart_format: boolean; redact: string[] | false; summarize: boolean; }; callbackBaseUrl?: string; timeout: number; } function loadConfig(env: string): DeepgramEnvConfig { const configs: Record<string, DeepgramEnvConfig> = { development: { apiKey: process.env.DEEPGRAM_API_KEY_DEV!, projectId: process.env.DEEPGRAM_PROJECT_ID_DEV!, model: 'base', maxConcurrency: 5, features: { diarize: false, smart_format: true, redact: false, summarize: false, }, callbackBaseUrl: 'http://localhost:3000', timeout: 60000, }, staging: { apiKey: process.env.DEEPGRAM_API_KEY_STAGING!, projectId: process.env.DEEPGRAM_PROJECT_ID_STAGING!, model: 'nova-3', maxConcurrency: 20, features: { diarize: true, smart_format: true, redact: ['pci', 'ssn'], summarize: true, }, callbackBaseUrl: 'https://staging.example.com', timeout: 30000, }, production: { apiKey: process.env.DEEPGRAM_API_KEY_PRODUCTION!, projectId: process.env.DEEPGRAM_PROJECT_ID_PRODUCTION!, model: 'nova-3', maxConcurrency: 100, features: { diarize: true, smart_format: true, redact: ['pci', 'ssn'], summarize: true, }, callbackBaseUrl: 'https://api.example.com', timeout: 30000, }, }; const config = configs[env]; if (!config) throw new Error(`Unknown environment: ${env}. Use: development, staging, production`); if (!config.apiKey) throw new Error(`DEEPGRAM_API_KEY_${env.toUpperCase()} not set`); return config; } const env = process.env.NODE_ENV ?? 'development'; const config = loadConfig(env);
Step 2: Client Factory
import { createClient, DeepgramClient } from '@deepgram/sdk'; class DeepgramClientFactory { private static clients = new Map<string, DeepgramClient>(); static getClient(env?: string): DeepgramClient { const environment = env ?? process.env.NODE_ENV ?? 'development'; if (!this.clients.has(environment)) { const config = loadConfig(environment); this.clients.set(environment, createClient(config.apiKey)); console.log(`Deepgram client created for: ${environment} (model: ${config.model})`); } return this.clients.get(environment)!; } // Convenience: transcribe with environment defaults static async transcribe(url: string, overrides: Record<string, any> = {}) { const environment = process.env.NODE_ENV ?? 'development'; const config = loadConfig(environment); const client = this.getClient(environment); const { result, error } = await client.listen.prerecorded.transcribeUrl( { url }, { model: config.model, smart_format: config.features.smart_format, diarize: config.features.diarize, redact: config.features.redact || undefined, summarize: config.features.summarize ? 'v2' : undefined, ...overrides, } ); if (error) throw error; return result; } // Reset for key rotation static reset(env?: string) { if (env) { this.clients.delete(env); } else { this.clients.clear(); } } }
Step 3: Environment Variables Template
# .env.development DEEPGRAM_API_KEY_DEV=dev-key-here DEEPGRAM_PROJECT_ID_DEV=dev-project-id # .env.staging DEEPGRAM_API_KEY_STAGING=staging-key-here DEEPGRAM_PROJECT_ID_STAGING=staging-project-id # .env.production (use secret manager, not file) # DEEPGRAM_API_KEY_PRODUCTION=production-key-here # DEEPGRAM_PROJECT_ID_PRODUCTION=production-project-id
Step 4: Docker Compose Multi-Profile
# docker-compose.yml x-common: &common build: . restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"] interval: 30s timeout: 10s services: app-dev: <<: *common profiles: ["development"] ports: - "3000:3000" environment: - NODE_ENV=development - DEEPGRAM_API_KEY_DEV=${DEEPGRAM_API_KEY_DEV} - DEEPGRAM_PROJECT_ID_DEV=${DEEPGRAM_PROJECT_ID_DEV} app-staging: <<: *common profiles: ["staging"] ports: - "3001:3000" environment: - NODE_ENV=staging - DEEPGRAM_API_KEY_STAGING=${DEEPGRAM_API_KEY_STAGING} - DEEPGRAM_PROJECT_ID_STAGING=${DEEPGRAM_PROJECT_ID_STAGING} app-production: <<: *common profiles: ["production"] ports: - "3000:3000" environment: - NODE_ENV=production - DEEPGRAM_API_KEY_PRODUCTION=${DEEPGRAM_API_KEY_PRODUCTION} - DEEPGRAM_PROJECT_ID_PRODUCTION=${DEEPGRAM_PROJECT_ID_PRODUCTION} deploy: resources: limits: memory: 512M
# Usage: docker compose --profile development up docker compose --profile staging up docker compose --profile production up
Step 5: Kubernetes Kustomize Overlays
# k8s/base/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: deepgram-config data: DEEPGRAM_MODEL: "nova-3" DEEPGRAM_SMART_FORMAT: "true" --- # k8s/overlays/development/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization bases: - ../../base patchesStrategicMerge: - configmap-patch.yaml secretGenerator: - name: deepgram-secrets literals: - api-key=dev-key-here --- # k8s/overlays/development/configmap-patch.yaml apiVersion: v1 kind: ConfigMap metadata: name: deepgram-config data: DEEPGRAM_MODEL: "base" DEEPGRAM_MAX_CONCURRENCY: "5"
Step 6: Environment Validation
async function validateEnvironments() { const envs = ['development', 'staging', 'production']; const results: Record<string, { valid: boolean; error?: string }> = {}; for (const env of envs) { try { const config = loadConfig(env); const client = createClient(config.apiKey); // Test 1: Key validity const { error: authError } = await client.manage.getProjects(); if (authError) throw new Error(`Auth failed: ${authError.message}`); // Test 2: Project access const { error: projError } = await client.manage.getProject(config.projectId); if (projError) throw new Error(`Project access failed: ${projError.message}`); // Test 3: Transcription works const { error: sttError } = await client.listen.prerecorded.transcribeUrl( { url: 'https://static.deepgram.com/examples/Bueller-Life-moves-702702706.wav' }, { model: config.model, smart_format: true } ); if (sttError) throw new Error(`STT failed: ${sttError.message}`); results[env] = { valid: true }; console.log(`[PASS] ${env}`); } catch (err: any) { results[env] = { valid: false, error: err.message }; console.log(`[FAIL] ${env}: ${err.message}`); } } const allValid = Object.values(results).every(r => r.valid); console.log(`\nValidation: ${allValid ? 'ALL PASS' : 'FAILURES DETECTED'}`); return results; }
Output
- Typed environment configuration (dev/staging/prod)
- Singleton client factory per environment
- Docker Compose multi-profile setup
- Kubernetes Kustomize overlays
- Environment validation script
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Missing env var | Set in |
| Wrong model in staging | Config mismatch | Check mapping |
| Cross-env key used | Shared key | Create separate projects per environment |
| Validation fails for one env | Key expired | Rotate key for that environment |