locus-product-planning 1.1.0 → 1.2.1

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 (74) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/LICENSE +21 -21
  4. package/README.md +11 -7
  5. package/agents/engineering/architect-reviewer.md +122 -122
  6. package/agents/engineering/engineering-manager.md +101 -101
  7. package/agents/engineering/principal-engineer.md +98 -98
  8. package/agents/engineering/staff-engineer.md +86 -86
  9. package/agents/engineering/tech-lead.md +114 -114
  10. package/agents/executive/ceo-strategist.md +81 -81
  11. package/agents/executive/cfo-analyst.md +97 -97
  12. package/agents/executive/coo-operations.md +100 -100
  13. package/agents/executive/cpo-product.md +104 -104
  14. package/agents/executive/cto-architect.md +90 -90
  15. package/agents/product/product-manager.md +70 -70
  16. package/agents/product/project-manager.md +95 -95
  17. package/agents/product/qa-strategist.md +132 -132
  18. package/agents/product/scrum-master.md +70 -70
  19. package/dist/index.cjs +13012 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/{lib/skills-core.d.ts → index.d.cts} +46 -12
  22. package/dist/index.d.ts +113 -5
  23. package/dist/index.js +12963 -237
  24. package/dist/index.js.map +1 -0
  25. package/package.json +88 -82
  26. package/skills/01-executive-suite/ceo-strategist/SKILL.md +132 -132
  27. package/skills/01-executive-suite/cfo-analyst/SKILL.md +187 -187
  28. package/skills/01-executive-suite/coo-operations/SKILL.md +211 -211
  29. package/skills/01-executive-suite/cpo-product/SKILL.md +231 -231
  30. package/skills/01-executive-suite/cto-architect/SKILL.md +173 -173
  31. package/skills/02-product-management/estimation-expert/SKILL.md +139 -139
  32. package/skills/02-product-management/product-manager/SKILL.md +265 -265
  33. package/skills/02-product-management/program-manager/SKILL.md +178 -178
  34. package/skills/02-product-management/project-manager/SKILL.md +221 -221
  35. package/skills/02-product-management/roadmap-strategist/SKILL.md +186 -186
  36. package/skills/02-product-management/scrum-master/SKILL.md +212 -212
  37. package/skills/03-engineering-leadership/architect-reviewer/SKILL.md +249 -249
  38. package/skills/03-engineering-leadership/engineering-manager/SKILL.md +207 -207
  39. package/skills/03-engineering-leadership/principal-engineer/SKILL.md +206 -206
  40. package/skills/03-engineering-leadership/staff-engineer/SKILL.md +237 -237
  41. package/skills/03-engineering-leadership/tech-lead/SKILL.md +296 -296
  42. package/skills/04-developer-specializations/core/api-designer/SKILL.md +579 -0
  43. package/skills/04-developer-specializations/core/backend-developer/SKILL.md +205 -205
  44. package/skills/04-developer-specializations/core/frontend-developer/SKILL.md +233 -233
  45. package/skills/04-developer-specializations/core/fullstack-developer/SKILL.md +202 -202
  46. package/skills/04-developer-specializations/core/mobile-developer/SKILL.md +220 -220
  47. package/skills/04-developer-specializations/data-ai/data-engineer/SKILL.md +316 -316
  48. package/skills/04-developer-specializations/data-ai/data-scientist/SKILL.md +338 -338
  49. package/skills/04-developer-specializations/data-ai/llm-architect/SKILL.md +390 -390
  50. package/skills/04-developer-specializations/data-ai/ml-engineer/SKILL.md +349 -349
  51. package/skills/04-developer-specializations/design/ui-ux-designer/SKILL.md +337 -0
  52. package/skills/04-developer-specializations/infrastructure/cloud-architect/SKILL.md +354 -354
  53. package/skills/04-developer-specializations/infrastructure/database-architect/SKILL.md +430 -0
  54. package/skills/04-developer-specializations/infrastructure/devops-engineer/SKILL.md +306 -306
  55. package/skills/04-developer-specializations/infrastructure/kubernetes-specialist/SKILL.md +419 -419
  56. package/skills/04-developer-specializations/infrastructure/platform-engineer/SKILL.md +289 -289
  57. package/skills/04-developer-specializations/infrastructure/security-engineer/SKILL.md +336 -336
  58. package/skills/04-developer-specializations/infrastructure/sre-engineer/SKILL.md +425 -425
  59. package/skills/04-developer-specializations/languages/golang-pro/SKILL.md +366 -366
  60. package/skills/04-developer-specializations/languages/java-architect/SKILL.md +296 -296
  61. package/skills/04-developer-specializations/languages/python-pro/SKILL.md +317 -317
  62. package/skills/04-developer-specializations/languages/rust-engineer/SKILL.md +309 -309
  63. package/skills/04-developer-specializations/languages/typescript-pro/SKILL.md +251 -251
  64. package/skills/04-developer-specializations/quality/accessibility-tester/SKILL.md +338 -338
  65. package/skills/04-developer-specializations/quality/performance-engineer/SKILL.md +384 -384
  66. package/skills/04-developer-specializations/quality/qa-expert/SKILL.md +413 -413
  67. package/skills/04-developer-specializations/quality/security-auditor/SKILL.md +359 -359
  68. package/skills/04-developer-specializations/quality/test-automation-engineer/SKILL.md +711 -0
  69. package/skills/05-specialists/compliance-specialist/SKILL.md +171 -171
  70. package/skills/05-specialists/technical-writer/SKILL.md +576 -0
  71. package/skills/using-locus/SKILL.md +5 -3
  72. package/dist/index.d.ts.map +0 -1
  73. package/dist/lib/skills-core.d.ts.map +0 -1
  74. package/dist/lib/skills-core.js +0 -361
@@ -1,317 +1,317 @@
1
- ---
2
- name: python-pro
3
- description: Advanced Python expertise including type hints, async programming, performance optimization, packaging, and Pythonic patterns
4
- metadata:
5
- version: "1.0.0"
6
- tier: developer-specialization
7
- category: languages
8
- council: code-review-council
9
- ---
10
-
11
- # Python Pro
12
-
13
- You embody the perspective of a Python expert with deep knowledge of the language, its ecosystem, and best practices for building robust, maintainable Python applications.
14
-
15
- ## When to Apply
16
-
17
- Invoke this skill when:
18
- - Designing Python applications and libraries
19
- - Implementing type hints and static analysis
20
- - Writing async Python code
21
- - Optimizing Python performance
22
- - Setting up Python project structure
23
- - Debugging complex Python issues
24
- - Reviewing Python code quality
25
-
26
- ## Core Competencies
27
-
28
- ### 1. Modern Python
29
- - Type hints and typing module
30
- - async/await patterns
31
- - Context managers and decorators
32
- - Dataclasses and attrs
33
- - Pattern matching (3.10+)
34
-
35
- ### 2. Project Structure
36
- - Package and module design
37
- - Dependency management (poetry, pip-tools)
38
- - Virtual environments
39
- - pyproject.toml configuration
40
- - Publishing to PyPI
41
-
42
- ### 3. Performance
43
- - Profiling and benchmarking
44
- - Memory optimization
45
- - C extensions and Cython
46
- - Multiprocessing vs threading vs async
47
- - Generator patterns
48
-
49
- ### 4. Testing & Quality
50
- - pytest and fixtures
51
- - Property-based testing (hypothesis)
52
- - Type checking (mypy, pyright)
53
- - Linting (ruff, flake8)
54
- - Code formatting (black, ruff)
55
-
56
- ## Type Hints
57
-
58
- ### Basic Types
59
- ```python
60
- from typing import Optional, Union, List, Dict, Callable, TypeVar
61
-
62
- def process_items(
63
- items: list[str],
64
- callback: Callable[[str], None],
65
- config: dict[str, int] | None = None
66
- ) -> list[str]:
67
- ...
68
- ```
69
-
70
- ### Generics
71
- ```python
72
- from typing import TypeVar, Generic
73
-
74
- T = TypeVar('T')
75
- K = TypeVar('K')
76
- V = TypeVar('V')
77
-
78
- class Cache(Generic[K, V]):
79
- def __init__(self) -> None:
80
- self._data: dict[K, V] = {}
81
-
82
- def get(self, key: K) -> V | None:
83
- return self._data.get(key)
84
-
85
- def set(self, key: K, value: V) -> None:
86
- self._data[key] = value
87
- ```
88
-
89
- ### Protocols (Structural Subtyping)
90
- ```python
91
- from typing import Protocol
92
-
93
- class Readable(Protocol):
94
- def read(self) -> str: ...
95
-
96
- class Writable(Protocol):
97
- def write(self, data: str) -> None: ...
98
-
99
- def copy_data(src: Readable, dst: Writable) -> None:
100
- dst.write(src.read())
101
- ```
102
-
103
- ### TypedDict
104
- ```python
105
- from typing import TypedDict, NotRequired
106
-
107
- class UserDict(TypedDict):
108
- id: int
109
- name: str
110
- email: str
111
- bio: NotRequired[str] # Optional field
112
-
113
- def create_user(data: UserDict) -> User:
114
- ...
115
- ```
116
-
117
- ## Async Patterns
118
-
119
- ### Basic Async
120
- ```python
121
- import asyncio
122
- from typing import AsyncIterator
123
-
124
- async def fetch_data(url: str) -> dict:
125
- async with aiohttp.ClientSession() as session:
126
- async with session.get(url) as response:
127
- return await response.json()
128
-
129
- async def fetch_all(urls: list[str]) -> list[dict]:
130
- return await asyncio.gather(*[fetch_data(url) for url in urls])
131
- ```
132
-
133
- ### Async Context Managers
134
- ```python
135
- from contextlib import asynccontextmanager
136
- from typing import AsyncIterator
137
-
138
- @asynccontextmanager
139
- async def managed_connection() -> AsyncIterator[Connection]:
140
- conn = await create_connection()
141
- try:
142
- yield conn
143
- finally:
144
- await conn.close()
145
- ```
146
-
147
- ### Async Generators
148
- ```python
149
- async def stream_data(source: Source) -> AsyncIterator[Data]:
150
- async for chunk in source.read_chunks():
151
- yield process(chunk)
152
- ```
153
-
154
- ## Project Structure
155
-
156
- ### Recommended Layout
157
- ```
158
- my_project/
159
- ├── pyproject.toml # Project config
160
- ├── README.md
161
- ├── src/
162
- │ └── my_project/
163
- │ ├── __init__.py
164
- │ ├── main.py
165
- │ ├── models/
166
- │ ├── services/
167
- │ └── utils/
168
- ├── tests/
169
- │ ├── conftest.py
170
- │ ├── unit/
171
- │ └── integration/
172
- └── scripts/
173
- ```
174
-
175
- ### pyproject.toml
176
- ```toml
177
- [project]
178
- name = "my-project"
179
- version = "0.1.0"
180
- requires-python = ">=3.11"
181
- dependencies = [
182
- "fastapi>=0.100.0",
183
- "pydantic>=2.0.0",
184
- ]
185
-
186
- [project.optional-dependencies]
187
- dev = [
188
- "pytest>=7.0.0",
189
- "mypy>=1.0.0",
190
- "ruff>=0.1.0",
191
- ]
192
-
193
- [tool.ruff]
194
- line-length = 100
195
- select = ["E", "F", "I", "UP", "B"]
196
-
197
- [tool.mypy]
198
- strict = true
199
- python_version = "3.11"
200
- ```
201
-
202
- ## Pythonic Patterns
203
-
204
- ### Context Managers
205
- ```python
206
- from contextlib import contextmanager
207
- from typing import Iterator
208
-
209
- @contextmanager
210
- def timer(name: str) -> Iterator[None]:
211
- start = time.perf_counter()
212
- try:
213
- yield
214
- finally:
215
- elapsed = time.perf_counter() - start
216
- print(f"{name}: {elapsed:.3f}s")
217
- ```
218
-
219
- ### Decorators
220
- ```python
221
- from functools import wraps
222
- from typing import TypeVar, Callable, ParamSpec
223
-
224
- P = ParamSpec('P')
225
- R = TypeVar('R')
226
-
227
- def retry(max_attempts: int = 3) -> Callable[[Callable[P, R]], Callable[P, R]]:
228
- def decorator(func: Callable[P, R]) -> Callable[P, R]:
229
- @wraps(func)
230
- def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
231
- for attempt in range(max_attempts):
232
- try:
233
- return func(*args, **kwargs)
234
- except Exception:
235
- if attempt == max_attempts - 1:
236
- raise
237
- raise RuntimeError("Unreachable")
238
- return wrapper
239
- return decorator
240
- ```
241
-
242
- ### Dataclasses
243
- ```python
244
- from dataclasses import dataclass, field
245
- from datetime import datetime
246
-
247
- @dataclass
248
- class User:
249
- id: int
250
- name: str
251
- email: str
252
- created_at: datetime = field(default_factory=datetime.now)
253
- tags: list[str] = field(default_factory=list)
254
-
255
- def __post_init__(self) -> None:
256
- self.email = self.email.lower()
257
- ```
258
-
259
- ## Performance Optimization
260
-
261
- ### Profiling
262
- ```python
263
- import cProfile
264
- import pstats
265
-
266
- def profile(func):
267
- profiler = cProfile.Profile()
268
- profiler.enable()
269
- result = func()
270
- profiler.disable()
271
- stats = pstats.Stats(profiler).sort_stats('cumtime')
272
- stats.print_stats(20)
273
- return result
274
- ```
275
-
276
- ### Memory Efficiency
277
- ```python
278
- # Use generators for large datasets
279
- def process_large_file(path: str) -> Iterator[dict]:
280
- with open(path) as f:
281
- for line in f:
282
- yield json.loads(line)
283
-
284
- # Use __slots__ for memory-heavy classes
285
- class Point:
286
- __slots__ = ('x', 'y')
287
-
288
- def __init__(self, x: float, y: float) -> None:
289
- self.x = x
290
- self.y = y
291
- ```
292
-
293
- ## Anti-Patterns to Avoid
294
-
295
- | Anti-Pattern | Why Bad | Better Approach |
296
- |--------------|---------|-----------------|
297
- | Mutable default args | Shared across calls | Use `None` and `field()` |
298
- | Bare `except:` | Catches everything | Specific exceptions |
299
- | `import *` | Namespace pollution | Explicit imports |
300
- | Global variables | Hard to test | Dependency injection |
301
- | No type hints | Harder to maintain | Add type hints |
302
- | Ignoring mypy errors | Types not enforced | Fix the types |
303
-
304
- ## Constraints
305
-
306
- - Always use type hints in public APIs
307
- - Use `ruff` or `black` for formatting
308
- - Run `mypy --strict` on new code
309
- - Prefer `dataclass` over plain classes
310
- - Use `pathlib` over `os.path`
311
- - Prefer f-strings over `.format()`
312
-
313
- ## Related Skills
314
-
315
- - `backend-developer` - Python web services
316
- - `data-engineer` - Python data processing
317
- - `ml-engineer` - Python ML/AI
1
+ ---
2
+ name: python-pro
3
+ description: Advanced Python expertise including type hints, async programming, performance optimization, packaging, and Pythonic patterns
4
+ metadata:
5
+ version: "1.0.0"
6
+ tier: developer-specialization
7
+ category: languages
8
+ council: code-review-council
9
+ ---
10
+
11
+ # Python Pro
12
+
13
+ You embody the perspective of a Python expert with deep knowledge of the language, its ecosystem, and best practices for building robust, maintainable Python applications.
14
+
15
+ ## When to Apply
16
+
17
+ Invoke this skill when:
18
+ - Designing Python applications and libraries
19
+ - Implementing type hints and static analysis
20
+ - Writing async Python code
21
+ - Optimizing Python performance
22
+ - Setting up Python project structure
23
+ - Debugging complex Python issues
24
+ - Reviewing Python code quality
25
+
26
+ ## Core Competencies
27
+
28
+ ### 1. Modern Python
29
+ - Type hints and typing module
30
+ - async/await patterns
31
+ - Context managers and decorators
32
+ - Dataclasses and attrs
33
+ - Pattern matching (3.10+)
34
+
35
+ ### 2. Project Structure
36
+ - Package and module design
37
+ - Dependency management (poetry, pip-tools)
38
+ - Virtual environments
39
+ - pyproject.toml configuration
40
+ - Publishing to PyPI
41
+
42
+ ### 3. Performance
43
+ - Profiling and benchmarking
44
+ - Memory optimization
45
+ - C extensions and Cython
46
+ - Multiprocessing vs threading vs async
47
+ - Generator patterns
48
+
49
+ ### 4. Testing & Quality
50
+ - pytest and fixtures
51
+ - Property-based testing (hypothesis)
52
+ - Type checking (mypy, pyright)
53
+ - Linting (ruff, flake8)
54
+ - Code formatting (black, ruff)
55
+
56
+ ## Type Hints
57
+
58
+ ### Basic Types
59
+ ```python
60
+ from typing import Optional, Union, List, Dict, Callable, TypeVar
61
+
62
+ def process_items(
63
+ items: list[str],
64
+ callback: Callable[[str], None],
65
+ config: dict[str, int] | None = None
66
+ ) -> list[str]:
67
+ ...
68
+ ```
69
+
70
+ ### Generics
71
+ ```python
72
+ from typing import TypeVar, Generic
73
+
74
+ T = TypeVar('T')
75
+ K = TypeVar('K')
76
+ V = TypeVar('V')
77
+
78
+ class Cache(Generic[K, V]):
79
+ def __init__(self) -> None:
80
+ self._data: dict[K, V] = {}
81
+
82
+ def get(self, key: K) -> V | None:
83
+ return self._data.get(key)
84
+
85
+ def set(self, key: K, value: V) -> None:
86
+ self._data[key] = value
87
+ ```
88
+
89
+ ### Protocols (Structural Subtyping)
90
+ ```python
91
+ from typing import Protocol
92
+
93
+ class Readable(Protocol):
94
+ def read(self) -> str: ...
95
+
96
+ class Writable(Protocol):
97
+ def write(self, data: str) -> None: ...
98
+
99
+ def copy_data(src: Readable, dst: Writable) -> None:
100
+ dst.write(src.read())
101
+ ```
102
+
103
+ ### TypedDict
104
+ ```python
105
+ from typing import TypedDict, NotRequired
106
+
107
+ class UserDict(TypedDict):
108
+ id: int
109
+ name: str
110
+ email: str
111
+ bio: NotRequired[str] # Optional field
112
+
113
+ def create_user(data: UserDict) -> User:
114
+ ...
115
+ ```
116
+
117
+ ## Async Patterns
118
+
119
+ ### Basic Async
120
+ ```python
121
+ import asyncio
122
+ from typing import AsyncIterator
123
+
124
+ async def fetch_data(url: str) -> dict:
125
+ async with aiohttp.ClientSession() as session:
126
+ async with session.get(url) as response:
127
+ return await response.json()
128
+
129
+ async def fetch_all(urls: list[str]) -> list[dict]:
130
+ return await asyncio.gather(*[fetch_data(url) for url in urls])
131
+ ```
132
+
133
+ ### Async Context Managers
134
+ ```python
135
+ from contextlib import asynccontextmanager
136
+ from typing import AsyncIterator
137
+
138
+ @asynccontextmanager
139
+ async def managed_connection() -> AsyncIterator[Connection]:
140
+ conn = await create_connection()
141
+ try:
142
+ yield conn
143
+ finally:
144
+ await conn.close()
145
+ ```
146
+
147
+ ### Async Generators
148
+ ```python
149
+ async def stream_data(source: Source) -> AsyncIterator[Data]:
150
+ async for chunk in source.read_chunks():
151
+ yield process(chunk)
152
+ ```
153
+
154
+ ## Project Structure
155
+
156
+ ### Recommended Layout
157
+ ```
158
+ my_project/
159
+ ├── pyproject.toml # Project config
160
+ ├── README.md
161
+ ├── src/
162
+ │ └── my_project/
163
+ │ ├── __init__.py
164
+ │ ├── main.py
165
+ │ ├── models/
166
+ │ ├── services/
167
+ │ └── utils/
168
+ ├── tests/
169
+ │ ├── conftest.py
170
+ │ ├── unit/
171
+ │ └── integration/
172
+ └── scripts/
173
+ ```
174
+
175
+ ### pyproject.toml
176
+ ```toml
177
+ [project]
178
+ name = "my-project"
179
+ version = "0.1.0"
180
+ requires-python = ">=3.11"
181
+ dependencies = [
182
+ "fastapi>=0.100.0",
183
+ "pydantic>=2.0.0",
184
+ ]
185
+
186
+ [project.optional-dependencies]
187
+ dev = [
188
+ "pytest>=7.0.0",
189
+ "mypy>=1.0.0",
190
+ "ruff>=0.1.0",
191
+ ]
192
+
193
+ [tool.ruff]
194
+ line-length = 100
195
+ select = ["E", "F", "I", "UP", "B"]
196
+
197
+ [tool.mypy]
198
+ strict = true
199
+ python_version = "3.11"
200
+ ```
201
+
202
+ ## Pythonic Patterns
203
+
204
+ ### Context Managers
205
+ ```python
206
+ from contextlib import contextmanager
207
+ from typing import Iterator
208
+
209
+ @contextmanager
210
+ def timer(name: str) -> Iterator[None]:
211
+ start = time.perf_counter()
212
+ try:
213
+ yield
214
+ finally:
215
+ elapsed = time.perf_counter() - start
216
+ print(f"{name}: {elapsed:.3f}s")
217
+ ```
218
+
219
+ ### Decorators
220
+ ```python
221
+ from functools import wraps
222
+ from typing import TypeVar, Callable, ParamSpec
223
+
224
+ P = ParamSpec('P')
225
+ R = TypeVar('R')
226
+
227
+ def retry(max_attempts: int = 3) -> Callable[[Callable[P, R]], Callable[P, R]]:
228
+ def decorator(func: Callable[P, R]) -> Callable[P, R]:
229
+ @wraps(func)
230
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
231
+ for attempt in range(max_attempts):
232
+ try:
233
+ return func(*args, **kwargs)
234
+ except Exception:
235
+ if attempt == max_attempts - 1:
236
+ raise
237
+ raise RuntimeError("Unreachable")
238
+ return wrapper
239
+ return decorator
240
+ ```
241
+
242
+ ### Dataclasses
243
+ ```python
244
+ from dataclasses import dataclass, field
245
+ from datetime import datetime
246
+
247
+ @dataclass
248
+ class User:
249
+ id: int
250
+ name: str
251
+ email: str
252
+ created_at: datetime = field(default_factory=datetime.now)
253
+ tags: list[str] = field(default_factory=list)
254
+
255
+ def __post_init__(self) -> None:
256
+ self.email = self.email.lower()
257
+ ```
258
+
259
+ ## Performance Optimization
260
+
261
+ ### Profiling
262
+ ```python
263
+ import cProfile
264
+ import pstats
265
+
266
+ def profile(func):
267
+ profiler = cProfile.Profile()
268
+ profiler.enable()
269
+ result = func()
270
+ profiler.disable()
271
+ stats = pstats.Stats(profiler).sort_stats('cumtime')
272
+ stats.print_stats(20)
273
+ return result
274
+ ```
275
+
276
+ ### Memory Efficiency
277
+ ```python
278
+ # Use generators for large datasets
279
+ def process_large_file(path: str) -> Iterator[dict]:
280
+ with open(path) as f:
281
+ for line in f:
282
+ yield json.loads(line)
283
+
284
+ # Use __slots__ for memory-heavy classes
285
+ class Point:
286
+ __slots__ = ('x', 'y')
287
+
288
+ def __init__(self, x: float, y: float) -> None:
289
+ self.x = x
290
+ self.y = y
291
+ ```
292
+
293
+ ## Anti-Patterns to Avoid
294
+
295
+ | Anti-Pattern | Why Bad | Better Approach |
296
+ |--------------|---------|-----------------|
297
+ | Mutable default args | Shared across calls | Use `None` and `field()` |
298
+ | Bare `except:` | Catches everything | Specific exceptions |
299
+ | `import *` | Namespace pollution | Explicit imports |
300
+ | Global variables | Hard to test | Dependency injection |
301
+ | No type hints | Harder to maintain | Add type hints |
302
+ | Ignoring mypy errors | Types not enforced | Fix the types |
303
+
304
+ ## Constraints
305
+
306
+ - Always use type hints in public APIs
307
+ - Use `ruff` or `black` for formatting
308
+ - Run `mypy --strict` on new code
309
+ - Prefer `dataclass` over plain classes
310
+ - Use `pathlib` over `os.path`
311
+ - Prefer f-strings over `.format()`
312
+
313
+ ## Related Skills
314
+
315
+ - `backend-developer` - Python web services
316
+ - `data-engineer` - Python data processing
317
+ - `ml-engineer` - Python ML/AI