litclaude-ai 0.2.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 (156) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/LICENSE +21 -0
  3. package/README.md +369 -0
  4. package/README_ko-KR.md +374 -0
  5. package/RELEASE_CHECKLIST.md +165 -0
  6. package/bin/litclaude-ai.js +643 -0
  7. package/cover.png +0 -0
  8. package/docs/agents.md +67 -0
  9. package/docs/hooks.md +134 -0
  10. package/docs/lsp.md +40 -0
  11. package/docs/migration.md +209 -0
  12. package/docs/workflow-compatibility-audit.md +119 -0
  13. package/generate_cover.py +123 -0
  14. package/package.json +48 -0
  15. package/plugins/litclaude/.claude-plugin/plugin.json +25 -0
  16. package/plugins/litclaude/.lsp.json +13 -0
  17. package/plugins/litclaude/.mcp.json +9 -0
  18. package/plugins/litclaude/agents/boulder-executor.md +12 -0
  19. package/plugins/litclaude/agents/librarian-researcher.md +15 -0
  20. package/plugins/litclaude/agents/oracle-verifier.md +16 -0
  21. package/plugins/litclaude/agents/prometheus-planner.md +13 -0
  22. package/plugins/litclaude/agents/qa-runner.md +16 -0
  23. package/plugins/litclaude/agents/quality-reviewer.md +17 -0
  24. package/plugins/litclaude/bin/litclaude-hook.js +110 -0
  25. package/plugins/litclaude/bin/litclaude-hud.js +271 -0
  26. package/plugins/litclaude/bin/litclaude-lsp-doctor.js +15 -0
  27. package/plugins/litclaude/bin/litclaude-mcp.js +70 -0
  28. package/plugins/litclaude/commands/deep-interview.md +21 -0
  29. package/plugins/litclaude/commands/dynamic-workflow.md +36 -0
  30. package/plugins/litclaude/commands/lit-loop.md +40 -0
  31. package/plugins/litclaude/commands/lit-plan.md +35 -0
  32. package/plugins/litclaude/commands/litgoal.md +30 -0
  33. package/plugins/litclaude/commands/review-work.md +35 -0
  34. package/plugins/litclaude/commands/start-work.md +36 -0
  35. package/plugins/litclaude/hooks/hooks.json +54 -0
  36. package/plugins/litclaude/lib/context-pressure.mjs +25 -0
  37. package/plugins/litclaude/lib/hud-accent-palette.mjs +58 -0
  38. package/plugins/litclaude/lib/litgoal/cli.mjs +266 -0
  39. package/plugins/litclaude/lib/litgoal/ledger.mjs +16 -0
  40. package/plugins/litclaude/lib/litgoal/paths.mjs +7 -0
  41. package/plugins/litclaude/lib/litgoal/state.mjs +67 -0
  42. package/plugins/litclaude/lib/mutated-file-paths.mjs +63 -0
  43. package/plugins/litclaude/lib/start-work-continuation.mjs +99 -0
  44. package/plugins/litclaude/lib/workflow-check.mjs +83 -0
  45. package/plugins/litclaude/skills/ai-slop-remover/SKILL.md +142 -0
  46. package/plugins/litclaude/skills/comment-checker/SKILL.md +55 -0
  47. package/plugins/litclaude/skills/debugging/SKILL.md +70 -0
  48. package/plugins/litclaude/skills/debugging/references/methodology/00-setup.md +108 -0
  49. package/plugins/litclaude/skills/debugging/references/methodology/02-investigate.md +126 -0
  50. package/plugins/litclaude/skills/debugging/references/methodology/04-oracle-triple.md +106 -0
  51. package/plugins/litclaude/skills/debugging/references/methodology/05-escalate.md +69 -0
  52. package/plugins/litclaude/skills/debugging/references/methodology/06-fix.md +116 -0
  53. package/plugins/litclaude/skills/debugging/references/methodology/08-qa.md +94 -0
  54. package/plugins/litclaude/skills/debugging/references/methodology/09-cleanup.md +164 -0
  55. package/plugins/litclaude/skills/debugging/references/methodology/partial-runtime-evidence.md +228 -0
  56. package/plugins/litclaude/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  57. package/plugins/litclaude/skills/debugging/references/runtimes/go.md +252 -0
  58. package/plugins/litclaude/skills/debugging/references/runtimes/native-binary.md +484 -0
  59. package/plugins/litclaude/skills/debugging/references/runtimes/node.md +260 -0
  60. package/plugins/litclaude/skills/debugging/references/runtimes/python.md +248 -0
  61. package/plugins/litclaude/skills/debugging/references/runtimes/rust.md +234 -0
  62. package/plugins/litclaude/skills/debugging/references/tools/ghidra.md +212 -0
  63. package/plugins/litclaude/skills/debugging/references/tools/playwright-cli.md +194 -0
  64. package/plugins/litclaude/skills/debugging/references/tools/pwndbg.md +263 -0
  65. package/plugins/litclaude/skills/debugging/references/tools/pwntools.md +265 -0
  66. package/plugins/litclaude/skills/deep-interview/SKILL.md +323 -0
  67. package/plugins/litclaude/skills/deep-interview/scripts/render_progress.py +193 -0
  68. package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +62 -0
  69. package/plugins/litclaude/skills/lit-loop/SKILL.md +144 -0
  70. package/plugins/litclaude/skills/lit-plan/SKILL.md +125 -0
  71. package/plugins/litclaude/skills/litgoal/SKILL.md +219 -0
  72. package/plugins/litclaude/skills/lsp/SKILL.md +63 -0
  73. package/plugins/litclaude/skills/programming/SKILL.md +106 -0
  74. package/plugins/litclaude/skills/programming/references/go/README.md +90 -0
  75. package/plugins/litclaude/skills/programming/references/go/backend-stack.md +641 -0
  76. package/plugins/litclaude/skills/programming/references/go/bootstrap.md +328 -0
  77. package/plugins/litclaude/skills/programming/references/go/bubbletea-v2.md +360 -0
  78. package/plugins/litclaude/skills/programming/references/go/cobra-stack.md +468 -0
  79. package/plugins/litclaude/skills/programming/references/go/concurrency.md +362 -0
  80. package/plugins/litclaude/skills/programming/references/go/data-modeling.md +329 -0
  81. package/plugins/litclaude/skills/programming/references/go/error-handling.md +359 -0
  82. package/plugins/litclaude/skills/programming/references/go/golangci-strict.md +236 -0
  83. package/plugins/litclaude/skills/programming/references/go/grpc-connect.md +375 -0
  84. package/plugins/litclaude/skills/programming/references/go/libraries.md +337 -0
  85. package/plugins/litclaude/skills/programming/references/go/one-liners.md +202 -0
  86. package/plugins/litclaude/skills/programming/references/go/sqlc-pgx.md +471 -0
  87. package/plugins/litclaude/skills/programming/references/go/testing.md +467 -0
  88. package/plugins/litclaude/skills/programming/references/go/type-patterns.md +298 -0
  89. package/plugins/litclaude/skills/programming/references/python/README.md +314 -0
  90. package/plugins/litclaude/skills/programming/references/python/async-anyio.md +442 -0
  91. package/plugins/litclaude/skills/programming/references/python/data-modeling.md +233 -0
  92. package/plugins/litclaude/skills/programming/references/python/data-processing.md +133 -0
  93. package/plugins/litclaude/skills/programming/references/python/error-handling.md +218 -0
  94. package/plugins/litclaude/skills/programming/references/python/fastapi-stack.md +316 -0
  95. package/plugins/litclaude/skills/programming/references/python/httpx2-optimization.md +360 -0
  96. package/plugins/litclaude/skills/programming/references/python/libraries.md +307 -0
  97. package/plugins/litclaude/skills/programming/references/python/one-liners.md +268 -0
  98. package/plugins/litclaude/skills/programming/references/python/orjson-stack.md +378 -0
  99. package/plugins/litclaude/skills/programming/references/python/pydantic-ai.md +285 -0
  100. package/plugins/litclaude/skills/programming/references/python/pyproject-strict.md +232 -0
  101. package/plugins/litclaude/skills/programming/references/python/textual-tui.md +201 -0
  102. package/plugins/litclaude/skills/programming/references/python/type-patterns.md +176 -0
  103. package/plugins/litclaude/skills/programming/references/rust/README.md +317 -0
  104. package/plugins/litclaude/skills/programming/references/rust/async-tokio.md +299 -0
  105. package/plugins/litclaude/skills/programming/references/rust/axum-stack.md +467 -0
  106. package/plugins/litclaude/skills/programming/references/rust/cargo-strict.md +317 -0
  107. package/plugins/litclaude/skills/programming/references/rust/clap-stack.md +409 -0
  108. package/plugins/litclaude/skills/programming/references/rust/concurrency.md +375 -0
  109. package/plugins/litclaude/skills/programming/references/rust/libraries.md +439 -0
  110. package/plugins/litclaude/skills/programming/references/rust/one-liners.md +291 -0
  111. package/plugins/litclaude/skills/programming/references/rust/proptest-insta.md +429 -0
  112. package/plugins/litclaude/skills/programming/references/rust/type-state.md +354 -0
  113. package/plugins/litclaude/skills/programming/references/rust/unsafe-discipline.md +250 -0
  114. package/plugins/litclaude/skills/programming/references/rust/zero-cost-safety.md +527 -0
  115. package/plugins/litclaude/skills/programming/references/rust-ub/README.md +289 -0
  116. package/plugins/litclaude/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
  117. package/plugins/litclaude/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
  118. package/plugins/litclaude/skills/programming/references/typescript/README.md +195 -0
  119. package/plugins/litclaude/skills/programming/references/typescript/backend-hono.md +672 -0
  120. package/plugins/litclaude/skills/programming/references/typescript/bootstrap.md +199 -0
  121. package/plugins/litclaude/skills/programming/references/typescript/data-modeling.md +202 -0
  122. package/plugins/litclaude/skills/programming/references/typescript/error-handling.md +169 -0
  123. package/plugins/litclaude/skills/programming/references/typescript/tsconfig-strict.md +152 -0
  124. package/plugins/litclaude/skills/programming/references/typescript/type-patterns.md +196 -0
  125. package/plugins/litclaude/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
  126. package/plugins/litclaude/skills/programming/scripts/go/new-project.py +138 -0
  127. package/plugins/litclaude/skills/programming/scripts/go/templates/.editorconfig +13 -0
  128. package/plugins/litclaude/skills/programming/scripts/go/templates/.golangci.yml +95 -0
  129. package/plugins/litclaude/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
  130. package/plugins/litclaude/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
  131. package/plugins/litclaude/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
  132. package/plugins/litclaude/skills/programming/scripts/go/templates/ci.yml +37 -0
  133. package/plugins/litclaude/skills/programming/scripts/go/templates/config.go +24 -0
  134. package/plugins/litclaude/skills/programming/scripts/go/templates/gitignore +15 -0
  135. package/plugins/litclaude/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
  136. package/plugins/litclaude/skills/programming/scripts/go/templates/run.go +15 -0
  137. package/plugins/litclaude/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
  138. package/plugins/litclaude/skills/programming/scripts/python/new-project.py +172 -0
  139. package/plugins/litclaude/skills/programming/scripts/python/new-script.py +116 -0
  140. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
  141. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
  142. package/plugins/litclaude/skills/programming/scripts/rust/new-project.py +175 -0
  143. package/plugins/litclaude/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
  144. package/plugins/litclaude/skills/programming/scripts/typescript/new-project.ts +177 -0
  145. package/plugins/litclaude/skills/refactor/SKILL.md +73 -0
  146. package/plugins/litclaude/skills/remove-ai-slops/SKILL.md +52 -0
  147. package/plugins/litclaude/skills/review-work/SKILL.md +331 -0
  148. package/plugins/litclaude/skills/rules/SKILL.md +66 -0
  149. package/plugins/litclaude/skills/start-work/SKILL.md +132 -0
  150. package/scripts/audit-plan-checkboxes.mjs +37 -0
  151. package/scripts/doctor.mjs +41 -0
  152. package/scripts/inspect-agent-tools.mjs +27 -0
  153. package/scripts/postinstall.mjs +50 -0
  154. package/scripts/qa-claude-plugin-smoke.sh +60 -0
  155. package/scripts/qa-portable-install.sh +136 -0
  156. package/scripts/validate-plugin.mjs +72 -0
@@ -0,0 +1,285 @@
1
+ # PydanticAI Reference (v1.x, 2026)
2
+
3
+ > Canonical patterns for wiring PydanticAI agents. Target: production usage, late-2025 / 2026.
4
+ > Source: [ai.pydantic.dev](https://ai.pydantic.dev) and [pydantic/pydantic-ai@`cad9569`](https://github.com/pydantic/pydantic-ai/blob/cad956910079737ea0886b50cef15777208f92e6).
5
+
6
+ ---
7
+
8
+ ## 1. Agent Constructor
9
+
10
+ ```python
11
+ from pydantic_ai import Agent
12
+
13
+ agent = Agent(
14
+ 'openai:gpt-5.2', # model (str | Model | None)
15
+ output_type=MyOutputModel, # structured output type; default=str
16
+ instructions='You are a...', # static or callable instructions
17
+ system_prompt='Be concise.', # static system prompt(s)
18
+ deps_type=MyDeps, # dependency type for type-checking only
19
+ name='my-agent', # optional, inferred from var name if omitted
20
+ retries=1, # default retries for tools + output validation
21
+ output_retries=None, # override retries for output validation only
22
+ tools=[my_tool], # list of Tool objects or plain functions
23
+ defer_model_check=False, # set True to skip env-var check at init time
24
+ end_strategy='early', # 'early' | 'graceful' | 'exhaustive'
25
+ )
26
+ ```
27
+
28
+ **Breaking change (v1.88.0)**: `result_type` was renamed to `output_type`. Use `output_type`.
29
+
30
+ ---
31
+
32
+ ## 2. Model Strings
33
+
34
+ Format: `provider:model-name`. The framework infers the provider from the prefix.
35
+
36
+ | Provider prefix | Example |
37
+ |---|---|
38
+ | `openai:` | `'openai:gpt-5.2'`, `'openai:gpt-4o'` |
39
+ | `anthropic:` | `'anthropic:claude-sonnet-4-6'`, `'anthropic:claude-opus-4-1'` |
40
+ | `google-gla:` | `'google-gla:gemini-3-flash-preview'` |
41
+ | `google-vertex:` | `'google-vertex:gemini-3-pro-preview'` |
42
+ | `bedrock:` | `'bedrock:anthropic.claude-sonnet-4-6'` |
43
+ | `xai:` / `grok:` | `'xai:grok-3'`, `'grok:grok-3-fast'` |
44
+ | `deepseek:` | `'deepseek:deepseek-chat'` |
45
+ | `cohere:` | `'cohere:command-r-08-2024'` |
46
+ | `gateway/...` | `'gateway/openai:gpt-5.2'` (PydanticAI Gateway) |
47
+
48
+ Model can also be omitted at construction and passed per-run: `agent.run(prompt, model='openai:gpt-5.2')`.
49
+
50
+ ---
51
+
52
+ ## 3. Tools
53
+
54
+ ### Decorator syntax
55
+
56
+ ```python
57
+ from pydantic_ai import Agent, RunContext
58
+
59
+ agent = Agent('openai:gpt-5.2', deps_type=str)
60
+
61
+ @agent.tool # default: receives RunContext as first arg
62
+ async def greet(ctx: RunContext[str], name: str) -> str:
63
+ return f"Hello {ctx.deps}, {name}!"
64
+
65
+ @agent.tool_plain # no context needed
66
+ async def roll_dice(sides: int) -> int:
67
+ import random
68
+ return random.randint(1, sides)
69
+ ```
70
+
71
+ ### `RunContext[Deps]`
72
+
73
+ First parameter of `@agent.tool` functions. Carries:
74
+
75
+ - `ctx.deps` — the dependency instance
76
+ - `ctx.model` — the model being used
77
+ - `ctx.usage` — token usage so far
78
+ - `ctx.messages` — conversation history
79
+ - `ctx.retry` / `ctx.max_retries` — current retry count
80
+ - `ctx.agent` — the running agent instance
81
+
82
+ Use `@agent.tool_plain` when the tool does **not** need any of the above.
83
+
84
+ ---
85
+
86
+ ## 4. Structured Output
87
+
88
+ Pass a Pydantic `BaseModel` (or `bool`, `int`, `list[str]`, etc.) as `output_type`. The result is accessed via `.output`.
89
+
90
+ ```python
91
+ from pydantic import BaseModel
92
+ from pydantic_ai import Agent
93
+
94
+ class City(BaseModel):
95
+ name: str
96
+ country: str
97
+ population_millions: float
98
+
99
+ agent = Agent('openai:gpt-5.2', output_type=City)
100
+ result = agent.run_sync('Tell me about Tokyo')
101
+ print(result.output) # City(name='Tokyo', country='Japan', ...)
102
+ print(result.output.name) # 'Tokyo'
103
+ ```
104
+
105
+ **Note**: `result.data` was renamed; the canonical accessor is `result.output`.
106
+
107
+ ---
108
+
109
+ ## 5. Async vs Sync
110
+
111
+ | Method | Mode | Returns |
112
+ |---|---|---|
113
+ | `await agent.run(prompt, ...)` | async | `AgentRunResult[OutputDataT]` |
114
+ | `agent.run_sync(prompt, ...)` | sync | `AgentRunResult[OutputDataT]` |
115
+ | `async with agent.run_stream(prompt, ...) as response:` | async streaming | `StreamedRunResult` |
116
+
117
+ ```python
118
+ # Sync
119
+ result = agent.run_sync('What is the capital of Italy?')
120
+ print(result.output)
121
+
122
+ # Async
123
+ result = await agent.run('What is the capital of France?')
124
+ print(result.output)
125
+
126
+ # Streaming
127
+ async with agent.run_stream('What is the capital of the UK?') as response:
128
+ async for text in response.stream_text():
129
+ print(text, end='')
130
+ # After streaming finishes:
131
+ print(response.output)
132
+ ```
133
+
134
+ `run_sync()` is a convenience wrapper over `loop.run_until_complete(self.run(...))`. Do not use it inside an active async context.
135
+
136
+ ---
137
+
138
+ ## 6. Dependencies
139
+
140
+ Use a `@dataclass` container, pass the **type** to `deps_type`, and pass an **instance** to `deps` at run time.
141
+
142
+ ```python
143
+ from dataclasses import dataclass
144
+ import httpx
145
+ from pydantic_ai import Agent, RunContext
146
+
147
+ @dataclass
148
+ class Deps:
149
+ api_key: str
150
+ http_client: httpx.AsyncClient
151
+
152
+ agent = Agent(
153
+ 'openai:gpt-5.2',
154
+ deps_type=Deps,
155
+ )
156
+
157
+ @agent.tool
158
+ async def fetch_data(ctx: RunContext[Deps], endpoint: str) -> str:
159
+ r = await ctx.deps.http_client.get(
160
+ endpoint,
161
+ headers={'Authorization': f'Bearer {ctx.deps.api_key}'},
162
+ )
163
+ r.raise_for_status()
164
+ return r.text
165
+
166
+ async def main():
167
+ async with httpx.AsyncClient() as client:
168
+ deps = Deps(api_key='sk-...', http_client=client)
169
+ result = await agent.run('Get /users', deps=deps)
170
+ print(result.output)
171
+ ```
172
+
173
+ ---
174
+
175
+ ## 7. Error Types & Retrying from a Tool
176
+
177
+ ```python
178
+ from pydantic_ai import Agent, ModelRetry, UnexpectedModelBehavior, capture_run_messages
179
+
180
+ agent = Agent('openai:gpt-5.2', retries=3)
181
+
182
+ @agent.tool_plain
183
+ def calc_volume(size: int) -> int:
184
+ if size == 42:
185
+ return size ** 3
186
+ raise ModelRetry('Please try again with size 42.')
187
+
188
+ with capture_run_messages() as messages:
189
+ try:
190
+ result = agent.run_sync('Get the volume of a box with size 6.')
191
+ except UnexpectedModelBehavior as e:
192
+ print('Error:', e) # "Tool 'calc_volume' exceeded max retries count of 3"
193
+ print('Cause:', e.__cause__) # ModelRetry('Please try again...')
194
+ print('Messages:', messages)
195
+ ```
196
+
197
+ - **`ModelRetry`** — raise from a tool, output validator, or capability hook to ask the model to retry.
198
+ - **`UnexpectedModelBehavior`** — raised when the retry limit is exceeded or the model API returns an unrecoverable error.
199
+ - **`capture_run_messages()`** — context manager that records all messages exchanged during a run for debugging.
200
+
201
+ ---
202
+
203
+ ## 8. Logfire Integration
204
+
205
+ One-line setup if the `logfire` extra is installed (included in the default `pydantic-ai` package):
206
+
207
+ ```python
208
+ import logfire
209
+
210
+ logfire.configure() # reads token from .logfire directory
211
+ logfire.instrument_pydantic_ai() # auto-traces all agent runs
212
+ ```
213
+
214
+ Alternatively, set `instrument=True` on the agent:
215
+
216
+ ```python
217
+ agent = Agent('openai:gpt-5.2', instrument=True)
218
+ ```
219
+
220
+ ---
221
+
222
+ ## 9. Minimal Complete Snippets
223
+
224
+ ### (a) Basic agent with structured output
225
+
226
+ ```python
227
+ from pydantic import BaseModel
228
+ from pydantic_ai import Agent
229
+
230
+ class City(BaseModel):
231
+ name: str
232
+ country: str
233
+
234
+ agent = Agent('openai:gpt-5.2', output_type=City)
235
+ result = agent.run_sync('Tell me about Paris')
236
+ print(result.output) # City(name='Paris', country='France')
237
+ ```
238
+
239
+ ### (b) Agent with tools and dependencies
240
+
241
+ ```python
242
+ from dataclasses import dataclass
243
+ from pydantic_ai import Agent, RunContext
244
+
245
+ @dataclass
246
+ class Deps:
247
+ api_key: str
248
+
249
+ agent = Agent('openai:gpt-5.2', deps_type=Deps)
250
+
251
+ @agent.tool
252
+ async def get_secret(ctx: RunContext[Deps], code: str) -> str:
253
+ if code == '1234':
254
+ return f'secret-for-{ctx.deps.api_key}'
255
+ return 'wrong code'
256
+
257
+ result = agent.run_sync('My code is 1234', deps=Deps(api_key='sk-abc'))
258
+ print(result.output)
259
+ ```
260
+
261
+ ### (c) Async streaming
262
+
263
+ ```python
264
+ import anyio
265
+ from pydantic_ai import Agent
266
+
267
+ agent = Agent('openai:gpt-5.2')
268
+
269
+ async def main() -> None:
270
+ async with agent.run_stream('Write a haiku about Python') as response:
271
+ async for text in response.stream_text():
272
+ print(text, end='')
273
+ print('\n---')
274
+ print('Final:', response.output)
275
+
276
+ anyio.run(main)
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Version Notes
282
+
283
+ - **V1** reached API stability in September 2025. Breaking changes are reserved for V2 (earliest April 2026).
284
+ - **v1.88.0** renamed `result_type` → `output_type` and `result_tool_name` / `result_tool_description` were removed. Use `output_type`.
285
+ - The canonical accessor for run results is `result.output` (not `result.data`).
@@ -0,0 +1,232 @@
1
+ # Strict pyproject.toml (basedpyright + ruff + uv)
2
+
3
+ The canonical "super strict but sane" config for modern Python projects. Copy-paste, then add your own dependencies.
4
+
5
+ ## Bootstrap
6
+
7
+ ```bash
8
+ # Application
9
+ uv init --app myproject
10
+ cd myproject
11
+
12
+ # Library (publishable to PyPI)
13
+ uv init --lib mylibrary
14
+ cd mylibrary
15
+
16
+ # Add dev tools
17
+ uv add --dev basedpyright ruff pytest
18
+ ```
19
+
20
+ `uv init` creates `pyproject.toml`, `.python-version`, and `src/` layout. Replace its `pyproject.toml` `[tool.*]` sections with the block below.
21
+
22
+ ## The full pyproject.toml
23
+
24
+ ```toml
25
+ [project]
26
+ name = "myproject"
27
+ version = "0.1.0"
28
+ description = "..."
29
+ readme = "README.md"
30
+ requires-python = ">=3.13"
31
+ dependencies = []
32
+
33
+ [dependency-groups]
34
+ dev = [
35
+ "basedpyright>=1.21",
36
+ "ruff>=0.8",
37
+ "pytest>=8",
38
+ "pytest-cov>=5",
39
+ ]
40
+
41
+ # ─────────────────────────────────────────────────────────────────
42
+ # basedpyright - typeCheckingMode = "all" sets every report flag to error
43
+ # Source: https://docs.basedpyright.com/latest/configuration/config-files/
44
+ # ─────────────────────────────────────────────────────────────────
45
+ [tool.basedpyright]
46
+ typeCheckingMode = "all"
47
+ pythonVersion = "3.13"
48
+ pythonPlatform = "All" # default in basedpyright; explicit for clarity
49
+ include = ["src", "tests"]
50
+ exclude = ["**/__pycache__", "**/.venv", "**/build", "**/dist"]
51
+
52
+ # Strict enforcement extras (most are already "error" under "all" mode,
53
+ # but listing them explicitly documents the intent)
54
+ reportUnusedCallResult = "warning" # flag ignored return values
55
+ reportUnnecessaryTypeIgnoreComment = "error" # stale type: ignore comments must die
56
+ reportUnusedVariable = "error" # unused variables are errors
57
+ reportMissingParameterType = "error" # every parameter must have a type
58
+ reportMissingReturnType = "error" # every function must declare its return type
59
+ reportPrivateUsage = "error" # respect _private convention
60
+
61
+ # Optional: gradual adoption baseline
62
+ # baselineFile = "./.basedpyright/baseline.json"
63
+
64
+ # ─────────────────────────────────────────────────────────────────
65
+ # ruff - select = ["ALL"] enables every rule, then we ignore the
66
+ # small set that conflicts with the formatter or is not useful.
67
+ # Source: https://docs.astral.sh/ruff/linter/#rule-selection
68
+ # ─────────────────────────────────────────────────────────────────
69
+ [tool.ruff]
70
+ target-version = "py313"
71
+ line-length = 88 # ruff/black default; 100 or 120 also fine
72
+ src = ["src", "tests"]
73
+
74
+ [tool.ruff.lint]
75
+ select = ["ALL"]
76
+ ignore = [
77
+ # Formatter conflicts (ruff itself tells you to ignore these)
78
+ "COM812", # missing trailing comma
79
+ "ISC001", # implicit string concat
80
+ # Docstyle conflicts (pick D211 over D203, D212 over D213)
81
+ "D203",
82
+ "D213",
83
+ # Project-specific noise
84
+ "CPY001", # missing copyright notice
85
+ "FBT001", # boolean positional arg in def
86
+ "FBT002", # boolean positional default in def
87
+ "TD002", # missing TODO author
88
+ "TD003", # missing TODO link
89
+ "FIX002", # line contains TODO (TODOs are allowed)
90
+ ]
91
+ fixable = ["ALL"]
92
+ unfixable = []
93
+
94
+ [tool.ruff.lint.per-file-ignores]
95
+ "tests/**/*.py" = [
96
+ "S101", # `assert` is the entire point of pytest
97
+ "ARG", # unused args (fixtures appear unused)
98
+ "PLR2004", # magic numbers in test data
99
+ "SLF001", # tests need access to private members
100
+ "D", # docstrings not required in tests
101
+ ]
102
+ "scripts/**/*.py" = [
103
+ "T201", # `print` allowed in scripts
104
+ "INP001", # implicit namespace package
105
+ ]
106
+
107
+ [tool.ruff.lint.pydocstyle]
108
+ convention = "google" # or "numpy" / "pep257"
109
+
110
+ [tool.ruff.lint.flake8-bugbear]
111
+ # typer / fastapi rely on call-as-default for parameter metadata.
112
+ # Without this, ruff B008 ("function call in default") fires on every typer/fastapi route.
113
+ extend-immutable-calls = [
114
+ "typer.Argument",
115
+ "typer.Option",
116
+ "fastapi.Depends",
117
+ "fastapi.Query",
118
+ "fastapi.Path",
119
+ "fastapi.Body",
120
+ "fastapi.Header",
121
+ "fastapi.Cookie",
122
+ "fastapi.File",
123
+ "fastapi.Form",
124
+ ]
125
+
126
+ [tool.ruff.format]
127
+ quote-style = "double"
128
+ indent-style = "space"
129
+ docstring-code-format = true
130
+ docstring-code-line-length = "dynamic"
131
+
132
+ # ─────────────────────────────────────────────────────────────────
133
+ # pytest
134
+ # ─────────────────────────────────────────────────────────────────
135
+ [tool.pytest.ini_options]
136
+ minversion = "8.0"
137
+ testpaths = ["tests"]
138
+ addopts = [
139
+ "-ra",
140
+ "--strict-config",
141
+ "--strict-markers",
142
+ ]
143
+ filterwarnings = ["error"]
144
+
145
+ # ─────────────────────────────────────────────────────────────────
146
+ # coverage
147
+ # ─────────────────────────────────────────────────────────────────
148
+ [tool.coverage.run]
149
+ source = ["src"]
150
+ branch = true
151
+
152
+ [tool.coverage.report]
153
+ exclude_lines = [
154
+ "pragma: no cover",
155
+ "if TYPE_CHECKING:",
156
+ "if typing.TYPE_CHECKING:",
157
+ "raise NotImplementedError",
158
+ "@(abc\\.)?abstractmethod",
159
+ ]
160
+ ```
161
+
162
+ ## Why these settings
163
+
164
+ ### basedpyright `typeCheckingMode = "all"`
165
+
166
+ basedpyright's modes, strictest first:
167
+
168
+ | Mode | Behavior |
169
+ |---|---|
170
+ | `"all"` | Every diagnostic at `error` |
171
+ | `"recommended"` | Same rules; less severe ones at `warning`; `failOnWarnings = true` makes CI still fail |
172
+ | `"strict"` | pyright's strict mode |
173
+ | `"standard"` | Default |
174
+ | `"basic"` / `"off"` | Loose / disabled |
175
+
176
+ `"all"` enables basedpyright-exclusive rules pyright lacks: `reportImplicitOverride`, `reportImplicitStringConcatenation`, `reportIncompatibleUnannotatedOverride`, `reportUnannotatedClassAttribute`. No need to opt-in to additional flags.
177
+
178
+ `pythonPlatform = "All"` is basedpyright's default (better than pyright's host-OS default) - it errors on platform-specific imports that fail on other OSes.
179
+
180
+ ### ruff `select = ["ALL"]`
181
+
182
+ The official docs say *"Use ALL with discretion. Enabling ALL will implicitly enable new rules whenever you upgrade."* For a strict skill that is the intended behavior - every new ruff rule should be considered an error until you justify ignoring it.
183
+
184
+ The minimal ignore set:
185
+
186
+ | Rule | Reason |
187
+ |---|---|
188
+ | `COM812`, `ISC001` | Conflict with `ruff format` (ruff itself documents this) |
189
+ | `D203` vs `D211`, `D213` vs `D212` | Mutually-exclusive docstring conventions; pick the modern one |
190
+ | `CPY001` | Most projects don't need a copyright header on every file |
191
+ | `FBT001`, `FBT002` | Boolean flags are ergonomic for CLI/typer; ban makes typer awkward |
192
+ | `TD002`, `TD003`, `FIX002` | TODOs without a JIRA link are fine in solo / internal code |
193
+
194
+ `ANN101` and `ANN102` were **removed in ruff 0.8.0** (Nov 2024). Do NOT include them in `ignore` - ruff errors on unknown rule codes.
195
+
196
+ `per-file-ignores` for `tests/**` is the standard pattern from real-world repos like `community-of-python/auto-typing-final` and `Preston-Landers/concurrent-log-handler`.
197
+
198
+ ## CI gate
199
+
200
+ ```bash
201
+ # In CI, fail on any violation:
202
+ uv run basedpyright
203
+ uv run ruff check
204
+ uv run ruff format --check
205
+ uv run pytest
206
+ ```
207
+
208
+ A single `make ci` target combining the four works fine.
209
+
210
+ ## Enforcement summary
211
+
212
+ The config above, combined with `scripts/check-no-excuse-rules.py`, enforces:
213
+
214
+ | What | How |
215
+ |---|---|
216
+ | Exhaustive match | basedpyright `all` mode + `assert_never` |
217
+ | No `Any` | basedpyright `all` mode + script `cast-any` rule |
218
+ | Ignored return values | `reportUnusedCallResult = "warning"` |
219
+ | Immutable default | Script `mutable-dataclass` + `missing-slots` rules |
220
+ | No null surprise | basedpyright strict `None` analysis |
221
+ | Constants are const | basedpyright catches `Final` reassignment |
222
+ | Unused variables | `reportUnusedVariable = "error"` |
223
+
224
+ ## Sources
225
+
226
+ - basedpyright modes: <https://docs.basedpyright.com/latest/configuration/config-files/#type-check-diagnostics-settings>
227
+ - basedpyright `"all"` vs `"recommended"`: <https://docs.basedpyright.com/latest/configuration/config-files/#recommended-and-all>
228
+ - basedpyright better defaults: <https://docs.basedpyright.com/latest/benefits-over-pyright/better-defaults/>
229
+ - ruff rule selection: <https://docs.astral.sh/ruff/linter/#rule-selection>
230
+ - ruff ANN101/ANN102 removed: <https://github.com/astral-sh/ruff/pull/14384>
231
+ - Real-world ALL config: <https://github.com/community-of-python/auto-typing-final/blob/main/pyproject.toml>
232
+ - PEP 735 dependency-groups: <https://peps.python.org/pep-0735/>