The Claude Code CLI v2.1.45+ emits a `rate_limit_event` message type that
the Python SDK v0.1.19 cannot parse, raising MessageParseError. Two bugs
resulted:
1. **False-positive rate limit**: check_rate_limit_error() matched
"rate_limit" in the exception string "Unknown message type:
rate_limit_event" via both an explicit type check and a regex fallback,
triggering 15-19s backoff + query re-send on every session.
2. **One-message-behind**: The MessageParseError killed the
receive_response() async generator, but the CLI subprocess was still
alive with buffered response data. Catching and returning meant the
response was never consumed. The next send_message() would read the
previous response first, creating a one-behind offset.
Changes:
- chat_constants.py: check_rate_limit_error() now returns (False, None)
for any MessageParseError, blocking both false-positive paths. Added
safe_receive_response() helper that retries receive_response() on
MessageParseError — the SDK's decoupled producer/consumer architecture
(anyio memory channel) allows the new generator to continue reading
remaining messages without data loss. Removed calculate_rate_limit_backoff
re-export and MAX_CHAT_RATE_LIMIT_RETRIES constant.
- spec_chat_session.py, assistant_chat_session.py, expand_chat_session.py:
Replaced retry-with-backoff loops with safe_receive_response() wrapper.
Removed asyncio.sleep backoff, query re-send, and rate_limited yield.
Cleaned up unused imports (asyncio, calculate_rate_limit_backoff,
MAX_CHAT_RATE_LIMIT_RETRIES).
- agent.py: Added inner retry loop around receive_response() with same
MessageParseError skip-and-restart pattern. Removed early-return that
truncated responses.
- types.ts: Removed SpecChatRateLimitedMessage,
AssistantChatRateLimitedMessage, and their union entries.
- useSpecChat.ts, useAssistantChat.ts, useExpandChat.ts: Removed dead
'rate_limited' case handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Claude CLI sends `rate_limit_event` messages that the SDK's
`parse_message()` doesn't recognize, raising `MessageParseError` and
crashing all three chat session types (spec, assistant, expand).
Changes:
- Bump claude-agent-sdk minimum from 0.1.0 to 0.1.39
- Add `check_rate_limit_error()` helper in chat_constants.py that
detects rate limits from both MessageParseError data payloads and
error message text patterns
- Wrap `receive_response()` loops in all three `_query_claude()` methods
with retry-on-rate-limit logic (up to 3 retries with backoff)
- Gracefully log and skip non-rate-limit MessageParseError instead of
crashing the session
- Add `rate_limited` message type to frontend TypeScript types and
handle it in useSpecChat, useAssistantChat, useExpandChat hooks to
show "Rate limited. Retrying in Xs..." system messages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete project rebrand from AutoCoder to AutoForge, touching 62 files
across Python backend, FastAPI server, React UI, documentation, config,
and CI/CD.
Key changes:
- Rename autocoder_paths.py -> autoforge_paths.py with backward-compat
migration from .autocoder/ -> .autoforge/ directories
- Update registry.py to migrate ~/.autocoder/ -> ~/.autoforge/ global
config directory with fallback support
- Update security.py with fallback reads from legacy .autocoder/ paths
- Rename .claude/commands and skills from gsd-to-autocoder-spec to
gsd-to-autoforge-spec
- Update all Python modules: client, prompts, progress, agent,
orchestrator, server routers and services
- Update React UI: package.json name, index.html title, localStorage
keys, all documentation sections, component references
- Update start scripts (bat/sh/py), examples, and .env.example
- Update CLAUDE.md and README.md with new branding and paths
- Update test files for new .autoforge/ directory structure
- Transfer git remote from leonvanzyl/autocoder to
AutoForgeAI/autoforge
Backward compatibility preserved: legacy .autocoder/ directories are
auto-detected and migrated on next agent start. Config fallback chain
checks both new and old paths.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>