A powerful CLI tool and library for monitoring rate limits across multiple LLM providers (Claude, Gemini, and z.ai). Perfect for developers, automation scripts, and monitoring systems that need to track API usage and avoid rate limit errors.
- Features
- Installation
- Quick Start
- Prerequisites
- Usage
- Output Format
- Configuration
- API Reference
- Use Cases
- Development
- FAQ
- Contributing
- License
- ✅ Multi-Provider Support: Check rate limits for Claude, Gemini, and z.ai in one command
- ✅ CLI & Library: Use as a standalone CLI tool or integrate into your Node.js projects
- ✅ JSON Output: Structured JSON output perfect for automation and monitoring
- ✅ Real-time Status: Get current usage and reset times for each provider
- ✅ Zero Configuration: Works out of the box with provider CLIs already installed
- ✅ TypeScript Support: Fully typed for TypeScript projects
- ✅ Lightweight: Minimal dependencies, fast execution
npm install -g @shaharia-lab/ai-limit-checkernpm install @shaharia-lab/ai-limit-checkerAfter installing globally, run with the --tools flag to specify which providers to check:
ai-limit-checker --tools=claude,gemini,zaiThe --tools flag is required and accepts comma-separated provider names.
Example Output:
[
{
"provider": "claude",
"status": "available",
"resetAt": 1704384000000,
"resetAtHuman": "2024-01-04T16:00:00.000Z"
},
{
"provider": "gemini",
"status": "rate_limit_exceed",
"resetAt": 1704393000000,
"resetAtHuman": "2024-01-04T18:30:00.000Z"
},
{
"provider": "zai",
"status": "available",
"resetAt": 1704412800000,
"resetAtHuman": "2024-01-05T00:00:00.000Z"
}
]- Node.js: Version 18.0.0 or higher
- npm: Latest version recommended
- Claude CLI: Install from claude.ai/code
- Ensure you're logged in:
claude
- Gemini CLI: Install from Google AI Studio
- Authentication configured with your API key
- Chrome Browser: Required for Playwright automation
- Environment Variables: Configure Chrome directories (see Configuration)
The --tools flag is required and specifies which providers to check.
# Check all providers
ai-limit-checker --tools=claude,gemini,zai
# Check only Claude
ai-limit-checker --tools=claude
# Check Claude and Gemini
ai-limit-checker --tools=claude,gemini
# Check only z.ai
ai-limit-checker --tools=zaiThe tool will automatically skip providers that are not available on your system and display a warning message:
- Claude: Skipped if the
claudeCLI is not installed - Gemini: Skipped if the
geminiCLI is not installed - z.ai: Skipped if Chrome environment variables (
CHROME_OUTPUT_DIR,CHROME_USER_DATA_DIR) are not set
Skipped providers will return status: "available" with resetAtHuman: "Unknown (skipped)".
#!/bin/bash
# Check if any provider is rate limited
result=$(ai-limit-checker --tools=claude,gemini,zai)
if echo "$result" | grep -q "rate_limit_exceed"; then
echo "Warning: One or more providers are rate limited!"
echo "$result" | jq '.[] | select(.status=="rate_limit_exceed")'
exit 1
fi
echo "All providers available"Add to your crontab to check limits every hour:
0 * * * * /usr/local/bin/ai-limit-checker --tools=claude,gemini,zai >> /var/log/llm-limits.log 2>&1import { checkLimits } from '@shaharia-lab/ai-limit-checker';
async function main() {
try {
// Check specific providers
const limits = await checkLimits(['claude', 'gemini', 'zai']);
// Or check all providers (no arguments)
// const limits = await checkLimits();
for (const limit of limits) {
console.log(`${limit.provider}: ${limit.status}`);
if (limit.resetAtHuman) {
console.log(` Resets at: ${limit.resetAtHuman}`);
}
}
} catch (error) {
console.error('Error checking limits:', error);
}
}
main();import { checkLimits, type LlmLimitStatus } from '@shaharia-lab/ai-limit-checker';
async function getAvailableProvider(): Promise<string | null> {
const limits = await checkLimits();
// Find the first available provider
const available = limits.find(limit => limit.status === 'available');
if (available) {
console.log(`Using ${available.provider}`);
return available.provider;
}
// All providers rate limited - find the one that resets soonest
const soonest = limits
.filter(l => l.resetAt && l.resetAt > 0)
.sort((a, b) => (a.resetAt! - b.resetAt!))[0];
if (soonest) {
const waitTime = soonest.resetAt! - Date.now();
console.log(`All providers limited. ${soonest.provider} resets in ${waitTime}ms`);
}
return null;
}
// Use in your application
const provider = await getAvailableProvider();
if (provider) {
// Make your API request to the available provider
}import { ClaudeClient, GeminiClient, ZaiClient } from '@shaharia-lab/ai-limit-checker';
// Check only Claude
const claudeClient = new ClaudeClient();
const claudeStatus = await claudeClient.getUsageStats();
console.log(`Claude session usage: ${claudeStatus.sessionUsed}%`);
// Check only Gemini
const geminiClient = new GeminiClient();
const geminiUsage = await geminiClient.getUsageStats();
geminiUsage.forEach(model => {
console.log(`${model.model}: ${model.usage}% (resets in ${model.resets})`);
});
// Check only z.ai (requires Chrome configuration)
const zaiClient = new ZaiClient({
outputDir: process.env.CHROME_OUTPUT_DIR!,
userDataDir: process.env.CHROME_USER_DATA_DIR!,
});
const zaiLimits = await zaiClient.getUsageQuota();
const tokensLimit = zaiLimits.find(l => l.type === 'TOKENS_LIMIT');
console.log(`z.ai tokens used: ${tokensLimit?.percentage}%`);Each provider returns a status object with the following structure:
interface LlmLimitStatus {
provider: string; // Provider name: 'claude', 'gemini', or 'zai'
status: 'rate_limit_exceed' | 'available'; // Current status
resetAt?: number; // Unix timestamp (ms) when limit resets
resetAtHuman?: string; // ISO 8601 formatted date string
}| Status | Description |
|---|---|
available |
Provider is operational and accepting requests |
rate_limit_exceed |
Provider has reached its rate limit threshold |
[
{
"provider": "claude",
"status": "available",
"resetAt": 1704384000000,
"resetAtHuman": "2024-01-04T16:00:00.000Z"
},
{
"provider": "gemini",
"status": "available",
"resetAt": 1704470400000,
"resetAtHuman": "2024-01-05T16:00:00.000Z"
},
{
"provider": "zai",
"status": "available",
"resetAt": 1704412800000,
"resetAtHuman": "2024-01-05T00:00:00.000Z"
}
][
{
"provider": "claude",
"status": "available",
"resetAt": 1704384000000,
"resetAtHuman": "2024-01-04T16:00:00.000Z"
},
{
"provider": "gemini",
"status": "rate_limit_exceed",
"resetAt": 1704393000000,
"resetAtHuman": "2024-01-04T18:30:00.000Z"
},
{
"provider": "zai",
"status": "available",
"resetAt": 0,
"resetAtHuman": "Unknown"
}
]z.ai requires Chrome browser automation using Playwright. Follow these steps:
mkdir -p ~/.chrome-data
mkdir -p ~/.chrome-outputLaunch Chrome with a persistent user data directory and log into z.ai:
google-chrome --user-data-dir="$HOME/.chrome-data"Note: On macOS, use:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir="$HOME/.chrome-data"- Navigate to z.ai
- Complete the login process
- Close the browser window
Add these to your shell profile (~/.bashrc, ~/.zshrc, or ~/.profile):
export CHROME_OUTPUT_DIR="$HOME/.chrome-output"
export CHROME_USER_DATA_DIR="$HOME/.chrome-data"Then reload your shell:
source ~/.bashrc # or ~/.zshrcecho $CHROME_OUTPUT_DIR
echo $CHROME_USER_DATA_DIRBoth should output the paths you set.
For project-specific configuration, create a .env file:
CHROME_OUTPUT_DIR=/path/to/chrome/output
CHROME_USER_DATA_DIR=/path/to/chrome/user-dataThen load it in your script:
import { config } from 'dotenv';
config();
import { checkLimits } from '@shaharia-lab/ai-limit-checker';
// ...Main function that checks provider limits.
function checkLimits(tools?: ProviderName[]): Promise<LlmLimitStatus[]>
type ProviderName = 'claude' | 'gemini' | 'zai';Parameters:
tools(optional): Array of provider names to check. If not provided, checks all providers.
Returns: Promise that resolves to an array of status objects for the specified providers.
Examples:
// Check specific providers
const limits = await checkLimits(['claude', 'gemini']);
// Check all providers
const allLimits = await checkLimits();Client for checking Claude CLI usage.
class ClaudeClient {
async getUsageStats(): Promise<ClaudeStatusInfo>
}
interface ClaudeStatusInfo {
sessionUsed: number; // Session usage percentage (0-100)
sessionResetTime: string; // Human-readable reset time
weeklyUsed: number; // Weekly usage percentage (0-100)
weeklyResetTime: string; // Human-readable weekly reset time
hasSubscription: boolean; // Whether user has a subscription
}Client for checking Gemini CLI usage.
class GeminiClient {
async getUsageStats(): Promise<GeminiModelUsage[]>
}
interface GeminiModelUsage {
model: string; // Model name (e.g., "gemini-2.5-flash")
requests: string; // Number of requests or "-"
usage: string; // Usage percentage
resets: string; // Time until reset (e.g., "2h 30m")
}Client for checking z.ai usage via browser automation.
class ZaiClient {
constructor(config: ZaiConfig)
async getUsageQuota(): Promise<ZaiLimit[]>
}
interface ZaiConfig {
outputDir: string; // Chrome output directory
userDataDir: string; // Chrome user data directory
}
interface ZaiLimit {
type: string; // Limit type (e.g., "TOKENS_LIMIT")
percentage: number; // Usage percentage (0-100)
nextResetTime?: number; // Unix timestamp of next reset
// ... other fields
}# .github/workflows/check-llm-limits.yml
name: Check LLM Limits
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
jobs:
check-limits:
runs-on: ubuntu-latest
steps:
- name: Install AI Limit Checker
run: npm install -g @shaharia-lab/ai-limit-checker
- name: Check Limits
run: |
ai-limit-checker --tools=claude,gemini,zai > limits.json
cat limits.json
- name: Alert on Rate Limit
run: |
if grep -q "rate_limit_exceed" limits.json; then
echo "::warning::One or more LLM providers are rate limited"
fiimport { checkLimits } from '@shaharia-lab/ai-limit-checker';
class LLMLoadBalancer {
async getOptimalProvider(): Promise<string> {
const limits = await checkLimits();
// Prefer available providers
const available = limits.filter(l => l.status === 'available');
if (available.length > 0) {
// Return random available provider for load distribution
return available[Math.floor(Math.random() * available.length)].provider;
}
// All limited - queue request for soonest reset
const soonest = limits
.filter(l => l.resetAt && l.resetAt > 0)
.sort((a, b) => a.resetAt! - b.resetAt!)[0];
throw new Error(`All providers limited. Retry after ${soonest.resetAtHuman}`);
}
}import { checkLimits } from '@shaharia-lab/ai-limit-checker';
import express from 'express';
const app = express();
app.get('/api/llm-status', async (req, res) => {
try {
const limits = await checkLimits();
res.json({
timestamp: new Date().toISOString(),
providers: limits,
healthy: limits.every(l => l.status === 'available')
});
} catch (error) {
res.status(500).json({ error: 'Failed to check limits' });
}
});
app.listen(3000, () => console.log('Dashboard running on http://localhost:3000'));import { checkLimits } from '@shaharia-lab/ai-limit-checker';
async function selectCostEffectiveProvider(preferCheaper: boolean = true) {
const limits = await checkLimits();
const available = limits.filter(l => l.status === 'available');
if (available.length === 0) {
throw new Error('No providers available');
}
// Example: Gemini is cheaper than Claude for most tasks
const costOrder = preferCheaper
? ['gemini', 'zai', 'claude']
: ['claude', 'zai', 'gemini'];
for (const provider of costOrder) {
if (available.some(a => a.provider === provider)) {
return provider;
}
}
return available[0].provider;
}- Node.js >= 18.0.0
- npm or yarn
- Git
# Clone the repository
git clone https://github.com/shaharia-lab/ai-limit-checker.git
cd ai-limit-checker
# Install dependencies
npm install
# Build the project
npm run build
# Link for local testing
npm linkai-limit-checker/
├── src/
│ ├── claude/ # Claude CLI client
│ ├── gemini/ # Gemini CLI client
│ ├── zai/ # z.ai browser automation client
│ ├── config/ # Environment configuration
│ ├── index.ts # Main library exports
│ └── cli.ts # CLI entry point
├── dist/ # Compiled JavaScript
├── package.json
├── tsconfig.json
└── README.md
npm run build# After linking
ai-limit-checker --tools=claude,gemini
# Or run directly
node dist/cli.js --tools=claudeA: No. The tool will gracefully skip providers that are not available on your system and display a warning message. Skipped providers return available status with resetAtHuman: "Unknown (skipped)".
A: The --tools flag is required and specifies which providers to check. It accepts comma-separated provider names (e.g., --tools=claude,gemini,zai). This allows you to check only the providers you're interested in.
A: It depends on your usage. For active development, checking every 5-10 minutes is reasonable. For production monitoring, every hour is usually sufficient.
A: The tool works fine without z.ai configured. Simply don't set the CHROME_OUTPUT_DIR and CHROME_USER_DATA_DIR environment variables. The z.ai check will return available status with unknown reset time.
A: Yes! For z.ai support in Docker, you'll need to install Chrome and configure Playwright. See the Playwright Docker documentation for details.
A: Yes! The tool is cross-platform. Note that Chrome paths may differ:
- Windows:
C:\Program Files\Google\Chrome\Application\chrome.exe - macOS:
/Applications/Google Chrome.app/Contents/MacOS/Google Chrome - Linux:
google-chromeorchromium-browser
A: Very accurate. The tool uses the same interfaces (CLIs and web interfaces) that you use manually, ensuring the data is as current as what the providers report.
A: Absolutely! We welcome contributions. Please see our Contributing section and open a PR.
We welcome contributions! Here's how you can help:
- Use the GitHub Issues page
- Include your Node.js version, OS, and error messages
- Provide steps to reproduce the issue
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Run tests and build:
npm run build - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
To add support for a new LLM provider:
- Create a new directory under
src/(e.g.,src/newprovider/) - Implement
client.tswith the provider's API/CLI interface - Define types in
types.ts - Update
src/index.tsto include the new provider incheckLimits() - Add documentation to README.md
- Submit a PR!
This project is licensed under the MIT License - see the LICENSE file for details.
- npm Package: https://www.npmjs.com/package/@shaharia-lab/ai-limit-checker
- GitHub Repository: https://github.com/shaharia-lab/ai-limit-checker
- Issue Tracker: https://github.com/shaharia-lab/ai-limit-checker/issues
- Changelog: https://github.com/shaharia-lab/ai-limit-checker/releases
- Built with Playwright for browser automation
- Uses node-pty for CLI interaction
- Developed by Shaharia Lab
Made with ❤️ by the Shaharia Lab team
If you find this tool useful, please consider giving it a ⭐ on GitHub!