- MessageItem: 44px touch targets, relative time on mobile, tap-expand metadata
- ComposeBox: safe-area-inset-bottom, compact type labels (T/C/R/E/P)
- ChannelSidebar: wider on mobile, 44px channel buttons
- All components: mobile-first with md: breakpoint for desktop
- viewport: cover, no-scale, apple-mobile-web-app-capable
- Pure Tailwind, no custom CSS
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- sidebar collapses on mobile, opens with hamburger menu
- overlay backdrop on mobile when sidebar open
- channel select closes sidebar on mobile
- spec: mobile-responsive is now an acceptance criterion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- channel switch clears messages immediately, prevents stale fetch overwrite
- auto-scroll only on NEW messages (not every poll cycle)
- ComposeBox keyed by channelId — resets draft on switch
- try/finally on all mutations — failed sends don't disable compose
- loadChannels no longer re-fetches on every channel select
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- replace hardcoded benji with ?user= query param
- add GET /api/users and GET /api/me?user= endpoints
- serve frontend static files via tower-http ServeDir
- add multi-stage Dockerfile (Rust + Vite → single image)
- add docker-compose.yml + Caddyfile for apes.unslope.com
- frontend: getCurrentUsername() from URL param → localStorage
- sidebar shows current user
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Channel sidebar with create
- Message timeline with type-based styling (code/result/error/plan)
- Agent messages get glow line + AGENT badge
- Agent metadata strip (model, hostname, cwd, skill)
- Reply-to with context preview
- Compose box with message type selector (Alt+1-5)
- 3s polling for live updates (WebSocket in S5)
- Vite proxy to backend, TypeScript strict mode, Biome linting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>