Maintainx Rate LimitsSAFE
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Overview
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
4f83675ca38aOBSERVED · 2026-10-09Host compatibility
What the documentation claims. We have not run a compatibility test.
| Host | Status | Notes |
|---|---|---|
| claude-code | mentioned | |
| cursor | mentioned |
What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
--- name: maintainx-rate-limits description: 'Implement MaintainX API rate limiting, pagination, and backoff patterns. Use when handling rate limit errors, implementing retry logic, or optimizing API request throughput for MaintainX. Trigger with phrases like "maintainx rate limit", "maintainx throttling", "maintainx 429", "maintainx retry", "maintainx backoff", "maintainx pagination". ' allowed-tools: Read, Write, Edit version: 1.11.0 license: MIT author: Jeremy Longshore <[email protected]> tags: - saas - maintainx - api compatibility: Designed for Claude Code --- # MaintainX Rate Limits ## Overview Handle MaintainX API rate limits gracefully with exponential backoff, cursor-based pagination, and request queuing to maximize throughput without triggering 429 errors. ## Prerequisites - MaintainX API access configured - Node.js 18+ with `axios` - Understanding of async/await patterns ## Instructions ### Step 1: Rate-Limited Client Wrapper ```typescript // src/rate-limited-client.ts import axios, { AxiosInstance, AxiosError } from 'axios'; export class RateLimitedClient { private http: AxiosInstance; private requestQueue: Array<() => void> = []; private activeRequests = 0; private maxConcurrent = 5; private minDelayMs = 100; // 10 requests/second max constructor(apiKey?: string) { const key = apiKey || process.env.MAINTAINX_API_KEY; if (!key) throw new Error('MAINTAINX_API_KEY required'); this.http = axios.create({ baseURL: 'https://api.getmaintainx.com/v1', headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json', }, timeout: 30_000, }); } private async throttle(): Promise<void> { if (this.activeRequests >= this.maxConcurrent) { await new Promise<void>((resolve) => this.requestQueue.push(resolve)); } this.activeRequests++; await new Promise((r) => setTimeout(r, this.minDelayMs)); } private release() { this.activeRequests--; const next = this.requestQueue.shift(); if (next) next(); } async request<T>(method: string, url: string, data?: any, params?: any): Promise<T> { await this.throttle(); try { const response = await this.retryWithBackoff( () => this.http.request<T>({ method, url, data, params }), ); return response.data; } finally { this.release(); } } private async retryWithBackoff<T>( fn: () => Promise<T>, maxRetries = 3, baseDelay = 1000, // 1 second initial backoff delay ): Promise<T> { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await fn(); } catch (err) { const axiosErr = err as AxiosError; const status = axiosErr.response?.status; if (status !== 429 && !(status && status >= 500) || attempt === maxRetries) { throw err; } // Honor Retry-After header const retryAfter = axiosErr.response?.headers?.['retry-after']; const delayMs = retryAfter ? parseInt(retryAfter) * 1000 : baseDelay * Math.pow(2, attempt) + Math.random() * 500; console.warn( `Rate limited (HTTP ${status}). Retry ${attempt + 1}/${maxRetries} in ${Math.round(delayMs)}ms`, ); await new Promise((r) => setTimeout(r, delayMs)); } } throw new Error('Unreachable'); } } ``` ### Step 2: Cursor-Based Pagination MaintainX returns a `cursor` field in list responses. Pass it as a query parameter to fetch the next page. ```typescript async function paginateAll<T>( client: RateLimitedClient, endpoint: string, resultKey: string, params?: Record<string, any>, ): Promise<T[]> { const allItems: T[] = []; let cursor: string | undefined; do { const response: any = await client.request('GET', endpoint, undefined, { ...params, limit: 100, cursor, }); const items = response[resultKey] as T[]; allItems.push(...items); cursor = response.cursor ?? undefined; // Log progress for long-running operations if (allItems.length % 500 === 0) { console.log(` Fetched ${allItems.length} items so far...`); } } while (cursor); return allItems; } // Usage const allWorkOrders = await paginateAll(client, '/workorders', 'workOrders', { status: 'OPEN', }); console.log(`Total: ${allWorkOrders.length} open work orders`); ``` ### Step 3: Batch Operations with p-queue ```typescript import PQueue from 'p-queue'; // 5 concurrent requests, max 10 per second const queue = new PQueue({ concurrency: 5, interval: 1000, // 1 second window for rate cap intervalCap: 10, }); async function batchUpdate( client: RateLimitedClient, updates: Array<{ id: number; data: any }>, ) { const results = await Promise.allSettled( updates.map((update) => queue.add(() => client.request('PATCH', `/workorders/${update.id}`, update.data), ), ), ); const succeeded = results.filter((r) => r.status === 'fulfilled').length; const failed = results.filter((r) => r.status === 'rejected').length; console.log(`Batch update: ${succeeded} succeeded, ${failed} failed`); return results; } // Close 100 completed work orders const completedOrders = await paginateAll( client, '/workorders', 'workOrders', { status: 'COMPLETED' }, ); await batchUpdate( client, completedOrders.map((wo: any) => ({ id: wo.id, data: { status: 'CLOSED' } })), ); ``` ### Step 4: Rate Limit Monitoring ```typescript // src/rate-monitor.ts class RateMonitor { private requests: number[] = []; private windowMs = 60_000; // 1 minute window record() { this.requests.push(Date.now()); this.cleanup(); } cleanup() { const cutoff = Date.now() - this.windowMs; this.requests = this.requests.filter((t) => t > cutoff); } getRate(): number { this.cleanup(); return this.requests.length; } report() { const rate = this.getRate(); const
Trust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | PASS |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (0)
No findings outside the package's declared scope.
Gates applied: no_behavioural_pass.
4f83675ca38afull audit observations/trust-audit/skill/jeremylongshore__maintainx-rate-limits.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-09 | 4f83675ca38a | SAFE | B | 89 | first audit |
Questions
What does the Maintainx Rate Limits skill do?
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Is Maintainx Rate Limits safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Maintainx Rate Limits access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
Which assistants does Maintainx Rate Limits work with?
Its documentation mentions claude-code and cursor. That is what the text claims, not a compatibility test we ran.
How current is this page?
The grade is for one exact copy of the source (4f83675ca38a), read on 2026-10-09. The repository is watched, and a new audit runs when it changes — this is the first audit.