claudify-agent 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.claude/QUICK-REFERENCE.md +213 -213
  2. package/.claude/cost-dashboard.md +162 -162
  3. package/.claude/docs/COST-OPTIMIZATION.md +402 -403
  4. package/.claude/docs/MCP-INTEGRATION-GUIDE.md +348 -348
  5. package/.claude/docs/PLAN-MODE-OPTIMIZATION.md +835 -836
  6. package/.claude/hooks/auto-learning-review.ts +200 -195
  7. package/.claude/hooks/auto-lint-fix.ts +60 -104
  8. package/.claude/hooks/auto-security-review.ts +314 -354
  9. package/.claude/hooks/auto-validate.ts +249 -348
  10. package/.claude/hooks/lib/claude-hook.ts +168 -0
  11. package/.claude/hooks/plan-quality-tracker.ts +598 -719
  12. package/.claude/rules/anti-patterns.md +22 -22
  13. package/.claude/rules/context-tier-1.md +41 -41
  14. package/.claude/rules/context-tier-2.md +285 -285
  15. package/.claude/rules/general.md +25 -25
  16. package/.claude/rules/mcp-auto-use.md +46 -46
  17. package/.claude/rules/parallel-exploration-auto.md +30 -31
  18. package/.claude/rules/plan-mode-execution.md +289 -289
  19. package/.claude/rules/plan-mode-research.md +34 -34
  20. package/.claude/rules/plan-mode-structure.md +166 -166
  21. package/.claude/rules/plan-mode-validation.md +129 -130
  22. package/.claude/rules/security-critical.md +19 -19
  23. package/.claude/rules/tool-auto-selection.md +45 -45
  24. package/.claude/rules/tool-strategy.md +22 -22
  25. package/.claude/scripts/security-scan.js +1 -1
  26. package/.claude/security-dashboard.md +142 -142
  27. package/.claude/settings.json +50 -0
  28. package/.claude/skills/debug-optimizer/SKILL.md +420 -399
  29. package/.claude/skills/learning-loop/SKILL.md +313 -308
  30. package/.claude/skills/mcp-mastery/SKILL.md +218 -214
  31. package/.claude/skills/nextjs-guide/SKILL.md +687 -687
  32. package/.claude/skills/parallel-exploration/SKILL.md +197 -193
  33. package/.claude/skills/plan-mode-mastery/SKILL.md +268 -263
  34. package/.claude/skills/python-guide/SKILL.md +822 -822
  35. package/.claude/skills/react-guide/SKILL.md +762 -762
  36. package/.claude/skills/{security.md → security-guide/SKILL.md} +10 -0
  37. package/.claude/skills/solidity-guide/SKILL.md +5 -0
  38. package/.claude/skills/tool-selection/SKILL.md +433 -428
  39. package/.claude/skills/vite-guide/SKILL.md +445 -445
  40. package/CLAUDE.md +1 -0
  41. package/README.md +74 -35
  42. package/README.vi.md +106 -0
  43. package/bin/cli.js +13 -4
  44. package/package.json +9 -1
  45. package/.claude/skills/debug-optimizer.md +0 -12
  46. package/.claude/skills/nextjs.md +0 -13
  47. package/.claude/skills/react.md +0 -12
@@ -1,822 +1,822 @@
1
- ---
2
- name: python-guide
3
- description: Apply Python best practices including PEP 8, clean code, testing, and project structure. Use when writing, reviewing, or refactoring Python code.
4
- ---
5
-
6
- # Python Best Practices
7
-
8
- ## Quick Start
9
-
10
- When working with Python code, follow these core principles:
11
-
12
- 1. **Follow PEP 8**: Use proper indentation, naming, and formatting
13
- 2. **Write tests**: Use pytest with >80% coverage
14
- 3. **Document**: Add docstrings and type hints
15
- 4. **Structure properly**: Separate concerns (routers, services, models)
16
- 5. **Validate early**: Use configuration validation at startup
17
- 6. **Automate quality**: Use Ruff, Black, mypy, pytest
18
-
19
- ## Code Style & Formatting
20
-
21
- ### PEP 8 Essentials
22
-
23
- **Indentation**:
24
- ```python
25
- # ✅ Good: 4 spaces
26
- def calculate_total(items):
27
- total = 0
28
- for item in items:
29
- total += item.price
30
- return total
31
- ```
32
-
33
- **Line Length**:
34
- ```python
35
- # ✅ Good: Max 79 characters (code), 72 (docstrings)
36
- result = (
37
- some_long_variable_name
38
- + another_long_variable_name
39
- + third_long_variable_name
40
- )
41
- ```
42
-
43
- **Blank Lines**:
44
- ```python
45
- # ✅ Good: 2 blank lines between top-level, 1 between methods
46
- class UserService:
47
- def __init__(self):
48
- pass
49
-
50
- def create_user(self):
51
- pass
52
-
53
-
54
- def helper_function():
55
- pass
56
- ```
57
-
58
- ### Naming Conventions
59
-
60
- ```python
61
- # ✅ Good: snake_case for functions/variables
62
- def calculate_total():
63
- pass
64
-
65
- user_count = 0
66
-
67
- # ✅ Good: PascalCase for classes
68
- class UserProfile:
69
- pass
70
-
71
- # ✅ Good: UPPERCASE for constants
72
- MAX_RETRIES = 3
73
- DEFAULT_TIMEOUT = 30
74
-
75
- # ✅ Good: _prefix for private, __prefix for name mangling
76
- class DataProcessor:
77
- def _internal_method(self):
78
- pass
79
-
80
- def __private_method(self):
81
- pass
82
- ```
83
-
84
- ### Imports
85
-
86
- ```python
87
- # ✅ Good: Standard library first, then third-party, then local
88
- import os
89
- import sys
90
- from typing import List, Optional
91
-
92
- import requests
93
- from fastapi import FastAPI
94
-
95
- from app.models import User
96
- from app.services import UserService
97
-
98
- # ✅ Good: Use explicit imports
99
- from collections import OrderedDict # Not: from collections import *
100
-
101
- # ✅ Good: Handle circular imports with TYPE_CHECKING
102
- from typing import TYPE_CHECKING
103
-
104
- if TYPE_CHECKING:
105
- from app.models import User
106
-
107
- def process_user(user: 'User'):
108
- pass
109
- ```
110
-
111
- ## Type Hints
112
-
113
- ### Basic Types
114
-
115
- ```python
116
- # ✅ Good: Use type hints for all functions
117
- def greet(name: str, age: int) -> str:
118
- return f"Hello {name}, age {age}"
119
-
120
- # ✅ Good: Use Optional for nullable
121
- from typing import Optional
122
-
123
- def find_user(user_id: int) -> Optional[User]:
124
- pass
125
-
126
- # ✅ Good: Use Union for multiple types
127
- from typing import Union
128
-
129
- def parse_value(value: Union[str, int, float]) -> Any:
130
- pass
131
-
132
- # ✅ Good: Use List, Dict, etc. from typing
133
- from typing import List, Dict
134
-
135
- def process_items(items: List[str]) -> Dict[str, int]:
136
- pass
137
- ```
138
-
139
- ### Advanced Types
140
-
141
- ```python
142
- # ✅ Good: Use Protocol for structural typing
143
- from typing import Protocol
144
-
145
- class Drawable(Protocol):
146
- def draw(self) -> None:
147
- ...
148
-
149
- def render(shape: Drawable):
150
- shape.draw()
151
-
152
- # ✅ Good: Use TypedDict for dictionaries
153
- from typing import TypedDict
154
-
155
- class UserConfig(TypedDict):
156
- username: str
157
- email: str
158
- age: int
159
-
160
- # ✅ Good: Use Literal for specific values
161
- from typing import Literal
162
-
163
- def set_status(status: Literal["active", "inactive", "pending"]):
164
- pass
165
-
166
- # ✅ Good: Use Callable for function types
167
- from typing import Callable
168
-
169
- def process_data(
170
- data: List[int],
171
- transformer: Callable[[int], int]
172
- ) -> List[int]:
173
- return [transformer(x) for x in data]
174
- ```
175
-
176
- ## Project Structure
177
-
178
- ### Production-Ready Layout
179
-
180
- ```
181
- project/
182
- ├── app/
183
- │ ├── __init__.py
184
- │ ├── main.py # Application entry point
185
- │ ├── api/ # API routes
186
- │ │ ├── __init__.py
187
- │ │ ├── routes/
188
- │ │ │ ├── users.py
189
- │ │ │ └── products.py
190
- │ │ └── deps.py # Dependencies
191
- │ ├── core/ # Core configuration
192
- │ │ ├── __init__.py
193
- │ │ ├── config.py # Settings
194
- │ │ ├── security.py # Auth/security
195
- │ │ └── logging.py # Logging config
196
- │ ├── models/ # Database models
197
- │ │ ├── __init__.py
198
- │ │ ├── user.py
199
- │ │ └── product.py
200
- │ ├── schemas/ # Pydantic schemas
201
- │ │ ├── __init__.py
202
- │ │ ├── user.py
203
- │ │ └── product.py
204
- │ ├── services/ # Business logic
205
- │ │ ├── __init__.py
206
- │ │ ├── user_service.py
207
- │ │ └── product_service.py
208
- │ ├── repositories/ # Data access
209
- │ │ ├── __init__.py
210
- │ │ ├── user_repo.py
211
- │ │ └── product_repo.py
212
- │ └── utils/ # Utilities
213
- │ ├── __init__.py
214
- │ └── helpers.py
215
- ├── tests/ # Test files
216
- │ ├── __init__.py
217
- │ ├── conftest.py # Shared fixtures
218
- │ ├── test_users.py
219
- │ └── test_products.py
220
- ├── scripts/ # Utility scripts
221
- │ ├── setup_db.py
222
- │ └── migrate.py
223
- ├── .env # Environment variables
224
- ├── .env.example # Template
225
- ├── pyproject.toml # Dependencies
226
- ├── pytest.ini # Test config
227
- ├── mypy.ini # Type checking
228
- ├── ruff.toml # Linting
229
- └── README.md
230
- ```
231
-
232
- ### Configuration Management
233
-
234
- ```python
235
- # ✅ Good: Use Pydantic Settings
236
- from pydantic_settings import BaseSettings
237
- from functools import lru_cache
238
-
239
- class Settings(BaseSettings):
240
- app_name: str = "My App"
241
- debug: bool = False
242
- database_url: str
243
- secret_key: str
244
- max_connections: int = 100
245
-
246
- class Config:
247
- env_file = ".env"
248
-
249
- @lru_cache()
250
- def get_settings() -> Settings:
251
- return Settings()
252
-
253
- # Usage
254
- settings = get_settings()
255
- ```
256
-
257
- ## Documentation
258
-
259
- ### Docstrings
260
-
261
- ```python
262
- # ✅ Good: Google style docstrings
263
- def calculate_total(
264
- items: List[Item],
265
- tax_rate: float = 0.1
266
- ) -> float:
267
- """
268
- Calculate total price including tax.
269
-
270
- Args:
271
- items: List of items to calculate total for
272
- tax_rate: Tax rate as decimal (default: 0.1)
273
-
274
- Returns:
275
- Total price including tax
276
-
277
- Raises:
278
- ValueError: If items list is empty or tax_rate is negative
279
-
280
- Example:
281
- >>> items = [Item(price=100), Item(price=200)]
282
- >>> calculate_total(items, 0.1)
283
- 330.0
284
- """
285
- if not items:
286
- raise ValueError("Items list cannot be empty")
287
- if tax_rate < 0:
288
- raise ValueError("Tax rate must be non-negative")
289
-
290
- subtotal = sum(item.price for item in items)
291
- return subtotal * (1 + tax_rate)
292
- ```
293
-
294
- ### Module Docstrings
295
-
296
- ```python
297
- """
298
- User management module.
299
-
300
- This module provides user-related business logic including:
301
- - User creation and validation
302
- - Authentication and authorization
303
- - Profile management
304
-
305
- Example:
306
- from app.services import UserService
307
-
308
- service = UserService()
309
- user = service.create_user("john", "john@example.com")
310
- """
311
- ```
312
-
313
- ## Testing
314
-
315
- ### Test Structure
316
-
317
- ```python
318
- # tests/test_users.py
319
- import pytest
320
- from app.services import UserService
321
- from app.models import User
322
-
323
- class TestUserService:
324
- """Test cases for UserService."""
325
-
326
- @pytest.fixture
327
- def user_service(self):
328
- """Create UserService instance."""
329
- return UserService()
330
-
331
- def test_create_user_success(self, user_service):
332
- """Should create user with valid data."""
333
- user = user_service.create_user(
334
- username="john",
335
- email="john@example.com"
336
- )
337
-
338
- assert user.username == "john"
339
- assert user.email == "john@example.com"
340
- assert user.id is not None
341
-
342
- def test_create_user_duplicate_email(self, user_service):
343
- """Should raise error for duplicate email."""
344
- user_service.create_user(
345
- username="john",
346
- email="john@example.com"
347
- )
348
-
349
- with pytest.raises(ValueError, match="Email already exists"):
350
- user_service.create_user(
351
- username="jane",
352
- email="john@example.com"
353
- )
354
-
355
- def test_create_user_invalid_email(self, user_service):
356
- """Should raise error for invalid email."""
357
- with pytest.raises(ValueError, match="Invalid email"):
358
- user_service.create_user(
359
- username="john",
360
- email="invalid-email"
361
- )
362
- ```
363
-
364
- ### Test Fixtures (conftest.py)
365
-
366
- ```python
367
- # tests/conftest.py
368
- import pytest
369
- from app.models import User
370
- from app.services import UserService
371
-
372
- @pytest.fixture
373
- def sample_user():
374
- """Create sample user for testing."""
375
- return User(
376
- id=1,
377
- username="testuser",
378
- email="test@example.com"
379
- )
380
-
381
- @pytest.fixture
382
- def user_service():
383
- """Create UserService with test configuration."""
384
- return UserService(test_mode=True)
385
-
386
- @pytest.fixture
387
- def mock_database(mocker):
388
- """Mock database operations."""
389
- mock = mocker.patch('app.db.database')
390
- mock.execute.return_value = []
391
- return mock
392
- ```
393
-
394
- ### Test Coverage
395
-
396
- ```bash
397
- # Run tests with coverage
398
- pytest --cov=app --cov-report=html
399
-
400
- # Minimum coverage requirement
401
- pytest --cov=app --cov-fail-under=80
402
-
403
- # Run specific test file
404
- pytest tests/test_users.py -v
405
-
406
- # Run with markers
407
- pytest -m slow # or -m fast, -m integration
408
- ```
409
-
410
- ## Error Handling
411
-
412
- ### Custom Exceptions
413
-
414
- ```python
415
- # app/exceptions.py
416
- class AppException(Exception):
417
- """Base exception for application."""
418
- def __init__(self, message: str, code: str = None):
419
- self.message = message
420
- self.code = code or self.__class__.__name__
421
- super().__init__(self.message)
422
-
423
- class UserNotFoundException(AppException):
424
- """Raised when user is not found."""
425
- def __init__(self, user_id: int):
426
- super().__init__(
427
- message=f"User with id {user_id} not found",
428
- code="USER_NOT_FOUND"
429
- )
430
-
431
- class ValidationError(AppException):
432
- """Raised when validation fails."""
433
- def __init__(self, message: str, field: str = None):
434
- super().__init__(message, "VALIDATION_ERROR")
435
- self.field = field
436
- ```
437
-
438
- ### Error Handling Patterns
439
-
440
- ```python
441
- # ✅ Good: Specific exception handling
442
- from app.exceptions import UserNotFoundException, ValidationError
443
-
444
- def get_user(user_id: int) -> User:
445
- try:
446
- user = user_repo.find_by_id(user_id)
447
- if not user:
448
- raise UserNotFoundException(user_id)
449
- return user
450
- except UserNotFoundException:
451
- raise
452
- except Exception as e:
453
- logger.error(f"Failed to get user {user_id}: {e}")
454
- raise AppException("Failed to retrieve user")
455
-
456
- # ✅ Good: Context managers for resources
457
- from contextlib import contextmanager
458
-
459
- @contextmanager
460
- def database_transaction():
461
- """Manage database transaction."""
462
- conn = get_connection()
463
- try:
464
- conn.begin()
465
- yield conn
466
- conn.commit()
467
- except Exception:
468
- conn.rollback()
469
- raise
470
- finally:
471
- conn.close()
472
- ```
473
-
474
- ## Design Patterns
475
-
476
- ### Repository Pattern
477
-
478
- ```python
479
- # app/repositories/base.py
480
- from abc import ABC, abstractmethod
481
- from typing import Generic, TypeVar, List, Optional
482
-
483
- T = TypeVar('T')
484
-
485
- class BaseRepository(ABC, Generic[T]):
486
- """Base repository with CRUD operations."""
487
-
488
- @abstractmethod
489
- def find_by_id(self, id: int) -> Optional[T]:
490
- pass
491
-
492
- @abstractmethod
493
- def find_all(self) -> List[T]:
494
- pass
495
-
496
- @abstractmethod
497
- def create(self, entity: T) -> T:
498
- pass
499
-
500
- @abstractmethod
501
- def update(self, id: int, entity: T) -> T:
502
- pass
503
-
504
- @abstractmethod
505
- def delete(self, id: int) -> bool:
506
- pass
507
-
508
- # app/repositories/user_repository.py
509
- class UserRepository(BaseRepository[User]):
510
- """User-specific repository."""
511
-
512
- def find_by_id(self, id: int) -> Optional[User]:
513
- # Implementation
514
- pass
515
-
516
- def find_by_email(self, email: str) -> Optional[User]:
517
- # Implementation
518
- pass
519
-
520
- def find_active_users(self) -> List[User]:
521
- # Implementation
522
- pass
523
- ```
524
-
525
- ### Service Layer Pattern
526
-
527
- ```python
528
- # app/services/user_service.py
529
- from app.repositories import UserRepository
530
- from app.schemas import UserCreate, UserUpdate
531
- from app.models import User
532
-
533
- class UserService:
534
- """Business logic for user operations."""
535
-
536
- def __init__(self, user_repo: UserRepository):
537
- self.user_repo = user_repo
538
-
539
- def create_user(self, data: UserCreate) -> User:
540
- """Create new user with validation."""
541
- # Validate email uniqueness
542
- existing = self.user_repo.find_by_email(data.email)
543
- if existing:
544
- raise ValidationError("Email already exists", "email")
545
-
546
- # Create user
547
- user = User(
548
- username=data.username,
549
- email=data.email,
550
- hashed_password=hash_password(data.password)
551
- )
552
-
553
- return self.user_repo.create(user)
554
-
555
- def update_user(self, user_id: int, data: UserUpdate) -> User:
556
- """Update existing user."""
557
- user = self.user_repo.find_by_id(user_id)
558
- if not user:
559
- raise UserNotFoundException(user_id)
560
-
561
- # Update fields
562
- if data.username:
563
- user.username = data.username
564
- if data.email:
565
- user.email = data.email
566
-
567
- return self.user_repo.update(user_id, user)
568
- ```
569
-
570
- ### Dependency Injection
571
-
572
- ```python
573
- # app/api/deps.py
574
- from functools import lru_cache
575
- from app.repositories import UserRepository
576
- from app.services import UserService
577
- from app.db import get_db
578
-
579
- @lru_cache()
580
- def get_user_repository() -> UserRepository:
581
- """Get UserRepository instance."""
582
- return UserRepository(get_db())
583
-
584
- @lru_cache()
585
- def get_user_service() -> UserService:
586
- """Get UserService instance."""
587
- return UserService(get_user_repository())
588
-
589
- # Usage in API routes
590
- from fastapi import Depends
591
-
592
- @app.get("/users/{user_id}")
593
- def get_user(
594
- user_id: int,
595
- service: UserService = Depends(get_user_service)
596
- ):
597
- user = service.get_user(user_id)
598
- return user
599
- ```
600
-
601
- ## Code Quality Tools
602
-
603
- ### Ruff Configuration (ruff.toml)
604
-
605
- ```toml
606
- [lint]
607
- select = [
608
- "E", # pycodestyle errors
609
- "W", # pycodestyle warnings
610
- "F", # Pyflakes
611
- "I", # isort
612
- "B", # flake8-bugbear
613
- "C4", # flake8-comprehensions
614
- "UP", # pyupgrade
615
- ]
616
-
617
- ignore = [
618
- "E501", # Line too long (handled by formatter)
619
- ]
620
-
621
- [lint.per-file-ignores]
622
- "__init__.py" = ["F401"] # Unused imports OK in __init__
623
- "tests/*" = ["S101"] # Assert OK in tests
624
-
625
- [format]
626
- quote-style = "double"
627
- indent-style = "space"
628
- line-ending = "auto"
629
- ```
630
-
631
- ### Pytest Configuration (pytest.ini)
632
-
633
- ```ini
634
- [pytest]
635
- testpaths = tests
636
- python_files = test_*.py
637
- python_classes = Test*
638
- python_functions = test_*
639
- addopts =
640
- -v
641
- --strict-markers
642
- --tb=short
643
- --cov=app
644
- --cov-report=term-missing
645
- markers =
646
- slow: marks tests as slow
647
- integration: marks tests as integration tests
648
- unit: marks tests as unit tests
649
- ```
650
-
651
- ### Mypy Configuration (mypy.ini)
652
-
653
- ```ini
654
- [mypy]
655
- python_version = 3.11
656
- warn_return_any = True
657
- warn_unused_configs = True
658
- disallow_untyped_defs = True
659
- disallow_incomplete_defs = True
660
- check_untyped_defs = True
661
- no_implicit_optional = True
662
- warn_redundant_casts = True
663
- warn_unused_ignores = True
664
-
665
- [mypy-tests.*]
666
- disallow_untyped_defs = False
667
- ```
668
-
669
- ## Anti-Patterns to Avoid
670
-
671
- ### ❌ Bad: Mutable Default Arguments
672
-
673
- ```python
674
- # ❌ Bad
675
- def add_item(item, items=[]):
676
- items.append(item)
677
- return items
678
-
679
- # ✅ Good
680
- def add_item(item, items=None):
681
- if items is None:
682
- items = []
683
- items.append(item)
684
- return items
685
- ```
686
-
687
- ### ❌ Bad: Bare Except
688
-
689
- ```python
690
- # ❌ Bad
691
- try:
692
- risky_operation()
693
- except:
694
- pass
695
-
696
- # ✅ Good
697
- try:
698
- risky_operation()
699
- except SpecificException as e:
700
- logger.error(f"Operation failed: {e}")
701
- raise
702
- ```
703
-
704
- ### ❌ Bad: Deep Nesting
705
-
706
- ```python
707
- # ❌ Bad
708
- def process_data(data):
709
- if data:
710
- for item in data:
711
- if item.valid:
712
- for subitem in item.subitems:
713
- if subitem.active:
714
- process(subitem)
715
-
716
- # ✅ Good
717
- def process_data(data):
718
- if not data:
719
- return
720
-
721
- for item in data:
722
- if not item.valid:
723
- continue
724
-
725
- for subitem in item.subitems:
726
- if subitem.active:
727
- process(subitem)
728
- ```
729
-
730
- ### ❌ Bad: Magic Numbers
731
-
732
- ```python
733
- # ❌ Bad
734
- def calculate_price(price):
735
- return price * 1.1 * 0.95
736
-
737
- # ✅ Good
738
- TAX_RATE = 0.1
739
- DISCOUNT_RATE = 0.05
740
-
741
- def calculate_price(price):
742
- return price * (1 + TAX_RATE) * (1 - DISCOUNT_RATE)
743
- ```
744
-
745
- ### ❌ Bad: God Classes
746
-
747
- ```python
748
- # ❌ Bad: Does everything
749
- class UserManager:
750
- def create_user(self): pass
751
- def delete_user(self): pass
752
- def send_email(self): pass
753
- def generate_report(self): pass
754
- def connect_db(self): pass
755
-
756
- # ✅ Good: Single responsibility
757
- class UserService:
758
- def create_user(self): pass
759
- def delete_user(self): pass
760
-
761
- class EmailService:
762
- def send_email(self): pass
763
-
764
- class ReportGenerator:
765
- def generate_report(self): pass
766
- ```
767
-
768
- ## Commands
769
-
770
- /python-guide-lint: Run Ruff linter and formatter
771
- /python-guide-test: Run pytest with coverage
772
- /python-guide-typecheck: Run mypy type checking
773
- /python-guide-format: Format code with Black/Ruff
774
-
775
- ## Examples
776
-
777
- ### Example 1: Create New Feature
778
-
779
- User: "Add user registration endpoint"
780
-
781
- Agent:
782
- 1. Create schema in `app/schemas/user.py`
783
- 2. Create service in `app/services/user_service.py`
784
- 3. Create repository in `app/repositories/user_repo.py`
785
- 4. Create route in `app/api/routes/users.py`
786
- 5. Write tests in `tests/test_users.py`
787
- 6. Run: `ruff check app && pytest tests/test_users.py`
788
-
789
- Follow patterns in existing code. Use type hints, docstrings, and proper error handling.
790
-
791
- ### Example 2: Refactor Legacy Code
792
-
793
- User: "Refactor this function"
794
-
795
- Agent:
796
- 1. Write tests for current behavior
797
- 2. Add type hints
798
- 3. Extract helper functions
799
- 4. Improve naming
800
- 5. Add docstrings
801
- 6. Run: `ruff check && mypy && pytest`
802
-
803
- Ensure tests pass before and after. Maintain backward compatibility.
804
-
805
- ### Example 3: Fix Bug
806
-
807
- User: "Fix null pointer exception"
808
-
809
- Agent:
810
- 1. Reproduce the bug with test
811
- 2. Identify root cause (missing None check)
812
- 3. Add proper None handling
813
- 4. Add type hints (Optional)
814
- 5. Run tests to verify fix
815
- 6. Run: `ruff check && mypy`
816
-
817
- ## Additional Resources
818
-
819
- - [PEP 8 Style Guide](https://peps.python.org/pep-0008/)
820
- - [Real Python Best Practices](https://realpython.com/tutorials/best-practices/)
821
- - [Python Code Quality Tools](https://realpython.com/python-code-quality/)
822
- - [FastAPI Best Practices](https://dev.to/building-production-ready-apis-with-fastapi-in-2026)
1
+ ---
2
+ name: python-guide
3
+ description: Apply Python best practices including PEP 8, clean code, testing, and project structure. Use when writing, reviewing, or refactoring Python code.
4
+ ---
5
+
6
+ # Python Best Practices
7
+
8
+ ## Quick Start
9
+
10
+ When working with Python code, follow these core principles:
11
+
12
+ 1. **Follow PEP 8**: Use proper indentation, naming, and formatting
13
+ 2. **Write tests**: Use pytest with >80% coverage
14
+ 3. **Document**: Add docstrings and type hints
15
+ 4. **Structure properly**: Separate concerns (routers, services, models)
16
+ 5. **Validate early**: Use configuration validation at startup
17
+ 6. **Automate quality**: Use Ruff, Black, mypy, pytest
18
+
19
+ ## Code Style & Formatting
20
+
21
+ ### PEP 8 Essentials
22
+
23
+ **Indentation**:
24
+ ```python
25
+ # ✅ Good: 4 spaces
26
+ def calculate_total(items):
27
+ total = 0
28
+ for item in items:
29
+ total += item.price
30
+ return total
31
+ ```
32
+
33
+ **Line Length**:
34
+ ```python
35
+ # ✅ Good: Max 79 characters (code), 72 (docstrings)
36
+ result = (
37
+ some_long_variable_name
38
+ + another_long_variable_name
39
+ + third_long_variable_name
40
+ )
41
+ ```
42
+
43
+ **Blank Lines**:
44
+ ```python
45
+ # ✅ Good: 2 blank lines between top-level, 1 between methods
46
+ class UserService:
47
+ def __init__(self):
48
+ pass
49
+
50
+ def create_user(self):
51
+ pass
52
+
53
+
54
+ def helper_function():
55
+ pass
56
+ ```
57
+
58
+ ### Naming Conventions
59
+
60
+ ```python
61
+ # ✅ Good: snake_case for functions/variables
62
+ def calculate_total():
63
+ pass
64
+
65
+ user_count = 0
66
+
67
+ # ✅ Good: PascalCase for classes
68
+ class UserProfile:
69
+ pass
70
+
71
+ # ✅ Good: UPPERCASE for constants
72
+ MAX_RETRIES = 3
73
+ DEFAULT_TIMEOUT = 30
74
+
75
+ # ✅ Good: _prefix for private, __prefix for name mangling
76
+ class DataProcessor:
77
+ def _internal_method(self):
78
+ pass
79
+
80
+ def __private_method(self):
81
+ pass
82
+ ```
83
+
84
+ ### Imports
85
+
86
+ ```python
87
+ # ✅ Good: Standard library first, then third-party, then local
88
+ import os
89
+ import sys
90
+ from typing import List, Optional
91
+
92
+ import requests
93
+ from fastapi import FastAPI
94
+
95
+ from app.models import User
96
+ from app.services import UserService
97
+
98
+ # ✅ Good: Use explicit imports
99
+ from collections import OrderedDict # Not: from collections import *
100
+
101
+ # ✅ Good: Handle circular imports with TYPE_CHECKING
102
+ from typing import TYPE_CHECKING
103
+
104
+ if TYPE_CHECKING:
105
+ from app.models import User
106
+
107
+ def process_user(user: 'User'):
108
+ pass
109
+ ```
110
+
111
+ ## Type Hints
112
+
113
+ ### Basic Types
114
+
115
+ ```python
116
+ # ✅ Good: Use type hints for all functions
117
+ def greet(name: str, age: int) -> str:
118
+ return f"Hello {name}, age {age}"
119
+
120
+ # ✅ Good: Use Optional for nullable
121
+ from typing import Optional
122
+
123
+ def find_user(user_id: int) -> Optional[User]:
124
+ pass
125
+
126
+ # ✅ Good: Use Union for multiple types
127
+ from typing import Union
128
+
129
+ def parse_value(value: Union[str, int, float]) -> Any:
130
+ pass
131
+
132
+ # ✅ Good: Use List, Dict, etc. from typing
133
+ from typing import List, Dict
134
+
135
+ def process_items(items: List[str]) -> Dict[str, int]:
136
+ pass
137
+ ```
138
+
139
+ ### Advanced Types
140
+
141
+ ```python
142
+ # ✅ Good: Use Protocol for structural typing
143
+ from typing import Protocol
144
+
145
+ class Drawable(Protocol):
146
+ def draw(self) -> None:
147
+ ...
148
+
149
+ def render(shape: Drawable):
150
+ shape.draw()
151
+
152
+ # ✅ Good: Use TypedDict for dictionaries
153
+ from typing import TypedDict
154
+
155
+ class UserConfig(TypedDict):
156
+ username: str
157
+ email: str
158
+ age: int
159
+
160
+ # ✅ Good: Use Literal for specific values
161
+ from typing import Literal
162
+
163
+ def set_status(status: Literal["active", "inactive", "pending"]):
164
+ pass
165
+
166
+ # ✅ Good: Use Callable for function types
167
+ from typing import Callable
168
+
169
+ def process_data(
170
+ data: List[int],
171
+ transformer: Callable[[int], int]
172
+ ) -> List[int]:
173
+ return [transformer(x) for x in data]
174
+ ```
175
+
176
+ ## Project Structure
177
+
178
+ ### Production-Ready Layout
179
+
180
+ ```
181
+ project/
182
+ ├── app/
183
+ │ ├── __init__.py
184
+ │ ├── main.py # Application entry point
185
+ │ ├── api/ # API routes
186
+ │ │ ├── __init__.py
187
+ │ │ ├── routes/
188
+ │ │ │ ├── users.py
189
+ │ │ │ └── products.py
190
+ │ │ └── deps.py # Dependencies
191
+ │ ├── core/ # Core configuration
192
+ │ │ ├── __init__.py
193
+ │ │ ├── config.py # Settings
194
+ │ │ ├── security.py # Auth/security
195
+ │ │ └── logging.py # Logging config
196
+ │ ├── models/ # Database models
197
+ │ │ ├── __init__.py
198
+ │ │ ├── user.py
199
+ │ │ └── product.py
200
+ │ ├── schemas/ # Pydantic schemas
201
+ │ │ ├── __init__.py
202
+ │ │ ├── user.py
203
+ │ │ └── product.py
204
+ │ ├── services/ # Business logic
205
+ │ │ ├── __init__.py
206
+ │ │ ├── user_service.py
207
+ │ │ └── product_service.py
208
+ │ ├── repositories/ # Data access
209
+ │ │ ├── __init__.py
210
+ │ │ ├── user_repo.py
211
+ │ │ └── product_repo.py
212
+ │ └── utils/ # Utilities
213
+ │ ├── __init__.py
214
+ │ └── helpers.py
215
+ ├── tests/ # Test files
216
+ │ ├── __init__.py
217
+ │ ├── conftest.py # Shared fixtures
218
+ │ ├── test_users.py
219
+ │ └── test_products.py
220
+ ├── scripts/ # Utility scripts
221
+ │ ├── setup_db.py
222
+ │ └── migrate.py
223
+ ├── .env # Environment variables
224
+ ├── .env.example # Template
225
+ ├── pyproject.toml # Dependencies
226
+ ├── pytest.ini # Test config
227
+ ├── mypy.ini # Type checking
228
+ ├── ruff.toml # Linting
229
+ └── README.md
230
+ ```
231
+
232
+ ### Configuration Management
233
+
234
+ ```python
235
+ # ✅ Good: Use Pydantic Settings
236
+ from pydantic_settings import BaseSettings
237
+ from functools import lru_cache
238
+
239
+ class Settings(BaseSettings):
240
+ app_name: str = "My App"
241
+ debug: bool = False
242
+ database_url: str
243
+ secret_key: str
244
+ max_connections: int = 100
245
+
246
+ class Config:
247
+ env_file = ".env"
248
+
249
+ @lru_cache()
250
+ def get_settings() -> Settings:
251
+ return Settings()
252
+
253
+ # Usage
254
+ settings = get_settings()
255
+ ```
256
+
257
+ ## Documentation
258
+
259
+ ### Docstrings
260
+
261
+ ```python
262
+ # ✅ Good: Google style docstrings
263
+ def calculate_total(
264
+ items: List[Item],
265
+ tax_rate: float = 0.1
266
+ ) -> float:
267
+ """
268
+ Calculate total price including tax.
269
+
270
+ Args:
271
+ items: List of items to calculate total for
272
+ tax_rate: Tax rate as decimal (default: 0.1)
273
+
274
+ Returns:
275
+ Total price including tax
276
+
277
+ Raises:
278
+ ValueError: If items list is empty or tax_rate is negative
279
+
280
+ Example:
281
+ >>> items = [Item(price=100), Item(price=200)]
282
+ >>> calculate_total(items, 0.1)
283
+ 330.0
284
+ """
285
+ if not items:
286
+ raise ValueError("Items list cannot be empty")
287
+ if tax_rate < 0:
288
+ raise ValueError("Tax rate must be non-negative")
289
+
290
+ subtotal = sum(item.price for item in items)
291
+ return subtotal * (1 + tax_rate)
292
+ ```
293
+
294
+ ### Module Docstrings
295
+
296
+ ```python
297
+ """
298
+ User management module.
299
+
300
+ This module provides user-related business logic including:
301
+ - User creation and validation
302
+ - Authentication and authorization
303
+ - Profile management
304
+
305
+ Example:
306
+ from app.services import UserService
307
+
308
+ service = UserService()
309
+ user = service.create_user("john", "john@example.com")
310
+ """
311
+ ```
312
+
313
+ ## Testing
314
+
315
+ ### Test Structure
316
+
317
+ ```python
318
+ # tests/test_users.py
319
+ import pytest
320
+ from app.services import UserService
321
+ from app.models import User
322
+
323
+ class TestUserService:
324
+ """Test cases for UserService."""
325
+
326
+ @pytest.fixture
327
+ def user_service(self):
328
+ """Create UserService instance."""
329
+ return UserService()
330
+
331
+ def test_create_user_success(self, user_service):
332
+ """Should create user with valid data."""
333
+ user = user_service.create_user(
334
+ username="john",
335
+ email="john@example.com"
336
+ )
337
+
338
+ assert user.username == "john"
339
+ assert user.email == "john@example.com"
340
+ assert user.id is not None
341
+
342
+ def test_create_user_duplicate_email(self, user_service):
343
+ """Should raise error for duplicate email."""
344
+ user_service.create_user(
345
+ username="john",
346
+ email="john@example.com"
347
+ )
348
+
349
+ with pytest.raises(ValueError, match="Email already exists"):
350
+ user_service.create_user(
351
+ username="jane",
352
+ email="john@example.com"
353
+ )
354
+
355
+ def test_create_user_invalid_email(self, user_service):
356
+ """Should raise error for invalid email."""
357
+ with pytest.raises(ValueError, match="Invalid email"):
358
+ user_service.create_user(
359
+ username="john",
360
+ email="invalid-email"
361
+ )
362
+ ```
363
+
364
+ ### Test Fixtures (conftest.py)
365
+
366
+ ```python
367
+ # tests/conftest.py
368
+ import pytest
369
+ from app.models import User
370
+ from app.services import UserService
371
+
372
+ @pytest.fixture
373
+ def sample_user():
374
+ """Create sample user for testing."""
375
+ return User(
376
+ id=1,
377
+ username="testuser",
378
+ email="test@example.com"
379
+ )
380
+
381
+ @pytest.fixture
382
+ def user_service():
383
+ """Create UserService with test configuration."""
384
+ return UserService(test_mode=True)
385
+
386
+ @pytest.fixture
387
+ def mock_database(mocker):
388
+ """Mock database operations."""
389
+ mock = mocker.patch('app.db.database')
390
+ mock.execute.return_value = []
391
+ return mock
392
+ ```
393
+
394
+ ### Test Coverage
395
+
396
+ ```bash
397
+ # Run tests with coverage
398
+ pytest --cov=app --cov-report=html
399
+
400
+ # Minimum coverage requirement
401
+ pytest --cov=app --cov-fail-under=80
402
+
403
+ # Run specific test file
404
+ pytest tests/test_users.py -v
405
+
406
+ # Run with markers
407
+ pytest -m slow # or -m fast, -m integration
408
+ ```
409
+
410
+ ## Error Handling
411
+
412
+ ### Custom Exceptions
413
+
414
+ ```python
415
+ # app/exceptions.py
416
+ class AppException(Exception):
417
+ """Base exception for application."""
418
+ def __init__(self, message: str, code: str = None):
419
+ self.message = message
420
+ self.code = code or self.__class__.__name__
421
+ super().__init__(self.message)
422
+
423
+ class UserNotFoundException(AppException):
424
+ """Raised when user is not found."""
425
+ def __init__(self, user_id: int):
426
+ super().__init__(
427
+ message=f"User with id {user_id} not found",
428
+ code="USER_NOT_FOUND"
429
+ )
430
+
431
+ class ValidationError(AppException):
432
+ """Raised when validation fails."""
433
+ def __init__(self, message: str, field: str = None):
434
+ super().__init__(message, "VALIDATION_ERROR")
435
+ self.field = field
436
+ ```
437
+
438
+ ### Error Handling Patterns
439
+
440
+ ```python
441
+ # ✅ Good: Specific exception handling
442
+ from app.exceptions import UserNotFoundException, ValidationError
443
+
444
+ def get_user(user_id: int) -> User:
445
+ try:
446
+ user = user_repo.find_by_id(user_id)
447
+ if not user:
448
+ raise UserNotFoundException(user_id)
449
+ return user
450
+ except UserNotFoundException:
451
+ raise
452
+ except Exception as e:
453
+ logger.error(f"Failed to get user {user_id}: {e}")
454
+ raise AppException("Failed to retrieve user")
455
+
456
+ # ✅ Good: Context managers for resources
457
+ from contextlib import contextmanager
458
+
459
+ @contextmanager
460
+ def database_transaction():
461
+ """Manage database transaction."""
462
+ conn = get_connection()
463
+ try:
464
+ conn.begin()
465
+ yield conn
466
+ conn.commit()
467
+ except Exception:
468
+ conn.rollback()
469
+ raise
470
+ finally:
471
+ conn.close()
472
+ ```
473
+
474
+ ## Design Patterns
475
+
476
+ ### Repository Pattern
477
+
478
+ ```python
479
+ # app/repositories/base.py
480
+ from abc import ABC, abstractmethod
481
+ from typing import Generic, TypeVar, List, Optional
482
+
483
+ T = TypeVar('T')
484
+
485
+ class BaseRepository(ABC, Generic[T]):
486
+ """Base repository with CRUD operations."""
487
+
488
+ @abstractmethod
489
+ def find_by_id(self, id: int) -> Optional[T]:
490
+ pass
491
+
492
+ @abstractmethod
493
+ def find_all(self) -> List[T]:
494
+ pass
495
+
496
+ @abstractmethod
497
+ def create(self, entity: T) -> T:
498
+ pass
499
+
500
+ @abstractmethod
501
+ def update(self, id: int, entity: T) -> T:
502
+ pass
503
+
504
+ @abstractmethod
505
+ def delete(self, id: int) -> bool:
506
+ pass
507
+
508
+ # app/repositories/user_repository.py
509
+ class UserRepository(BaseRepository[User]):
510
+ """User-specific repository."""
511
+
512
+ def find_by_id(self, id: int) -> Optional[User]:
513
+ # Implementation
514
+ pass
515
+
516
+ def find_by_email(self, email: str) -> Optional[User]:
517
+ # Implementation
518
+ pass
519
+
520
+ def find_active_users(self) -> List[User]:
521
+ # Implementation
522
+ pass
523
+ ```
524
+
525
+ ### Service Layer Pattern
526
+
527
+ ```python
528
+ # app/services/user_service.py
529
+ from app.repositories import UserRepository
530
+ from app.schemas import UserCreate, UserUpdate
531
+ from app.models import User
532
+
533
+ class UserService:
534
+ """Business logic for user operations."""
535
+
536
+ def __init__(self, user_repo: UserRepository):
537
+ self.user_repo = user_repo
538
+
539
+ def create_user(self, data: UserCreate) -> User:
540
+ """Create new user with validation."""
541
+ # Validate email uniqueness
542
+ existing = self.user_repo.find_by_email(data.email)
543
+ if existing:
544
+ raise ValidationError("Email already exists", "email")
545
+
546
+ # Create user
547
+ user = User(
548
+ username=data.username,
549
+ email=data.email,
550
+ hashed_password=hash_password(data.password)
551
+ )
552
+
553
+ return self.user_repo.create(user)
554
+
555
+ def update_user(self, user_id: int, data: UserUpdate) -> User:
556
+ """Update existing user."""
557
+ user = self.user_repo.find_by_id(user_id)
558
+ if not user:
559
+ raise UserNotFoundException(user_id)
560
+
561
+ # Update fields
562
+ if data.username:
563
+ user.username = data.username
564
+ if data.email:
565
+ user.email = data.email
566
+
567
+ return self.user_repo.update(user_id, user)
568
+ ```
569
+
570
+ ### Dependency Injection
571
+
572
+ ```python
573
+ # app/api/deps.py
574
+ from functools import lru_cache
575
+ from app.repositories import UserRepository
576
+ from app.services import UserService
577
+ from app.db import get_db
578
+
579
+ @lru_cache()
580
+ def get_user_repository() -> UserRepository:
581
+ """Get UserRepository instance."""
582
+ return UserRepository(get_db())
583
+
584
+ @lru_cache()
585
+ def get_user_service() -> UserService:
586
+ """Get UserService instance."""
587
+ return UserService(get_user_repository())
588
+
589
+ # Usage in API routes
590
+ from fastapi import Depends
591
+
592
+ @app.get("/users/{user_id}")
593
+ def get_user(
594
+ user_id: int,
595
+ service: UserService = Depends(get_user_service)
596
+ ):
597
+ user = service.get_user(user_id)
598
+ return user
599
+ ```
600
+
601
+ ## Code Quality Tools
602
+
603
+ ### Ruff Configuration (ruff.toml)
604
+
605
+ ```toml
606
+ [lint]
607
+ select = [
608
+ "E", # pycodestyle errors
609
+ "W", # pycodestyle warnings
610
+ "F", # Pyflakes
611
+ "I", # isort
612
+ "B", # flake8-bugbear
613
+ "C4", # flake8-comprehensions
614
+ "UP", # pyupgrade
615
+ ]
616
+
617
+ ignore = [
618
+ "E501", # Line too long (handled by formatter)
619
+ ]
620
+
621
+ [lint.per-file-ignores]
622
+ "__init__.py" = ["F401"] # Unused imports OK in __init__
623
+ "tests/*" = ["S101"] # Assert OK in tests
624
+
625
+ [format]
626
+ quote-style = "double"
627
+ indent-style = "space"
628
+ line-ending = "auto"
629
+ ```
630
+
631
+ ### Pytest Configuration (pytest.ini)
632
+
633
+ ```ini
634
+ [pytest]
635
+ testpaths = tests
636
+ python_files = test_*.py
637
+ python_classes = Test*
638
+ python_functions = test_*
639
+ addopts =
640
+ -v
641
+ --strict-markers
642
+ --tb=short
643
+ --cov=app
644
+ --cov-report=term-missing
645
+ markers =
646
+ slow: marks tests as slow
647
+ integration: marks tests as integration tests
648
+ unit: marks tests as unit tests
649
+ ```
650
+
651
+ ### Mypy Configuration (mypy.ini)
652
+
653
+ ```ini
654
+ [mypy]
655
+ python_version = 3.11
656
+ warn_return_any = True
657
+ warn_unused_configs = True
658
+ disallow_untyped_defs = True
659
+ disallow_incomplete_defs = True
660
+ check_untyped_defs = True
661
+ no_implicit_optional = True
662
+ warn_redundant_casts = True
663
+ warn_unused_ignores = True
664
+
665
+ [mypy-tests.*]
666
+ disallow_untyped_defs = False
667
+ ```
668
+
669
+ ## Anti-Patterns to Avoid
670
+
671
+ ### ❌ Bad: Mutable Default Arguments
672
+
673
+ ```python
674
+ # ❌ Bad
675
+ def add_item(item, items=[]):
676
+ items.append(item)
677
+ return items
678
+
679
+ # ✅ Good
680
+ def add_item(item, items=None):
681
+ if items is None:
682
+ items = []
683
+ items.append(item)
684
+ return items
685
+ ```
686
+
687
+ ### ❌ Bad: Bare Except
688
+
689
+ ```python
690
+ # ❌ Bad
691
+ try:
692
+ risky_operation()
693
+ except:
694
+ pass
695
+
696
+ # ✅ Good
697
+ try:
698
+ risky_operation()
699
+ except SpecificException as e:
700
+ logger.error(f"Operation failed: {e}")
701
+ raise
702
+ ```
703
+
704
+ ### ❌ Bad: Deep Nesting
705
+
706
+ ```python
707
+ # ❌ Bad
708
+ def process_data(data):
709
+ if data:
710
+ for item in data:
711
+ if item.valid:
712
+ for subitem in item.subitems:
713
+ if subitem.active:
714
+ process(subitem)
715
+
716
+ # ✅ Good
717
+ def process_data(data):
718
+ if not data:
719
+ return
720
+
721
+ for item in data:
722
+ if not item.valid:
723
+ continue
724
+
725
+ for subitem in item.subitems:
726
+ if subitem.active:
727
+ process(subitem)
728
+ ```
729
+
730
+ ### ❌ Bad: Magic Numbers
731
+
732
+ ```python
733
+ # ❌ Bad
734
+ def calculate_price(price):
735
+ return price * 1.1 * 0.95
736
+
737
+ # ✅ Good
738
+ TAX_RATE = 0.1
739
+ DISCOUNT_RATE = 0.05
740
+
741
+ def calculate_price(price):
742
+ return price * (1 + TAX_RATE) * (1 - DISCOUNT_RATE)
743
+ ```
744
+
745
+ ### ❌ Bad: God Classes
746
+
747
+ ```python
748
+ # ❌ Bad: Does everything
749
+ class UserManager:
750
+ def create_user(self): pass
751
+ def delete_user(self): pass
752
+ def send_email(self): pass
753
+ def generate_report(self): pass
754
+ def connect_db(self): pass
755
+
756
+ # ✅ Good: Single responsibility
757
+ class UserService:
758
+ def create_user(self): pass
759
+ def delete_user(self): pass
760
+
761
+ class EmailService:
762
+ def send_email(self): pass
763
+
764
+ class ReportGenerator:
765
+ def generate_report(self): pass
766
+ ```
767
+
768
+ ## Commands
769
+
770
+ /python-guide-lint: Run Ruff linter and formatter
771
+ /python-guide-test: Run pytest with coverage
772
+ /python-guide-typecheck: Run mypy type checking
773
+ /python-guide-format: Format code with Black/Ruff
774
+
775
+ ## Examples
776
+
777
+ ### Example 1: Create New Feature
778
+
779
+ User: "Add user registration endpoint"
780
+
781
+ Agent:
782
+ 1. Create schema in `app/schemas/user.py`
783
+ 2. Create service in `app/services/user_service.py`
784
+ 3. Create repository in `app/repositories/user_repo.py`
785
+ 4. Create route in `app/api/routes/users.py`
786
+ 5. Write tests in `tests/test_users.py`
787
+ 6. Run: `ruff check app && pytest tests/test_users.py`
788
+
789
+ Follow patterns in existing code. Use type hints, docstrings, and proper error handling.
790
+
791
+ ### Example 2: Refactor Legacy Code
792
+
793
+ User: "Refactor this function"
794
+
795
+ Agent:
796
+ 1. Write tests for current behavior
797
+ 2. Add type hints
798
+ 3. Extract helper functions
799
+ 4. Improve naming
800
+ 5. Add docstrings
801
+ 6. Run: `ruff check && mypy && pytest`
802
+
803
+ Ensure tests pass before and after. Maintain backward compatibility.
804
+
805
+ ### Example 3: Fix Bug
806
+
807
+ User: "Fix null pointer exception"
808
+
809
+ Agent:
810
+ 1. Reproduce the bug with test
811
+ 2. Identify root cause (missing None check)
812
+ 3. Add proper None handling
813
+ 4. Add type hints (Optional)
814
+ 5. Run tests to verify fix
815
+ 6. Run: `ruff check && mypy`
816
+
817
+ ## Additional Resources
818
+
819
+ - [PEP 8 Style Guide](https://peps.python.org/pep-0008/)
820
+ - [Real Python Best Practices](https://realpython.com/tutorials/best-practices/)
821
+ - [Python Code Quality Tools](https://realpython.com/python-code-quality/)
822
+ - [FastAPI Best Practices](https://dev.to/building-production-ready-apis-with-fastapi-in-2026)