---
name: "Surface API rate limit warnings in chat"
---

# Story 365: Surface API rate limit warnings in chat

## User Story

As a project owner watching the chat, I want to see rate limit warnings surfaced directly in the conversation when they appear in the agent's PTY output, so that I know immediately when an agent is being throttled without having to watch server logs.

## Acceptance Criteria

- [x] Server detects rate limit warnings in pty-debug output lines
- [x] When a rate limit warning is detected, a notification is sent to the active chat (Matrix/Slack/WhatsApp)
- [x] The notification includes which agent/story triggered the rate limit
- [x] Rate limit notifications are debounced to avoid spamming the chat with repeated warnings

## Technical Context

Claude Code emits `rate_limit_event` JSON in its streaming output:

```json
{
  "type": "rate_limit_event",
  "rate_limit_info": {
    "status": "allowed_warning",
    "resetsAt": 1774443600,
    "rateLimitType": "seven_day",
    "utilization": 0.82,
    "isUsingOverage": false,
    "surpassedThreshold": 0.75
  }
}
```

Key fields:
- `status`: `"allowed_warning"` when approaching limit, likely `"blocked"` or similar when hard-limited
- `rateLimitType`: e.g. `"seven_day"` rolling window
- `utilization`: 0.0–1.0 fraction of limit consumed
- `resetsAt`: Unix timestamp when the window resets
- `surpassedThreshold`: the threshold that triggered the warning (e.g. 0.75 = 75%)

These events are already logged as `[pty-debug] raw line:` in the server logs. The PTY reader in `server/src/llm/providers/claude_code.rs` (line ~234) sees them but doesn't currently parse or act on them.

## Out of Scope

- TBD

## Test Results

<!-- huskies-test-results: {"unit":[{"name":"rate_limit_event_json_sends_watcher_warning","status":"pass","details":"PTY reader detects rate_limit_event JSON and emits RateLimitWarning watcher event"},{"name":"rate_limit_warning_sends_notification_with_agent_and_story","status":"pass","details":"Notification listener sends chat message with agent and story info"},{"name":"rate_limit_warning_is_debounced","status":"pass","details":"Second warning within 60s window is suppressed"},{"name":"rate_limit_warnings_for_different_agents_both_notify","status":"pass","details":"Different agents are debounced independently"},{"name":"format_rate_limit_notification_includes_agent_and_story","status":"pass","details":"Notification text includes story number, name, and agent name"},{"name":"format_rate_limit_notification_falls_back_to_item_id","status":"pass","details":"Falls back to item_id when story name is unavailable"}],"integration":[]} -->

### Unit Tests (6 passed, 0 failed)

- ✅ rate_limit_event_json_sends_watcher_warning — PTY reader detects rate_limit_event JSON and emits RateLimitWarning watcher event
- ✅ rate_limit_warning_sends_notification_with_agent_and_story — Notification listener sends chat message with agent and story info
- ✅ rate_limit_warning_is_debounced — Second warning within 60s window is suppressed
- ✅ rate_limit_warnings_for_different_agents_both_notify — Different agents are debounced independently
- ✅ format_rate_limit_notification_includes_agent_and_story — Notification text includes story number, name, and agent name
- ✅ format_rate_limit_notification_falls_back_to_item_id — Falls back to item_id when story name is unavailable

### Integration Tests (0 passed, 0 failed)

*No integration tests recorded.*
