@martinffx/atelier 2.0.0 → 3.0.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 (81) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +94 -253
  3. package/package.json +1 -1
  4. package/skills/{spec-orchestrator → atelier-orchestrator}/SKILL.md +3 -3
  5. package/skills/atelier-setup/SKILL.md +80 -0
  6. package/skills/code-review/references/reviewers.md +3 -3
  7. package/skills/code-review/references/rq.md +6 -6
  8. package/skills/spec-brainstorm/SKILL.md +5 -5
  9. package/skills/spec-implement/SKILL.md +2 -3
  10. package/skills/spec-plan/SKILL.md +21 -29
  11. package/skills/spec-plan/references/plan_template.md +77 -0
  12. package/skills/python-architecture/SKILL.md +0 -148
  13. package/skills/python-architecture/references/data-modeling.md +0 -558
  14. package/skills/python-architecture/references/ddd.md +0 -569
  15. package/skills/python-architecture/references/functional-core.md +0 -337
  16. package/skills/python-build-tools/SKILL.md +0 -153
  17. package/skills/python-build-tools/references/basedpyright.md +0 -321
  18. package/skills/python-build-tools/references/ruff.md +0 -225
  19. package/skills/python-build-tools/references/uv.md +0 -257
  20. package/skills/python-fastapi/SKILL.md +0 -184
  21. package/skills/python-fastapi/references/api-design.md +0 -563
  22. package/skills/python-fastapi/references/dependencies.md +0 -479
  23. package/skills/python-fastapi/references/middleware.md +0 -475
  24. package/skills/python-fastapi/references/validation.md +0 -497
  25. package/skills/python-modern-python/SKILL.md +0 -201
  26. package/skills/python-modern-python/references/async.md +0 -76
  27. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  28. package/skills/python-modern-python/references/typing.md +0 -96
  29. package/skills/python-monorepo/SKILL.md +0 -146
  30. package/skills/python-monorepo/references/docker.md +0 -515
  31. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  32. package/skills/python-monorepo/references/workspace-config.md +0 -341
  33. package/skills/python-sqlalchemy/SKILL.md +0 -119
  34. package/skills/python-sqlalchemy/references/async.md +0 -51
  35. package/skills/python-sqlalchemy/references/models.md +0 -67
  36. package/skills/python-sqlalchemy/references/queries.md +0 -57
  37. package/skills/python-temporal/SKILL.md +0 -128
  38. package/skills/python-temporal/references/patterns.md +0 -87
  39. package/skills/python-temporal/references/testing.md +0 -54
  40. package/skills/python-testing/SKILL.md +0 -161
  41. package/skills/python-testing/references/boundaries.md +0 -449
  42. package/skills/python-testing/references/mocking.md +0 -449
  43. package/skills/python-testing/references/pytest.md +0 -524
  44. package/skills/typescript-api-design/SKILL.md +0 -396
  45. package/skills/typescript-api-design/references/error-responses.md +0 -469
  46. package/skills/typescript-build-tools/SKILL.md +0 -447
  47. package/skills/typescript-build-tools/references/biome.md +0 -436
  48. package/skills/typescript-build-tools/references/bun.md +0 -432
  49. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  50. package/skills/typescript-build-tools/references/vitest.md +0 -518
  51. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  52. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  53. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  54. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  55. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  56. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  57. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  58. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  59. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  60. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  61. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  62. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  63. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  64. package/skills/typescript-effect-ts/SKILL.md +0 -341
  65. package/skills/typescript-effect-ts/references/core.md +0 -412
  66. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  67. package/skills/typescript-effect-ts/references/resources.md +0 -476
  68. package/skills/typescript-effect-ts/references/schema.md +0 -536
  69. package/skills/typescript-effect-ts/references/services.md +0 -461
  70. package/skills/typescript-fastify/SKILL.md +0 -405
  71. package/skills/typescript-fastify/references/plugins.md +0 -329
  72. package/skills/typescript-fastify/references/typeid.md +0 -315
  73. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  74. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  75. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  76. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  77. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  78. package/skills/typescript-testing/SKILL.md +0 -353
  79. package/skills/typescript-testing/references/mocking.md +0 -675
  80. package/skills/typescript-testing/references/msw.md +0 -852
  81. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
@@ -1,337 +0,0 @@
1
- # Functional Core / Imperative Shell
2
-
3
- The functional core pattern separates pure business logic from side effects, creating highly testable and maintainable code.
4
-
5
- ## Core Concept
6
-
7
- **Functional Core:**
8
- - Pure functions with no side effects
9
- - Deterministic: same input always produces same output
10
- - No IO operations (database, HTTP, files, time, random)
11
- - Easy to test (no mocks needed)
12
- - Business logic and domain rules
13
-
14
- **Imperative Shell:**
15
- - Thin layer handling all side effects
16
- - Coordinates external dependencies
17
- - Calls functional core for decisions
18
- - Hard to test (but simple enough to not need testing)
19
-
20
- ## Pattern Structure
21
-
22
- ```
23
- ┌─────────────────────────────────┐
24
- │ Imperative Shell │
25
- │ (HTTP, Database, Files, Time) │
26
- │ │
27
- │ ┌───────────────────────────┐ │
28
- │ │ Functional Core │ │
29
- │ │ (Pure Business Logic) │ │
30
- │ │ - Calculations │ │
31
- │ │ - Decisions │ │
32
- │ │ - Transformations │ │
33
- │ └───────────────────────────┘ │
34
- │ │
35
- └─────────────────────────────────┘
36
- ```
37
-
38
- ## Examples
39
-
40
- ### ❌ Bad: Mixed Concerns
41
-
42
- ```python
43
- import requests
44
- from datetime import datetime
45
- from database import save_order
46
-
47
- def process_order(order_id: str) -> None:
48
- """Everything mixed together - hard to test"""
49
- # IO
50
- response = requests.get(f"/api/orders/{order_id}")
51
- order_data = response.json()
52
-
53
- # Business logic
54
- if order_data["total"] > 100:
55
- discount = 0.1
56
- else:
57
- discount = 0
58
-
59
- # More IO
60
- order_data["discount"] = discount
61
- order_data["processed_at"] = datetime.now().isoformat()
62
-
63
- # More IO
64
- save_order(order_data)
65
- ```
66
-
67
- **Problems:**
68
- - Can't test business logic without HTTP, database, time
69
- - Hard to verify discount calculation
70
- - Slow tests (real IO)
71
- - Unpredictable (depends on current time)
72
-
73
- ### ✅ Good: Separated Concerns
74
-
75
- ```python
76
- # ===== Functional Core (pure functions) =====
77
- from decimal import Decimal
78
- from dataclasses import dataclass
79
- from datetime import datetime
80
-
81
- @dataclass
82
- class OrderData:
83
- total: Decimal
84
- discount: Decimal
85
- processed_at: datetime
86
-
87
- def calculate_discount(total: Decimal) -> Decimal:
88
- """Pure function - no side effects"""
89
- if total > 100:
90
- return Decimal("0.1")
91
- return Decimal("0")
92
-
93
- def apply_discount(order: OrderData, discount: Decimal, processed_at: datetime) -> OrderData:
94
- """Pure function - returns new data"""
95
- return OrderData(
96
- total=order.total * (1 - discount),
97
- discount=discount,
98
- processed_at=processed_at
99
- )
100
-
101
- # ===== Imperative Shell (IO coordination) =====
102
- import requests
103
- from database import save_order
104
-
105
- def process_order(order_id: str) -> None:
106
- """Thin shell - just coordinates IO"""
107
- # IO: fetch data
108
- response = requests.get(f"/api/orders/{order_id}")
109
- order_data = response.json()
110
-
111
- # Convert to domain model
112
- order = OrderData(
113
- total=Decimal(order_data["total"]),
114
- discount=Decimal("0"),
115
- processed_at=datetime.now() # IO: current time
116
- )
117
-
118
- # Pure: calculate discount
119
- discount = calculate_discount(order.total)
120
-
121
- # Pure: apply discount
122
- processed_order = apply_discount(order, discount, datetime.now())
123
-
124
- # IO: save result
125
- save_order({
126
- "total": float(processed_order.total),
127
- "discount": float(processed_order.discount),
128
- "processed_at": processed_order.processed_at.isoformat()
129
- })
130
- ```
131
-
132
- **Benefits:**
133
- - Test `calculate_discount` with no mocks
134
- - Test `apply_discount` with deterministic inputs
135
- - Shell is simple enough to not need tests
136
- - Fast tests (no real IO)
137
- - Predictable behavior
138
-
139
- ## Testing Pure Functions
140
-
141
- ```python
142
- import pytest
143
- from decimal import Decimal
144
-
145
- def test_discount_for_large_order():
146
- """No mocks needed!"""
147
- result = calculate_discount(Decimal("150"))
148
- assert result == Decimal("0.1")
149
-
150
- def test_no_discount_for_small_order():
151
- """No setup, no teardown"""
152
- result = calculate_discount(Decimal("50"))
153
- assert result == Decimal("0")
154
-
155
- def test_apply_discount():
156
- """Deterministic test"""
157
- order = OrderData(
158
- total=Decimal("100"),
159
- discount=Decimal("0"),
160
- processed_at=datetime(2024, 1, 1)
161
- )
162
-
163
- result = apply_discount(
164
- order,
165
- Decimal("0.1"),
166
- datetime(2024, 1, 2)
167
- )
168
-
169
- assert result.total == Decimal("90")
170
- assert result.discount == Decimal("0.1")
171
- assert result.processed_at == datetime(2024, 1, 2)
172
- ```
173
-
174
- ## Identifying Side Effects
175
-
176
- Ask these questions:
177
- 1. **Does it perform IO?** (Database, HTTP, files, logging)
178
- 2. **Does it depend on current time?** (datetime.now(), time.time())
179
- 3. **Does it use randomness?** (random.random(), uuid.uuid4())
180
- 4. **Does it mutate state?** (list.append(), dict.update())
181
- 5. **Does it depend on global state?** (environment variables, config)
182
-
183
- If yes to any → **Imperative Shell**
184
- If no to all → **Functional Core**
185
-
186
- ## Pushing Side Effects to the Edges
187
-
188
- ### ❌ Bad: Side effects in the middle
189
-
190
- ```python
191
- def calculate_price(product_id: str) -> Decimal:
192
- """Pure function name, but has hidden IO"""
193
- product = db.get_product(product_id) # Hidden side effect!
194
- return product.price * Decimal("1.1")
195
- ```
196
-
197
- ### ✅ Good: Accept data as parameter
198
-
199
- ```python
200
- def calculate_price(product: Product) -> Decimal:
201
- """Truly pure - takes data, returns result"""
202
- return product.price * Decimal("1.1")
203
-
204
- def get_calculated_price(product_id: str) -> Decimal:
205
- """Shell function - name reflects IO"""
206
- product = db.get_product(product_id) # IO is explicit
207
- return calculate_price(product) # Delegates to pure function
208
- ```
209
-
210
- ## Handling Time as a Side Effect
211
-
212
- ### ❌ Bad: Hidden time dependency
213
-
214
- ```python
215
- def is_expired(user: User) -> bool:
216
- """Not pure - depends on current time"""
217
- return user.expires_at < datetime.now()
218
- ```
219
-
220
- ### ✅ Good: Pass time as parameter
221
-
222
- ```python
223
- def is_expired(user: User, current_time: datetime) -> bool:
224
- """Pure - time is explicit parameter"""
225
- return user.expires_at < current_time
226
-
227
- def check_user_expiration(user: User) -> bool:
228
- """Shell - provides current time"""
229
- return is_expired(user, datetime.now())
230
- ```
231
-
232
- ## Advanced: Decision/Effect Separation
233
-
234
- For complex workflows, separate decisions from effects:
235
-
236
- ```python
237
- from dataclasses import dataclass
238
- from enum import Enum
239
-
240
- class Effect(Enum):
241
- SEND_EMAIL = "send_email"
242
- CHARGE_CARD = "charge_card"
243
- CREATE_ORDER = "create_order"
244
-
245
- @dataclass
246
- class Decision:
247
- """Pure data describing what to do"""
248
- effects: list[Effect]
249
- order_data: dict
250
-
251
- def decide_order_workflow(cart: Cart, user: User, payment: Payment) -> Decision:
252
- """Pure function - returns description of effects"""
253
- effects = []
254
-
255
- if user.requires_verification:
256
- effects.append(Effect.SEND_EMAIL)
257
-
258
- if payment.amount > 0:
259
- effects.append(Effect.CHARGE_CARD)
260
-
261
- effects.append(Effect.CREATE_ORDER)
262
-
263
- return Decision(
264
- effects=effects,
265
- order_data={"cart": cart, "user": user, "payment": payment}
266
- )
267
-
268
- def execute_order_workflow(cart: Cart, user: User, payment: Payment) -> None:
269
- """Shell - executes the effects"""
270
- decision = decide_order_workflow(cart, user, payment)
271
-
272
- for effect in decision.effects:
273
- if effect == Effect.SEND_EMAIL:
274
- email_service.send_verification(user.email)
275
- elif effect == Effect.CHARGE_CARD:
276
- payment_service.charge(payment.token, payment.amount)
277
- elif effect == Effect.CREATE_ORDER:
278
- order_service.create(decision.order_data)
279
- ```
280
-
281
- **Benefits:**
282
- - Test decisions without executing effects
283
- - Retry-safe (decisions are pure)
284
- - Effects can be logged, audited, replayed
285
-
286
- ## Guidelines
287
-
288
- 1. **Start with pure functions**: Write business logic first without IO
289
- 2. **Name functions honestly**: `get_user()` implies IO, `calculate_discount()` implies pure
290
- 3. **Minimize shell thickness**: Keep imperative shell as thin as possible
291
- 4. **Test the core**: Focus tests on functional core (business logic)
292
- 5. **Accept data, don't fetch it**: Pure functions take parameters, don't call repositories
293
- 6. **Return new data**: Don't mutate, return new values
294
- 7. **Make time explicit**: Pass datetime as parameter instead of calling `datetime.now()`
295
-
296
- ## When to Break the Rules
297
-
298
- **Logging**: Acceptable side effect in functional core if:
299
- - Non-invasive (doesn't change behavior)
300
- - Can be disabled/stubbed in tests
301
- - Doesn't affect return value
302
-
303
- ```python
304
- import logging
305
-
306
- logger = logging.getLogger(__name__)
307
-
308
- def calculate_discount(total: Decimal) -> Decimal:
309
- """Logging is acceptable side effect"""
310
- if total > 100:
311
- logger.debug(f"Applying discount to order total: {total}")
312
- return Decimal("0.1")
313
- return Decimal("0")
314
- ```
315
-
316
- **Caching**: Acceptable mutation if:
317
- - Implementation detail (doesn't affect observable behavior)
318
- - Transparent to callers
319
- - Doesn't break determinism
320
-
321
- ```python
322
- from functools import lru_cache
323
-
324
- @lru_cache(maxsize=128)
325
- def fibonacci(n: int) -> int:
326
- """Pure function with internal caching"""
327
- if n < 2:
328
- return n
329
- return fibonacci(n - 1) + fibonacci(n - 2)
330
- ```
331
-
332
- ## Summary
333
-
334
- - **Functional Core**: Pure functions, business logic, easy to test
335
- - **Imperative Shell**: IO coordination, thin layer, simple
336
- - **Benefits**: Testability, reliability, maintainability
337
- - **Key insight**: Most bugs are in business logic, not IO - make that testable
@@ -1,153 +0,0 @@
1
- ---
2
- name: python-build-tools
3
- description: Python project tooling with uv, mise, ruff, basedpyright, and pytest. Use when setting up pyproject.toml, running builds, typechecking, configuring tests, linting, formatting, or managing Python environments.
4
- user-invocable: false
5
- ---
6
-
7
- # Python Build Tools
8
-
9
- Modern Python development tooling using uv, mise, ruff, basedpyright, and pytest.
10
-
11
- ## Quick Start
12
-
13
- ### Minimal pyproject.toml
14
-
15
- ```toml
16
- [project]
17
- name = "my-project"
18
- version = "0.1.0"
19
- requires-python = ">=3.12"
20
- dependencies = ["fastapi", "pydantic"]
21
-
22
- [project.optional-dependencies]
23
- dev = ["pytest>=8.0.0", "ruff>=0.8.0", "basedpyright>=1.0.0"]
24
-
25
- [build-system]
26
- requires = ["hatchling"]
27
- build-backend = "hatchling.build"
28
-
29
- [tool.ruff]
30
- target-version = "py312"
31
-
32
- [tool.ruff.lint]
33
- select = ["E", "F", "I", "N", "UP", "RUF"]
34
-
35
- [tool.basedpyright]
36
- typeCheckingMode = "strict"
37
-
38
- [tool.pytest.ini_options]
39
- testpaths = ["tests"]
40
- ```
41
-
42
- ### Setup Project
43
-
44
- ```bash
45
- uv init my-project && cd my-project
46
- uv sync
47
- uv add fastapi pydantic
48
- uv add --dev pytest ruff basedpyright
49
- ```
50
-
51
- ## Tool Overview
52
-
53
- | Tool | Purpose | Replaces |
54
- |------|---------|----------|
55
- | **uv** | Package management | pip, virtualenv |
56
- | **mise** | Version & tasks | pyenv, asdf |
57
- | **ruff** | Lint & format | black, isort, flake8 |
58
- | **basedpyright** | Type checking | mypy |
59
- | **pytest** | Testing | unittest |
60
-
61
- ## Common Commands
62
-
63
- ### Lint and Format
64
-
65
- ```bash
66
- uv run ruff check --fix .
67
- uv run ruff format .
68
- ```
69
-
70
- ### Type Check
71
-
72
- ```bash
73
- uv run basedpyright
74
- uv run basedpyright src/main.py
75
- ```
76
-
77
- ### Test
78
-
79
- ```bash
80
- uv run pytest
81
- uv run pytest --cov=src --cov-report=html
82
- ```
83
-
84
- ### Manage Dependencies
85
-
86
- ```bash
87
- uv add fastapi
88
- uv add --dev pytest
89
- uv lock --upgrade
90
- uv tree
91
- ```
92
-
93
- ## Mise Configuration
94
-
95
- Create `.mise.toml` for consistent development:
96
-
97
- ```toml
98
- [tools]
99
- python = "3.12"
100
-
101
- [tasks.lint]
102
- run = "uv run ruff check --fix ."
103
-
104
- [tasks.format]
105
- run = "uv run ruff format ."
106
-
107
- [tasks.typecheck]
108
- run = "uv run basedpyright"
109
-
110
- [tasks.test]
111
- run = "uv run pytest"
112
-
113
- [tasks.check]
114
- depends = ["lint", "format", "typecheck", "test"]
115
- ```
116
-
117
- Usage:
118
-
119
- ```bash
120
- mise install
121
- mise run check
122
- ```
123
-
124
- ## Type Hints Example
125
-
126
- ```python
127
- from decimal import Decimal
128
- from typing import Optional
129
-
130
- def calculate_discount(
131
- total: Decimal,
132
- rate: Optional[Decimal] = None
133
- ) -> Decimal:
134
- if rate is None:
135
- rate = Decimal("0.1")
136
- return total * rate
137
- ```
138
-
139
- ## Best Practices
140
-
141
- 1. Use uv for all package management (faster, reliable)
142
- 2. Pin Python version with mise
143
- 3. Configure tools in pyproject.toml
144
- 4. Enable strict type checking
145
- 5. Run checks before commit
146
-
147
- ## References
148
-
149
- For detailed configuration and advanced patterns:
150
-
151
- - **[references/uv.md](references/uv.md)** - Workspaces, scripts, dependency management
152
- - **[references/ruff.md](references/ruff.md)** - Rules, per-file ignores, pre-commit integration
153
- - **[references/basedpyright.md](references/basedpyright.md)** - Type patterns, generics, protocols