Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions architecture_boundaries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# FileKitty Architecture Boundaries: Python vs Swift

## Overview
This document defines the clear separation of responsibilities between Python backend and Swift UI for FileKitty's hybrid architecture.

## Python Backend Responsibilities

### Core Logic (βœ… Stays in Python)
- **File Processing**: Reading, parsing, and content extraction
- **Tree Generation**: Directory traversal and markdown tree creation
- **Python Code Analysis**: AST parsing for classes/functions
- **Content Aggregation**: Combining files into markdown output
- **Hash Calculation**: File integrity and staleness detection
- **Language Detection**: File type and syntax highlighting determination
- **Project Root Detection**: Finding repository/project boundaries

### Data Management (βœ… Stays in Python)
- **Session Serialization**: JSON conversion and file I/O
- **History Management**: State persistence and navigation
- **Settings Storage**: Configuration and preferences
- **File Metadata**: Size, modification dates, permissions
- **Error Handling**: File access and processing errors

### Business Logic (βœ… Stays in Python)
- **Output Filtering**: Ignore patterns and file exclusion
- **Content Formatting**: Markdown generation and styling
- **Selection Logic**: Class/function filtering
- **Path Normalization**: Display paths and project-relative paths
- **Validation**: Input sanitization and security checks

## Swift UI Responsibilities

### User Interface (πŸ”„ Migrates to Swift)
- **File List Display**: Tree view of selected files
- **File Selection**: Drag & drop, file picker dialogs
- **Text Display**: Markdown rendering and syntax highlighting
- **Navigation**: History back/forward buttons
- **Settings UI**: Preferences and configuration panels
- **Progress Indicators**: Loading states and operation feedback

### User Interactions (πŸ”„ Migrates to Swift)
- **Drag & Drop**: File and folder handling
- **Context Menus**: Right-click actions
- **Keyboard Shortcuts**: Navigation and actions
- **Copy/Paste**: Clipboard operations
- **Export/Save**: File output operations
- **Search/Filter**: UI-level filtering and navigation

### Platform Integration (πŸ”„ Migrates to Swift)
- **macOS Integration**: Dock, menu bar, notifications
- **File System Access**: Sandboxed file operations
- **Window Management**: Sizing, positioning, multi-window
- **Accessibility**: VoiceOver and assistive technologies
- **Dark Mode**: Theme and appearance handling

## Shared/Bridge Layer

### Data Exchange (πŸ”„ New Implementation)
- **JSON Communication**: Request/response handling
- **Session Management**: State synchronization
- **Error Propagation**: Python errors to Swift UI
- **Progress Updates**: Long-running operation status
- **Validation**: Input/output data verification

### CLI Interface (πŸ”„ New Implementation)
- **Command Processing**: Python CLI entry point
- **Argument Parsing**: Swift β†’ Python parameter passing
- **Output Formatting**: Structured JSON responses
- **Error Handling**: Consistent error format
- **Process Management**: Python subprocess lifecycle

## Migration Strategy

### Phase 1: Foundation
1. **Keep Python Logic Intact**: No changes to core processing
2. **Create CLI Interface**: New command-line entry point
3. **Implement Data Models**: PromptSession and supporting classes
4. **Define JSON Schema**: Request/response contracts

### Phase 2: Bridge Implementation
1. **Python CLI Module**: Handle Swift β†’ Python communication
2. **Swift HTTP/Process Client**: Handle Python subprocess calls
3. **Data Serialization**: JSON encoding/decoding on both sides
4. **Error Handling**: Consistent error propagation

### Phase 3: UI Migration
1. **File List View**: Replace PyQt5 QListWidget
2. **Text Display**: Replace PyQt5 QTextEdit
3. **Menu/Toolbar**: Replace PyQt5 menus
4. **Settings Dialog**: Replace PyQt5 preferences

### Phase 4: Polish
1. **Platform Features**: macOS-specific integration
2. **Performance**: Optimize Swift ↔ Python communication
3. **Testing**: Comprehensive integration testing
4. **Documentation**: User guides and API docs

### Phase 5: Packaging & Release
1. **Swift Build**: `swift build -c release` for optimized binary
2. **Code Signing**: Sign SwiftUI app with developer certificate
3. **DMG Creation**: `create-dmg` with custom background and layout
4. **Notarization**: Submit to Apple for security approval
5. **GitHub Release**: `gh release create v0-swift-alpha` with signed DMG
6. **Release Notes**: Document new SwiftUI features and migration notes

## Key Principles

### 1. Minimal Python Changes
- Keep existing Python logic unchanged where possible
- Add new CLI interface without breaking existing code
- Maintain backward compatibility with current features

### 2. Clear Separation
- Python: Data processing, business logic, file operations
- Swift: UI, user interaction, platform integration
- Bridge: Communication, serialization, error handling

### 3. Incremental Migration
- Start with basic file processing
- Add features incrementally
- Maintain working application at each step

### 4. Data Integrity
- Consistent data models between Python and Swift
- Comprehensive validation and error handling
- Atomic operations where possible

## Benefits of This Architecture

### For Python
- **Leverage Existing Code**: Minimal rewrite required
- **Maintain Complexity**: Keep sophisticated logic in Python
- **Cross-Platform**: Python backend remains portable
- **Testing**: Existing Python tests continue to work

### For Swift
- **Native Performance**: Fast, responsive UI
- **Platform Integration**: Full macOS feature support
- **Modern UX**: SwiftUI declarative interface
- **Maintainability**: Type-safe, compiled UI layer

### For Users
- **Better Performance**: Native Swift UI responsiveness
- **Native Feel**: macOS-standard interface patterns
- **Enhanced Features**: Platform-specific capabilities
- **Reliability**: Compiled UI with runtime Python backend
242 changes: 242 additions & 0 deletions example_payloads.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
{
"examples": {
"process_files_request": {
"action": "process_files",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:30:00Z",
"payload": {
"files": [
"/Users/rob/code/FileKitty/src/filekitty/models.py",
"/Users/rob/code/FileKitty/src/filekitty/app_logic.py"
],
"selection_state": {
"mode": "All Files",
"selected_file": null,
"selected_items": []
},
"settings": {
"include_tree": true,
"tree_base_dir": "/Users/rob/code/FileKitty",
"tree_ignore_regex": "\\.git|\\.pyc|\\.DS_Store",
"include_date_modified": true,
"auto_copy": false,
"use_llm_timestamp": false
}
}
},
"process_files_response": {
"action": "process_files",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:30:02Z",
"success": true,
"payload": {
"prompt_session": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:30:00Z",
"files": [
"/Users/rob/code/FileKitty/src/filekitty/models.py",
"/Users/rob/code/FileKitty/src/filekitty/app_logic.py"
],
"file_metadata": [
{
"path": "/Users/rob/code/FileKitty/src/filekitty/models.py",
"display_path": "src/filekitty/models.py",
"is_text_file": true,
"language": "python",
"last_modified": "2025-07-05T14:25:00Z",
"file_hash": "abc123def456789012345678901234567890abcdef123456789012345678901234",
"size_bytes": 5432
},
{
"path": "/Users/rob/code/FileKitty/src/filekitty/app_logic.py",
"display_path": "src/filekitty/app_logic.py",
"is_text_file": true,
"language": "python",
"last_modified": "2025-07-05T12:00:00Z",
"file_hash": "def456789012345678901234567890abcdef123456789012345678901234567890",
"size_bytes": 2048
}
],
"selection_state": {
"mode": "All Files",
"selected_file": null,
"selected_items": []
},
"project_root": "/Users/rob/code/FileKitty",
"tree_snapshot": {
"base_path": "/Users/rob/code/FileKitty",
"base_path_display": "FileKitty/",
"ignore_regex": "\\.git|\\.pyc|\\.DS_Store",
"rendered": "# Folder Tree of FileKitty/\\n\\n```text\\nFileKitty/\\nβ”œβ”€β”€ src/\\nβ”‚ └── filekitty/\\nβ”‚ β”œβ”€β”€ models.py\\nβ”‚ β”œβ”€β”€ app_logic.py\\nβ”‚ └── __init__.py\\nβ”œβ”€β”€ README.md\\n└── pyproject.toml\\n```"
},
"output_text": "# Folder Tree of FileKitty/\\n\\n```text\\nFileKitty/\\nβ”œβ”€β”€ src/\\nβ”‚ └── filekitty/\\nβ”‚ β”œβ”€β”€ models.py\\nβ”‚ β”œβ”€β”€ app_logic.py\\nβ”‚ └── __init__.py\\nβ”œβ”€β”€ README.md\\n└── pyproject.toml\\n```\\n\\n# src/filekitty/models.py\\n**Last modified: Jul 05, 2025 2:25 PM PST**\\n\\n```python\\n\"\"\"Data models for FileKitty Swift integration.\"\"\"\\n\\nimport json\\nfrom dataclasses import dataclass, field\\nfrom datetime import datetime\\nfrom typing import Any, Dict, List, Optional\\n\\n\\n@dataclass\\nclass FileMetadata:\\n \"\"\"Metadata for a single file in the session.\"\"\"\\n path: str\\n display_path: str\\n is_text_file: bool\\n # ... rest of file content\\n```\\n\\n# src/filekitty/app_logic.py\\n**Last modified: Jul 05, 2025 12:00 PM PST**\\n\\n```python\\nimport sys\\nfrom pathlib import Path\\n\\nfrom PyQt5.QtCore import QEvent, Qt\\nfrom PyQt5.QtWidgets import QApplication\\n\\nfrom filekitty.ui.main_window import FilePicker\\n\\n\\nclass FileKittyApp(QApplication):\\n # ... rest of file content\\n```",
"settings": {
"include_tree": true,
"tree_base_dir": "/Users/rob/code/FileKitty",
"tree_ignore_regex": "\\.git|\\.pyc|\\.DS_Store",
"include_date_modified": true,
"auto_copy": false,
"use_llm_timestamp": false
}
}
}
},
"get_python_symbols_request": {
"action": "get_python_symbols",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:31:00Z",
"payload": {
"files": [
"/Users/rob/code/FileKitty/src/filekitty/models.py",
"/Users/rob/code/FileKitty/src/filekitty/app_logic.py"
]
}
},
"get_python_symbols_response": {
"action": "get_python_symbols",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:31:01Z",
"success": true,
"payload": {
"symbols": {
"/Users/rob/code/FileKitty/src/filekitty/models.py": {
"classes": ["FileMetadata", "TreeSnapshot", "SelectionState", "PromptSession"],
"functions": []
},
"/Users/rob/code/FileKitty/src/filekitty/app_logic.py": {
"classes": ["FileKittyApp"],
"functions": ["main"]
}
},
"errors": []
}
},
"update_selection_request": {
"action": "update_selection",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:32:00Z",
"payload": {
"selection_state": {
"mode": "Single File",
"selected_file": "/Users/rob/code/FileKitty/src/filekitty/models.py",
"selected_items": ["PromptSession", "FileMetadata"]
}
}
},
"update_selection_response": {
"action": "update_selection",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:32:01Z",
"success": true,
"payload": {
"output_text": "# Folder Tree of FileKitty/\\n\\n```text\\nFileKitty/\\nβ”œβ”€β”€ src/\\nβ”‚ └── filekitty/\\nβ”‚ β”œβ”€β”€ models.py\\nβ”‚ β”œβ”€β”€ app_logic.py\\nβ”‚ └── __init__.py\\nβ”œβ”€β”€ README.md\\n└── pyproject.toml\\n```\\n\\n# src/filekitty/models.py\\n**Last modified: Jul 05, 2025 2:25 PM PST**\\n\\n```python\\n@dataclass\\nclass FileMetadata:\\n \"\"\"Metadata for a single file in the session.\"\"\"\\n path: str\\n display_path: str\\n is_text_file: bool\\n language: Optional[str] = None\\n last_modified: Optional[datetime] = None\\n file_hash: Optional[str] = None\\n size_bytes: Optional[int] = None\\n\\n\\n@dataclass\\nclass PromptSession:\\n \"\"\"Complete session state for FileKitty.\"\"\"\\n id: str\\n timestamp: datetime\\n files: List[str]\\n file_metadata: List[FileMetadata]\\n selection_state: SelectionState\\n project_root: Optional[str] = None\\n tree_snapshot: Optional[TreeSnapshot] = None\\n output_text: Optional[str] = None\\n settings: Dict[str, Any] = field(default_factory=dict)\\n # ... methods omitted for brevity\\n```"
}
},
"save_session_request": {
"action": "save_session",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:33:00Z",
"payload": {
"file_path": "/Users/rob/Documents/filekitty_session.json"
}
},
"save_session_response": {
"action": "save_session",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:33:01Z",
"success": true,
"payload": {
"saved_path": "/Users/rob/Documents/filekitty_session.json"
}
},
"load_session_request": {
"action": "load_session",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:34:00Z",
"payload": {
"file_path": "/Users/rob/Documents/filekitty_session.json"
}
},
"load_session_response": {
"action": "load_session",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:34:01Z",
"success": true,
"payload": {
"prompt_session": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:30:00Z",
"files": [
"/Users/rob/code/FileKitty/src/filekitty/models.py",
"/Users/rob/code/FileKitty/src/filekitty/app_logic.py"
],
"file_metadata": [
{
"path": "/Users/rob/code/FileKitty/src/filekitty/models.py",
"display_path": "src/filekitty/models.py",
"is_text_file": true,
"language": "python",
"last_modified": "2025-07-05T14:25:00Z",
"file_hash": "abc123def456789012345678901234567890abcdef123456789012345678901234",
"size_bytes": 5432
}
],
"selection_state": {
"mode": "Single File",
"selected_file": "/Users/rob/code/FileKitty/src/filekitty/models.py",
"selected_items": ["PromptSession", "FileMetadata"]
},
"project_root": "/Users/rob/code/FileKitty",
"tree_snapshot": {
"base_path": "/Users/rob/code/FileKitty",
"base_path_display": "FileKitty/",
"ignore_regex": "\\.git|\\.pyc|\\.DS_Store",
"rendered": "# Folder Tree of FileKitty/\\n\\n```text\\nFileKitty/\\nβ”œβ”€β”€ src/\\nβ”‚ └── filekitty/\\nβ”‚ β”œβ”€β”€ models.py\\nβ”‚ β”œβ”€β”€ app_logic.py\\nβ”‚ └── __init__.py\\nβ”œβ”€β”€ README.md\\n└── pyproject.toml\\n```"
},
"output_text": "# Filtered content based on selection...",
"settings": {
"include_tree": true,
"tree_base_dir": "/Users/rob/code/FileKitty",
"tree_ignore_regex": "\\.git|\\.pyc|\\.DS_Store",
"include_date_modified": true,
"auto_copy": false,
"use_llm_timestamp": false
}
}
}
},
"error_response": {
"action": "process_files",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-07-05T14:35:00Z",
"success": false,
"error": {
"type": "FileNotFoundError",
"message": "One or more files could not be found",
"details": {
"missing_files": [
"/Users/rob/code/FileKitty/nonexistent.py"
],
"accessible_files": [
"/Users/rob/code/FileKitty/src/filekitty/models.py"
]
}
}
},
"validation_error_response": {
"action": "update_selection",
"session_id": "invalid-session-id",
"timestamp": "2025-07-05T14:36:00Z",
"success": false,
"error": {
"type": "ValidationError",
"message": "Invalid session ID format",
"details": {
"field": "session_id",
"expected": "Valid UUID string",
"received": "invalid-session-id"
}
}
}
}
}
Loading