memory-journal-mcp 7.2.0 → 7.4.0
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.
- package/README.md +69 -64
- package/dist/{chunk-GR4T3SRW.js → chunk-5ZA77VUW.js} +688 -121
- package/dist/{chunk-ORV7ZZOE.js → chunk-P5V2VY6N.js} +365 -74
- package/dist/{chunk-IWKLHSPU.js → chunk-WXDEVIFL.js} +6 -6
- package/dist/cli.js +9 -4
- package/dist/github-integration-YODGZH3K.js +1 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +3 -3
- package/dist/{tools-CXR2FEB2.js → tools-WZUENKJ6.js} +2 -2
- package/package.json +4 -4
- package/skills/README.md +5 -1
- package/skills/docker/SKILL.md +262 -0
- package/skills/github-actions/SKILL.md +315 -0
- package/skills/package.json +5 -1
- package/skills/python/SKILL.md +257 -0
- package/skills/tailwind-css/SKILL.md +268 -0
- package/dist/github-integration-2TFMXHIJ.js +0 -1
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-actions
|
|
3
|
+
description: |
|
|
4
|
+
Master GitHub Actions CI/CD workflows with production-grade security and
|
|
5
|
+
performance patterns. Use when writing workflow YAML, configuring CI/CD
|
|
6
|
+
pipelines, setting up matrix strategies, caching dependencies, managing
|
|
7
|
+
artifacts, or implementing reusable workflows. Triggers on "GitHub Actions",
|
|
8
|
+
"CI/CD", "workflow", "actions/checkout", "matrix strategy", "reusable
|
|
9
|
+
workflow", "SHA pinning", ".github/workflows".
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# GitHub Actions CI/CD Engineering Standards
|
|
13
|
+
|
|
14
|
+
This skill codifies 2026 GitHub Actions best practices — secure supply chains, efficient caching, reusable workflows, and hardened permission models.
|
|
15
|
+
|
|
16
|
+
## 1. Security: SHA Pinning (Mandatory)
|
|
17
|
+
|
|
18
|
+
### Pin Every Third-Party Action to a Commit SHA
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
# ✅ Good: SHA-pinned (immutable, auditable)
|
|
22
|
+
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.2.2
|
|
23
|
+
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde8c81c89c3166c0 # v4.2.0
|
|
24
|
+
|
|
25
|
+
# ❌ Bad: Tag-pinned (mutable, vulnerable to supply chain attacks)
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
- uses: actions/setup-node@v4
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- **ALWAYS** pin to full-length commit SHAs — tags are mutable and can be hijacked
|
|
31
|
+
- **ALWAYS** add a trailing comment with the version for human readability
|
|
32
|
+
- **Use tools** like `step-security/harden-runner` or `pin-github-action` CLI to automate SHA resolution
|
|
33
|
+
- **Audit quarterly** — review all pinned SHAs when updating workflow dependencies
|
|
34
|
+
|
|
35
|
+
### Permission Hardening
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
# Set restrictive defaults at the workflow level
|
|
39
|
+
permissions:
|
|
40
|
+
contents: read
|
|
41
|
+
|
|
42
|
+
jobs:
|
|
43
|
+
build:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
# Grant specific permissions per-job
|
|
46
|
+
permissions:
|
|
47
|
+
contents: read
|
|
48
|
+
packages: write
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **ALWAYS** set `permissions:` at the workflow level — use `read-all` or specify individually
|
|
52
|
+
- **NEVER** use `permissions: write-all` — it grants maximum privileges
|
|
53
|
+
- **Grant write only where needed** — per-job, not per-workflow
|
|
54
|
+
|
|
55
|
+
## 2. Workflow Structure
|
|
56
|
+
|
|
57
|
+
### Standard CI Template
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
name: CI
|
|
61
|
+
|
|
62
|
+
on:
|
|
63
|
+
push:
|
|
64
|
+
branches: [main]
|
|
65
|
+
pull_request:
|
|
66
|
+
branches: [main]
|
|
67
|
+
|
|
68
|
+
permissions:
|
|
69
|
+
contents: read
|
|
70
|
+
|
|
71
|
+
concurrency:
|
|
72
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
73
|
+
cancel-in-progress: true
|
|
74
|
+
|
|
75
|
+
jobs:
|
|
76
|
+
lint:
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@<sha> # v4
|
|
80
|
+
- uses: actions/setup-node@<sha> # v4
|
|
81
|
+
with:
|
|
82
|
+
node-version-file: .node-version
|
|
83
|
+
cache: pnpm
|
|
84
|
+
- run: pnpm install --frozen-lockfile
|
|
85
|
+
- run: pnpm run lint
|
|
86
|
+
- run: pnpm run typecheck
|
|
87
|
+
|
|
88
|
+
test:
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
needs: lint
|
|
91
|
+
steps:
|
|
92
|
+
- uses: actions/checkout@<sha> # v4
|
|
93
|
+
- uses: actions/setup-node@<sha> # v4
|
|
94
|
+
with:
|
|
95
|
+
node-version-file: .node-version
|
|
96
|
+
cache: pnpm
|
|
97
|
+
- run: pnpm install --frozen-lockfile
|
|
98
|
+
- run: pnpm test
|
|
99
|
+
|
|
100
|
+
build:
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
needs: test
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/checkout@<sha> # v4
|
|
105
|
+
- uses: actions/setup-node@<sha> # v4
|
|
106
|
+
with:
|
|
107
|
+
node-version-file: .node-version
|
|
108
|
+
cache: pnpm
|
|
109
|
+
- run: pnpm install --frozen-lockfile
|
|
110
|
+
- run: pnpm run build
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Key Structural Rules
|
|
114
|
+
|
|
115
|
+
- **ALWAYS** set `concurrency` with `cancel-in-progress: true` to prevent stale runs
|
|
116
|
+
- **Use `needs:`** to create a dependency chain: lint → test → build → deploy
|
|
117
|
+
- **Use `.node-version`** or `.python-version` files — never hardcode versions in workflows
|
|
118
|
+
- **Use `--frozen-lockfile`** — never let CI modify the lock file
|
|
119
|
+
|
|
120
|
+
## 3. Caching
|
|
121
|
+
|
|
122
|
+
### Package Manager Caching
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
# Node.js (pnpm)
|
|
126
|
+
- uses: actions/setup-node@<sha>
|
|
127
|
+
with:
|
|
128
|
+
node-version-file: .node-version
|
|
129
|
+
cache: pnpm
|
|
130
|
+
|
|
131
|
+
# Python (uv)
|
|
132
|
+
- uses: actions/setup-python@<sha>
|
|
133
|
+
with:
|
|
134
|
+
python-version-file: .python-version
|
|
135
|
+
- run: pip install uv
|
|
136
|
+
- uses: actions/cache@<sha>
|
|
137
|
+
with:
|
|
138
|
+
path: ~/.cache/uv
|
|
139
|
+
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
140
|
+
restore-keys: uv-${{ runner.os }}-
|
|
141
|
+
|
|
142
|
+
# Go
|
|
143
|
+
- uses: actions/setup-go@<sha>
|
|
144
|
+
with:
|
|
145
|
+
go-version-file: go.mod
|
|
146
|
+
cache: true
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Custom Caching Rules
|
|
150
|
+
|
|
151
|
+
- **Key on lock file hash** — `${{ hashFiles('pnpm-lock.yaml') }}`
|
|
152
|
+
- **Use `restore-keys`** for fallback to partial cache hits
|
|
153
|
+
- **Cache the package manager's global cache**, not `node_modules` directly
|
|
154
|
+
- **Don't cache everything** — simplicity trumps marginal speedup
|
|
155
|
+
|
|
156
|
+
## 4. Matrix Strategy
|
|
157
|
+
|
|
158
|
+
### Basic Matrix
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
jobs:
|
|
162
|
+
test:
|
|
163
|
+
strategy:
|
|
164
|
+
fail-fast: false
|
|
165
|
+
matrix:
|
|
166
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
167
|
+
node: [20, 22]
|
|
168
|
+
exclude:
|
|
169
|
+
- os: windows-latest
|
|
170
|
+
node: 20
|
|
171
|
+
runs-on: ${{ matrix.os }}
|
|
172
|
+
steps:
|
|
173
|
+
- uses: actions/setup-node@<sha>
|
|
174
|
+
with:
|
|
175
|
+
node-version: ${{ matrix.node }}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Dynamic Matrix
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
jobs:
|
|
182
|
+
prepare:
|
|
183
|
+
runs-on: ubuntu-latest
|
|
184
|
+
outputs:
|
|
185
|
+
matrix: ${{ steps.set.outputs.matrix }}
|
|
186
|
+
steps:
|
|
187
|
+
- id: set
|
|
188
|
+
run: |
|
|
189
|
+
echo 'matrix={"include":[{"project":"api"},{"project":"web"}]}' >> "$GITHUB_OUTPUT"
|
|
190
|
+
|
|
191
|
+
build:
|
|
192
|
+
needs: prepare
|
|
193
|
+
strategy:
|
|
194
|
+
matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }}
|
|
195
|
+
runs-on: ubuntu-latest
|
|
196
|
+
steps:
|
|
197
|
+
- run: echo "Building ${{ matrix.project }}"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Rules
|
|
201
|
+
|
|
202
|
+
- **Use `fail-fast: false`** for test matrices — you want to see all failures, not just the first
|
|
203
|
+
- **Use `include`/`exclude`** to fine-tune — don't generate invalid combinations
|
|
204
|
+
- **Use `max-parallel`** if jobs contend for shared resources (APIs, databases)
|
|
205
|
+
|
|
206
|
+
## 5. Reusable Workflows
|
|
207
|
+
|
|
208
|
+
### Defining a Reusable Workflow
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
# .github/workflows/reusable-build.yml
|
|
212
|
+
name: Reusable Build
|
|
213
|
+
|
|
214
|
+
on:
|
|
215
|
+
workflow_call:
|
|
216
|
+
inputs:
|
|
217
|
+
node-version:
|
|
218
|
+
type: string
|
|
219
|
+
default: '22'
|
|
220
|
+
secrets:
|
|
221
|
+
NPM_TOKEN:
|
|
222
|
+
required: true
|
|
223
|
+
|
|
224
|
+
permissions:
|
|
225
|
+
contents: read
|
|
226
|
+
|
|
227
|
+
jobs:
|
|
228
|
+
build:
|
|
229
|
+
runs-on: ubuntu-latest
|
|
230
|
+
steps:
|
|
231
|
+
- uses: actions/checkout@<sha>
|
|
232
|
+
- uses: actions/setup-node@<sha>
|
|
233
|
+
with:
|
|
234
|
+
node-version: ${{ inputs.node-version }}
|
|
235
|
+
registry-url: https://registry.npmjs.org
|
|
236
|
+
- run: pnpm install --frozen-lockfile
|
|
237
|
+
- run: pnpm build
|
|
238
|
+
env:
|
|
239
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Calling a Reusable Workflow
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
jobs:
|
|
246
|
+
build:
|
|
247
|
+
uses: ./.github/workflows/reusable-build.yml
|
|
248
|
+
with:
|
|
249
|
+
node-version: '22'
|
|
250
|
+
secrets:
|
|
251
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Rules
|
|
255
|
+
|
|
256
|
+
- **Pass secrets explicitly** — avoid `secrets: inherit` (grants broader access than needed)
|
|
257
|
+
- **Pin reusable workflows** to SHA or tag in production
|
|
258
|
+
- **Use `workflow_call` inputs** for all configuration — don't rely on `env` or file conventions
|
|
259
|
+
- **Separate concerns**: reusable workflows = entire jobs; composite actions = reusable steps
|
|
260
|
+
|
|
261
|
+
## 6. Artifacts (v4)
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
# Upload
|
|
265
|
+
- uses: actions/upload-artifact@<sha> # v4
|
|
266
|
+
with:
|
|
267
|
+
name: build-output
|
|
268
|
+
path: dist/
|
|
269
|
+
retention-days: 7
|
|
270
|
+
compression-level: 6
|
|
271
|
+
|
|
272
|
+
# Download (in a different job)
|
|
273
|
+
- uses: actions/download-artifact@<sha> # v4
|
|
274
|
+
with:
|
|
275
|
+
name: build-output
|
|
276
|
+
path: dist/
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Rules
|
|
280
|
+
|
|
281
|
+
- **v4 artifacts are immutable** — you cannot overwrite the same artifact name
|
|
282
|
+
- **Use unique names per job** — don't upload from parallel matrix jobs to the same name
|
|
283
|
+
- **Set `retention-days`** — don't rely on org defaults (storage costs add up)
|
|
284
|
+
- **Use `compression-level: 0`** for already-compressed files (`.zip`, `.tar.gz`)
|
|
285
|
+
- **v3 and v4 are incompatible** — do not mix upload-artifact@v3 with download-artifact@v4
|
|
286
|
+
|
|
287
|
+
## 7. Environment Protection
|
|
288
|
+
|
|
289
|
+
```yaml
|
|
290
|
+
jobs:
|
|
291
|
+
deploy:
|
|
292
|
+
runs-on: ubuntu-latest
|
|
293
|
+
environment:
|
|
294
|
+
name: production
|
|
295
|
+
url: https://myapp.example.com
|
|
296
|
+
steps:
|
|
297
|
+
- run: echo "Deploying to production"
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
- **Use `environment:`** for production deployments — enables approval gates
|
|
301
|
+
- **Configure required reviewers** in repo Settings → Environments
|
|
302
|
+
- **Use environment-scoped secrets** — production secrets should not be accessible in CI
|
|
303
|
+
|
|
304
|
+
## 8. Anti-Patterns (Never Do These)
|
|
305
|
+
|
|
306
|
+
| Anti-Pattern | Why It's Wrong | Do This Instead |
|
|
307
|
+
| ------------------------------------------- | --------------------------------- | ------------------------------------ |
|
|
308
|
+
| `uses: action@v4` | Mutable tag, supply chain risk | Pin to full commit SHA |
|
|
309
|
+
| `permissions: write-all` | Maximum privilege, dangerous | Explicit per-job permissions |
|
|
310
|
+
| `continue-on-error: true` on security steps | Suppresses critical failures | Hard-fail on security gates |
|
|
311
|
+
| `secrets: inherit` | Over-broad secret access | Pass secrets explicitly |
|
|
312
|
+
| Hardcoded `node-version: 22` | Version drift across workflows | Use `.node-version` file |
|
|
313
|
+
| No `concurrency:` | Stale runs waste minutes | Always set with `cancel-in-progress` |
|
|
314
|
+
| `if: always()` on non-cleanup steps | Runs even after critical failures | Use `if: success()` (default) |
|
|
315
|
+
| Caching `node_modules` directly | Fragile, platform-specific | Cache package manager global cache |
|
package/skills/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neverinfamous-agent-skills",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Foundational AI agent metacognitive skills and workflows for the Adamic ecosystem.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "README.md",
|
|
@@ -12,17 +12,21 @@
|
|
|
12
12
|
"README.md",
|
|
13
13
|
"autonomous-dev/",
|
|
14
14
|
"bun/",
|
|
15
|
+
"docker/",
|
|
16
|
+
"github-actions/",
|
|
15
17
|
"github-commander/",
|
|
16
18
|
"gitlab/",
|
|
17
19
|
"golang/",
|
|
18
20
|
"mysql/",
|
|
19
21
|
"playwright-standard/",
|
|
20
22
|
"postgres/",
|
|
23
|
+
"python/",
|
|
21
24
|
"react-best-practices/",
|
|
22
25
|
"rust/",
|
|
23
26
|
"shadcn-ui/",
|
|
24
27
|
"skill-builder/",
|
|
25
28
|
"sqlite/",
|
|
29
|
+
"tailwind-css/",
|
|
26
30
|
"typescript/",
|
|
27
31
|
"vitest-standard/"
|
|
28
32
|
],
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python
|
|
3
|
+
description: |
|
|
4
|
+
Master modern Python development with production-grade tooling and idioms.
|
|
5
|
+
Use when writing Python code, configuring project structure, managing
|
|
6
|
+
dependencies with uv, linting with ruff, adding type hints, writing pytest
|
|
7
|
+
tests, or building FastAPI/Django/Flask applications. Triggers on "Python",
|
|
8
|
+
"FastAPI", "Django", "Flask", "pytest", "uv", "ruff", "pyproject.toml".
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Python Engineering Standards
|
|
12
|
+
|
|
13
|
+
This skill codifies 2026 Python best practices — modern tooling (`uv`, `ruff`), strict typing, and idiomatic patterns that produce maintainable, performant code.
|
|
14
|
+
|
|
15
|
+
## 1. Project Setup & Structure
|
|
16
|
+
|
|
17
|
+
### Tooling: `uv` (Not pip/pipenv/poetry)
|
|
18
|
+
|
|
19
|
+
`uv` is the standard package manager for Python in 2026. It replaces pip, pipenv, and poetry with a single, fast Rust binary.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv init <project-name> # Initialize a new project
|
|
23
|
+
uv add <package> # Add a dependency
|
|
24
|
+
uv add --dev <package> # Add a dev dependency
|
|
25
|
+
uv run <command> # Run a command in the project's venv
|
|
26
|
+
uv sync # Install all deps from uv.lock
|
|
27
|
+
uv python install 3.13 # Install a specific Python version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- **ALWAYS** commit both `pyproject.toml` AND `uv.lock` to version control.
|
|
31
|
+
- **NEVER** use `requirements.txt` for new projects — it is a legacy pattern.
|
|
32
|
+
- **NEVER** use `pip install` directly — use `uv add` to keep the lock file in sync.
|
|
33
|
+
|
|
34
|
+
### Directory Layout: `src/` Layout
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
my-project/
|
|
38
|
+
├── .python-version # Pin Python version (e.g., 3.13)
|
|
39
|
+
├── pyproject.toml # Single source of truth for config
|
|
40
|
+
├── uv.lock # Deterministic lock file
|
|
41
|
+
├── src/
|
|
42
|
+
│ └── my_package/
|
|
43
|
+
│ ├── __init__.py
|
|
44
|
+
│ ├── main.py
|
|
45
|
+
│ └── models.py
|
|
46
|
+
└── tests/
|
|
47
|
+
├── __init__.py
|
|
48
|
+
├── conftest.py # Shared fixtures
|
|
49
|
+
└── test_main.py
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **Use `src/` layout** for packages and production apps — it prevents tests from accidentally importing the local source instead of the installed package.
|
|
53
|
+
- **Group by domain**, not file type — prefer `users/`, `billing/`, `auth/` over `models/`, `utils/`, `services/`.
|
|
54
|
+
- **Use `kebab-case`** for directory names, `snake_case` for Python modules.
|
|
55
|
+
|
|
56
|
+
### `pyproject.toml` Configuration (PEP 621)
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
[project]
|
|
60
|
+
name = "my-package"
|
|
61
|
+
version = "0.1.0"
|
|
62
|
+
requires-python = ">=3.12"
|
|
63
|
+
dependencies = [
|
|
64
|
+
"httpx>=0.27",
|
|
65
|
+
"pydantic>=2.0",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[project.optional-dependencies]
|
|
69
|
+
dev = ["pytest>=8.0", "ruff>=0.8", "mypy>=1.13"]
|
|
70
|
+
|
|
71
|
+
[tool.ruff]
|
|
72
|
+
target-version = "py312"
|
|
73
|
+
line-length = 88
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint]
|
|
76
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
77
|
+
|
|
78
|
+
[tool.pytest.ini_options]
|
|
79
|
+
testpaths = ["tests"]
|
|
80
|
+
pythonpath = ["src"]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 2. Type Hints (Mandatory)
|
|
84
|
+
|
|
85
|
+
Type hints are **not optional** — they are foundational design tools.
|
|
86
|
+
|
|
87
|
+
### Rules
|
|
88
|
+
|
|
89
|
+
- **Use built-in generics** (Python 3.9+): `list[str]`, `dict[str, int]`, `tuple[int, ...]`
|
|
90
|
+
- **Use union syntax** (Python 3.10+): `str | None` instead of `Optional[str]`
|
|
91
|
+
- **Avoid `Any`** — use `object`, `Unknown`, or narrow with type guards
|
|
92
|
+
- **Use `TypedDict`** for dict-shaped data with known keys
|
|
93
|
+
- **Use `Protocol`** for structural subtyping instead of ABCs
|
|
94
|
+
- **Run static analysis**: `mypy --strict` or `pyright`
|
|
95
|
+
|
|
96
|
+
### Examples
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# ✅ Good
|
|
100
|
+
def get_user(user_id: int) -> User | None:
|
|
101
|
+
...
|
|
102
|
+
|
|
103
|
+
class Config(TypedDict):
|
|
104
|
+
host: str
|
|
105
|
+
port: int
|
|
106
|
+
debug: bool
|
|
107
|
+
|
|
108
|
+
# ❌ Bad
|
|
109
|
+
def get_user(user_id): # Missing type hints
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
def process(data: Any): # Untyped escape hatch
|
|
113
|
+
...
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 3. Code Quality: `ruff`
|
|
117
|
+
|
|
118
|
+
Ruff is the **all-in-one** linter and formatter for Python. It replaces Flake8, Black, isort, pyupgrade, and more.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
ruff check --fix . # Lint with auto-fix
|
|
122
|
+
ruff format . # Format (replaces Black)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Configuration in `pyproject.toml`
|
|
126
|
+
|
|
127
|
+
```toml
|
|
128
|
+
[tool.ruff]
|
|
129
|
+
target-version = "py312"
|
|
130
|
+
line-length = 88
|
|
131
|
+
src = ["src", "tests"]
|
|
132
|
+
|
|
133
|
+
[tool.ruff.lint]
|
|
134
|
+
select = [
|
|
135
|
+
"E", # pycodestyle errors
|
|
136
|
+
"F", # pyflakes
|
|
137
|
+
"I", # isort
|
|
138
|
+
"UP", # pyupgrade
|
|
139
|
+
"B", # bugbear
|
|
140
|
+
"SIM", # simplify
|
|
141
|
+
"RUF", # ruff-specific
|
|
142
|
+
]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- **NEVER** use `# noqa` to suppress linter errors unless the suppression is explicitly justified by a comment explaining _why_.
|
|
146
|
+
- **NEVER** use `# type: ignore` — fix the type error or use a proper type guard.
|
|
147
|
+
|
|
148
|
+
## 4. Error Handling
|
|
149
|
+
|
|
150
|
+
### Patterns
|
|
151
|
+
|
|
152
|
+
- **Use specific exception types** — never catch bare `except:` or `except Exception:`
|
|
153
|
+
- **Create custom exceptions** inheriting from a base project exception
|
|
154
|
+
- **Use `from` for exception chaining**: `raise ValueError("msg") from original_error`
|
|
155
|
+
- **Never swallow exceptions silently** — at minimum, log them
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# ✅ Good
|
|
159
|
+
class AppError(Exception):
|
|
160
|
+
"""Base exception for the application."""
|
|
161
|
+
|
|
162
|
+
class NotFoundError(AppError):
|
|
163
|
+
"""Raised when a resource is not found."""
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
user = get_user(user_id)
|
|
167
|
+
except DatabaseError as e:
|
|
168
|
+
raise NotFoundError(f"User {user_id} not found") from e
|
|
169
|
+
|
|
170
|
+
# ❌ Bad
|
|
171
|
+
try:
|
|
172
|
+
user = get_user(user_id)
|
|
173
|
+
except: # Bare except — catches SystemExit, KeyboardInterrupt
|
|
174
|
+
pass # Silently swallowed
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 5. Testing with `pytest`
|
|
178
|
+
|
|
179
|
+
### Structure
|
|
180
|
+
|
|
181
|
+
- **AAA pattern**: Arrange, Act, Assert — one concern per test
|
|
182
|
+
- **Use fixtures** for setup/teardown, not classes with `setUp()`/`tearDown()`
|
|
183
|
+
- **Use `conftest.py`** for shared fixtures across test modules
|
|
184
|
+
- **Use `@pytest.mark.parametrize`** for data-driven tests
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
@pytest.fixture
|
|
188
|
+
def client(tmp_path: Path) -> TestClient:
|
|
189
|
+
"""Create a test client with a temporary database."""
|
|
190
|
+
app = create_app(db_path=tmp_path / "test.db")
|
|
191
|
+
return TestClient(app)
|
|
192
|
+
|
|
193
|
+
@pytest.mark.parametrize("status_code,expected", [
|
|
194
|
+
(200, True),
|
|
195
|
+
(404, False),
|
|
196
|
+
(500, False),
|
|
197
|
+
])
|
|
198
|
+
def test_is_success(status_code: int, expected: bool) -> None:
|
|
199
|
+
assert is_success(status_code) == expected
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Running Tests
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
uv run pytest # Run all tests
|
|
206
|
+
uv run pytest tests/test_main.py # Run specific file
|
|
207
|
+
uv run pytest -k "test_user" # Run by pattern
|
|
208
|
+
uv run pytest --cov=src --cov-report=term-missing # Coverage
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 6. Async & Concurrency
|
|
212
|
+
|
|
213
|
+
- **Use `asyncio`** for I/O-bound concurrency (HTTP calls, DB queries)
|
|
214
|
+
- **Use `async def` / `await`** — never mix sync and async code paths
|
|
215
|
+
- **Use `asyncio.TaskGroup`** (Python 3.11+) for structured concurrency
|
|
216
|
+
- **Use `httpx`** (async-native) instead of `requests` for HTTP clients
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
async with asyncio.TaskGroup() as tg:
|
|
220
|
+
task1 = tg.create_task(fetch_user(user_id))
|
|
221
|
+
task2 = tg.create_task(fetch_orders(user_id))
|
|
222
|
+
# Both tasks complete here — exceptions propagate cleanly
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 7. Data Validation: Pydantic v2
|
|
226
|
+
|
|
227
|
+
- **Use Pydantic models** at system boundaries (API requests, config files, DB results)
|
|
228
|
+
- **Never trust external input** — validate with `model_validate()`, not dict access
|
|
229
|
+
- **Use `Field()` validators** for constraints, not manual `if` checks
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from pydantic import BaseModel, Field
|
|
233
|
+
|
|
234
|
+
class CreateUserRequest(BaseModel):
|
|
235
|
+
name: str = Field(min_length=1, max_length=100)
|
|
236
|
+
email: str = Field(pattern=r"^[\w.-]+@[\w.-]+\.\w+$")
|
|
237
|
+
age: int = Field(ge=0, le=150)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## 8. Anti-Patterns (Never Do These)
|
|
241
|
+
|
|
242
|
+
| Anti-Pattern | Why It's Wrong | Do This Instead |
|
|
243
|
+
| ------------------------------------ | ---------------------------------- | ---------------------------- |
|
|
244
|
+
| `import *` | Pollutes namespace, breaks tooling | Explicit imports |
|
|
245
|
+
| Mutable default args (`def f(x=[])`) | Shared across calls | Use `None` + assign |
|
|
246
|
+
| Global mutable state | Thread-unsafe, untestable | Dependency injection |
|
|
247
|
+
| `os.path` for path manipulation | Platform-inconsistent | Use `pathlib.Path` |
|
|
248
|
+
| `print()` for logging | No levels, no rotation | Use `logging` or `structlog` |
|
|
249
|
+
| `== None` / `== True` | Wrong semantics | `is None` / `is True` |
|
|
250
|
+
|
|
251
|
+
## 9. Web Frameworks Quick Reference
|
|
252
|
+
|
|
253
|
+
| Framework | Best For | Key Pattern |
|
|
254
|
+
| ----------- | ---------------------------- | --------------------------------------------------------- |
|
|
255
|
+
| **FastAPI** | REST APIs, async, auto-docs | Pydantic models, dependency injection, `async def` routes |
|
|
256
|
+
| **Django** | Full-stack, admin, ORM | Models → Views → Templates, `manage.py`, migrations |
|
|
257
|
+
| **Flask** | Lightweight APIs, prototypes | Blueprints, application factory pattern |
|