rate-limit-safeguards
Skill0 starsChanged 6 months agoMITView on GitHub
This skill documents the architecture and operational patterns for preventing API rate-limit crashes in automated AI agent task loops. The core insight: never inject tasks into a session that cannot respond. Instead, queue them and drain slowly on recovery. Born from a real incident where a feedback loop of automated prompts into a rate-limited session extended the lockout period catastrophically. The queue system eliminates that class of failure. Apply these safeguards whenever: - You are building or modifying a scheduled…
In this repository17 other files it gives its agents.
- blog-banner-creationSkill
- daily-blog-draftSkill
- image-generationSkill
- script-to-speechSkill
- company-deep-diveSkill
- email-verificationSkill
- funnel-playbookSkill
- google-ads-auditSkill
- landing-page-funnelSkill
- linkedin-content-image-typesSkill
- viral-comment-strategySkill
- autonomous-task-reliabilitySkill
- build-your-brainSkill
- diagram-generatorSkill
- expert-councilSkill
- liaclSkill
- parallel-researchSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 6 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 36
Dedup by type: If the same task type is already in the queue, the duplicate is dropped silently.
- Distinctive: line 48
If either signal is fresh, the session is responsive.
- Distinctive: line 94
When queue size reaches 10+ items, an alert is sent to the operator via your preferred notification channel (Telegram, Slack, email, etc.) …
- Distinctive: line 130
Stale detection: If lock older than TTL, automatically reclaimed (prevents a crashed task from permanently blocking the queue)
- Distinctive: line 146
Principle: Prefer sequential spawning with spacing over concurrent hard caps.
- Distinctive: line 208
Add the drain block at the start of your main loop (before any new injections):
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Rate Limit Safeguards & Task Queue System
Overview
This skill documents the architecture and operational patterns for preventing API rate-limit crashes in automated AI agent task loops. The core insight: never inject tasks into a session that cannot respond. Instead, queue them and drain slowly on recovery.
Born from a real incident where a feedback loop of automated prompts into a rate-limited session extended the lockout period catastrophically. The queue system eliminates that class of failure.
When to Use
Apply these safeguards whenever:
- You are building or modifying a scheduled task injection system
- You are spawning 3+ agents in a single session
- You observe signs of rate-limit pressure (slow responses, early compaction, growing queue)
- You are designing any system that sends repeated automated prompts to an AI session
Architecture
Queue System
Tasks that cannot be injected immediately are stored in a JSON queue file and drained slowly once the session recovers. No task is ever lost -- just spaced out.
/tmp/task_queue.jsonQueue entry structure:
{"type": "task-type-name", "message": "...", "queued_at": 1743500000}Dedup by type: If the same task type is already in the queue, the duplicate is dropped silently. This prevents backlog explosion for recurring tasks.
Responsiveness Detection
session_is_responsive() uses two signals:
- Activity file modification time -- checks the most recently modified activity file
for your session. If modified within
RECENT_THRESHOLD=300seconds (5 minutes), session is considered active. - Human interaction file -- checks a human interaction timestamp file against the same 300-second threshold.
If either signal is fresh, the session is responsive. Both stale = unresponsive = queue mode.
inject_or_queue Routing
Central routing function called by every scheduled task:
inject_or_queue "task-type" "$TASK_MESSAGE" "$SESSION"Decision tree:
SESSION_RESPONSIVE == trueANDCYCLE_INJECTIONS < MAX_INJECTIONS_PER_CYCLE-> Acquire lock, inject via tmux send-keys, increment counter, release lock- Any other condition
->
queue_task()-- append to JSON queue, log "Queued task:<type>"
Queue Drain on Recovery
At the start of each cycle, if the session is responsive and the queue is non-empty:
drain_queue 2 30 "$SESSION"Parameters:
max_drain=2-- drain at most 2 tasks per cyclespacing=30-- wait 30 seconds between each drained task- Oldest entries drained first (sorted by
queued_at) - Drained count is added to
CYCLE_INJECTIONSbefore any new injections
Cycle Injection Cap
MAX_INJECTIONS_PER_CYCLE=3Total injections (queue drain + new) per 30-minute cycle. This prevents API overload when multiple tasks become due simultaneously (e.g., after a 2-hour outage clears).
Budget allocation example:
- Queue had 5 items -> drain 2 (uses 2 of 3 slots)
- 1 new task slot remaining for new tasks this cycle
- Remaining 3 queue items defer to next cycle automatically
Alert System
When queue size reaches 10+ items, an alert is sent to the operator via your preferred notification channel (Telegram, Slack, email, etc.) once per alert period. Use a guard file to prevent repeated alerts. Alert resets when queue drops below 10.
Implementation
Key Configuration Values
| Variable | Value | Purpose |
TASK_QUEUE_FILE | /tmp/task_queue.json | Queue storage |
RECENT_THRESHOLD | 300 (5 min) | Responsiveness window |
MAX_INJECTIONS_PER_CYCLE | 3 | Per-cycle injection cap |
LOCK_TTL | 900 (15 min) | Lock staleness threshold |
| Queue alert threshold | 10 items | Alert trigger |
| Drain per cycle | 2 | Max queue drain per cycle |
| Drain spacing | 30s | Delay between drained tasks |
Key Functions
| Function | Purpose |
session_is_responsive() | Returns 0 if session active, 1 if stale |
inject_or_queue(type, msg, session) | Routes task to injection or queue |
queue_task(type, message) | Appends to JSON queue with dedup |
drain_queue(max, spacing, session) | Drains N oldest tasks with spacing |
queue_size() | Returns current queue length |
acquire_lock(name) | Creates lock file. Returns 1 if held. |
release_lock(name) | Removes lock file (caller must be holder) |
Lock System
Prevents multiple simultaneous tmux injections:
- Lock file:
/tmp/task_inject_lock - TTL: 15 minutes (
LOCK_TTL=900) - Stale detection: If lock older than TTL, automatically reclaimed (prevents a crashed task from permanently blocking the queue)
inject_or_queuehandles lock internally. Callers do NOT call acquire/release directly.
Agent Spawning Guidelines
These are separate from the task queue but address the same root cause: API overload from too many concurrent requests.
| Scenario | Approach |
| 1-2 independent agents | Parallel is fine |
| 3+ agents | Sequential -- wait for each to complete before spawning next |
| Background agents | Max 2 concurrent. Use run_in_background: true. |
| After spawning background agent | Wait at least 30 seconds before spawning another |
Principle: Prefer sequential spawning with spacing over concurrent hard caps. Spacing prevents API burst without sacrificing throughput on single-agent tasks.
What Caused the Original Crash
Root cause: Automated prompts kept firing into a rate-limited session.
Mechanism:
- The AI session hit API rate limits -- session became unresponsive
- Scheduled tasks continued injecting every 30 minutes
- Each injection consumed API tokens (the tmux send-keys itself triggered API calls)
- The token consumption extended the rate-limit lockout period
- Extended lockout meant more tasks piled up, compounding the problem
- Feedback loop sustained itself for hours
Fix applied: The queue system prevents injection entirely when the session is unresponsive. Tasks accumulate in JSON without touching the API. When the session recovers, they drain slowly (2 per cycle, 30s spacing, under the 3-injection cap), staying well under per-minute limits.
Recovery Protocol
When rate-limited:
- Automatic handling -- the queue system accumulates tasks in the queue file without injecting them. No manual intervention needed.
- When session recovers -- next cycle detects responsiveness, drains up to 2 queued tasks with 30-second spacing, respecting the 3-injection cap.
- If outage exceeds ~5 cycles (~150 min) -- queue grows to 10+ items, operator is alerted. They can assess whether manual intervention is needed.
- Resume normal operations -- once session activity resumes, the queue drains automatically over subsequent cycles.
- Manual drain -- the queue self-resolves. No manual intervention needed unless the alert
fires and the operator determines the backlog is stale/irrelevant (in which case:
echo "[]" > /tmp/task_queue.json).
Signs of Approaching Rate Limits
Watch for these early warning signals:
- Response times increasing noticeably
- Tool calls taking longer than usual
- Context compaction firing earlier than expected
- Task queue growing (check:
python3 -c "import json; print(len(json.load(open('/tmp/task_queue.json'))))") - Alert notification about queue size
Adoption Guide
To adopt this pattern in your own AI agent setup:
- Implement the queue functions:
session_is_responsive()queue_task()drain_queue()queue_size()inject_or_queue()acquire_lock()/release_lock()
- Replace all direct
tmux send-keysinjection calls withinject_or_queue "type" "$MSG" "$SESSION" - Add the drain block at the start of your main loop (before any new injections):
SESSION_RESPONSIVE="false" CYCLE_INJECTIONS=0 if session_is_responsive; then SESSION_RESPONSIVE="true" Q_SIZE=$(queue_size) if [[ $Q_SIZE -gt 0 ]]; then DRAINED=$(drain_queue 2 30 "$SESSION") CYCLE_INJECTIONS=$((CYCLE_INJECTIONS + DRAINED)) fi fi - Set alert thresholds appropriate for your notification channel and operator preferences.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

