Flutter directory layout and module organization for ReCursor.
recursor/
├── apps/
│ └── mobile/ # Flutter mobile app (iOS + Android)
│ ├── android/
│ ├── ios/
│ ├── lib/
│ │ ├── main.dart # App entry point
│ │ ├── app.dart # MaterialApp, router, theme
│ │ ├── core/ # App-wide infrastructure
│ │ ├── features/ # Feature modules
│ │ └── shared/ # Shared UI components
│ ├── test/ # Unit + widget tests
│ ├── integration_test/ # Integration tests
│ ├── assets/ # Fonts, images, certificates
│ ├── pubspec.yaml
│ └── analysis_options.yaml
│
├── packages/
│ └── bridge/ # TypeScript WebSocket bridge server
│ ├── src/
│ │ ├── server.ts # WebSocket server entry
│ │ ├── agents/ # Agent adapters (Claude Code, OpenCode, etc.)
│ │ ├── hooks/ # Claude Code Hooks receiver
│ │ ├── git/ # Git operation handlers
│ │ ├── terminal/ # Terminal session manager
│ │ ├── auth/ # Token validation, rate limiting
│ │ └── notifications/ # Event queue + WebSocket dispatch
│ ├── package.json
│ └── tsconfig.json
│
├── docs/ # Documentation (this folder)
├── .github/
│ └── workflows/ # CI/CD pipelines
│ ├── test.yml # PR test pipeline
│ └── deploy.yml # Build + deploy pipeline
├── fastlane/ # Fastlane config (iOS + Android)
└── README.md
core/
├── config/
│ ├── app_config.dart # Environment config (dev, staging, prod)
│ ├── router.dart # GoRouter route definitions
│ └── theme.dart # Material theme, colors, typography
│
├── network/
│ ├── websocket_service.dart # WebSocket client (connect, reconnect, heartbeat)
│ ├── websocket_messages.dart # Message type definitions (from bridge-protocol.md)
│ └── connection_state.dart # Connection state enum + notifier
│
├── auth/
│ ├── auth_provider.dart # Riverpod auth state provider
│ ├── auth_repository.dart # OAuth + PAT token management
│ ├── token_storage.dart # flutter_secure_storage wrapper
│ └── github_oauth.dart # OAuth2 flow handler
│
├── storage/
│ ├── database.dart # Drift database definition
│ ├── tables/ # Drift table definitions
│ │ ├── sessions.dart
│ │ ├── messages.dart
│ │ ├── agents.dart
│ │ ├── approvals.dart
│ │ └── sync_queue.dart
│ ├── daos/ # Data access objects
│ │ ├── session_dao.dart
│ │ ├── message_dao.dart
│ │ └── sync_dao.dart
│ └── preferences.dart # Hive key-value store wrapper
│
├── notifications/
│ ├── notification_service.dart # Local notification setup (flutter_local_notifications)
│ ├── notification_handler.dart # WebSocket event -> in-app banner / local notification routing
│ └── notification_center.dart # In-app notification list, unread count, persistence
│
└── sync/
├── sync_service.dart # Offline queue flush + pull logic
├── sync_queue.dart # Queue operations (enqueue, dequeue, retry)
└── conflict_resolver.dart # Last-write-wins + user prompt
Each feature follows a consistent internal structure:
features/<feature>/
├── data/
│ ├── models/ # Data transfer objects, JSON serialization
│ └── repositories/ # Repository implementations
├── domain/
│ ├── entities/ # Domain models (immutable, no JSON)
│ └── providers/ # Riverpod providers (state + logic)
└── presentation/
├── screens/ # Full-page widgets
├── widgets/ # Feature-specific reusable widgets
└── controllers/ # UI logic (if needed beyond providers)
Feature modules:
features/
├── chat/ # Agent chat interface
│ ├── data/
│ │ ├── models/
│ │ │ ├── chat_message.dart
│ │ │ └── chat_session.dart
│ │ └── repositories/
│ │ └── chat_repository.dart
│ ├── domain/
│ │ ├── entities/
│ │ │ └── message.dart
│ │ └── providers/
│ │ ├── chat_provider.dart
│ │ └── session_provider.dart
│ └── presentation/
│ ├── screens/
│ │ ├── chat_screen.dart
│ │ └── session_list_screen.dart
│ └── widgets/
│ ├── message_bubble.dart
│ ├── streaming_text.dart
│ ├── chat_input_bar.dart
│ ├── tool_card.dart # OpenCode-style tool card
│ ├── message_part.dart # OpenCode-style message parts
│ └── voice_input_sheet.dart
│
├── diff/ # Code diff viewer
│ ├── data/
│ │ └── repositories/
│ │ └── diff_repository.dart
│ ├── domain/
│ │ └── providers/
│ │ └── diff_provider.dart
│ └── presentation/
│ ├── screens/
│ │ └── diff_viewer_screen.dart
│ └── widgets/
│ ├── diff_viewer.dart # OpenCode-style diff viewer
│ ├── diff_file_card.dart
│ ├── diff_hunk_view.dart
│ └── syntax_highlighted_text.dart
│
├── session/ # Session management
│ ├── data/
│ │ └── repositories/
│ │ └── session_repository.dart
│ ├── domain/
│ │ └── providers/
│ │ └── session_provider.dart
│ └── presentation/
│ ├── screens/
│ │ └── session_detail_screen.dart
│ └── widgets/
│ ├── session_timeline.dart # OpenCode-style timeline
│ ├── session_card.dart
│ └── event_badge.dart
│
├── git/ # Git operations
│ ├── data/
│ │ └── repositories/
│ │ └── git_repository.dart
│ ├── domain/
│ │ └── providers/
│ │ └── git_provider.dart
│ └── presentation/
│ ├── screens/
│ │ ├── commit_screen.dart
│ │ └── branch_screen.dart
│ └── widgets/
│ ├── git_status_card.dart
│ └── file_change_tile.dart
│
├── approvals/ # Tool call approvals
│ ├── data/
│ │ └── repositories/
│ │ └── approval_repository.dart
│ ├── domain/
│ │ └── providers/
│ │ └── approval_provider.dart
│ └── presentation/
│ ├── screens/
│ │ └── approval_detail_screen.dart
│ └── widgets/
│ ├── approval_card.dart
│ ├── risk_indicator.dart
│ └── modification_editor.dart
│
├── terminal/ # Terminal session
│ ├── data/
│ │ └── repositories/
│ │ └── terminal_repository.dart
│ ├── domain/
│ │ └── providers/
│ │ └── terminal_provider.dart
│ └── presentation/
│ ├── screens/
│ │ └── terminal_screen.dart
│ └── widgets/
│ ├── terminal_output.dart
│ └── ansi_renderer.dart
│
├── agents/ # Agent management
│ ├── data/
│ │ └── repositories/
│ │ └── agent_repository.dart
│ ├── domain/
│ │ └── providers/
│ │ └── agent_provider.dart
│ └── presentation/
│ ├── screens/
│ │ ├── agent_list_screen.dart
│ │ └── agent_config_screen.dart
│ └── widgets/
│ └── agent_card.dart
│
├── auth/ # Authentication
│ ├── data/
│ │ └── repositories/
│ │ └── auth_repository.dart
│ ├── domain/
│ │ └── providers/
│ │ └── auth_provider.dart
│ └── presentation/
│ ├── screens/
│ │ ├── login_screen.dart
│ │ └── splash_screen.dart
│ └── widgets/
│ └── auth_button.dart
│
└── settings/ # App settings
└── presentation/
├── screens/
│ └── settings_screen.dart
└── widgets/
└── setting_tile.dart
shared/
├── widgets/
│ ├── loading_indicator.dart # Consistent loading states
│ ├── error_card.dart # Error display
│ ├── empty_state.dart # Empty list placeholder
│ ├── connection_status_bar.dart # Online/offline indicator
│ ├── code_block.dart # Syntax-highlighted code
│ ├── expandable_card.dart # Reusable expandable pattern
│ └── markdown_view.dart # Markdown rendering
│
├── constants/
│ ├── colors.dart # App color palette
│ ├── typography.dart # Text styles
│ └── dimens.dart # Spacing, sizing constants
│
└── utils/
├── date_formatter.dart # Date/time formatting
├── diff_parser.dart # Unified diff parsing
└── ansi_parser.dart # ANSI color code parsing
bridge/
├── server.ts # Express + WebSocket server entry
├── config.ts # Environment configuration
├── types.ts # TypeScript type definitions
│
├── websocket/
│ ├── server.ts # WebSocket server setup
│ ├── connection_manager.ts # Client connection tracking
│ └── message_handler.ts # Message routing
│
├── hooks/
│ ├── receiver.ts # Claude Code Hooks HTTP endpoint
│ ├── validator.ts # Event validation
│ └── event_queue.ts # Event queuing for offline replay
│
├── agents/
│ ├── agent_sdk_adapter.ts # Agent SDK integration
│ ├── session_manager.ts # Session lifecycle management
│ └── tool_executor.ts # Tool execution wrapper
│
├── git/
│ ├── git_service.ts # Git operations
│ └── diff_parser.ts # Diff generation
│
├── terminal/
│ ├── terminal_manager.ts # Terminal session management
│ └── output_stream.ts # Terminal output streaming
│
├── auth/
│ ├── token_validator.ts # JWT/auth token validation
│ └── rate_limiter.ts # Rate limiting
│
└── notifications/
├── event_bus.ts # Internal event bus
└── dispatcher.ts # WebSocket dispatch
-
Feature-Based Organization: Each feature is self-contained with its own data, domain, and presentation layers.
-
Clean Architecture: Dependencies flow inward:
- Presentation depends on Domain
- Domain depends on Data
- Data depends on Core
-
Riverpod for State: All state management uses Riverpod providers, defined in
domain/providers/. -
Repository Pattern: All data access goes through repositories, which abstract local (Drift/Hive) vs. remote (WebSocket) sources.
-
OpenCode UI Patterns: UI components follow OpenCode patterns (tool cards, diff viewer, session timeline).
- Data Models — Drift schemas and domain entities
- Architecture Overview — System architecture
- OpenCode UI Patterns — UI component mapping
Last updated: 2026-03-17