[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F82QRWDPPR3TK6SZG3G5K5":3,"skill-same:01M6F82QRWDPPR3TK6SZG3G5K5":82},{"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":50,"linkOnly":51,"markdownContent":52,"markdownBody":53,"frontMatter":54,"refName":59,"commitSha":60,"skillDirectory":61,"forksCount":62,"repositoryHtmlUrl":63,"repositoryHomepageUrl":6,"ownerHtmlUrl":64,"ownerBlogUrl":65,"ownerDescription":66,"updatedAt":67,"install":68,"resources":81},"01M6F82QRWDPPR3TK6SZG3G5K5","maintainx-cost-tuning",null,"Optimize MaintainX API usage for cost efficiency.\nUse when managing API costs, optimizing request volume,\nor implementing cost-effective integration patterns with MaintainX.\nTrigger with phrases like \"maintainx cost\", \"maintainx billing\",\n\"reduce maintainx usage\", \"maintainx api costs\", \"maintainx optimization\".","Dicklesworthstone\u002Fpi_agent_rust","Dicklesworthstone","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F35050222?v=4","01M6CG26AR942CSVMN1M5E3DSE","Jeff Emanuel","01M6CG26EPP71PSHW1VDS71121",1991,"MIT","https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fmaintainx-pack\u002Fskills\u002Fmaintainx-cost-tuning\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,44,45,46,47,48,49],"tuning","maintainx cost tuning","cost","volume","when","request","reduce","for","implementing","usage","with","billing","trigger","io","efficiency","npm","optimize","patterns","use","edit","write","read","Bash","api","Optimization","integration","2026-11-10 10:12:30",false,"---\nname: maintainx-cost-tuning\ndescription: |\n  Optimize MaintainX API usage for cost efficiency.\n  Use when managing API costs, optimizing request volume,\n  or implementing cost-effective integration patterns with MaintainX.\n  Trigger with phrases like \"maintainx cost\", \"maintainx billing\",\n  \"reduce maintainx usage\", \"maintainx api costs\", \"maintainx optimization\".\nallowed-tools: Read, Write, Edit, Bash(npm:*)\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\n---\n\n# MaintainX Cost Tuning\n\n## Overview\n\nOptimize your MaintainX API usage for cost efficiency while maintaining functionality.\n\n## Prerequisites\n\n- MaintainX integration deployed\n- API usage monitoring in place\n- Understanding of pricing tiers\n\n## Cost Optimization Strategies\n\n| Strategy | Savings Potential | Implementation Effort |\n|----------|------------------|----------------------|\n| Caching | 40-60% | Low |\n| Batch operations | 20-30% | Medium |\n| Webhook over polling | 50-70% | Medium |\n| Smart pagination | 10-20% | Low |\n| Request deduplication | 15-25% | Low |\n\n## Instructions\n\n### Step 1: API Usage Tracking\n\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Fapi-usage.ts\n\ninterface UsageMetric {\n  endpoint: string;\n  method: string;\n  timestamp: Date;\n  responseSize: number;\n  cached: boolean;\n}\n\nclass ApiUsageTracker {\n  private metrics: UsageMetric[] = [];\n  private dailyUsage: Map\u003Cstring, number> = new Map();\n\n  track(metric: Omit\u003CUsageMetric, 'timestamp'>): void {\n    this.metrics.push({\n      ...metric,\n      timestamp: new Date(),\n    });\n\n    \u002F\u002F Update daily counter\n    const today = new Date().toISOString().split('T')[0];\n    const key = `${today}:${metric.endpoint}`;\n    this.dailyUsage.set(key, (this.dailyUsage.get(key) || 0) + 1);\n  }\n\n  getUsageReport(days = 7): any {\n    const now = Date.now();\n    const cutoff = now - days * 24 * 60 * 60 * 1000;\n\n    const recentMetrics = this.metrics.filter(\n      m => m.timestamp.getTime() > cutoff\n    );\n\n    \u002F\u002F Group by endpoint\n    const byEndpoint: Record\u003Cstring, number> = {};\n    recentMetrics.forEach(m => {\n      byEndpoint[m.endpoint] = (byEndpoint[m.endpoint] || 0) + 1;\n    });\n\n    \u002F\u002F Calculate cache hit rate\n    const cacheHits = recentMetrics.filter(m => m.cached).length;\n    const cacheHitRate = recentMetrics.length > 0\n      ? cacheHits \u002F recentMetrics.length\n      : 0;\n\n    \u002F\u002F Identify optimization opportunities\n    const opportunities = this.identifyOpportunities(byEndpoint, cacheHitRate);\n\n    return {\n      period: `${days} days`,\n      totalRequests: recentMetrics.length,\n      byEndpoint,\n      cacheHitRate: `${(cacheHitRate * 100).toFixed(1)}%`,\n      estimatedSavings: this.calculateSavings(recentMetrics),\n      opportunities,\n    };\n  }\n\n  private identifyOpportunities(\n    byEndpoint: Record\u003Cstring, number>,\n    cacheHitRate: number\n  ): string[] {\n    const opportunities: string[] = [];\n\n    \u002F\u002F High-frequency endpoints that could be cached\n    Object.entries(byEndpoint).forEach(([endpoint, count]) => {\n      if (count > 1000 && !endpoint.includes('create')) {\n        opportunities.push(\n          `High volume on ${endpoint} (${count} requests) - consider caching`\n        );\n      }\n    });\n\n    \u002F\u002F Low cache hit rate\n    if (cacheHitRate \u003C 0.3) {\n      opportunities.push(\n        `Low cache hit rate (${(cacheHitRate * 100).toFixed(1)}%) - improve caching strategy`\n      );\n    }\n\n    return opportunities;\n  }\n\n  private calculateSavings(metrics: UsageMetric[]): string {\n    const totalRequests = metrics.length;\n    const cachedRequests = metrics.filter(m => m.cached).length;\n\n    \u002F\u002F Estimate cost per request (varies by plan)\n    const costPerRequest = 0.001;  \u002F\u002F Example: $0.001 per request\n\n    const savedRequests = cachedRequests;\n    const savings = savedRequests * costPerRequest;\n\n    return `$${savings.toFixed(2)} saved from ${savedRequests} cached requests`;\n  }\n}\n\nexport const usageTracker = new ApiUsageTracker();\n```\n\n### Step 2: Smart Caching Strategy\n\n```typescript\n\u002F\u002F src\u002Fcache\u002Fsmart-cache.ts\n\ninterface CacheStrategy {\n  ttlSeconds: number;\n  staleWhileRevalidate: boolean;\n  priority: 'high' | 'medium' | 'low';\n}\n\nconst cacheStrategies: Record\u003Cstring, CacheStrategy> = {\n  \u002F\u002F Static data - cache longer\n  'locations': { ttlSeconds: 3600, staleWhileRevalidate: true, priority: 'low' },\n  'users': { ttlSeconds: 1800, staleWhileRevalidate: true, priority: 'low' },\n  'assets': { ttlSeconds: 900, staleWhileRevalidate: true, priority: 'medium' },\n\n  \u002F\u002F Dynamic data - cache shorter\n  'workorders:list': { ttlSeconds: 60, staleWhileRevalidate: true, priority: 'high' },\n  'workorders:single': { ttlSeconds: 300, staleWhileRevalidate: true, priority: 'medium' },\n};\n\nclass SmartCache {\n  private cache: CacheManager;\n\n  async getOrFetch\u003CT>(\n    key: string,\n    fetchFn: () => Promise\u003CT>,\n    strategyKey: string\n  ): Promise\u003CT> {\n    const strategy = cacheStrategies[strategyKey] || {\n      ttlSeconds: 300,\n      staleWhileRevalidate: false,\n      priority: 'medium',\n    };\n\n    \u002F\u002F Try cache first\n    const cached = await this.cache.get\u003CT>(key);\n\n    if (cached) {\n      usageTracker.track({\n        endpoint: strategyKey,\n        method: 'GET',\n        responseSize: 0,\n        cached: true,\n      });\n\n      \u002F\u002F Stale-while-revalidate: return cached, refresh in background\n      if (strategy.staleWhileRevalidate) {\n        this.revalidateInBackground(key, fetchFn, strategy);\n      }\n\n      return cached;\n    }\n\n    \u002F\u002F Fetch fresh data\n    const data = await fetchFn();\n\n    usageTracker.track({\n      endpoint: strategyKey,\n      method: 'GET',\n      responseSize: JSON.stringify(data).length,\n      cached: false,\n    });\n\n    \u002F\u002F Cache the result\n    await this.cache.set(key, data, strategy.ttlSeconds);\n\n    return data;\n  }\n\n  private async revalidateInBackground\u003CT>(\n    key: string,\n    fetchFn: () => Promise\u003CT>,\n    strategy: CacheStrategy\n  ): Promise\u003Cvoid> {\n    \u002F\u002F Don't await - runs in background\n    fetchFn()\n      .then(data => this.cache.set(key, data, strategy.ttlSeconds))\n      .catch(err => console.error('Background revalidation failed:', err));\n  }\n}\n```\n\n### Step 3: Webhook-Based Updates\n\n```typescript\n\u002F\u002F src\u002Fsync\u002Fwebhook-sync.ts\n\n\u002F\u002F Instead of polling, use webhooks to stay in sync\nclass WebhookBasedSync {\n  private localCache: Map\u003Cstring, any> = new Map();\n\n  constructor() {\n    \u002F\u002F Initialize cache from MaintainX on startup\n    this.initializeCache();\n\n    \u002F\u002F Register webhook handlers\n    this.registerWebhookHandlers();\n  }\n\n  private async initializeCache(): Promise\u003Cvoid> {\n    console.log('Initializing local cache from MaintainX...');\n\n    \u002F\u002F One-time full sync\n    const workOrders = await getAllWorkOrders(client, { status: 'OPEN' });\n    workOrders.forEach(wo => this.localCache.set(`workorder:${wo.id}`, wo));\n\n    console.log(`Cached ${workOrders.length} work orders`);\n  }\n\n  private registerWebhookHandlers(): void {\n    \u002F\u002F Update cache from webhooks instead of polling\n    on('workorder.created', async (event) => {\n      this.localCache.set(`workorder:${event.data.id}`, event.data);\n    });\n\n    on('workorder.updated', async (event) => {\n      this.localCache.set(`workorder:${event.data.id}`, event.data);\n    });\n\n    on('workorder.deleted', async (event) => {\n      this.localCache.delete(`workorder:${event.data.id}`);\n    });\n  }\n\n  \u002F\u002F Get data from cache - no API call needed\n  getWorkOrder(id: string): WorkOrder | undefined {\n    return this.localCache.get(`workorder:${id}`);\n  }\n\n  \u002F\u002F Only call API when data doesn't exist locally\n  async getWorkOrderWithFallback(id: string): Promise\u003CWorkOrder> {\n    const cached = this.localCache.get(`workorder:${id}`);\n    if (cached) return cached;\n\n    \u002F\u002F Fallback to API\n    const workOrder = await client.getWorkOrder(id);\n    this.localCache.set(`workorder:${id}`, workOrder);\n    return workOrder;\n  }\n}\n\n\u002F\u002F Cost comparison:\n\u002F\u002F Polling every 30 seconds = 2,880 requests\u002Fday = $2.88\u002Fday (at $0.001\u002Frequest)\n\u002F\u002F Webhooks = ~100 events\u002Fday = $0.10\u002Fday (at $0.001\u002Frequest)\n\u002F\u002F Savings = 96.5%\n```\n\n### Step 4: Request Batching\n\n```typescript\n\u002F\u002F src\u002Foptimization\u002Fbatch-requests.ts\n\n\u002F\u002F Instead of individual requests, batch where possible\nclass BatchRequestManager {\n  private pendingWorkOrderIds: Set\u003Cstring> = new Set();\n  private batchTimeout: NodeJS.Timeout | null = null;\n  private batchResolvers: Map\u003Cstring, (wo: WorkOrder) => void> = new Map();\n\n  async getWorkOrder(id: string): Promise\u003CWorkOrder> {\n    return new Promise((resolve) => {\n      this.pendingWorkOrderIds.add(id);\n      this.batchResolvers.set(id, resolve);\n\n      \u002F\u002F Schedule batch execution\n      if (!this.batchTimeout) {\n        this.batchTimeout = setTimeout(() => this.executeBatch(), 50);\n      }\n    });\n  }\n\n  private async executeBatch(): Promise\u003Cvoid> {\n    const ids = Array.from(this.pendingWorkOrderIds);\n    this.pendingWorkOrderIds.clear();\n    this.batchTimeout = null;\n\n    if (ids.length === 0) return;\n\n    console.log(`Batching ${ids.length} work order requests`);\n\n    \u002F\u002F Fetch all at once (if API supports batch endpoint)\n    \u002F\u002F Otherwise, parallel fetch with rate limiting\n    const workOrders = await Promise.all(\n      ids.map(id => client.getWorkOrder(id))\n    );\n\n    \u002F\u002F Resolve individual promises\n    workOrders.forEach((wo, i) => {\n      const resolver = this.batchResolvers.get(ids[i]);\n      if (resolver) {\n        resolver(wo);\n        this.batchResolvers.delete(ids[i]);\n      }\n    });\n\n    \u002F\u002F Cost savings: 10 individual requests -> 1 batch = 90% reduction\n  }\n}\n```\n\n### Step 5: Efficient Data Fetching\n\n```typescript\n\u002F\u002F src\u002Foptimization\u002Fefficient-fetch.ts\n\n\u002F\u002F Only fetch what you need\nasync function fetchMinimalWorkOrderData(\n  client: MaintainXClient,\n  params: WorkOrderQueryParams\n): Promise\u003CWorkOrderSummary[]> {\n  const response = await client.getWorkOrders({\n    ...params,\n    \u002F\u002F Request only necessary fields if API supports field selection\n    \u002F\u002F fields: ['id', 'title', 'status', 'priority', 'dueDate'],\n    limit: params.limit || 50,  \u002F\u002F Don't over-fetch\n  });\n\n  \u002F\u002F Transform to minimal objects\n  return response.workOrders.map(wo => ({\n    id: wo.id,\n    title: wo.title,\n    status: wo.status,\n    priority: wo.priority,\n    dueDate: wo.dueDate,\n  }));\n}\n\n\u002F\u002F Pagination with early termination\nasync function fetchUntilCondition(\n  client: MaintainXClient,\n  condition: (wo: WorkOrder) => boolean,\n  params: WorkOrderQueryParams = {}\n): Promise\u003CWorkOrder[]> {\n  const results: WorkOrder[] = [];\n  let cursor: string | undefined;\n\n  do {\n    const response = await client.getWorkOrders({ ...params, cursor, limit: 100 });\n\n    for (const wo of response.workOrders) {\n      if (condition(wo)) {\n        results.push(wo);\n      } else {\n        \u002F\u002F Early termination - don't fetch more pages\n        return results;\n      }\n    }\n\n    cursor = response.nextCursor || undefined;\n  } while (cursor && results.length \u003C 1000);  \u002F\u002F Safety limit\n\n  return results;\n}\n```\n\n### Step 6: Cost Dashboard\n\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Fcost-dashboard.ts\n\ninterface CostReport {\n  period: string;\n  totalRequests: number;\n  estimatedCost: number;\n  byEndpoint: Record\u003Cstring, { count: number; cost: number }>;\n  recommendations: string[];\n}\n\nfunction generateCostReport(days = 30): CostReport {\n  const usage = usageTracker.getUsageReport(days);\n\n  \u002F\u002F Cost per request (adjust based on your plan)\n  const costPerRequest = 0.001;\n\n  const byEndpoint: Record\u003Cstring, { count: number; cost: number }> = {};\n  Object.entries(usage.byEndpoint).forEach(([endpoint, count]) => {\n    byEndpoint[endpoint] = {\n      count: count as number,\n      cost: (count as number) * costPerRequest,\n    };\n  });\n\n  \u002F\u002F Sort by cost descending\n  const sortedEndpoints = Object.entries(byEndpoint)\n    .sort((a, b) => b[1].cost - a[1].cost);\n\n  const recommendations: string[] = [];\n\n  \u002F\u002F Top cost endpoint\n  if (sortedEndpoints.length > 0) {\n    const [topEndpoint, topUsage] = sortedEndpoints[0];\n    recommendations.push(\n      `Highest cost: ${topEndpoint} ($${topUsage.cost.toFixed(2)}) - ` +\n      `Consider caching or webhooks`\n    );\n  }\n\n  \u002F\u002F Low cache hit rate\n  const cacheHitRate = parseFloat(usage.cacheHitRate);\n  if (cacheHitRate \u003C 50) {\n    const potentialSavings = usage.totalRequests * 0.5 * costPerRequest;\n    recommendations.push(\n      `Cache hit rate is ${cacheHitRate.toFixed(0)}% - ` +\n      `Improving to 50% could save $${potentialSavings.toFixed(2)}`\n    );\n  }\n\n  return {\n    period: `${days} days`,\n    totalRequests: usage.totalRequests,\n    estimatedCost: usage.totalRequests * costPerRequest,\n    byEndpoint,\n    recommendations,\n  };\n}\n```\n\n## Output\n\n- API usage tracking implemented\n- Smart caching strategy\n- Webhook-based sync instead of polling\n- Request batching\n- Cost dashboard and reports\n\n## Cost Savings Summary\n\n| Optimization | Before | After | Savings |\n|-------------|--------|-------|---------|\n| Caching | 10,000\u002Fday | 4,000\u002Fday | 60% |\n| Webhooks vs polling | 2,880\u002Fday | 100\u002Fday | 97% |\n| Batching | 500\u002Fday | 100\u002Fday | 80% |\n| Total estimate | 13,380\u002Fday | 4,200\u002Fday | 69% |\n\n## Resources\n\n- [MaintainX Pricing](https:\u002F\u002Fwww.getmaintainx.com\u002Fpricing)\n- [MaintainX API Documentation](https:\u002F\u002Fmaintainx.dev\u002F)\n\n## Next Steps\n\nFor architecture patterns, see `maintainx-reference-architecture`.\n","# MaintainX Cost Tuning\n\n## Overview\n\nOptimize your MaintainX API usage for cost efficiency while maintaining functionality.\n\n## Prerequisites\n\n- MaintainX integration deployed\n- API usage monitoring in place\n- Understanding of pricing tiers\n\n## Cost Optimization Strategies\n\n| Strategy | Savings Potential | Implementation Effort |\n|----------|------------------|----------------------|\n| Caching | 40-60% | Low |\n| Batch operations | 20-30% | Medium |\n| Webhook over polling | 50-70% | Medium |\n| Smart pagination | 10-20% | Low |\n| Request deduplication | 15-25% | Low |\n\n## Instructions\n\n### Step 1: API Usage Tracking\n\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Fapi-usage.ts\n\ninterface UsageMetric {\n  endpoint: string;\n  method: string;\n  timestamp: Date;\n  responseSize: number;\n  cached: boolean;\n}\n\nclass ApiUsageTracker {\n  private metrics: UsageMetric[] = [];\n  private dailyUsage: Map\u003Cstring, number> = new Map();\n\n  track(metric: Omit\u003CUsageMetric, 'timestamp'>): void {\n    this.metrics.push({\n      ...metric,\n      timestamp: new Date(),\n    });\n\n    \u002F\u002F Update daily counter\n    const today = new Date().toISOString().split('T')[0];\n    const key = `${today}:${metric.endpoint}`;\n    this.dailyUsage.set(key, (this.dailyUsage.get(key) || 0) + 1);\n  }\n\n  getUsageReport(days = 7): any {\n    const now = Date.now();\n    const cutoff = now - days * 24 * 60 * 60 * 1000;\n\n    const recentMetrics = this.metrics.filter(\n      m => m.timestamp.getTime() > cutoff\n    );\n\n    \u002F\u002F Group by endpoint\n    const byEndpoint: Record\u003Cstring, number> = {};\n    recentMetrics.forEach(m => {\n      byEndpoint[m.endpoint] = (byEndpoint[m.endpoint] || 0) + 1;\n    });\n\n    \u002F\u002F Calculate cache hit rate\n    const cacheHits = recentMetrics.filter(m => m.cached).length;\n    const cacheHitRate = recentMetrics.length > 0\n      ? cacheHits \u002F recentMetrics.length\n      : 0;\n\n    \u002F\u002F Identify optimization opportunities\n    const opportunities = this.identifyOpportunities(byEndpoint, cacheHitRate);\n\n    return {\n      period: `${days} days`,\n      totalRequests: recentMetrics.length,\n      byEndpoint,\n      cacheHitRate: `${(cacheHitRate * 100).toFixed(1)}%`,\n      estimatedSavings: this.calculateSavings(recentMetrics),\n      opportunities,\n    };\n  }\n\n  private identifyOpportunities(\n    byEndpoint: Record\u003Cstring, number>,\n    cacheHitRate: number\n  ): string[] {\n    const opportunities: string[] = [];\n\n    \u002F\u002F High-frequency endpoints that could be cached\n    Object.entries(byEndpoint).forEach(([endpoint, count]) => {\n      if (count > 1000 && !endpoint.includes('create')) {\n        opportunities.push(\n          `High volume on ${endpoint} (${count} requests) - consider caching`\n        );\n      }\n    });\n\n    \u002F\u002F Low cache hit rate\n    if (cacheHitRate \u003C 0.3) {\n      opportunities.push(\n        `Low cache hit rate (${(cacheHitRate * 100).toFixed(1)}%) - improve caching strategy`\n      );\n    }\n\n    return opportunities;\n  }\n\n  private calculateSavings(metrics: UsageMetric[]): string {\n    const totalRequests = metrics.length;\n    const cachedRequests = metrics.filter(m => m.cached).length;\n\n    \u002F\u002F Estimate cost per request (varies by plan)\n    const costPerRequest = 0.001;  \u002F\u002F Example: $0.001 per request\n\n    const savedRequests = cachedRequests;\n    const savings = savedRequests * costPerRequest;\n\n    return `$${savings.toFixed(2)} saved from ${savedRequests} cached requests`;\n  }\n}\n\nexport const usageTracker = new ApiUsageTracker();\n```\n\n### Step 2: Smart Caching Strategy\n\n```typescript\n\u002F\u002F src\u002Fcache\u002Fsmart-cache.ts\n\ninterface CacheStrategy {\n  ttlSeconds: number;\n  staleWhileRevalidate: boolean;\n  priority: 'high' | 'medium' | 'low';\n}\n\nconst cacheStrategies: Record\u003Cstring, CacheStrategy> = {\n  \u002F\u002F Static data - cache longer\n  'locations': { ttlSeconds: 3600, staleWhileRevalidate: true, priority: 'low' },\n  'users': { ttlSeconds: 1800, staleWhileRevalidate: true, priority: 'low' },\n  'assets': { ttlSeconds: 900, staleWhileRevalidate: true, priority: 'medium' },\n\n  \u002F\u002F Dynamic data - cache shorter\n  'workorders:list': { ttlSeconds: 60, staleWhileRevalidate: true, priority: 'high' },\n  'workorders:single': { ttlSeconds: 300, staleWhileRevalidate: true, priority: 'medium' },\n};\n\nclass SmartCache {\n  private cache: CacheManager;\n\n  async getOrFetch\u003CT>(\n    key: string,\n    fetchFn: () => Promise\u003CT>,\n    strategyKey: string\n  ): Promise\u003CT> {\n    const strategy = cacheStrategies[strategyKey] || {\n      ttlSeconds: 300,\n      staleWhileRevalidate: false,\n      priority: 'medium',\n    };\n\n    \u002F\u002F Try cache first\n    const cached = await this.cache.get\u003CT>(key);\n\n    if (cached) {\n      usageTracker.track({\n        endpoint: strategyKey,\n        method: 'GET',\n        responseSize: 0,\n        cached: true,\n      });\n\n      \u002F\u002F Stale-while-revalidate: return cached, refresh in background\n      if (strategy.staleWhileRevalidate) {\n        this.revalidateInBackground(key, fetchFn, strategy);\n      }\n\n      return cached;\n    }\n\n    \u002F\u002F Fetch fresh data\n    const data = await fetchFn();\n\n    usageTracker.track({\n      endpoint: strategyKey,\n      method: 'GET',\n      responseSize: JSON.stringify(data).length,\n      cached: false,\n    });\n\n    \u002F\u002F Cache the result\n    await this.cache.set(key, data, strategy.ttlSeconds);\n\n    return data;\n  }\n\n  private async revalidateInBackground\u003CT>(\n    key: string,\n    fetchFn: () => Promise\u003CT>,\n    strategy: CacheStrategy\n  ): Promise\u003Cvoid> {\n    \u002F\u002F Don't await - runs in background\n    fetchFn()\n      .then(data => this.cache.set(key, data, strategy.ttlSeconds))\n      .catch(err => console.error('Background revalidation failed:', err));\n  }\n}\n```\n\n### Step 3: Webhook-Based Updates\n\n```typescript\n\u002F\u002F src\u002Fsync\u002Fwebhook-sync.ts\n\n\u002F\u002F Instead of polling, use webhooks to stay in sync\nclass WebhookBasedSync {\n  private localCache: Map\u003Cstring, any> = new Map();\n\n  constructor() {\n    \u002F\u002F Initialize cache from MaintainX on startup\n    this.initializeCache();\n\n    \u002F\u002F Register webhook handlers\n    this.registerWebhookHandlers();\n  }\n\n  private async initializeCache(): Promise\u003Cvoid> {\n    console.log('Initializing local cache from MaintainX...');\n\n    \u002F\u002F One-time full sync\n    const workOrders = await getAllWorkOrders(client, { status: 'OPEN' });\n    workOrders.forEach(wo => this.localCache.set(`workorder:${wo.id}`, wo));\n\n    console.log(`Cached ${workOrders.length} work orders`);\n  }\n\n  private registerWebhookHandlers(): void {\n    \u002F\u002F Update cache from webhooks instead of polling\n    on('workorder.created', async (event) => {\n      this.localCache.set(`workorder:${event.data.id}`, event.data);\n    });\n\n    on('workorder.updated', async (event) => {\n      this.localCache.set(`workorder:${event.data.id}`, event.data);\n    });\n\n    on('workorder.deleted', async (event) => {\n      this.localCache.delete(`workorder:${event.data.id}`);\n    });\n  }\n\n  \u002F\u002F Get data from cache - no API call needed\n  getWorkOrder(id: string): WorkOrder | undefined {\n    return this.localCache.get(`workorder:${id}`);\n  }\n\n  \u002F\u002F Only call API when data doesn't exist locally\n  async getWorkOrderWithFallback(id: string): Promise\u003CWorkOrder> {\n    const cached = this.localCache.get(`workorder:${id}`);\n    if (cached) return cached;\n\n    \u002F\u002F Fallback to API\n    const workOrder = await client.getWorkOrder(id);\n    this.localCache.set(`workorder:${id}`, workOrder);\n    return workOrder;\n  }\n}\n\n\u002F\u002F Cost comparison:\n\u002F\u002F Polling every 30 seconds = 2,880 requests\u002Fday = $2.88\u002Fday (at $0.001\u002Frequest)\n\u002F\u002F Webhooks = ~100 events\u002Fday = $0.10\u002Fday (at $0.001\u002Frequest)\n\u002F\u002F Savings = 96.5%\n```\n\n### Step 4: Request Batching\n\n```typescript\n\u002F\u002F src\u002Foptimization\u002Fbatch-requests.ts\n\n\u002F\u002F Instead of individual requests, batch where possible\nclass BatchRequestManager {\n  private pendingWorkOrderIds: Set\u003Cstring> = new Set();\n  private batchTimeout: NodeJS.Timeout | null = null;\n  private batchResolvers: Map\u003Cstring, (wo: WorkOrder) => void> = new Map();\n\n  async getWorkOrder(id: string): Promise\u003CWorkOrder> {\n    return new Promise((resolve) => {\n      this.pendingWorkOrderIds.add(id);\n      this.batchResolvers.set(id, resolve);\n\n      \u002F\u002F Schedule batch execution\n      if (!this.batchTimeout) {\n        this.batchTimeout = setTimeout(() => this.executeBatch(), 50);\n      }\n    });\n  }\n\n  private async executeBatch(): Promise\u003Cvoid> {\n    const ids = Array.from(this.pendingWorkOrderIds);\n    this.pendingWorkOrderIds.clear();\n    this.batchTimeout = null;\n\n    if (ids.length === 0) return;\n\n    console.log(`Batching ${ids.length} work order requests`);\n\n    \u002F\u002F Fetch all at once (if API supports batch endpoint)\n    \u002F\u002F Otherwise, parallel fetch with rate limiting\n    const workOrders = await Promise.all(\n      ids.map(id => client.getWorkOrder(id))\n    );\n\n    \u002F\u002F Resolve individual promises\n    workOrders.forEach((wo, i) => {\n      const resolver = this.batchResolvers.get(ids[i]);\n      if (resolver) {\n        resolver(wo);\n        this.batchResolvers.delete(ids[i]);\n      }\n    });\n\n    \u002F\u002F Cost savings: 10 individual requests -> 1 batch = 90% reduction\n  }\n}\n```\n\n### Step 5: Efficient Data Fetching\n\n```typescript\n\u002F\u002F src\u002Foptimization\u002Fefficient-fetch.ts\n\n\u002F\u002F Only fetch what you need\nasync function fetchMinimalWorkOrderData(\n  client: MaintainXClient,\n  params: WorkOrderQueryParams\n): Promise\u003CWorkOrderSummary[]> {\n  const response = await client.getWorkOrders({\n    ...params,\n    \u002F\u002F Request only necessary fields if API supports field selection\n    \u002F\u002F fields: ['id', 'title', 'status', 'priority', 'dueDate'],\n    limit: params.limit || 50,  \u002F\u002F Don't over-fetch\n  });\n\n  \u002F\u002F Transform to minimal objects\n  return response.workOrders.map(wo => ({\n    id: wo.id,\n    title: wo.title,\n    status: wo.status,\n    priority: wo.priority,\n    dueDate: wo.dueDate,\n  }));\n}\n\n\u002F\u002F Pagination with early termination\nasync function fetchUntilCondition(\n  client: MaintainXClient,\n  condition: (wo: WorkOrder) => boolean,\n  params: WorkOrderQueryParams = {}\n): Promise\u003CWorkOrder[]> {\n  const results: WorkOrder[] = [];\n  let cursor: string | undefined;\n\n  do {\n    const response = await client.getWorkOrders({ ...params, cursor, limit: 100 });\n\n    for (const wo of response.workOrders) {\n      if (condition(wo)) {\n        results.push(wo);\n      } else {\n        \u002F\u002F Early termination - don't fetch more pages\n        return results;\n      }\n    }\n\n    cursor = response.nextCursor || undefined;\n  } while (cursor && results.length \u003C 1000);  \u002F\u002F Safety limit\n\n  return results;\n}\n```\n\n### Step 6: Cost Dashboard\n\n```typescript\n\u002F\u002F src\u002Fmonitoring\u002Fcost-dashboard.ts\n\ninterface CostReport {\n  period: string;\n  totalRequests: number;\n  estimatedCost: number;\n  byEndpoint: Record\u003Cstring, { count: number; cost: number }>;\n  recommendations: string[];\n}\n\nfunction generateCostReport(days = 30): CostReport {\n  const usage = usageTracker.getUsageReport(days);\n\n  \u002F\u002F Cost per request (adjust based on your plan)\n  const costPerRequest = 0.001;\n\n  const byEndpoint: Record\u003Cstring, { count: number; cost: number }> = {};\n  Object.entries(usage.byEndpoint).forEach(([endpoint, count]) => {\n    byEndpoint[endpoint] = {\n      count: count as number,\n      cost: (count as number) * costPerRequest,\n    };\n  });\n\n  \u002F\u002F Sort by cost descending\n  const sortedEndpoints = Object.entries(byEndpoint)\n    .sort((a, b) => b[1].cost - a[1].cost);\n\n  const recommendations: string[] = [];\n\n  \u002F\u002F Top cost endpoint\n  if (sortedEndpoints.length > 0) {\n    const [topEndpoint, topUsage] = sortedEndpoints[0];\n    recommendations.push(\n      `Highest cost: ${topEndpoint} ($${topUsage.cost.toFixed(2)}) - ` +\n      `Consider caching or webhooks`\n    );\n  }\n\n  \u002F\u002F Low cache hit rate\n  const cacheHitRate = parseFloat(usage.cacheHitRate);\n  if (cacheHitRate \u003C 50) {\n    const potentialSavings = usage.totalRequests * 0.5 * costPerRequest;\n    recommendations.push(\n      `Cache hit rate is ${cacheHitRate.toFixed(0)}% - ` +\n      `Improving to 50% could save $${potentialSavings.toFixed(2)}`\n    );\n  }\n\n  return {\n    period: `${days} days`,\n    totalRequests: usage.totalRequests,\n    estimatedCost: usage.totalRequests * costPerRequest,\n    byEndpoint,\n    recommendations,\n  };\n}\n```\n\n## Output\n\n- API usage tracking implemented\n- Smart caching strategy\n- Webhook-based sync instead of polling\n- Request batching\n- Cost dashboard and reports\n\n## Cost Savings Summary\n\n| Optimization | Before | After | Savings |\n|-------------|--------|-------|---------|\n| Caching | 10,000\u002Fday | 4,000\u002Fday | 60% |\n| Webhooks vs polling | 2,880\u002Fday | 100\u002Fday | 97% |\n| Batching | 500\u002Fday | 100\u002Fday | 80% |\n| Total estimate | 13,380\u002Fday | 4,200\u002Fday | 69% |\n\n## Resources\n\n- [MaintainX Pricing](https:\u002F\u002Fwww.getmaintainx.com\u002Fpricing)\n- [MaintainX API Documentation](https:\u002F\u002Fmaintainx.dev\u002F)\n\n## Next Steps\n\nFor architecture patterns, see `maintainx-reference-architecture`.\n",{"name":5,"author":55,"license":15,"version":56,"description":57,"allowed-tools":58},"Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Optimize MaintainX API usage for cost efficiency.\nUse when managing API costs, optimizing request volume,\nor implementing cost-effective integration patterns with MaintainX.\nTrigger with phrases like \"maintainx cost\", \"maintainx billing\",\n\"reduce maintainx usage\", \"maintainx api costs\", \"maintainx optimization\".\n","Read, Write, Edit, Bash(npm:*)","main","90b50ed0778745a80fd5bfb13b1843d45b9e82f7","tests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fmaintainx-pack\u002Fskills\u002Fmaintainx-cost-tuning",234,"https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust","https:\u002F\u002Fgithub.com\u002FDicklesworthstone","https:\u002F\u002Fwww.jeffreyemanuel.com\u002F","Building in NY","2026-11-13 11:50:27",{"source":8,"skillName":5,"commands":69,"prompt":79,"zipAvailable":80},[70,73,76],{"tool":71,"command":72},"npx","npx skills add Dicklesworthstone\u002Fpi_agent_rust --skill maintainx-cost-tuning",{"tool":74,"command":75},"bunx","bunx skills add Dicklesworthstone\u002Fpi_agent_rust --skill maintainx-cost-tuning",{"tool":77,"command":78},"pnpm","pnpm dlx skills add Dicklesworthstone\u002Fpi_agent_rust --skill maintainx-cost-tuning","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FDicklesworthstone\u002Fpi_agent_rust\u002Fblob\u002Fmain\u002Ftests\u002Fext_conformance\u002Fartifacts\u002Fplugins-community\u002Fplugins\u002Fsaas-packs\u002Fmaintainx-pack\u002Fskills\u002Fmaintainx-cost-tuning\u002FSKILL.md",true,[],[83,122,146,172,199,221],{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":87,"licenseFileUrl":88,"sourceHtmlUrl":89,"categories":90,"keywords":96,"publishedAt":50},"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",[91],{"categoryNo":92,"categoryName":93,"taxonomyType":94,"taxonomyTypeDesc":95},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,42,115,116,117,118,119,31,120,121],"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","multi","jsx","suite",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":87,"licenseFileUrl":126,"sourceHtmlUrl":127,"categories":128,"keywords":133,"publishedAt":50},"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",[129,132],{"categoryNo":130,"categoryName":131,"taxonomyType":94,"taxonomyTypeDesc":95},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":92,"categoryName":93,"taxonomyType":94,"taxonomyTypeDesc":95},[134,135,136,102,137,138,98,139,140,141,112,142,143,144,145,34,31],"testing","webapp testing","webapp","screenshots","playwright","debugging","toolkit","browser","logs","applications","behavior","local",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":150,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":50},"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",[],[154,155,156,157,158,159,160,161,42,162,163,164,165,166,167,168,34,169,170,171,31,28],"analysis","neuropixels analysis","spike","metrics","data","open","quality","user","recordings","Neural","motion","visual","quality metrics","unit","sorting","curation","recording","load",{"skillNo":173,"name":174,"nameZh":6,"description":175,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":87,"licenseFileUrl":176,"sourceHtmlUrl":177,"categories":178,"keywords":182,"publishedAt":50},"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",[179],{"categoryNo":180,"categoryName":181,"taxonomyType":94,"taxonomyTypeDesc":95},"01JBSEEDCAT000000000000023","Skill与智能体开发",[183,184,185,186,187,188,189,190,191,192,193,194,195,196,34,31,197,28,198],"skill creator","creator","workflows","create","update","capabilities","knowledge","tool","integrations","specialized","guide","new skill","existing skill","users","Existing","new",{"skillNo":200,"name":201,"nameZh":6,"description":202,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":203,"sourceHtmlUrl":204,"categories":205,"keywords":207,"publishedAt":50},"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",[206],{"categoryNo":180,"categoryName":181,"taxonomyType":94,"taxonomyTypeDesc":95},[201,208,209,210,211,212,213,141,214,215,42,216,217,218,219,31,220],"google","browser automation","gemini","automation","auth","code","library","management","only","document","query","Citation","source",{"skillNo":222,"name":223,"nameZh":6,"description":224,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":87,"licenseFileUrl":225,"sourceHtmlUrl":226,"categories":227,"keywords":234,"publishedAt":50},"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",[228,231],{"categoryNo":229,"categoryName":230,"taxonomyType":94,"taxonomyTypeDesc":95},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":232,"categoryName":233,"taxonomyType":94,"taxonomyTypeDesc":95},"01JBSEEDCAT000000000000016","图像与多媒体",[235,236,237,184,238,113,239,240,189,42,241,196,242,243,244,31,29,28],"slack gif creator","slack","gif","validation","constraints","Animation","me","make","Utilities","concepts"]