speak-multi-env-setup
Configure Speak across development, staging, and production environments. Use when setting up multi-environment deployments, configuring per-environment secrets, or implementing environment-specific Speak configurations. Trigger with phrases like "speak environments", "speak staging", "speak dev prod", "speak environment setup", "speak config by env". allowed-tools: Read, Write, Edit, Bash(aws:*), Bash(gcloud:*), Bash(vault:*) version: 1.0.0 license: MIT author: Jeremy Longshore <jeremy@intentsolutions.io>
Allowed Tools
No tools specified
Provided by Plugin
speak-pack
Claude Code skill pack for Speak AI Language Learning Platform (24 skills)
Installation
This skill is included in the speak-pack plugin:
/plugin install speak-pack@claude-code-plugins-plus
Click to copy
Instructions
# Speak Multi-Environment Setup
## Overview
Configure Speak across development, staging, and production environments for language learning applications.
## Prerequisites
- Separate Speak accounts or API keys per environment
- Secret management solution (Vault, AWS Secrets Manager, etc.)
- CI/CD pipeline with environment variables
- Environment detection in application
## Environment Strategy
| Environment | Purpose | API Keys | Data | Languages |
|-------------|---------|----------|------|-----------|
| Development | Local dev | Sandbox keys | Mock/test | All enabled |
| Staging | Pre-prod validation | Staging keys | Test data | All enabled |
| Production | Live users | Production keys | Real data | Enabled per plan |
## Configuration Structure
```
config/
โโโ speak/
โ โโโ base.json # Shared config
โ โโโ development.json # Dev overrides
โ โโโ staging.json # Staging overrides
โ โโโ production.json # Prod overrides
```
### base.json
```json
{
"timeout": 30000,
"retries": 3,
"cache": {
"enabled": true,
"ttlSeconds": 300
},
"audio": {
"maxDuration": 60,
"format": "wav",
"sampleRate": 16000
},
"supportedLanguages": ["en", "es", "fr", "de", "ko", "ja", "zh-CN", "pt-BR"]
}
```
### development.json
```json
{
"baseUrl": "https://api-sandbox.speak.com",
"debug": true,
"cache": {
"enabled": false
},
"mockMode": true,
"features": {
"experimentalTutor": true,
"betaSpeechEngine": true,
"allLanguages": true
}
}
```
### staging.json
```json
{
"baseUrl": "https://api-staging.speak.com",
"debug": false,
"features": {
"experimentalTutor": true,
"betaSpeechEngine": false,
"allLanguages": true
},
"rateLimits": {
"lessonsPerHour": 100,
"audioMinutesPerHour": 60
}
}
```
### production.json
```json
{
"baseUrl": "https://api.speak.com",
"debug": false,
"retries": 5,
"features": {
"experimentalTutor": false,
"betaSpeechEngine": false,
"allLanguages": false
},
"rateLimits": {
"lessonsPerHour": 1000,
"audioMinutesPerHour": 500
}
}
```
## Environment Detection
```typescript
// src/speak/config.ts
import baseConfig from '../../config/speak/base.json';
type Environment = 'development' | 'staging' | 'production';
function detectEnvironment(): Environment {
// Check multiple sources for environment
const env = process.env.SPEAK_ENV ||
process.env.NODE_ENV ||
'development';
const validEnvs: Environment[] = ['development', 'staging', 'production'];
return validEnvs.includes(env as Environment)
? (env as Environment)
: 'development';
}
export function getSpeakConfig(): SpeakConfig {
const env = detectEnvironment();
const envConfig = require(`../../config/speak/${env}.json`);
return {
...baseConfig,
...envConfig,
apiKey: process.env.SPEAK_API_KEY!,
appId: process.env.SPEAK_APP_ID!,
webhookSecret: process.env.SPEAK_WEBHOOK_SECRET,
environment: env,
};
}
```
## Secret Management by Environment
### Local Development
```bash
# .env.local (git-ignored)
SPEAK_ENV=development
SPEAK_API_KEY=sk_sandbox_***
SPEAK_APP_ID=app_dev_***
SPEAK_MOCK_MODE=true
```
### CI/CD (GitHub Actions)
```yaml
jobs:
deploy:
environment: ${{ matrix.environment }}
env:
SPEAK_ENV: ${{ matrix.environment }}
SPEAK_API_KEY: ${{ secrets[format('SPEAK_API_KEY_{0}', matrix.environment)] }}
SPEAK_APP_ID: ${{ secrets[format('SPEAK_APP_ID_{0}', matrix.environment)] }}
strategy:
matrix:
environment: [staging, production]
```
### Production (Vault/Secrets Manager)
```bash
# AWS Secrets Manager
aws secretsmanager get-secret-value \
--secret-id speak/production/credentials
# GCP Secret Manager
gcloud secrets versions access latest \
--secret=speak-production-api-key
# HashiCorp Vault
vault kv get -field=api_key secret/speak/production
```
## Environment Isolation
### Prevent Production Operations in Non-Prod
```typescript
function guardProductionOperation(operation: string): void {
const config = getSpeakConfig();
if (config.environment !== 'production') {
console.warn(`[speak] ${operation} blocked in ${config.environment}`);
throw new Error(`${operation} only allowed in production`);
}
}
// Usage
async function deleteUserData(userId: string): Promise {
guardProductionOperation('deleteUserData');
await speakClient.users.delete(userId);
}
```
### Environment-Specific Lesson Restrictions
```typescript
function getAvailableLanguages(): string[] {
const config = getSpeakConfig();
if (config.features?.allLanguages) {
return config.supportedLanguages;
}
// Production: Only enabled languages for user's plan
return getUserPlanLanguages();
}
function canAccessFeature(feature: string): boolean {
const config = getSpeakConfig();
return config.features?.[feature] ?? false;
}
```
## Feature Flags by Environment
```typescript
interface FeatureFlags {
experimentalTutor: boolean;
betaSpeechEngine: boolean;
newPronunciationModel: boolean;
gamificationV2: boolean;
offlineMode: boolean;
}
const featureFlags: Record = {
development: {
experimentalTutor: true,
betaSpeechEngine: true,
newPronunciationModel: true,
gamificationV2: true,
offlineMode: true,
},
staging: {
experimentalTutor: true,
betaSpeechEngine: true,
newPronunciationModel: true,
gamificationV2: false,
offlineMode: false,
},
production: {
experimentalTutor: false,
betaSpeechEngine: false,
newPronunciationModel: false,
gamificationV2: false,
offlineMode: false,
},
};
export function isFeatureEnabled(feature: keyof FeatureFlags): boolean {
const env = detectEnvironment();
return featureFlags[env][feature];
}
```
## Environment-Specific Audio Storage
```typescript
interface AudioStorageConfig {
type: 'local' | 's3' | 'gcs';
bucket?: string;
encryption: boolean;
retention: number; // days
}
const audioStorage: Record = {
development: {
type: 'local',
encryption: false,
retention: 1,
},
staging: {
type: 's3',
bucket: 'speak-staging-audio',
encryption: true,
retention: 7,
},
production: {
type: 's3',
bucket: 'speak-production-audio',
encryption: true,
retention: 30,
},
};
```
## Environment Health Checks
```typescript
async function verifyEnvironmentConfig(): Promise {
const config = getSpeakConfig();
const checks = {
apiKeyValid: false,
canConnect: false,
correctEnvironment: false,
featuresAccessible: false,
};
try {
// Verify API key
const health = await speakClient.health.check();
checks.apiKeyValid = true;
checks.canConnect = health.healthy;
// Verify we're hitting the right environment
const expectedBase = config.baseUrl;
checks.correctEnvironment = health.endpoint.includes(
config.environment === 'production' ? 'api.speak.com' : `api-${config.environment}`
);
// Verify feature access
if (config.features?.experimentalTutor) {
checks.featuresAccessible = await canAccessExperimentalTutor();
} else {
checks.featuresAccessible = true;
}
} catch (error) {
console.error('Environment verification failed:', error);
}
return {
environment: config.environment,
checks,
allPassed: Object.values(checks).every(Boolean),
};
}
```
## Output
- Multi-environment config structure
- Environment detection logic
- Secure secret management
- Production safeguards enabled
- Feature flags by environment
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| Wrong environment | Missing SPEAK_ENV | Set environment variable |
| Secret not found | Wrong secret path | Verify secret manager config |
| Config merge fails | Invalid JSON | Validate config files |
| Production guard triggered | Wrong environment | Check SPEAK_ENV value |
| Feature unavailable | Wrong environment | Verify feature flags |
## Examples
### Quick Environment Check
```typescript
const config = getSpeakConfig();
console.log(`Environment: ${config.environment}`);
console.log(`API Base: ${config.baseUrl}`);
console.log(`Mock Mode: ${config.mockMode ? 'ON' : 'OFF'}`);
console.log(`Features:`, config.features);
```
### Environment Switching Script
```bash
#!/bin/bash
# switch-speak-env.sh
case "$1" in
dev)
export SPEAK_ENV=development
export SPEAK_API_KEY=$(vault kv get -field=api_key secret/speak/development)
;;
staging)
export SPEAK_ENV=staging
export SPEAK_API_KEY=$(vault kv get -field=api_key secret/speak/staging)
;;
prod)
export SPEAK_ENV=production
export SPEAK_API_KEY=$(vault kv get -field=api_key secret/speak/production)
;;
esac
echo "Switched to $SPEAK_ENV environment"
```
## Resources
- [Speak Environments Guide](https://developer.speak.com/docs/environments)
- [12-Factor App Config](https://12factor.net/config)
- [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/)
## Next Steps
For observability setup, see `speak-observability`.