-
Notifications
You must be signed in to change notification settings - Fork 232
[Feature]: #355
Description
Issue Type
- ✨
feature- New feature (non-breaking change which adds functionality) - ⚡
performance- Performance improvement - 🖥️
backend- Backend-related feature - 🎨
frontend- Frontend-related feature
Component Scope
Frontend (React/UI)
Problem Statement
When Claude Code session hooks produce stdout output (e.g., SessionStart hooks injecting context), the messages arrive as type "system" with a content string and no subtype. These get routed to the ChatMessage component (chat bubble) instead of the collapsible SystemMessage card.
This makes session startup very noisy — multiple hooks can produce 50+ lines of context text that fills the chat view before the user sees any actual conversation. Users with several hooks configured see a wall of system text every time they start or resume a session.
Proposed Solution
The SystemMessage component already handles system content messages — it checks via isSystemContentMessage (type === "system" with content string and no subtype) and strips ANSI codes for display. But the message list render router never sends these messages there.
The fix is adding one type check in the render routing chain, before the isChatMessage fallback:
Current routing:
isSystemOrResultMessage → SystemMessage
isToolUseMessage → ToolUseMessage
isToolResultMessage → ToolResultMessage
isPlanMessage → PlanMessage
isThinkingMessage → ThinkingMessage
isTodoMessage → TodoMessage
isChatMessage → ChatMessage ← system content falls through here
Fixed routing:
isSystemOrResultMessage → SystemMessage
isToolUseMessage → ToolUseMessage
isToolResultMessage → ToolResultMessage
isPlanMessage → PlanMessage
isThinkingMessage → ThinkingMessage
isTodoMessage → TodoMessage
isSystemContentMessage → SystemMessage ← NEW: catch hook output
isChatMessage → ChatMessage
No new components or props needed — just connecting existing detection and rendering code.
Use Cases
- SessionStart hooks: Users who inject project context, calendar info, or workflow reminders via hooks see clean collapsible cards instead of wall of text
- Multiple hooks: Users with 3-5 hooks (common in project setups) can collapse all of them and immediately see the conversation
- Resuming sessions: Every resume triggers hooks again — collapsed cards prevent re-reading the same context repeatedly
Alternatives Considered
- Suppressing hook output entirely: loses useful information, users sometimes want to verify hooks ran
- Patching the compiled dist/ after install: fragile, breaks on updates
- Forking the repo, unnecessary maintenance burden for a one-line routing fix
The proposed solution is better because it uses existing code and gives users collapsible cards they can expand when needed.
Priority
Medium - Would significantly improve my workflow
Implementation Complexity (if known)
Simple - Small change or addition
Implementation Considerations
The isSystemContentMessage function (checks type === "system" && "content" in msg && typeof content === "string" && !("subtype" in msg)) and the SystemMessage rendering path for these messages already exist in the codebase. The change is one additional conditional in the message list renderer's routing chain. No dependencies, no breaking changes, no performance impact.
Examples or Mockups
Currently, hook output looks like this in the chat:
[full-width chat bubble]
Claude
You have access to Nextcloud Calendar via the Chronos MCP server...
Key details:
- CalDAV endpoint: ...
- User: ...
(20+ more lines)
[another full-width chat bubble]
Claude
IMPORTANT: Before starting any project work, run: git pull
Then read brainbox/CLAUDE.md...
(15+ more lines)
With the fix, these would render as:
[System] ▶ (collapsed, one line each — click to expand)
Contribution
- I would be willing to implement this feature myself
- I would be willing to help test this feature
- I would be willing to help with documentation
- I would be willing to provide feedback during development
Additional Context
Discovered while performance-testing Claude Code web UIs. The routing gap appears intentional in the SystemMessage component (it has the content rendering path) but the message list renderer never directs traffic there.
Checklist
- I have searched existing issues and feature requests to make sure this is not a duplicate
- I have provided a clear problem statement and proposed solution
- I understand that feature requests are prioritized based on community needs and maintainer capacity