applyTo |
---|
** |
This document outlines the coding standards, architectural patterns, and best practices for the Project M codebase. It's designed to help new engineers quickly understand our approach and contribute effectively to the project.
Project M is a markdown-based project management tool that combines the hierarchical organization of Workflowy, the intelligent assistance of ChatGPT, and the dashboard capabilities of tools like Jira. The project uses a modular architecture to handle document parsing, task management, AI integration, and dashboard generation.
Project M aims to build a comprehensive project management solution that leverages the simplicity of markdown with powerful organizational and AI capabilities. The project serves as both a practical tool and a platform for exploring modern software architecture patterns.
The primary focus areas are:
- Fast prototyping: Ensuring runnable code at every step of development
- Learning implementation: Building systems from scratch to understand how they work and learn new concepts
- Applicability and compatibility with Rust: My intention is to have some of my project (or parts of them) coded in Rust. It is important to keep that in mind when designing solutions, so that they can the knowledge and implementation can be "transferred" into other languages (namely Rust)
- Modular architecture: Creating loosely coupled components that can be independently developed and tested
- AI integration: Seamlessly incorporating AI assistance into project workflows
- User experience focus: Prioritizing intuitive interfaces and smooth user interactions
- Document Engine: Core markdown parsing and manipulation functionality
- Task Management: Systems for tracking, organizing, and managing project tasks
- AI Integration: Natural language processing and intelligent assistance features
- Dashboard System: Data visualization and high-level project overview components
- Common Utilities: Shared functionality across the project
The project is organized into progressive milestones:
-
Milestone 0.1: Fundamentals
- Basic markdown parsing engine
- Core task management functionality
- Simple hierarchical organization
-
Milestone 0.2: Stability & Performance
- Improved parsing algorithms
- Performance optimizations for large documents
- Robust error handling
-
Milestone 0.3-0.9: Feature Expansion
- AI integration for task suggestions
- Dashboard generation and visualization
- Search and filtering capabilities
- Real-time collaboration features
- Plugin architecture
- Export and integration with external tools
-
Milestone 1.0+: Advanced Features
- Advanced AI workflows
- Custom dashboard templates
- Mobile and web interfaces
- Enterprise features and scaling
The ultimate goal is to create a foundation for advanced project management workflows that combine the best of hierarchical organization, intelligent assistance, and comprehensive project visibility.
- Python 3.10 is required for this project
- We use Black for code formatting with a line length of 120 characters
- Run
black .
before committing to ensure consistent formatting
- Group imports in the following order:
- Standard library imports
- Third-party library imports
- Project imports
- Within each group, use alphabetical ordering
- Use absolute imports for project modules
Example:
import abc
from dataclasses import dataclass
from typing import List, Optional, Dict
import numpy as np
from termcolor import colored
from projectm.ai.core import QueryProcessor
from projectm.ai.core.context import AIContext
from projectm.common.logging import get_logger
- Use type hints for all function parameters and return values
- Use generics (TypeVar) when appropriate
- Prefer composition of simple types over complex nested types
Example:
from typing import Dict, List, Optional, TypeVar
T = TypeVar("T")
def get_tasks_with_status(status_type: str, project_id: Optional[str] = None) -> List[int]:
"""Get tasks with a specific status type."""
# Implementation
- Classes:
PascalCase
- Functions/Methods:
snake_case
- Variables:
snake_case
- Constants:
UPPER_SNAKE_CASE
- Private members: Prefix with underscore (
_private_method
) - Type variables: Single uppercase letter or
PascalCase
with descriptive name
- Use TODOs to mark areas that need improvement, but include specific details about what needs to be done
- For complex algorithms or non-obvious code, include explanatory comments
- Avoid commented-out code in the main branch
Our project uses a modular architecture with clear separation of concerns:
- Documents: Core markdown document representation and manipulation
- Tasks: Task management and tracking functionality
- AI Services: Integration with language models and intelligent assistance
- Dashboards: Data aggregation and visualization components
- Components should have single responsibility and clear interfaces
- Use dataclasses with
slots=True
for memory efficiency - Components should minimize dependencies on other components
Example:
@dataclass(slots=True)
class TaskComponent:
title: str
status: str
priority: int = 1
due_date: Optional[str] = None
def update_status(self, new_status: str) -> None:
self.status = new_status
- Each service should focus on a specific domain area
- Services should be stateless when possible
- Use dependency injection for service dependencies
- Implement clear interfaces for all services
Example:
class TaskService:
def update_task_status(self, task_id: str, status: str):
# Process task status updates
- Query Processor: Handles natural language queries and commands
- Context Manager: Maintains project context and history
- Response Generator: Formats and presents AI-generated content
- Identify hot paths in the code (frequently executed or performance-critical sections)
- For hot paths, prioritize performance over readability
- Document performance-critical code with benchmarks when possible
- Consider using NumPy for numerical operations in hot paths
- Use
slots=True
in dataclasses to reduce memory overhead - Be mindful of object creation in loops
- Consider using efficient data structures for large document processing
- Avoid deep copying large data structures when possible
- For code not in hot paths, prioritize readability and maintainability
- Use clear variable names and add explanatory comments
- Break complex functions into smaller, well-named functions
- Patterns that lead to unpredictable performance, for example: things that run at O(n), GC-like code patterns, etc.
- Things that don't scale well - for instance, using instances for things that can have millions of instances created per second
- When you identify performance issues but don't have time to fix them immediately, add a detailed TODO comment
- Include specific measurements or observations about the performance issue
Example:
# TODO: This is a performance bottleneck. Current implementation uses O(n²) time complexity.
# Consider using suffix trees or other efficient string matching algorithms to reduce to O(n log n).
- When faced with a complex design decision, document the reasoning behind the chosen approach
- Be clear about the trade-offs and alternatives considered
- Make sure to review common practices in similar projects, and patterns that can be adopted from other languages (like Rust) that can be applied to Python
- If the decision isn't clear-cut, make sure to consult with the owner, present the options and pros/cons, and suggest at least 3 options to choose from
- Use pytest for all tests
- Group tests by module/functionality in the
tests/
directory - Follow the Arrange-Act-Assert pattern for test structure
Example:
def test_task_status_update(task_manager: TaskManager):
"""Test that task status updates are applied correctly."""
# Arrange
task_id = task_manager.create_task("Test Task", "todo")
# Act
task_manager.update_status(task_id, "in_progress")
# Assert
task = task_manager.get_task(task_id)
assert task.status == "in_progress"
- Aim for high test coverage, especially for core functionality
- Use
pytest-cov
to measure coverage - Focus on testing behavior rather than implementation details
- Include edge cases and error conditions in tests
- Unit Tests: Test individual functions or classes in isolation
- Integration Tests: Test interactions between components
- System Tests: Test end-to-end behavior of the application
- Use the
perf/
directory for performance benchmarks - Compare performance before and after optimizations
- Set up automated performance regression testing when possible
- Do not document overly simple code
- Avoid fluff, for example:
def sort_in_place(arr: List[int]):
""" Sorts a list of ints in place """ <----- avoid this. it is very clear from the function signature what it does.
...
- Use docstrings for all public functions, classes, and methods
- Follow this format for docstrings:
def function_name(param1: Type, param2: Type) -> ReturnType:
"""
Short description of what the function does.
Longer description if needed with more details.
:param param1: Description of param1
:param param2: Description of param2
:return: Description of return value
:raises ExceptionType: When and why this exception is raised
"""
- Document architectural decisions and patterns
- Explain the relationships between different components
- Use diagrams when helpful (can be included as images or ASCII art)