[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F81Z4G3HVSEDW2BSPPC7VR":3,"skill-same:01M6F81Z4G3HVSEDW2BSPPC7VR":80},{"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":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":62,"ownerHtmlUrl":63,"ownerBlogUrl":6,"ownerDescription":64,"updatedAt":65,"install":66,"resources":79},"01M6F81Z4G3HVSEDW2BSPPC7VR","castai-rate-limits",null,"Handle CAST AI API rate limits with backoff and request queuing.\nUse when hitting 429 errors, optimizing API call patterns,\nor implementing rate-aware batch operations.\nTrigger with phrases like \"cast ai rate limit\", \"cast ai 429\",\n\"cast ai throttle\", \"cast ai API limits\".","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",66,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fcastai-rate-limits\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"castai rate limits","castai","call","429","throttle","backoff","trigger","io","ai api","cast","kubernetes","patterns","use","edit","write","read","api","Optimization","batch","code","2026-11-10 10:12:30",false,"---\nname: castai-rate-limits\ndescription: |\n  Handle CAST AI API rate limits with backoff and request queuing.\n  Use when hitting 429 errors, optimizing API call patterns,\n  or implementing rate-aware batch operations.\n  Trigger with phrases like \"cast ai rate limit\", \"cast ai 429\",\n  \"cast ai throttle\", \"cast ai API limits\".\nallowed-tools: Read, Write, Edit\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\ntags: [saas, kubernetes, cost-optimization, castai]\ncompatible-with: claude-code\n---\n\n# CAST AI Rate Limits\n\n## Overview\n\nThe CAST AI REST API enforces rate limits per API key. The autoscaler agent communicates cluster state at 15-second intervals. For custom API integrations, implement exponential backoff and request queuing to avoid hitting limits.\n\n## Prerequisites\n\n- CAST AI API key configured\n- Understanding of the API endpoints you call\n\n## Rate Limit Behavior\n\n| Aspect | Value |\n|--------|-------|\n| Rate limit scope | Per API key |\n| Response on limit | HTTP 429 with `Retry-After` header |\n| Agent sync interval | Every 15 seconds |\n| Recommended polling | No more than once per 30 seconds |\n\n## Instructions\n\n### Step 1: Detect Rate Limits from Response Headers\n\n```typescript\nasync function castaiRequest(path: string): Promise\u003CResponse> {\n  const response = await fetch(`https:\u002F\u002Fapi.cast.ai${path}`, {\n    headers: { \"X-API-Key\": process.env.CASTAI_API_KEY! },\n  });\n\n  \u002F\u002F Log rate limit headers for monitoring\n  const remaining = response.headers.get(\"X-RateLimit-Remaining\");\n  const reset = response.headers.get(\"X-RateLimit-Reset\");\n  if (remaining) {\n    console.log(`Rate limit remaining: ${remaining}, resets: ${reset}`);\n  }\n\n  if (response.status === 429) {\n    const retryAfter = parseInt(response.headers.get(\"Retry-After\") ?? \"5\");\n    throw new RateLimitError(retryAfter);\n  }\n\n  return response;\n}\n\nclass RateLimitError extends Error {\n  constructor(public retryAfterSeconds: number) {\n    super(`Rate limited. Retry after ${retryAfterSeconds}s`);\n  }\n}\n```\n\n### Step 2: Exponential Backoff with Jitter\n\n```typescript\nasync function withBackoff\u003CT>(\n  fn: () => Promise\u003CT>,\n  maxRetries = 5\n): Promise\u003CT> {\n  for (let attempt = 0; attempt \u003C= maxRetries; attempt++) {\n    try {\n      return await fn();\n    } catch (err) {\n      if (attempt === maxRetries) throw err;\n\n      let delayMs: number;\n      if (err instanceof RateLimitError) {\n        delayMs = err.retryAfterSeconds * 1000;\n      } else {\n        delayMs = Math.min(1000 * Math.pow(2, attempt), 30000);\n      }\n      \u002F\u002F Add jitter to prevent thundering herd\n      delayMs += Math.random() * 1000;\n\n      console.log(`Retry ${attempt + 1}\u002F${maxRetries} in ${delayMs}ms`);\n      await new Promise((r) => setTimeout(r, delayMs));\n    }\n  }\n  throw new Error(\"Unreachable\");\n}\n```\n\n### Step 3: Request Queue for Batch Operations\n\n```typescript\nimport PQueue from \"p-queue\";\n\n\u002F\u002F Limit concurrent requests and enforce interval\nconst castaiQueue = new PQueue({\n  concurrency: 3,\n  interval: 1000,\n  intervalCap: 5,   \u002F\u002F Max 5 requests per second\n});\n\nasync function queuedCastAIRequest\u003CT>(fn: () => Promise\u003CT>): Promise\u003CT> {\n  return castaiQueue.add(() => withBackoff(fn));\n}\n\n\u002F\u002F Batch process multiple clusters\nconst clusterIds = [\"id1\", \"id2\", \"id3\", \"id4\", \"id5\"];\nconst savings = await Promise.all(\n  clusterIds.map((id) =>\n    queuedCastAIRequest(() =>\n      fetch(`https:\u002F\u002Fapi.cast.ai\u002Fv1\u002Fkubernetes\u002Fclusters\u002F${id}\u002Fsavings`, {\n        headers: { \"X-API-Key\": process.env.CASTAI_API_KEY! },\n      }).then((r) => r.json())\n    )\n  )\n);\n```\n\n### Step 4: Polling Best Practice\n\n```typescript\n\u002F\u002F Do NOT poll faster than 30 seconds for cluster state\n\u002F\u002F The agent syncs every 15s; polling faster adds no value\n\nasync function pollClusterStatus(\n  clusterId: string,\n  intervalMs = 30000\n): Promise\u003Cvoid> {\n  const timer = setInterval(async () => {\n    try {\n      const status = await queuedCastAIRequest(() =>\n        fetch(\n          `https:\u002F\u002Fapi.cast.ai\u002Fv1\u002Fkubernetes\u002Fexternal-clusters\u002F${clusterId}`,\n          { headers: { \"X-API-Key\": process.env.CASTAI_API_KEY! } }\n        ).then((r) => r.json())\n      );\n      console.log(`Cluster ${clusterId}: ${status.agentStatus}`);\n    } catch (err) {\n      console.error(\"Poll failed:\", err);\n    }\n  }, intervalMs);\n}\n```\n\n## Error Handling\n\n| Scenario | Detection | Response |\n|----------|-----------|----------|\n| 429 with Retry-After | Check header | Wait exact duration |\n| 429 without header | Status code only | Exponential backoff from 1s |\n| 5xx errors | Status >= 500 | Retry up to 3 times |\n| Connection timeout | Fetch throws | Retry with longer timeout |\n\n## Resources\n\n- [CAST AI API Reference](https:\u002F\u002Fapi.cast.ai\u002Fv1\u002Fspec\u002Fopenapi.json)\n- [p-queue](https:\u002F\u002Fgithub.com\u002Fsindresorhus\u002Fp-queue) -- concurrent request queue\n\n## Next Steps\n\nFor security configuration, see `castai-security-basics`.\n\n","# CAST AI Rate Limits\n\n## Overview\n\nThe CAST AI REST API enforces rate limits per API key. The autoscaler agent communicates cluster state at 15-second intervals. For custom API integrations, implement exponential backoff and request queuing to avoid hitting limits.\n\n## Prerequisites\n\n- CAST AI API key configured\n- Understanding of the API endpoints you call\n\n## Rate Limit Behavior\n\n| Aspect | Value |\n|--------|-------|\n| Rate limit scope | Per API key |\n| Response on limit | HTTP 429 with `Retry-After` header |\n| Agent sync interval | Every 15 seconds |\n| Recommended polling | No more than once per 30 seconds |\n\n## Instructions\n\n### Step 1: Detect Rate Limits from Response Headers\n\n```typescript\nasync function castaiRequest(path: string): Promise\u003CResponse> {\n  const response = await fetch(`https:\u002F\u002Fapi.cast.ai${path}`, {\n    headers: { \"X-API-Key\": process.env.CASTAI_API_KEY! },\n  });\n\n  \u002F\u002F Log rate limit headers for monitoring\n  const remaining = response.headers.get(\"X-RateLimit-Remaining\");\n  const reset = response.headers.get(\"X-RateLimit-Reset\");\n  if (remaining) {\n    console.log(`Rate limit remaining: ${remaining}, resets: ${reset}`);\n  }\n\n  if (response.status === 429) {\n    const retryAfter = parseInt(response.headers.get(\"Retry-After\") ?? \"5\");\n    throw new RateLimitError(retryAfter);\n  }\n\n  return response;\n}\n\nclass RateLimitError extends Error {\n  constructor(public retryAfterSeconds: number) {\n    super(`Rate limited. Retry after ${retryAfterSeconds}s`);\n  }\n}\n```\n\n### Step 2: Exponential Backoff with Jitter\n\n```typescript\nasync function withBackoff\u003CT>(\n  fn: () => Promise\u003CT>,\n  maxRetries = 5\n): Promise\u003CT> {\n  for (let attempt = 0; attempt \u003C= maxRetries; attempt++) {\n    try {\n      return await fn();\n    } catch (err) {\n      if (attempt === maxRetries) throw err;\n\n      let delayMs: number;\n      if (err instanceof RateLimitError) {\n        delayMs = err.retryAfterSeconds * 1000;\n      } else {\n        delayMs = Math.min(1000 * Math.pow(2, attempt), 30000);\n      }\n      \u002F\u002F Add jitter to prevent thundering herd\n      delayMs += Math.random() * 1000;\n\n      console.log(`Retry ${attempt + 1}\u002F${maxRetries} in ${delayMs}ms`);\n      await new Promise((r) => setTimeout(r, delayMs));\n    }\n  }\n  throw new Error(\"Unreachable\");\n}\n```\n\n### Step 3: Request Queue for Batch Operations\n\n```typescript\nimport PQueue from \"p-queue\";\n\n\u002F\u002F Limit concurrent requests and enforce interval\nconst castaiQueue = new PQueue({\n  concurrency: 3,\n  interval: 1000,\n  intervalCap: 5,   \u002F\u002F Max 5 requests per second\n});\n\nasync function queuedCastAIRequest\u003CT>(fn: () => Promise\u003CT>): Promise\u003CT> {\n  return castaiQueue.add(() => withBackoff(fn));\n}\n\n\u002F\u002F Batch process multiple clusters\nconst clusterIds = [\"id1\", \"id2\", \"id3\", \"id4\", \"id5\"];\nconst savings = await Promise.all(\n  clusterIds.map((id) =>\n    queuedCastAIRequest(() =>\n      fetch(`https:\u002F\u002Fapi.cast.ai\u002Fv1\u002Fkubernetes\u002Fclusters\u002F${id}\u002Fsavings`, {\n        headers: { \"X-API-Key\": process.env.CASTAI_API_KEY! },\n      }).then((r) => r.json())\n    )\n  )\n);\n```\n\n### Step 4: Polling Best Practice\n\n```typescript\n\u002F\u002F Do NOT poll faster than 30 seconds for cluster state\n\u002F\u002F The agent syncs every 15s; polling faster adds no value\n\nasync function pollClusterStatus(\n  clusterId: string,\n  intervalMs = 30000\n): Promise\u003Cvoid> {\n  const timer = setInterval(async () => {\n    try {\n      const status = await queuedCastAIRequest(() =>\n        fetch(\n          `https:\u002F\u002Fapi.cast.ai\u002Fv1\u002Fkubernetes\u002Fexternal-clusters\u002F${clusterId}`,\n          { headers: { \"X-API-Key\": process.env.CASTAI_API_KEY! } }\n        ).then((r) => r.json())\n      );\n      console.log(`Cluster ${clusterId}: ${status.agentStatus}`);\n    } catch (err) {\n      console.error(\"Poll failed:\", err);\n    }\n  }, intervalMs);\n}\n```\n\n## Error Handling\n\n| Scenario | Detection | Response |\n|----------|-----------|----------|\n| 429 with Retry-After | Check header | Wait exact duration |\n| 429 without header | Status code only | Exponential backoff from 1s |\n| 5xx errors | Status >= 500 | Retry up to 3 times |\n| Connection timeout | Fetch throws | Retry with longer timeout |\n\n## Resources\n\n- [CAST AI API Reference](https:\u002F\u002Fapi.cast.ai\u002Fv1\u002Fspec\u002Fopenapi.json)\n- [p-queue](https:\u002F\u002Fgithub.com\u002Fsindresorhus\u002Fp-queue) -- concurrent request queue\n\n## Next Steps\n\nFor security configuration, see `castai-security-basics`.\n\n",{"name":5,"tags":49,"author":52,"license":15,"version":53,"description":54,"allowed-tools":55,"compatible-with":56},[50,34,51,25],"saas","cost-optimization","Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Handle CAST AI API rate limits with backoff and request queuing.\nUse when hitting 429 errors, optimizing API call patterns,\nor implementing rate-aware batch operations.\nTrigger with phrases like \"cast ai rate limit\", \"cast ai 429\",\n\"cast ai throttle\", \"cast ai API limits\".\n","Read, Write, Edit","claude-code","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fcastai-rate-limits",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":67,"prompt":77,"zipAvailable":78},[68,71,74],{"tool":69,"command":70},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill castai-rate-limits",{"tool":72,"command":73},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill castai-rate-limits",{"tool":75,"command":76},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill castai-rate-limits","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fcastai-rate-limits\u002FSKILL.md",true,[],[81,95,105,114,120,127],{"skillNo":82,"name":83,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":91,"publishedAt":44},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[86],{"categoryNo":87,"categoryName":88,"taxonomyType":89,"taxonomyTypeDesc":90},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[92,93,94],"model","model hierarchy","model hierarchy skill",{"skillNo":96,"name":97,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":101,"publishedAt":44},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[100],{"categoryNo":87,"categoryName":88,"taxonomyType":89,"taxonomyTypeDesc":90},[102,103,104],"MCP","zoom","zoom mcp",{"skillNo":106,"name":107,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":110,"publishedAt":44},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[111,112,113,103],"sdk","zoom apps sdk","apps",{"skillNo":115,"name":116,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":119,"publishedAt":44},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[116],{"skillNo":121,"name":122,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":126,"publishedAt":44},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[125],{"categoryNo":87,"categoryName":88,"taxonomyType":89,"taxonomyTypeDesc":90},[122],{"skillNo":128,"name":129,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":44},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[129]]