[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CHC4XEEDYDEV1JFHPRFZ51":3,"skill-same:01M6CHC4XEEDYDEV1JFHPRFZ51":91},{"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":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":53,"commitSha":54,"skillDirectory":55,"forksCount":56,"repositoryHtmlUrl":57,"repositoryHomepageUrl":6,"ownerHtmlUrl":58,"ownerBlogUrl":59,"ownerDescription":60,"updatedAt":61,"install":62,"resources":75},"01M6CHC4XEEDYDEV1JFHPRFZ51","apollo-multi-env-setup",null,"Configure Apollo.io multi-environment setup.\nUse when setting up development, staging, and production environments,\nor managing multiple Apollo configurations.\nTrigger with phrases like \"apollo environments\", \"apollo staging\",\n\"apollo dev prod\", \"apollo multi-tenant\", \"apollo env config\".","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\u002Fapollo-pack\u002Fskills\u002Fapollo-multi-env-setup\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,42,43],"setup","multi","env setup","env","apollo multi env setup","apollo","when","config","tenant","environments","io","multi-environment","up","use","environment","edit","write","read","curl","configure","Bash","Production","kubectl","dev","development","2026-11-10 10:12:30",false,"---\nname: apollo-multi-env-setup\ndescription: |\n  Configure Apollo.io multi-environment setup.\n  Use when setting up development, staging, and production environments,\n  or managing multiple Apollo configurations.\n  Trigger with phrases like \"apollo environments\", \"apollo staging\",\n  \"apollo dev prod\", \"apollo multi-tenant\", \"apollo env config\".\nallowed-tools: Read, Write, Edit, Bash(kubectl:*), Bash(curl:*)\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\n---\n\n# Apollo Multi-Environment Setup\n\n## Overview\nConfigure Apollo.io for multiple environments (development, staging, production) with proper isolation, configuration management, and deployment strategies.\n\n## Environment Strategy\n\n| Environment | Purpose | API Key | Rate Limit | Data Access |\n|-------------|---------|---------|------------|-------------|\n| Development | Local dev | Dev\u002FSandbox | Low (10\u002Fmin) | Test data only |\n| Staging | Pre-prod testing | Staging key | Medium (50\u002Fmin) | Limited prod |\n| Production | Live system | Production key | Full (100\u002Fmin) | Full access |\n\n## Configuration Structure\n\n```typescript\n\u002F\u002F src\u002Fconfig\u002Fapollo\u002Fenvironments.ts\nimport { z } from 'zod';\n\nconst EnvironmentConfigSchema = z.object({\n  apiKey: z.string().min(1),\n  baseUrl: z.string().url().default('https:\u002F\u002Fapi.apollo.io\u002Fv1'),\n  rateLimit: z.number().positive(),\n  timeout: z.number().positive().default(30000),\n  cacheEnabled: z.boolean().default(true),\n  cacheTtl: z.number().positive().default(300),\n  features: z.object({\n    search: z.boolean().default(true),\n    enrichment: z.boolean().default(true),\n    sequences: z.boolean().default(false),\n    webhooks: z.boolean().default(false),\n  }),\n  logging: z.object({\n    level: z.enum(['debug', 'info', 'warn', 'error']),\n    redactPII: z.boolean().default(true),\n  }),\n});\n\ntype EnvironmentConfig = z.infer\u003Ctypeof EnvironmentConfigSchema>;\n\nconst configs: Record\u003Cstring, EnvironmentConfig> = {\n  development: {\n    apiKey: process.env.APOLLO_API_KEY_DEV || '',\n    baseUrl: 'https:\u002F\u002Fapi.apollo.io\u002Fv1',\n    rateLimit: 10,\n    timeout: 30000,\n    cacheEnabled: true,\n    cacheTtl: 60, \u002F\u002F Short cache in dev\n    features: {\n      search: true,\n      enrichment: true,\n      sequences: false, \u002F\u002F Disabled in dev\n      webhooks: false,\n    },\n    logging: {\n      level: 'debug',\n      redactPII: false, \u002F\u002F Show full data in dev\n    },\n  },\n\n  staging: {\n    apiKey: process.env.APOLLO_API_KEY_STAGING || '',\n    baseUrl: 'https:\u002F\u002Fapi.apollo.io\u002Fv1',\n    rateLimit: 50,\n    timeout: 30000,\n    cacheEnabled: true,\n    cacheTtl: 300,\n    features: {\n      search: true,\n      enrichment: true,\n      sequences: true,\n      webhooks: true,\n    },\n    logging: {\n      level: 'info',\n      redactPII: true,\n    },\n  },\n\n  production: {\n    apiKey: process.env.APOLLO_API_KEY || '',\n    baseUrl: 'https:\u002F\u002Fapi.apollo.io\u002Fv1',\n    rateLimit: 90, \u002F\u002F Buffer below 100\n    timeout: 30000,\n    cacheEnabled: true,\n    cacheTtl: 900, \u002F\u002F 15 min in prod\n    features: {\n      search: true,\n      enrichment: true,\n      sequences: true,\n      webhooks: true,\n    },\n    logging: {\n      level: 'warn',\n      redactPII: true,\n    },\n  },\n};\n\nexport function getConfig(): EnvironmentConfig {\n  const env = process.env.NODE_ENV || 'development';\n  const config = configs[env];\n\n  if (!config) {\n    throw new Error(`Unknown environment: ${env}`);\n  }\n\n  \u002F\u002F Validate configuration\n  const result = EnvironmentConfigSchema.safeParse(config);\n  if (!result.success) {\n    throw new Error(`Invalid Apollo config for ${env}: ${result.error.message}`);\n  }\n\n  return result.data;\n}\n\nexport function validateEnvironment(): void {\n  const config = getConfig();\n\n  if (!config.apiKey) {\n    throw new Error('Apollo API key is required');\n  }\n\n  console.log(`Apollo configured for ${process.env.NODE_ENV || 'development'}`);\n  console.log(`  Rate limit: ${config.rateLimit}\u002Fmin`);\n  console.log(`  Features: ${Object.entries(config.features).filter(([,v]) => v).map(([k]) => k).join(', ')}`);\n}\n```\n\n## Environment Files\n\n```bash\n# .env.development\nNODE_ENV=development\nAPOLLO_API_KEY_DEV=your-dev-api-key\nAPOLLO_RATE_LIMIT=10\nAPOLLO_CACHE_TTL=60\nAPOLLO_LOG_LEVEL=debug\n\n# .env.staging\nNODE_ENV=staging\nAPOLLO_API_KEY_STAGING=your-staging-api-key\nAPOLLO_RATE_LIMIT=50\nAPOLLO_CACHE_TTL=300\nAPOLLO_LOG_LEVEL=info\n\n# .env.production\nNODE_ENV=production\nAPOLLO_API_KEY=your-prod-api-key\nAPOLLO_RATE_LIMIT=90\nAPOLLO_CACHE_TTL=900\nAPOLLO_LOG_LEVEL=warn\n```\n\n## Kubernetes ConfigMaps\n\n```yaml\n# k8s\u002Fconfigmaps\u002Fapollo-config-dev.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: apollo-config\n  namespace: development\ndata:\n  NODE_ENV: \"development\"\n  APOLLO_RATE_LIMIT: \"10\"\n  APOLLO_CACHE_TTL: \"60\"\n  APOLLO_LOG_LEVEL: \"debug\"\n  APOLLO_FEATURES_SEARCH: \"true\"\n  APOLLO_FEATURES_ENRICHMENT: \"true\"\n  APOLLO_FEATURES_SEQUENCES: \"false\"\n  APOLLO_FEATURES_WEBHOOKS: \"false\"\n---\n# k8s\u002Fconfigmaps\u002Fapollo-config-staging.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: apollo-config\n  namespace: staging\ndata:\n  NODE_ENV: \"staging\"\n  APOLLO_RATE_LIMIT: \"50\"\n  APOLLO_CACHE_TTL: \"300\"\n  APOLLO_LOG_LEVEL: \"info\"\n  APOLLO_FEATURES_SEARCH: \"true\"\n  APOLLO_FEATURES_ENRICHMENT: \"true\"\n  APOLLO_FEATURES_SEQUENCES: \"true\"\n  APOLLO_FEATURES_WEBHOOKS: \"true\"\n---\n# k8s\u002Fconfigmaps\u002Fapollo-config-prod.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: apollo-config\n  namespace: production\ndata:\n  NODE_ENV: \"production\"\n  APOLLO_RATE_LIMIT: \"90\"\n  APOLLO_CACHE_TTL: \"900\"\n  APOLLO_LOG_LEVEL: \"warn\"\n  APOLLO_FEATURES_SEARCH: \"true\"\n  APOLLO_FEATURES_ENRICHMENT: \"true\"\n  APOLLO_FEATURES_SEQUENCES: \"true\"\n  APOLLO_FEATURES_WEBHOOKS: \"true\"\n```\n\n## Secrets Management\n\n```yaml\n# k8s\u002Fsecrets\u002Fapollo-secrets.yaml (use sealed-secrets in practice)\napiVersion: v1\nkind: Secret\nmetadata:\n  name: apollo-secrets\n  namespace: ${NAMESPACE}\ntype: Opaque\nstringData:\n  api-key: ${APOLLO_API_KEY}\n  webhook-secret: ${APOLLO_WEBHOOK_SECRET}\n```\n\n```bash\n# Using External Secrets Operator\napiVersion: external-secrets.io\u002Fv1beta1\nkind: ExternalSecret\nmetadata:\n  name: apollo-secrets\nspec:\n  refreshInterval: 1h\n  secretStoreRef:\n    name: gcp-secret-manager\n    kind: ClusterSecretStore\n  target:\n    name: apollo-secrets\n  data:\n    - secretKey: api-key\n      remoteRef:\n        key: apollo-api-key-${ENV}\n    - secretKey: webhook-secret\n      remoteRef:\n        key: apollo-webhook-secret-${ENV}\n```\n\n## Environment-Aware Client\n\n```typescript\n\u002F\u002F src\u002Flib\u002Fapollo\u002Fenv-client.ts\nimport { getConfig } from '..\u002F..\u002Fconfig\u002Fapollo\u002Fenvironments';\n\nclass EnvironmentAwareApolloClient {\n  private config = getConfig();\n\n  async request\u003CT>(options: RequestOptions): Promise\u003CT> {\n    \u002F\u002F Check feature flag\n    if (!this.isFeatureEnabled(options.feature)) {\n      throw new Error(`Feature ${options.feature} is disabled in ${process.env.NODE_ENV}`);\n    }\n\n    \u002F\u002F Apply environment-specific rate limiting\n    await this.rateLimiter.acquire();\n\n    \u002F\u002F Make request with environment config\n    const response = await axios({\n      ...options,\n      baseURL: this.config.baseUrl,\n      timeout: this.config.timeout,\n      params: {\n        ...options.params,\n        api_key: this.config.apiKey,\n      },\n    });\n\n    \u002F\u002F Log based on environment\n    this.log('info', `Apollo ${options.method} ${options.url}`, {\n      status: response.status,\n      duration: response.headers['x-response-time'],\n    });\n\n    return response.data;\n  }\n\n  private isFeatureEnabled(feature: string): boolean {\n    return this.config.features[feature as keyof typeof this.config.features] ?? true;\n  }\n\n  private log(level: string, message: string, meta?: object): void {\n    if (this.shouldLog(level)) {\n      const sanitized = this.config.logging.redactPII\n        ? this.redactPII(meta)\n        : meta;\n      console[level as 'log'](`[Apollo] ${message}`, sanitized);\n    }\n  }\n\n  private shouldLog(level: string): boolean {\n    const levels = ['debug', 'info', 'warn', 'error'];\n    return levels.indexOf(level) >= levels.indexOf(this.config.logging.level);\n  }\n}\n```\n\n## Testing Across Environments\n\n```typescript\n\u002F\u002F tests\u002Fintegration\u002Fenv-tests.ts\ndescribe('Environment Configuration', () => {\n  const originalEnv = process.env.NODE_ENV;\n\n  afterEach(() => {\n    process.env.NODE_ENV = originalEnv;\n  });\n\n  it('loads development config correctly', () => {\n    process.env.NODE_ENV = 'development';\n    const config = getConfig();\n    expect(config.rateLimit).toBe(10);\n    expect(config.features.sequences).toBe(false);\n  });\n\n  it('loads staging config correctly', () => {\n    process.env.NODE_ENV = 'staging';\n    const config = getConfig();\n    expect(config.rateLimit).toBe(50);\n    expect(config.features.sequences).toBe(true);\n  });\n\n  it('loads production config correctly', () => {\n    process.env.NODE_ENV = 'production';\n    const config = getConfig();\n    expect(config.rateLimit).toBe(90);\n    expect(config.logging.redactPII).toBe(true);\n  });\n\n  it('throws on missing API key', () => {\n    process.env.NODE_ENV = 'production';\n    delete process.env.APOLLO_API_KEY;\n    expect(() => validateEnvironment()).toThrow();\n  });\n});\n```\n\n## Environment Promotion\n\n```bash\n#!\u002Fbin\u002Fbash\n# scripts\u002Fpromote-to-staging.sh\n\necho \"Promoting to staging environment...\"\n\n# Verify staging key is configured\nif [ -z \"$APOLLO_API_KEY_STAGING\" ]; then\n  echo \"Error: APOLLO_API_KEY_STAGING not set\"\n  exit 1\nfi\n\n# Run staging tests\nNODE_ENV=staging npm run test:integration\n\n# Deploy to staging\nkubectl apply -f k8s\u002Fconfigmaps\u002Fapollo-config-staging.yaml\nkubectl apply -f k8s\u002Fsecrets\u002Fapollo-secrets-staging.yaml\nkubectl rollout restart deployment\u002Fapollo-service -n staging\n\n# Verify deployment\nkubectl rollout status deployment\u002Fapollo-service -n staging\ncurl -sf https:\u002F\u002Fstaging.example.com\u002Fhealth\u002Fapollo || exit 1\n\necho \"Successfully promoted to staging\"\n```\n\n## Output\n- Environment-specific configurations\n- Kubernetes ConfigMaps and Secrets\n- Environment-aware client\n- Feature flags per environment\n- Environment promotion scripts\n\n## Error Handling\n| Issue | Resolution |\n|-------|------------|\n| Wrong environment | Check NODE_ENV variable |\n| Missing API key | Verify secrets configuration |\n| Feature disabled | Check environment config |\n| Rate limit mismatch | Verify config values |\n\n## Resources\n- [12-Factor App Configuration](https:\u002F\u002F12factor.net\u002Fconfig)\n- [Kubernetes ConfigMaps](https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fconfiguration\u002Fconfigmap\u002F)\n- [External Secrets Operator](https:\u002F\u002Fexternal-secrets.io\u002F)\n\n## Next Steps\nProceed to `apollo-observability` for monitoring setup.\n","# Apollo Multi-Environment Setup\n\n## Overview\nConfigure Apollo.io for multiple environments (development, staging, production) with proper isolation, configuration management, and deployment strategies.\n\n## Environment Strategy\n\n| Environment | Purpose | API Key | Rate Limit | Data Access |\n|-------------|---------|---------|------------|-------------|\n| Development | Local dev | Dev\u002FSandbox | Low (10\u002Fmin) | Test data only |\n| Staging | Pre-prod testing | Staging key | Medium (50\u002Fmin) | Limited prod |\n| Production | Live system | Production key | Full (100\u002Fmin) | Full access |\n\n## Configuration Structure\n\n```typescript\n\u002F\u002F src\u002Fconfig\u002Fapollo\u002Fenvironments.ts\nimport { z } from 'zod';\n\nconst EnvironmentConfigSchema = z.object({\n  apiKey: z.string().min(1),\n  baseUrl: z.string().url().default('https:\u002F\u002Fapi.apollo.io\u002Fv1'),\n  rateLimit: z.number().positive(),\n  timeout: z.number().positive().default(30000),\n  cacheEnabled: z.boolean().default(true),\n  cacheTtl: z.number().positive().default(300),\n  features: z.object({\n    search: z.boolean().default(true),\n    enrichment: z.boolean().default(true),\n    sequences: z.boolean().default(false),\n    webhooks: z.boolean().default(false),\n  }),\n  logging: z.object({\n    level: z.enum(['debug', 'info', 'warn', 'error']),\n    redactPII: z.boolean().default(true),\n  }),\n});\n\ntype EnvironmentConfig = z.infer\u003Ctypeof EnvironmentConfigSchema>;\n\nconst configs: Record\u003Cstring, EnvironmentConfig> = {\n  development: {\n    apiKey: process.env.APOLLO_API_KEY_DEV || '',\n    baseUrl: 'https:\u002F\u002Fapi.apollo.io\u002Fv1',\n    rateLimit: 10,\n    timeout: 30000,\n    cacheEnabled: true,\n    cacheTtl: 60, \u002F\u002F Short cache in dev\n    features: {\n      search: true,\n      enrichment: true,\n      sequences: false, \u002F\u002F Disabled in dev\n      webhooks: false,\n    },\n    logging: {\n      level: 'debug',\n      redactPII: false, \u002F\u002F Show full data in dev\n    },\n  },\n\n  staging: {\n    apiKey: process.env.APOLLO_API_KEY_STAGING || '',\n    baseUrl: 'https:\u002F\u002Fapi.apollo.io\u002Fv1',\n    rateLimit: 50,\n    timeout: 30000,\n    cacheEnabled: true,\n    cacheTtl: 300,\n    features: {\n      search: true,\n      enrichment: true,\n      sequences: true,\n      webhooks: true,\n    },\n    logging: {\n      level: 'info',\n      redactPII: true,\n    },\n  },\n\n  production: {\n    apiKey: process.env.APOLLO_API_KEY || '',\n    baseUrl: 'https:\u002F\u002Fapi.apollo.io\u002Fv1',\n    rateLimit: 90, \u002F\u002F Buffer below 100\n    timeout: 30000,\n    cacheEnabled: true,\n    cacheTtl: 900, \u002F\u002F 15 min in prod\n    features: {\n      search: true,\n      enrichment: true,\n      sequences: true,\n      webhooks: true,\n    },\n    logging: {\n      level: 'warn',\n      redactPII: true,\n    },\n  },\n};\n\nexport function getConfig(): EnvironmentConfig {\n  const env = process.env.NODE_ENV || 'development';\n  const config = configs[env];\n\n  if (!config) {\n    throw new Error(`Unknown environment: ${env}`);\n  }\n\n  \u002F\u002F Validate configuration\n  const result = EnvironmentConfigSchema.safeParse(config);\n  if (!result.success) {\n    throw new Error(`Invalid Apollo config for ${env}: ${result.error.message}`);\n  }\n\n  return result.data;\n}\n\nexport function validateEnvironment(): void {\n  const config = getConfig();\n\n  if (!config.apiKey) {\n    throw new Error('Apollo API key is required');\n  }\n\n  console.log(`Apollo configured for ${process.env.NODE_ENV || 'development'}`);\n  console.log(`  Rate limit: ${config.rateLimit}\u002Fmin`);\n  console.log(`  Features: ${Object.entries(config.features).filter(([,v]) => v).map(([k]) => k).join(', ')}`);\n}\n```\n\n## Environment Files\n\n```bash\n# .env.development\nNODE_ENV=development\nAPOLLO_API_KEY_DEV=your-dev-api-key\nAPOLLO_RATE_LIMIT=10\nAPOLLO_CACHE_TTL=60\nAPOLLO_LOG_LEVEL=debug\n\n# .env.staging\nNODE_ENV=staging\nAPOLLO_API_KEY_STAGING=your-staging-api-key\nAPOLLO_RATE_LIMIT=50\nAPOLLO_CACHE_TTL=300\nAPOLLO_LOG_LEVEL=info\n\n# .env.production\nNODE_ENV=production\nAPOLLO_API_KEY=your-prod-api-key\nAPOLLO_RATE_LIMIT=90\nAPOLLO_CACHE_TTL=900\nAPOLLO_LOG_LEVEL=warn\n```\n\n## Kubernetes ConfigMaps\n\n```yaml\n# k8s\u002Fconfigmaps\u002Fapollo-config-dev.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: apollo-config\n  namespace: development\ndata:\n  NODE_ENV: \"development\"\n  APOLLO_RATE_LIMIT: \"10\"\n  APOLLO_CACHE_TTL: \"60\"\n  APOLLO_LOG_LEVEL: \"debug\"\n  APOLLO_FEATURES_SEARCH: \"true\"\n  APOLLO_FEATURES_ENRICHMENT: \"true\"\n  APOLLO_FEATURES_SEQUENCES: \"false\"\n  APOLLO_FEATURES_WEBHOOKS: \"false\"\n---\n# k8s\u002Fconfigmaps\u002Fapollo-config-staging.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: apollo-config\n  namespace: staging\ndata:\n  NODE_ENV: \"staging\"\n  APOLLO_RATE_LIMIT: \"50\"\n  APOLLO_CACHE_TTL: \"300\"\n  APOLLO_LOG_LEVEL: \"info\"\n  APOLLO_FEATURES_SEARCH: \"true\"\n  APOLLO_FEATURES_ENRICHMENT: \"true\"\n  APOLLO_FEATURES_SEQUENCES: \"true\"\n  APOLLO_FEATURES_WEBHOOKS: \"true\"\n---\n# k8s\u002Fconfigmaps\u002Fapollo-config-prod.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: apollo-config\n  namespace: production\ndata:\n  NODE_ENV: \"production\"\n  APOLLO_RATE_LIMIT: \"90\"\n  APOLLO_CACHE_TTL: \"900\"\n  APOLLO_LOG_LEVEL: \"warn\"\n  APOLLO_FEATURES_SEARCH: \"true\"\n  APOLLO_FEATURES_ENRICHMENT: \"true\"\n  APOLLO_FEATURES_SEQUENCES: \"true\"\n  APOLLO_FEATURES_WEBHOOKS: \"true\"\n```\n\n## Secrets Management\n\n```yaml\n# k8s\u002Fsecrets\u002Fapollo-secrets.yaml (use sealed-secrets in practice)\napiVersion: v1\nkind: Secret\nmetadata:\n  name: apollo-secrets\n  namespace: ${NAMESPACE}\ntype: Opaque\nstringData:\n  api-key: ${APOLLO_API_KEY}\n  webhook-secret: ${APOLLO_WEBHOOK_SECRET}\n```\n\n```bash\n# Using External Secrets Operator\napiVersion: external-secrets.io\u002Fv1beta1\nkind: ExternalSecret\nmetadata:\n  name: apollo-secrets\nspec:\n  refreshInterval: 1h\n  secretStoreRef:\n    name: gcp-secret-manager\n    kind: ClusterSecretStore\n  target:\n    name: apollo-secrets\n  data:\n    - secretKey: api-key\n      remoteRef:\n        key: apollo-api-key-${ENV}\n    - secretKey: webhook-secret\n      remoteRef:\n        key: apollo-webhook-secret-${ENV}\n```\n\n## Environment-Aware Client\n\n```typescript\n\u002F\u002F src\u002Flib\u002Fapollo\u002Fenv-client.ts\nimport { getConfig } from '..\u002F..\u002Fconfig\u002Fapollo\u002Fenvironments';\n\nclass EnvironmentAwareApolloClient {\n  private config = getConfig();\n\n  async request\u003CT>(options: RequestOptions): Promise\u003CT> {\n    \u002F\u002F Check feature flag\n    if (!this.isFeatureEnabled(options.feature)) {\n      throw new Error(`Feature ${options.feature} is disabled in ${process.env.NODE_ENV}`);\n    }\n\n    \u002F\u002F Apply environment-specific rate limiting\n    await this.rateLimiter.acquire();\n\n    \u002F\u002F Make request with environment config\n    const response = await axios({\n      ...options,\n      baseURL: this.config.baseUrl,\n      timeout: this.config.timeout,\n      params: {\n        ...options.params,\n        api_key: this.config.apiKey,\n      },\n    });\n\n    \u002F\u002F Log based on environment\n    this.log('info', `Apollo ${options.method} ${options.url}`, {\n      status: response.status,\n      duration: response.headers['x-response-time'],\n    });\n\n    return response.data;\n  }\n\n  private isFeatureEnabled(feature: string): boolean {\n    return this.config.features[feature as keyof typeof this.config.features] ?? true;\n  }\n\n  private log(level: string, message: string, meta?: object): void {\n    if (this.shouldLog(level)) {\n      const sanitized = this.config.logging.redactPII\n        ? this.redactPII(meta)\n        : meta;\n      console[level as 'log'](`[Apollo] ${message}`, sanitized);\n    }\n  }\n\n  private shouldLog(level: string): boolean {\n    const levels = ['debug', 'info', 'warn', 'error'];\n    return levels.indexOf(level) >= levels.indexOf(this.config.logging.level);\n  }\n}\n```\n\n## Testing Across Environments\n\n```typescript\n\u002F\u002F tests\u002Fintegration\u002Fenv-tests.ts\ndescribe('Environment Configuration', () => {\n  const originalEnv = process.env.NODE_ENV;\n\n  afterEach(() => {\n    process.env.NODE_ENV = originalEnv;\n  });\n\n  it('loads development config correctly', () => {\n    process.env.NODE_ENV = 'development';\n    const config = getConfig();\n    expect(config.rateLimit).toBe(10);\n    expect(config.features.sequences).toBe(false);\n  });\n\n  it('loads staging config correctly', () => {\n    process.env.NODE_ENV = 'staging';\n    const config = getConfig();\n    expect(config.rateLimit).toBe(50);\n    expect(config.features.sequences).toBe(true);\n  });\n\n  it('loads production config correctly', () => {\n    process.env.NODE_ENV = 'production';\n    const config = getConfig();\n    expect(config.rateLimit).toBe(90);\n    expect(config.logging.redactPII).toBe(true);\n  });\n\n  it('throws on missing API key', () => {\n    process.env.NODE_ENV = 'production';\n    delete process.env.APOLLO_API_KEY;\n    expect(() => validateEnvironment()).toThrow();\n  });\n});\n```\n\n## Environment Promotion\n\n```bash\n#!\u002Fbin\u002Fbash\n# scripts\u002Fpromote-to-staging.sh\n\necho \"Promoting to staging environment...\"\n\n# Verify staging key is configured\nif [ -z \"$APOLLO_API_KEY_STAGING\" ]; then\n  echo \"Error: APOLLO_API_KEY_STAGING not set\"\n  exit 1\nfi\n\n# Run staging tests\nNODE_ENV=staging npm run test:integration\n\n# Deploy to staging\nkubectl apply -f k8s\u002Fconfigmaps\u002Fapollo-config-staging.yaml\nkubectl apply -f k8s\u002Fsecrets\u002Fapollo-secrets-staging.yaml\nkubectl rollout restart deployment\u002Fapollo-service -n staging\n\n# Verify deployment\nkubectl rollout status deployment\u002Fapollo-service -n staging\ncurl -sf https:\u002F\u002Fstaging.example.com\u002Fhealth\u002Fapollo || exit 1\n\necho \"Successfully promoted to staging\"\n```\n\n## Output\n- Environment-specific configurations\n- Kubernetes ConfigMaps and Secrets\n- Environment-aware client\n- Feature flags per environment\n- Environment promotion scripts\n\n## Error Handling\n| Issue | Resolution |\n|-------|------------|\n| Wrong environment | Check NODE_ENV variable |\n| Missing API key | Verify secrets configuration |\n| Feature disabled | Check environment config |\n| Rate limit mismatch | Verify config values |\n\n## Resources\n- [12-Factor App Configuration](https:\u002F\u002F12factor.net\u002Fconfig)\n- [Kubernetes ConfigMaps](https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fconfiguration\u002Fconfigmap\u002F)\n- [External Secrets Operator](https:\u002F\u002Fexternal-secrets.io\u002F)\n\n## Next Steps\nProceed to `apollo-observability` for monitoring setup.\n",{"name":5,"author":49,"license":15,"version":50,"description":51,"allowed-tools":52},"Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Configure Apollo.io multi-environment setup.\nUse when setting up development, staging, and production environments,\nor managing multiple Apollo configurations.\nTrigger with phrases like \"apollo environments\", \"apollo staging\",\n\"apollo dev prod\", \"apollo multi-tenant\", \"apollo env config\".\n","Read, Write, Edit, Bash(kubectl:*), Bash(curl:*)","main","7439377908fdee98c9bb5863391212b95453de95","tests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fapollo-pack\u002Fskills\u002Fapollo-multi-env-setup",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":63,"prompt":73,"zipAvailable":74},[64,67,70],{"tool":65,"command":66},"npx","npx skills add Dicklesworthstone\u002Fpi_agent_rust --skill apollo-multi-env-setup",{"tool":68,"command":69},"bunx","bunx skills add Dicklesworthstone\u002Fpi_agent_rust --skill apollo-multi-env-setup",{"tool":71,"command":72},"pnpm","pnpm dlx skills add Dicklesworthstone\u002Fpi_agent_rust --skill apollo-multi-env-setup","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fapollo-pack\u002Fskills\u002Fapollo-multi-env-setup\u002FSKILL.md",true,[76,81,87],{"path":77,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"LICENSE","许可证",1071,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fdanthamanvoiss-salesportl-print-quality-review-orchestrator\u002FLICENSE",{"path":82,"resourceType":83,"resourceTypeDesc":84,"sizeBytes":85,"sourceHtmlUrl":86},"SOURCE.md","REFERENCE","参考文档",489,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fdanthamanvoiss-salesportl-print-quality-review-orchestrator\u002FSOURCE.md",{"path":88,"resourceType":83,"resourceTypeDesc":84,"sizeBytes":89,"sourceHtmlUrl":90},"TRUST.auto.yaml",2217,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fdanthamanvoiss-salesportl-print-quality-review-orchestrator\u002FTRUST.auto.yaml",[92,131,156,182,209,231],{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":96,"licenseFileUrl":97,"sourceHtmlUrl":98,"categories":99,"keywords":105,"publishedAt":44},"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",[100],{"categoryNo":101,"categoryName":102,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,32,124,125,126,127,20,128,129,130],"web artifacts builder","web","artifacts","artifacts builder","builder","frontend","css","components","react","component","routing","state management","state","shadcn","file","ui","Tools","Tailwind","html","single-file","simple","ui components","for","jsx","suite",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":96,"licenseFileUrl":135,"sourceHtmlUrl":136,"categories":137,"keywords":142,"publishedAt":44},"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",[138,141],{"categoryNo":139,"categoryName":140,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":101,"categoryName":102,"taxonomyType":103,"taxonomyTypeDesc":104},[143,144,145,111,146,147,107,148,149,150,121,151,152,153,154,155,128],"testing","webapp testing","webapp","screenshots","playwright","debugging","toolkit","browser","logs","applications","behavior","local","with",{"skillNo":157,"name":158,"nameZh":6,"description":159,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":160,"sourceHtmlUrl":161,"categories":162,"keywords":163,"publishedAt":44},"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",[],[164,165,166,167,168,169,170,171,32,172,173,174,175,176,177,178,155,179,180,181,128,25],"analysis","neuropixels analysis","spike","metrics","data","open","quality","user","recordings","Neural","motion","visual","quality metrics","unit","sorting","curation","recording","load",{"skillNo":183,"name":184,"nameZh":6,"description":185,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":96,"licenseFileUrl":186,"sourceHtmlUrl":187,"categories":188,"keywords":192,"publishedAt":44},"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",[189],{"categoryNo":190,"categoryName":191,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000023","Skill与智能体开发",[193,194,195,196,197,198,199,200,201,202,203,204,205,206,155,128,207,25,208],"skill creator","creator","workflows","create","update","capabilities","knowledge","tool","integrations","specialized","guide","new skill","existing skill","users","Existing","new",{"skillNo":210,"name":211,"nameZh":6,"description":212,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":213,"sourceHtmlUrl":214,"categories":215,"keywords":217,"publishedAt":44},"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",[216],{"categoryNo":190,"categoryName":191,"taxonomyType":103,"taxonomyTypeDesc":104},[211,218,219,220,221,222,223,150,224,225,32,226,227,228,229,128,230],"google","browser automation","gemini","automation","auth","code","library","management","only","document","query","Citation","source",{"skillNo":232,"name":233,"nameZh":6,"description":234,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":96,"licenseFileUrl":235,"sourceHtmlUrl":236,"categories":237,"keywords":244,"publishedAt":44},"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",[238,241],{"categoryNo":239,"categoryName":240,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":242,"categoryName":243,"taxonomyType":103,"taxonomyTypeDesc":104},"01JBSEEDCAT000000000000016","图像与多媒体",[245,246,247,194,248,122,249,250,199,32,251,206,252,253,254,128,255,25],"slack gif creator","slack","gif","validation","constraints","Animation","me","make","Utilities","concepts","request"]