Skip to content

Commit a90648c

Browse files
committed
docs: add technical architecture docs and research reports
Add remaining phases documentation, transport specification, hook display implementation slice, and research reports on third-party remote control. - Add REMAINING_PHASES.md with current MVP status and scope - Add transports.md with transport provider behavior and stability - Add IMPL_SLICE_HOOK_DISPLAY.md for hook timeline implementation - Add research reports on remote control API availability and patterns
1 parent 399f3f0 commit a90648c

6 files changed

Lines changed: 2002 additions & 0 deletions
Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
# Implementation Slice: Hook Event Display
2+
3+
> **Status:** PROPOSED
4+
> **Date:** 2026-03-21
5+
> **Priority:** P0 (First testable user experience)
6+
7+
## Executive Summary
8+
9+
This implementation slice delivers **one complete end-to-end flow**: Claude Code session events flow from hooks to mobile app and render as OpenCode-style tool cards. This is the highest-value slice because:
10+
11+
1. **Primary integration path** - Hooks are the documented way to observe Claude Code sessions
12+
2. **Minimal dependencies** - No Agent SDK API key required for observation mode
13+
3. **Immediate verification** - User can see tool_use/tool_result events appear in real-time
14+
4. **Architecture-preserving** - Agent-agnostic event types with Claude-specific adapters
15+
16+
---
17+
18+
## Scope Definition
19+
20+
### In Scope
21+
22+
| Component | Scope | Lines Changed (Est.) |
23+
|-----------|-------|---------------------|
24+
| **Mobile: Event State** | Riverpod providers for incoming `claude_event` messages | ~200 |
25+
| **Mobile: Tool Card Widget** | OpenCode-style card for tool_use/tool_result | ~300 |
26+
| **Mobile: Event Timeline** | Scrolling list of events with timestamps | ~150 |
27+
| **Bridge: Protocol Verification** | End-to-end test for hook → websocket flow | ~100 |
28+
| **Docs: Setup Guide** | How to configure Claude Code hooks for ReCursor | ~100 |
29+
30+
**Total estimated:** ~850 lines across 8-10 files
31+
32+
### Explicitly Deferred (Future Slices)
33+
34+
| Deferred Item | Rationale |
35+
|---------------|-----------|
36+
| Agent SDK chat interface | Requires API key, separate user flow |
37+
| Approval workflow | Requires session state management |
38+
| Git diff rendering | Depends on tool result parsing |
39+
| Settings/configuration UI | Not needed for first flow |
40+
41+
---
42+
43+
## Architecture Context
44+
45+
```
46+
┌─────────────────────────────────────────────────────────────────┐
47+
│ IMPLEMENTATION SLICE │
48+
├─────────────────────────────────────────────────────────────────┤
49+
│ │
50+
│ Claude Code ──POST──► Bridge ──WebSocket──► Mobile ──Display │
51+
│ │ │ │ │
52+
│ Hooks.json /hooks/event claude_event ToolCard │
53+
│ │ │ │
54+
│ (Existing) (New Provider) (New Widget)│
55+
│ │
56+
└─────────────────────────────────────────────────────────────────┘
57+
```
58+
59+
**What already exists (preserve):**
60+
- Bridge: `/hooks/event` endpoint (packages/bridge/src/hooks/receiver.ts)
61+
- Bridge: EventQueue with broadcast (packages/bridge/src/hooks/event_queue.ts)
62+
- Bridge: Protocol mapper for hook events to BridgeMessage (packages/bridge/src/hooks/protocol_mapper.ts)
63+
- Mobile: WebSocket service receiving messages (apps/mobile/lib/core/network/websocket_service.dart)
64+
- Mobile: BridgeMessage types including `claudeEvent` (apps/mobile/lib/core/network/websocket_messages.dart)
65+
66+
**What's missing:**
67+
- Mobile: State management to transform incoming `claude_event` messages into UI-usable models
68+
- Mobile: Tool card widget rendering (OpenCode-style)
69+
- Mobile: Timeline/scrollable list to display events
70+
71+
---
72+
73+
## Implementation Plan
74+
75+
### Phase 1: Mobile Event State (Est. 200 lines, 2-3 files)
76+
77+
**Goal:** Transform incoming `claude_event` WebSocket messages into typed, observable state.
78+
79+
#### Files to Create/Modify
80+
81+
| File | Action | Description |
82+
|------|--------|-------------|
83+
| `apps/mobile/lib/features/session/domain/models/event_models.dart` | CREATE | Dart models for HookEvent types |
84+
| `apps/mobile/lib/features/session/domain/providers/event_provider.dart` | CREATE | Riverpod provider to collect events from WebSocket stream |
85+
| `apps/mobile/lib/features/session/domain/providers/` | MODIFY | Wire event provider into WebSocket message listener |
86+
87+
#### Task Breakdown
88+
89+
```markdown
90+
### Phase 1: Mobile Event State
91+
92+
- [ ] 1. Create `apps/mobile/lib/features/session/domain/models/event_models.dart` [S, Risk: L]
93+
- [ ] 1.1. Define `HookEvent` sealed class with event types [XS]
94+
- [ ] 1.2. Define `ToolUseEvent` subclass with tool, params, risk_level [XS]
95+
- [ ] 1.3. Define `ToolResultEvent` subclass with tool, result, duration [XS]
96+
- [ ] 1.4. Define `SessionStartEvent`, `SessionEndEvent`, `MessageEvent` subclasses [XS]
97+
- [ ] 1.5. Add `fromJson` factory for parsing BridgeMessage payloads [S]
98+
99+
- [ ] 2. Create `apps/mobile/lib/features/session/domain/providers/event_provider.dart` [S, Risk: L]
100+
- [ ] 2.1. Define `EventNotifier` extending `AsyncNotifier<List<HookEvent>>` [XS]
101+
- [ ] 2.2. Implement `addEvent(HookEvent event)` method [XS]
102+
- [ ] 2.3. Implement `getEventsForSession(String sessionId)` filter [XS]
103+
- [ ] 2.4. Expose `eventsProvider` for widget consumption [XS]
104+
105+
- [ ] 3. Wire event provider to WebSocket stream [XS, Risk: L]
106+
- [ ] 3.1. Locate WebSocket message listener in websocket_service.dart [XS]
107+
- [ ] 3.2. Add event provider reference injection [XS]
108+
- [ ] 3.3. Route `claude_event` messages to event provider [XS]
109+
```
110+
111+
### Phase 2: Tool Card Widget (Est. 300 lines, 3-4 files)
112+
113+
**Goal:** Render tool_use and tool_result events as OpenCode-style cards.
114+
115+
#### Files to Create/Modify
116+
117+
| File | Action | Description |
118+
|------|--------|-------------|
119+
| `apps/mobile/lib/features/session/presentation/widgets/tool_card.dart` | CREATE | StatefulWidget for tool_use/tool_result display |
120+
| `apps/mobile/lib/features/session/presentation/widgets/tool_icon.dart` | CREATE | Icon mapping by tool type (Read, Edit, Bash, etc.) |
121+
| `apps/mobile/lib/features/session/presentation/widgets/status_indicator.dart` | CREATE | Visual status (pending, running, completed, error) |
122+
123+
#### Task Breakdown
124+
125+
```markdown
126+
### Phase 2: Tool Card Widget
127+
128+
- [ ] 4. Create `apps/mobile/lib/features/session/presentation/widgets/tool_icon.dart` [XS, Risk: L]
129+
- [ ] 4.1. Define `ToolIcon` widget with `toolName` parameter [XS]
130+
- [ ] 4.2. Map tool names to icons (Edit→edit, Read→description, Bash→terminal) [XS]
131+
- [ ] 4.3. Use Material icons with theme colors [XS]
132+
133+
- [ ] 5. Create `apps/mobile/lib/features/session/presentation/widgets/status_indicator.dart` [XS, Risk: L]
134+
- [ ] 5.1. Define `StatusIndicator` widget with `ToolStatus` enum [XS]
135+
- [ ] 5.2. Map statuses to colors (pending→grey, running→blue, completed→green, error→red) [XS]
136+
- [ ] 5.3. Add animated progress for 'running' status [XS]
137+
138+
- [ ] 6. Create `apps/mobile/lib/features/session/presentation/widgets/tool_card.dart` [M, Risk: L]
139+
- [ ] 6.1. Define `ToolCard` widget accepting `HookEvent` [XS]
140+
- [ ] 6.2. Add collapsible header with ToolIcon, tool name, status [S]
141+
- [ ] 6.3. Implement expandable body showing input params (truncated) [S]
142+
- [ ] 6.4. Add tool result section for tool_result events [S]
143+
- [ ] 6.5. Support dark/light theme via Theme.of(context) [XS]
144+
- [ ] 6.6. Add timestamp and duration display [XS]
145+
```
146+
147+
### Phase 3: Event Timeline (Est. 150 lines, 2 files)
148+
149+
**Goal:** Display scrolling list of events from current session.
150+
151+
#### Files to Create/Modify
152+
153+
| File | Action | Description |
154+
|------|--------|-------------|
155+
| `apps/mobile/lib/features/session/presentation/widgets/event_timeline.dart` | CREATE | ListView of ToolCards with auto-scroll |
156+
| `apps/mobile/lib/features/session/presentation/screens/session_screen.dart` | CREATE | Main session view placeholder |
157+
158+
#### Task Breakdown
159+
160+
```markdown
161+
### Phase 3: Event Timeline
162+
163+
- [ ] 7. Create `apps/mobile/lib/features/session/presentation/widgets/event_timeline.dart` [S, Risk: L]
164+
- [ ] 7.1. Define `EventTimeline` widget consuming `eventsProvider` [XS]
165+
- [ ] 7.2. Build ListView.builder with ToolCard items [XS]
166+
- [ ] 7.3. Implement auto-scroll to newest event with ScrollController [XS]
167+
- [ ] 7.4. Add empty state message for no events [XS]
168+
- [ ] 7.5. Use `ref.watch` to reactively update on new events [XS]
169+
170+
- [ ] 8. Create `apps/mobile/lib/features/session/presentation/screens/session_screen.dart` [S, Risk: L]
171+
- [ ] 8.1. Define `SessionScreen` with AppBar and EventTimeline body [XS]
172+
- [ ] 8.2. Add session ID display in AppBar title [XS]
173+
- [ ] 8.3. Wire to app navigation after health verification passes [S]
174+
```
175+
176+
### Phase 4: End-to-End Verification (Est. 100 lines, 2-3 files)
177+
178+
**Goal:** Verify bridge correctly transforms and forwards hook events.
179+
180+
#### Files to Create/Modify
181+
182+
| File | Action | Description |
183+
|------|--------|-------------|
184+
| `packages/bridge/tests/hooks/event_flow.test.ts` | CREATE | Integration test for hook → websocket |
185+
| `apps/mobile/test/features/session/event_flow_test.dart` | CREATE | Widget test for event rendering |
186+
187+
#### Task Breakdown
188+
189+
```markdown
190+
### Phase 4: End-to-End Verification
191+
192+
- [ ] 9. Create `packages/bridge/tests/hooks/event_flow.test.ts` [S, Risk: M]
193+
- [ ] 9.1. Mock WebSocket server ConnectionManager [S]
194+
- [ ] 9.2. POST sample hook event to `/hooks/event` [XS]
195+
- [ ] 9.3. Verify event queued in EventQueue [XS]
196+
- [ ] 9.4. Verify broadcast called with BridgeMessage [XS]
197+
198+
- [ ] 10. Create `apps/mobile/test/features/session/event_flow_test.dart` [S, Risk: M]
199+
- [ ] 10.1. Create mock WebSocket service injecting events [S]
200+
- [ ] 10.2. Render EventTimeline widget [XS]
201+
- [ ] 10.3. Inject sample claude_event message [XS]
202+
- [ ] 10.4. Verify ToolCard appears with correct data [S]
203+
204+
- [ ] 11. Run all tests and verify 100% pass [XS, Risk: L]
205+
- [ ] 11.1. Run `npm test` in packages/bridge [XS]
206+
- [ ] 11.2. Run `flutter test` in apps/mobile [XS]
207+
- [ ] 11.3. Fix any failing tests [Variable]
208+
```
209+
210+
### Phase 5: Documentation (Est. 100 lines, 1 file)
211+
212+
**Goal:** Clear setup instructions for users to configure Claude Code hooks.
213+
214+
#### Files to Create/Modify
215+
216+
| File | Action | Description |
217+
|------|--------|-------------|
218+
| `docs/setup/claude-code-hooks-setup.md` | CREATE | Step-by-step hook configuration guide |
219+
220+
#### Task Breakdown
221+
222+
```markdown
223+
### Phase 5: Documentation
224+
225+
- [ ] 12. Create `docs/setup/claude-code-hooks-setup.md` [S, Risk: L]
226+
- [ ] 12.1. Document hooks.json location (~/.claude/hooks/hooks.json) [XS]
227+
- [ ] 12.2. Provide curl command template for bridge URL [XS]
228+
- [ ] 12.3. List supported event types and their payloads [S]
229+
- [ ] 12.4. Add troubleshooting section for common issues [S]
230+
- [ ] 12.5. Include example hooks.json for ReCursor [S]
231+
```
232+
233+
---
234+
235+
## Existing Modifications to Preserve
236+
237+
The following files have uncommitted changes that **must not be modified** by this slice:
238+
239+
| File | Change Type | Description |
240+
|------|-------------|-------------|
241+
| `apps/mobile/lib/core/network/websocket_messages.dart` | Modified | Added `ConnectionPurpose` enum and purpose field - **DO NOT TOUCH** |
242+
| `apps/mobile/lib/core/network/websocket_service.dart` | Modified | Added purpose parameter to connect() - **DO NOT TOUCH** |
243+
| `packages/bridge/src/types.ts` | Modified | Added `ConnectionPurpose` type - **DO NOT TOUCH** |
244+
| `packages/bridge/src/websocket/connection_manager.ts` | Modified | Added purpose tracking to MobileClient - **DO NOT TOUCH** |
245+
| `packages/bridge/src/websocket/connection_mode.ts` | Modified | Connection mode detection logic - **DO NOT TOUCH** |
246+
| `packages/bridge/src/websocket/message_handler.ts` | Modified | Purpose handling in auth - **DO NOT TOUCH** |
247+
248+
**Strategy:** All new code goes in `features/session/` directory, not in `core/network/`.
249+
250+
---
251+
252+
## Testing Strategy
253+
254+
### Unit Tests
255+
256+
- `event_models_test.dart` - JSON parsing for all event types
257+
- `event_provider_test.dart` - State management logic
258+
- `tool_card_test.dart` - Widget rendering with various statuses
259+
260+
### Integration Tests
261+
262+
- Bridge: POST hook event → WebSocket broadcast
263+
- Mobile: WebSocket receive → State update → Widget render
264+
265+
### Manual Verification
266+
267+
1. Start bridge server: `npm run dev` in `packages/bridge`
268+
2. Start mobile app: `flutter run` in `apps/mobile`
269+
3. Connect mobile to bridge (use stored credentials or manual entry)
270+
4. POST test hook event to `http://localhost:3000/hooks/event`
271+
5. Verify tool card appears in mobile app within 2 seconds
272+
273+
---
274+
275+
## Success Criteria
276+
277+
| Criterion | Verification Method |
278+
|-----------|---------------------|
279+
| Events appear in mobile app | Screenshot of EventTimeline with tool cards |
280+
| End-to-end test passes | `npm test` + `flutter test` output |
281+
| No regressions in existing tests | All existing tests pass |
282+
| Documentation complete | User can configure hooks without help |
283+
| Architecture preserved | No modifications to websocket_messages.dart or websocket_service.dart |
284+
285+
---
286+
287+
## Risk Assessment
288+
289+
| Risk | Likelihood | Impact | Mitigation |
290+
|------|-------------|--------|------------|
291+
| Breaking existing connection flow | Low | High | All new code in `features/session/`, not `core/network/` |
292+
| Hook event format changes upstream | Low | Medium | Document Claude Code version tested against |
293+
| Performance with many events | Low | Low | EventQueue already handles 1000 event limit |
294+
| Mobile state race conditions | Medium | Medium | Use Riverpod's built-in async handling |
295+
296+
---
297+
298+
## Effort Estimate
299+
300+
| Phase | Effort | Risk | Dependencies |
301+
|-------|--------|------|--------------|
302+
| Phase 1: Event State | M (4h) | L | None |
303+
| Phase 2: Tool Cards | M (6h) | L | Phase 1 |
304+
| Phase 3: Timeline | S (2h) | L | Phase 2 |
305+
| Phase 4: Verification | S (3h) | M | Phases 1-3 |
306+
| Phase 5: Documentation | S (1h) | L | None |
307+
| **Total** | **M (16h / ~2 days)** | **L** | - |
308+
309+
---
310+
311+
## Files Summary
312+
313+
**New files to create (10):**
314+
```
315+
apps/mobile/lib/features/session/
316+
├── domain/
317+
│ ├── models/
318+
│ │ └── event_models.dart # Phase 1
319+
│ └── providers/
320+
│ └── event_provider.dart # Phase 1
321+
└── presentation/
322+
├── screens/
323+
│ └── session_screen.dart # Phase 3
324+
└── widgets/
325+
├── event_timeline.dart # Phase 3
326+
├── status_indicator.dart # Phase 2
327+
├── tool_card.dart # Phase 2
328+
└── tool_icon.dart # Phase 2
329+
330+
packages/bridge/tests/hooks/
331+
└── event_flow.test.ts # Phase 4
332+
333+
apps/mobile/test/features/session/
334+
└── event_flow_test.dart # Phase 4
335+
336+
docs/setup/
337+
└── claude-code-hooks-setup.md # Phase 5
338+
```
339+
340+
**Files to modify (1):**
341+
```
342+
apps/mobile/lib/features/startup/domain/bridge_startup_controller.dart
343+
# Wire session screen after health verification (Phase 3)
344+
```
345+
346+
**Existing modified files to preserve (not touch):**
347+
- See "Existing Modifications to Preserve" section above
348+
349+
---
350+
351+
## Acceptance Checklist
352+
353+
Before marking complete:
354+
355+
- [ ] All new files compile without errors
356+
- [ ] All unit tests pass (`flutter test`, `npm test`)
357+
- [ ] Manual test: POST hook event appears in mobile within 2 seconds
358+
- [ ] Documentation allows user to configure hooks independently
359+
- [ ] No modifications to existing `websocket_service.dart` or `websocket_messages.dart`
360+
- [ ] Architecture pattern matches `docs/architecture/overview.md` (agent-agnostic)
361+
362+
---
363+
364+
*Last updated: 2026-03-21*

0 commit comments

Comments
 (0)