diff --git a/AGENTS.md b/AGENTS.md
index 3d94034e..04df2a8f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -50,9 +50,10 @@ app/ # Next.js App Router (all source code)
├── api/chat/sse/ # SSE endpoint for real-time chat updates
├── assets/ # Static assets (fonts, images)
├── components/ # Shared React components (with co-located tests)
+├── config.ts # Site metadata, links, external usernames
├── health/ # Health check endpoint for monitoring
├── lib/ # Utility libraries and core logic
-│ └── discord/ # Discord API and Gateway integration
+│ └── discord/ # Discord API, Gateway, and bot integration
├── listening/[[...period]]/ # Listening stats page (optional catch-all)
│ └── components/ # Route-specific components
├── layout.tsx # Root layout
@@ -60,6 +61,7 @@ app/ # Next.js App Router (all source code)
├── global-error.tsx # Global error boundary
└── global-not-found.tsx # Global 404 page
+instrumentation.ts # Server startup hooks (bot subscription)
mocks/ # Test mocks (MSW handlers, env vars)
```
@@ -72,9 +74,19 @@ mocks/ # Test mocks (MSW handlers, env vars)
- `@/*` → `app/*`
- `@/mocks/*` → `mocks/*`
+### Next.js Config
+
+Key settings in `next.config.ts`:
+
+- `output: "standalone"` — self-contained build for Docker deployment
+- `cacheComponents: true` — Next.js 16 Cache Components
+- `reactCompiler: true` — React Compiler (auto-memoization)
+- `typedRoutes: true` — type-safe `` hrefs
+- `experimental: { globalNotFound: true }` — top-level 404 page
+
### Typed Routes
-`typedRoutes` is enabled for type-safe `` hrefs. For optional catch-all routes like `[[...param]]`, use a trailing slash to link to the base path (e.g., `/listening/` not `/listening`).
+For optional catch-all routes like `[[...param]]`, use a trailing slash to link to the base path (e.g., `/listening/` not `/listening`).
### Environment Variables
@@ -101,6 +113,7 @@ Set `SKIP_ENV_VALIDATION=true` to skip validation (used in CI/Docker).
- **Gateway** (`app/lib/discord/gateway.ts`): WebSocket for real-time notifications with auto-reconnect and heartbeat
- **SSE** (`app/api/chat/sse/route.ts`): Streams chat updates to clients
- DataLoader with LRU cache (100 entries) batches user info requests
+- Rate limit "gate" system prevents retry storms when Discord returns 429s
- Messages from site use "username: content" prefix format for attribution
### WakaTime Integration
@@ -116,9 +129,10 @@ Set `SKIP_ENV_VALIDATION=true` to skip validation (used in CI/Docker).
### Anthropic Integration (simon-bot)
-- `app/lib/anthropic.ts`: Claude Haiku 4.5 for chat responses
-- Triggered by "simon-bot" mention (case-insensitive, word boundary: `/\bsimon[- ]?bot\b/i`)
-- 5-second timeout, runs async via Next.js `after()` to avoid blocking
+- `app/lib/anthropic.ts`: Claude Haiku 4.5 for chat responses with tool use (chat history, WakaTime, Last.fm)
+- `app/lib/discord/bot.ts`: Bot logic — triggered by "simon-bot" mention (regex: `/\bsimon[- ]?bot\b/i`)
+- Started at server boot via `instrumentation.ts` → `startBotSubscription()` (long-lived Gateway WebSocket subscription, not per-request)
+- 5-second timeout per API call, Redis-based message deduplication (60s TTL) across instances
- Responses posted as threaded Discord replies
## Patterns