Research covers: - Claude Code plugin best practices from Anthropic - TUI design principles from lazygit, btop, and awesome-tuis - Ink/React terminal UI performance patterns - Current architecture problems analysis - Architecture recommendations Key findings: - Event-driven over polling for real-time updates - Use <Static> component for stable UI sections - Custom hooks + useReducer for state management - Keep bash hooks minimal, move logic to TypeScript 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8.0 KiB
Claude HUD Research Findings
This document captures research conducted to inform the architecture and implementation of claude-hud v2.
1. Claude Code Plugin Best Practices
Sources
Key Principles
-
Low-level and Unopinionated: Claude Code provides close to raw model access without forcing specific workflows. This design philosophy creates a flexible, customizable, scriptable, and safe power tool.
-
Plugin Components:
- Hooks: Customize behavior at key points (PreToolUse, PostToolUse, Stop, SessionStart, SessionEnd, etc.)
- Commands: Slash commands defined in markdown files
- Skills: Knowledge and workflows bundled together
- Subagents: Purpose-built agents for specialized tasks
- MCP Servers: Connect to tools and data sources
-
Hook Architecture:
- Hooks execute shell scripts in response to lifecycle events
- Input is provided via environment variables and stdin (JSON)
- Output is captured from stdout
- Non-blocking writes to FIFOs are critical for performance
-
Best Practices:
- Use CLAUDE.md for project-specific guidance
- Commands can use
$ARGUMENTSfor parameterization - MCP servers can be project-scoped, global, or checked in
- Debug with
--mcp-debugflag
Implications for claude-hud
- Event-driven over polling: Hooks provide real-time events; polling should be minimized
- Non-blocking I/O: Critical for not slowing down Claude Code
- Session lifecycle awareness: Need to handle SessionStart, SessionEnd, and session switching gracefully
2. TUI Design Principles (lazygit, btop, etc.)
Sources
What Makes Great TUIs
-
Visual Organization & Consistency
- Set of boxes ("views") with consistent behavior
- Most views visible at all times (unless zoomed)
- Strong visual hierarchy
-
Core UX Principles
- Simplicity
- Consistency
- Discoverability
- Sane defaults
- Shortcuts for common flows
- Interactivity
-
Enhanced Visualization
- Present complex information in structured, readable ways
- Use graphs and charts for time-series data
- Make patterns visible at a glance
-
Keyboard-Driven Navigation
- Vim-style keybindings (h/j/k/l, q to quit)
- Consistent across the application
- / for filtering, y for copy
-
Reduced Context Switching
- All relevant information in one view
- No need to switch to other terminals/tools
-
Learning Curve & Discoverability
- Stick to familiar terms and abstractions
- Guide users through complex operations
- Make advanced features discoverable
Implications for claude-hud
- Single canonical layout: Don't overcomplicate with modes
- Information density: Show what matters most prominently
- Consistency: Same patterns throughout the UI
- Glanceable: Key metrics visible at a glance
- No interactivity needed: View-only is fine for a metrics dashboard
3. Ink/React Terminal UI Patterns
Sources
Key Features & Patterns
-
Core Components
<Text>: Fundamental text rendering with colors, styling<Box>: Flexbox-based layout container<Static>: Renders content once, never updates (CRITICAL for performance)<Transform>: Output transformation utility
-
Performance Optimization
Frame Rate Control:
<App> // Configure max FPS to reduce CPU usage<Static>Component (CRITICAL):- Renders items permanently above the UI
- Cannot update after display
- Perfect for logs, completed items
- Almost 2x more performant in Ink 3
- Used by Jest, Tap, Gatsby for large outputs
Incremental Rendering:
- Only updates changed lines
- Reduces flickering
- Better for frequently updating UIs
-
Focus Management
useFocushook for component focususeFocusManagerfor complex navigation- Tab to cycle through focusable components
-
Console Logging
- Ink intercepts console.log/error
- Displays correctly above the UI
- Prevents interference with rendering
Critical Performance Insight
The <Static> component is key for preventing flickering:
- Use for persistent headers, completed items
- Only dynamic content should re-render
- Separating static from dynamic prevents full redraws
Implications for claude-hud
- Use
<Static>strategically: Headers, section dividers should not re-render - Minimize re-renders: Only update components that actually changed
- Memoization: Use React.memo, useMemo, useCallback
- Debounce rapid updates: Context updates shouldn't cause rapid re-renders
- Single source of truth: Avoid multiple polling sources causing conflicting updates
4. Current Architecture Problems
Based on analysis of the existing codebase:
Data Flow Issues
- Multiple polling sources (30s each): settings, context, transcript
- Race conditions: FIFO cleanup timing issues
- Silent error handling: Errors swallowed, hard to debug
- State inconsistency: Multiple sources can cause flickering
Code Quality Issues
- app.tsx is 300+ lines: Too much in one file
- Type assertions: Using
asinstead of proper discriminated unions - No linting/formatting: Inconsistent code style
- Missing tests: Several components untested
Session Handling Issues
- Session attachment fails: /new /exit /resume don't work smoothly
- No cleanup on session switch: Stale data persists
5. Architecture Recommendations
Based on research, here are the recommended approaches:
State Management
Recommendation: Custom hooks + useReducer
- Not XState (overkill for this use case)
- Not Context API alone (prop drilling isn't an issue)
- Custom hooks encapsulate related state logic
- useReducer for complex state transitions
Data Flow
Recommendation: Event-driven with minimal polling
- Primary: Hook events via FIFO (real-time)
- Secondary: Single consolidated poll for data not in events
- Eliminate redundant polling sources
Shell Scripts
Recommendation: Keep bash for hooks, move logic to TypeScript
- Hooks MUST be shell scripts (Claude Code requirement)
- But keep them minimal - just pass data to FIFO
- Complex logic in TypeScript (testable)
Session Handling
Recommendation: Session ID in events + graceful reconnection
- Track session ID in all events
- Detect session changes and reset state
- Reconnect FIFO with exponential backoff
6. Action Items from Research
- Refactor to event-driven architecture: Single FIFO, minimal polling
- Use
<Static>for stable UI sections: Prevent unnecessary re-renders - Extract state to custom hooks: useContextState, useToolStream, etc.
- Add proper error handling: No silent catches, structured logging
- Implement session tracking: Detect /new /exit /resume
- Add ESLint + Prettier: Consistent code quality
- Comprehensive tests: Especially for state transitions