agentleFS
puretechnycpuretechnyc/purebrain-skills/skills/operations/rate-limit-safeguards/SKILL.md

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…

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
  1. Distinctive:

    Dedup by type: If the same task type is already in the queue, the duplicate is dropped silently.

    line 36
  2. Distinctive:

    If either signal is fresh, the session is responsive.

    line 48
  3. Distinctive:

    When queue size reaches 10+ items, an alert is sent to the operator via your preferred notification channel (Telegram, Slack, email, etc.) …

    line 94
  4. Distinctive:

    Stale detection: If lock older than TTL, automatically reclaimed (prevents a crashed task from permanently blocking the queue)

    line 130
  5. Distinctive:

    Principle: Prefer sequential spawning with spacing over concurrent hard caps.

    line 146
  6. Distinctive:

    Add the drain block at the start of your main loop (before any new injections):

    line 208

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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.json

Queue 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:

  1. Activity file modification time -- checks the most recently modified activity file for your session. If modified within RECENT_THRESHOLD=300 seconds (5 minutes), session is considered active.
  2. 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 == true AND CYCLE_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 cycle
  • spacing=30 -- wait 30 seconds between each drained task
  • Oldest entries drained first (sorted by queued_at)
  • Drained count is added to CYCLE_INJECTIONS before any new injections

Cycle Injection Cap

MAX_INJECTIONS_PER_CYCLE=3

Total 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

VariableValuePurpose
TASK_QUEUE_FILE/tmp/task_queue.jsonQueue storage
RECENT_THRESHOLD300 (5 min)Responsiveness window
MAX_INJECTIONS_PER_CYCLE3Per-cycle injection cap
LOCK_TTL900 (15 min)Lock staleness threshold
Queue alert threshold10 itemsAlert trigger
Drain per cycle2Max queue drain per cycle
Drain spacing30sDelay between drained tasks

Key Functions

FunctionPurpose
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_queue handles 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.

ScenarioApproach
1-2 independent agentsParallel is fine
3+ agentsSequential -- wait for each to complete before spawning next
Background agentsMax 2 concurrent. Use run_in_background: true.
After spawning background agentWait 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:

  1. The AI session hit API rate limits -- session became unresponsive
  2. Scheduled tasks continued injecting every 30 minutes
  3. Each injection consumed API tokens (the tmux send-keys itself triggered API calls)
  4. The token consumption extended the rate-limit lockout period
  5. Extended lockout meant more tasks piled up, compounding the problem
  6. 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:

  1. Automatic handling -- the queue system accumulates tasks in the queue file without injecting them. No manual intervention needed.
  2. When session recovers -- next cycle detects responsiveness, drains up to 2 queued tasks with 30-second spacing, respecting the 3-injection cap.
  3. If outage exceeds ~5 cycles (~150 min) -- queue grows to 10+ items, operator is alerted. They can assess whether manual intervention is needed.
  4. Resume normal operations -- once session activity resumes, the queue drains automatically over subsequent cycles.
  5. 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:

  1. Implement the queue functions:
    • session_is_responsive()
    • queue_task()
    • drain_queue()
    • queue_size()
    • inject_or_queue()
    • acquire_lock() / release_lock()
  2. Replace all direct tmux send-keys injection calls with inject_or_queue "type" "$MSG" "$SESSION"
  3. 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
  4. Set alert thresholds appropriate for your notification channel and operator preferences.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.