@mrciphersmith/keryx 0.3.5 → 0.3.6

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 (76) hide show
  1. package/dist/cli.js +872 -316
  2. package/docs/README.md +2 -0
  3. package/package.json +1 -1
  4. package/src/gdskills/bundled/install-manifest.json +319 -76
  5. package/src/gdskills/bundled/stacks/django/agent-refs.json +3 -0
  6. package/src/gdskills/bundled/stacks/django/governance/eval.json +1763 -0
  7. package/src/gdskills/bundled/stacks/django/governance/scout.json +40 -0
  8. package/src/gdskills/bundled/stacks/django/pack.json +43 -0
  9. package/src/gdskills/bundled/stacks/django/rules/coding-style.mdc +80 -0
  10. package/src/gdskills/bundled/stacks/django/rules/patterns.mdc +92 -0
  11. package/src/gdskills/bundled/stacks/django/rules/security.mdc +92 -0
  12. package/src/gdskills/bundled/stacks/django/rules/testing.mdc +89 -0
  13. package/src/gdskills/bundled/stacks/django/skills/django-build-fix/SKILL.md +149 -0
  14. package/src/gdskills/bundled/stacks/django/skills/django-build-fix/evals.json +49 -0
  15. package/src/gdskills/bundled/stacks/django/skills/django-code-review/SKILL.md +137 -0
  16. package/src/gdskills/bundled/stacks/django/skills/django-code-review/evals.json +48 -0
  17. package/src/gdskills/bundled/stacks/django/skills/django-implementation/SKILL.md +147 -0
  18. package/src/gdskills/bundled/stacks/django/skills/django-implementation/evals.json +75 -0
  19. package/src/gdskills/bundled/stacks/django/skills/django-migrate/SKILL.md +166 -0
  20. package/src/gdskills/bundled/stacks/django/skills/django-migrate/evals.json +49 -0
  21. package/src/gdskills/bundled/stacks/django/skills/django-testing/SKILL.md +130 -0
  22. package/src/gdskills/bundled/stacks/django/skills/django-testing/evals.json +48 -0
  23. package/src/gdskills/bundled/stacks/fastapi/agent-refs.json +3 -0
  24. package/src/gdskills/bundled/stacks/fastapi/governance/eval.json +1777 -0
  25. package/src/gdskills/bundled/stacks/fastapi/governance/scout.json +34 -0
  26. package/src/gdskills/bundled/stacks/fastapi/pack.json +43 -0
  27. package/src/gdskills/bundled/stacks/fastapi/rules/coding-style.mdc +68 -0
  28. package/src/gdskills/bundled/stacks/fastapi/rules/patterns.mdc +108 -0
  29. package/src/gdskills/bundled/stacks/fastapi/rules/security.mdc +99 -0
  30. package/src/gdskills/bundled/stacks/fastapi/rules/testing.mdc +85 -0
  31. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-build-fix/SKILL.md +157 -0
  32. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-build-fix/evals.json +76 -0
  33. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-code-review/SKILL.md +150 -0
  34. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-code-review/evals.json +74 -0
  35. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-implementation/SKILL.md +158 -0
  36. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-implementation/evals.json +75 -0
  37. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-testing/SKILL.md +146 -0
  38. package/src/gdskills/bundled/stacks/fastapi/skills/fastapi-testing/evals.json +74 -0
  39. package/src/gdskills/bundled/stacks/java-kotlin-spring/agent-refs.json +3 -0
  40. package/src/gdskills/bundled/stacks/java-kotlin-spring/governance/eval.json +2194 -0
  41. package/src/gdskills/bundled/stacks/java-kotlin-spring/governance/scout.json +39 -0
  42. package/src/gdskills/bundled/stacks/java-kotlin-spring/pack.json +40 -0
  43. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/coding-style.mdc +67 -0
  44. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/patterns.mdc +65 -0
  45. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/security.mdc +69 -0
  46. package/src/gdskills/bundled/stacks/java-kotlin-spring/rules/testing.mdc +80 -0
  47. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-build-fix/SKILL.md +144 -0
  48. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-build-fix/evals.json +74 -0
  49. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-code-review/SKILL.md +129 -0
  50. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-code-review/evals.json +74 -0
  51. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-implementation/SKILL.md +147 -0
  52. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-implementation/evals.json +75 -0
  53. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-migrate/SKILL.md +139 -0
  54. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-migrate/evals.json +74 -0
  55. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-testing/SKILL.md +128 -0
  56. package/src/gdskills/bundled/stacks/java-kotlin-spring/skills/java-kotlin-spring-testing/evals.json +73 -0
  57. package/src/gdskills/bundled/stacks/python/agent-refs.json +2 -1
  58. package/src/gdskills/bundled/stacks/python/pack.json +1 -1
  59. package/src/gdskills/bundled/stacks/rust/agent-refs.json +3 -0
  60. package/src/gdskills/bundled/stacks/rust/governance/eval.json +1823 -0
  61. package/src/gdskills/bundled/stacks/rust/governance/scout.json +32 -0
  62. package/src/gdskills/bundled/stacks/rust/pack.json +42 -0
  63. package/src/gdskills/bundled/stacks/rust/rules/coding-style.mdc +93 -0
  64. package/src/gdskills/bundled/stacks/rust/rules/patterns.mdc +85 -0
  65. package/src/gdskills/bundled/stacks/rust/rules/security.mdc +85 -0
  66. package/src/gdskills/bundled/stacks/rust/rules/testing.mdc +82 -0
  67. package/src/gdskills/bundled/stacks/rust/skills/rust-build-fix/SKILL.md +141 -0
  68. package/src/gdskills/bundled/stacks/rust/skills/rust-build-fix/evals.json +78 -0
  69. package/src/gdskills/bundled/stacks/rust/skills/rust-code-review/SKILL.md +127 -0
  70. package/src/gdskills/bundled/stacks/rust/skills/rust-code-review/evals.json +72 -0
  71. package/src/gdskills/bundled/stacks/rust/skills/rust-implementation/SKILL.md +133 -0
  72. package/src/gdskills/bundled/stacks/rust/skills/rust-implementation/evals.json +79 -0
  73. package/src/gdskills/bundled/stacks/rust/skills/rust-testing/SKILL.md +130 -0
  74. package/src/gdskills/bundled/stacks/rust/skills/rust-testing/evals.json +75 -0
  75. package/src/gdskills/bundled/agents/python-build-fixer.md +0 -52
  76. package/src/gdskills/bundled/agents/python-code-auditor.md +0 -49
@@ -0,0 +1,76 @@
1
+ {
2
+ "triggers": {
3
+ "positive": [
4
+ "Our API crashes on boot right after I wired up a new Depends() chain -- what's throwing it off?",
5
+ "I just wired a new router into main.py and now uvicorn won't even boot -- ImportError somewhere in the chain. Can you track it down?",
6
+ "One of my FastAPI dependency functions keeps blowing up with 'unable to resolve dependency' at app startup -- mind digging into why?",
7
+ "mypy is failing on this FastAPI path operation's return type",
8
+ "ruff check is failing on our FastAPI project, fix the violations",
9
+ "Got a weird Pydantic error on model instantiation that I can't make sense of -- here's the traceback, can you figure out what's wrong?",
10
+ "Every request to my new FastAPI endpoints comes back 404 even though I swear I included the router -- what did I mess up?"
11
+ ],
12
+ "negative": [
13
+ "Fix this generic ModuleNotFoundError unrelated to FastAPI's own wiring",
14
+ "Fix this Django migration conflict blocking makemigrations from running",
15
+ "Implement a new FastAPI endpoint that lists orders",
16
+ "Write pytest tests for this FastAPI router",
17
+ "Review this FastAPI diff for security issues",
18
+ "Fix the TypeScript build failure in our Node service",
19
+ "Our pip dependency resolver reports a version conflict between two unrelated packages"
20
+ ]
21
+ },
22
+ "scenarios": [
23
+ {
24
+ "id": "pydantic-mismatch-not-any",
25
+ "prompt": "A Pydantic model in our FastAPI project raises `PydanticUserError` at import time -- the message says the model can't use both `Config` and `model_config` -- after someone added `model_config = ConfigDict(...)` to a model that still has its original `class Config:` block. How do you fix it?",
26
+ "strictness": "high",
27
+ "expected_behavior": [
28
+ {
29
+ "grader": "judge",
30
+ "rubric": "A correct answer diagnoses the actual cause -- the model defines BOTH the old v1-style `class Config:` block AND the new `model_config = ConfigDict(...)` attribute at the same time, which Pydantic v2 rejects as an error (not merely a deprecation warning) -- and fixes it by removing one of the two, migrating any settings from `class Config:` into `model_config`, rather than making the error disappear by widening field types to Any/dict.",
31
+ "pass_criteria": [
32
+ "identifies the root cause: the model defines both `class Config:` and `model_config = ConfigDict(...)` at once, which Pydantic v2 raises an error for -- not that `class Config:` exists at all (using it alone is only a deprecation warning, not this error)",
33
+ "names the concrete fix: remove the `class Config:` block and move any settings it held into `model_config = ConfigDict(...)` (translating v1 keys to their v2 equivalents, e.g. `orm_mode` -> `from_attributes`), leaving the model with exactly one config mechanism, consistent with the project's actual pinned Pydantic version",
34
+ "shows or names the specific change (the class body converted, or the settings migrated), not just 'fix the config conflict' in the abstract"
35
+ ],
36
+ "fail_criteria": [
37
+ "proposes retyping the model's fields as `Any`/`dict` (or removing Pydantic validation from the model) to make the error stop, instead of removing the duplicate config mechanism. Mentioning that this would be wrong is not itself a failure."
38
+ ]
39
+ }
40
+ ],
41
+ "calibration": {
42
+ "known_right": "This is Pydantic's `config-both` error: the model still has its original `class Config:` block (v1 style), and someone added `model_config = ConfigDict(...)` (v2 style) alongside it without removing the old one -- Pydantic v2 raises `PydanticUserError` when a model carries both at once, since it can't tell which is authoritative. Using `class Config:` on its own is only a deprecation warning; it's having *both* attributes present that turns it into a hard error. The fix is to keep only one: remove the `class Config:` block and fold whatever it set into `model_config`, translating v1 keys to their v2 names (e.g. `orm_mode` becomes `from_attributes`). Once the model has just `model_config = ConfigDict(...)` and no inner `Config` class, rerun the app import to confirm the error is gone, then rerun `mypy`/`pytest` since the merged settings may shift field behavior slightly.",
43
+ "known_wrong": "Simplest fix: since Pydantic is complaining about the config machinery, just drop strict typing on the affected fields and use `Any` so there's nothing left for the conflicting config to validate:\n\n```python\nclass NotificationSettings(BaseModel):\n channel: Any\n retry_limit: Any\n\n class Config:\n orm_mode = True\n\n model_config = ConfigDict(from_attributes=True)\n```\n\nThis doesn't actually touch the `Config`/`model_config` conflict, but since the fields are now untyped the validation errors that were showing up alongside the startup failure go away, which looks like it fixed the problem.",
44
+ "vague": "Sounds like the model has both old and new Pydantic config styles defined on it at the same time -- keep only one of them instead of leaving both in place.",
45
+ "subtle_wrong": "Since the complaint is about `model_config` conflicting with something, the fastest fix is to just set `model_config` to an empty dict so it doesn't carry any settings that could clash:\n\n```python\nclass NotificationSettings(BaseModel):\n channel: str\n retry_limit: int\n\n class Config:\n orm_mode = True\n\n model_config = ConfigDict()\n```\n\nThat should stop `model_config` from conflicting with anything `Config` sets, since it's empty now. The `class Config:` block is left in place since that's where `orm_mode` still lives."
46
+ },
47
+ "anti_patterns": ["`Any`"]
48
+ },
49
+ {
50
+ "id": "dependency-resolution-not-removed",
51
+ "prompt": "Our FastAPI app fails to start with an error that a dependency function's parameter cannot be resolved. Fix it.",
52
+ "strictness": "high",
53
+ "expected_behavior": [
54
+ {
55
+ "grader": "judge",
56
+ "rubric": "A correct answer diagnoses which parameter FastAPI could not resolve and fixes it by giving that parameter a proper Depends()/request-data annotation, rather than removing the Depends() wiring and calling the dependency function directly. Because the prompt supplies no code or exact error text, an answer that first asks for the actual error message and the dependency function's signature, while explicitly ruling out removing Depends() as the eventual fix, is also correct.",
57
+ "pass_criteria": [
58
+ "either names the concrete fix -- giving the unresolved parameter a proper `Depends(...)` (or a request-data annotation like `Query(...)`/a plain type FastAPI can parse) -- once the failing signature is known, or asks for the actual error message and the dependency function's signature before proposing a fix, since neither was supplied",
59
+ "explains that FastAPI couldn't determine how to resolve one of the dependency's own parameters, and that the fix is to give that parameter a source FastAPI understands, not to bypass dependency injection",
60
+ "commits to keeping `Depends(...)`-based injection in place once the fix is identified or known"
61
+ ],
62
+ "fail_criteria": [
63
+ "proposes removing the `Depends(...)` wiring and calling the dependency function directly (or hard-coding its return value) to make the startup error disappear. Mentioning that this would be wrong is not itself a failure."
64
+ ]
65
+ }
66
+ ],
67
+ "calibration": {
68
+ "known_right": "I'd need the actual startup error message and the dependency function's signature to name the exact fix -- FastAPI's error names which parameter it couldn't resolve, and that's the one to look at. In general, this happens when a dependency function has a parameter with no default and no annotation FastAPI recognizes as either request data (a `Query(...)`/`Path(...)`/plain scalar type) or another `Depends(...)`. The fix is to give that specific parameter the annotation it's missing -- e.g. if it's meant to come from another dependency, add `Depends(other_dep)`; if it's meant to come from the request, annotate it with the right FastAPI parameter type. I wouldn't remove `Depends(...)` from the call site to sidestep the error -- that would lose dependency injection (and `app.dependency_overrides` testability) for that value entirely; once the real fix is applied, rerun the app-startup check to confirm it resolves cleanly.",
69
+ "known_wrong": "Easiest fix: since FastAPI can't figure out how to resolve the parameter, just call the dependency function directly inside the path operation instead of injecting it through `Depends(...)`:\n\n```python\n@router.get(\"/items\")\ndef read_items(user_id: int):\n db = get_db_session() # called directly, no Depends()\n return db.query(Item).filter_by(owner_id=user_id).all()\n```\n\nThis sidesteps FastAPI's dependency resolution entirely, so the startup error goes away immediately and the endpoint still gets a working session. You lose the ability to override it in tests via `app.dependency_overrides`, but that's a minor tradeoff for getting the app running again quickly.",
70
+ "vague": "Figure out which parameter FastAPI can't resolve and give it the annotation it needs instead of working around the dependency system.",
71
+ "subtle_wrong": "Since the unresolved parameter is causing the whole app to fail at startup, the pragmatic move is to give it a hard-coded default value so FastAPI stops trying to resolve it as a dependency at all:\n\n```python\ndef get_db(session_factory=default_session_factory):\n return session_factory()\n```\n\nThat clears the resolution error because the parameter now has a plain default instead of an unresolved dependency, and the app starts. It's a bit less flexible than proper injection, but it unblocks startup without having to dig into why the original wiring didn't resolve."
72
+ },
73
+ "anti_patterns": ["Depends"]
74
+ }
75
+ ]
76
+ }
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: fastapi-code-review
3
+ description: "Use when reviewing FastAPI changes for correctness and safety risks -- checks a synchronous driver or library call left in a route handler's coroutine, request bodies accepted as dict/Any instead of Pydantic models, missing response_model filtering, missing or misplaced auth dependencies, unsafe CORS configuration, and hard-coded secrets. Read-only: reports findings, does not edit code, and is scoped to FastAPI's own request lifecycle rather than general-purpose backend correctness."
4
+ triggers:
5
+ - "review this FastAPI diff"
6
+ - "audit this FastAPI branch before merging"
7
+ - "review this FastAPI endpoint for an unsafe CORS or auth misconfiguration"
8
+ - "audit this FastAPI router"
9
+ - "review this FastAPI path operation for a blocking database driver call"
10
+ - "check this FastAPI code for missing response_model"
11
+ metadata:
12
+ origin: authored
13
+ category: review
14
+ version: "1.0.0"
15
+ compatible_harnesses: "claude,codex,cursor,zed,opencode"
16
+ license: "MIT"
17
+ ---
18
+
19
+ # FastAPI code review
20
+
21
+ Review a set of FastAPI changes for correctness, resource-safety, and
22
+ security risk specific to FastAPI's own request lifecycle. Read-only: this
23
+ skill reports findings, it never edits code. Scoped to FastAPI-specific
24
+ defects; for generic Python correctness/resource/typing review (mutable
25
+ defaults, broad `except`, unclosed resources) use `python-code-review`, for
26
+ a language-agnostic security sweep use `review-security-code`, for fixing
27
+ what this skill finds use `fastapi-build-fix` (checker failures) or hand
28
+ the report to the author.
29
+
30
+ ## Workflow
31
+
32
+ ### Step 1: Scope the review
33
+
34
+ 1. Identify the changed FastAPI files (`git diff` against the review base,
35
+ or the files the requester names) — path operations, dependencies,
36
+ Pydantic schemas, middleware/app setup.
37
+ 2. Read `pyproject.toml` for the project's configured `ruff`/`mypy` rules
38
+ and pinned FastAPI/Pydantic versions — a finding this skill would raise
39
+ that the project's own linter already enforces and passes is lower
40
+ priority than one static tooling cannot catch.
41
+ 3. Read enough of the surrounding router/dependency graph to judge whether
42
+ a flagged pattern is actually a bug in context (e.g. whether a
43
+ dependency really is meant to be public, or whether a sync call really
44
+ has no async alternative available).
45
+
46
+ ### Step 2: Check each changed file against these categories
47
+
48
+ **Async correctness**
49
+ - A blocking call (sync DB driver, `requests.get`, `time.sleep`, blocking
50
+ file I/O) directly inside an `async def` path operation or `async def`
51
+ dependency, instead of `def` (which FastAPI threadpools automatically) or
52
+ an async client.
53
+ - A `def` path operation declared `async def` purely for "consistency"
54
+ where its body has no actual async work — not a bug, but worth a note if
55
+ it invites a future blocking call to land inside it unnoticed.
56
+
57
+ **Request validation**
58
+ - A request body accepted as raw `dict`/`Any`, or read manually via `await
59
+ request.json()`, where a Pydantic `BaseModel` should validate it instead.
60
+ - A Pydantic field with no shape constraint (`Field(...)` bounds,
61
+ `Literal`, `pattern`) where an unconstrained value flows into something
62
+ size- or shape-sensitive downstream (a file path, a numeric calculation,
63
+ a SQL parameter).
64
+
65
+ **Response modeling**
66
+ - A path operation returning a model/ORM object with no `response_model`
67
+ (or return-type annotation FastAPI can use as one), especially when the
68
+ underlying object carries a field the response should not expose (a
69
+ password hash, an internal flag).
70
+ - A `response_model` that includes a field it shouldn't, or omits a field
71
+ callers actually need — read the model definition, not just its
72
+ presence.
73
+
74
+ **Dependency injection and auth**
75
+ - A path operation that should require authentication with no
76
+ `Depends(get_current_user)`-equivalent dependency present.
77
+ - Auth logic duplicated inline in a path operation instead of factored into
78
+ a shared dependency, making it easy for a future endpoint to omit it by
79
+ accident.
80
+ - A dependency missing `yield`-based teardown for a resource that needs
81
+ closing (a DB session, a lock).
82
+
83
+ **Security** (full list: `rules/security.mdc`)
84
+ - `CORSMiddleware` configured with `allow_origins=["*"]` combined with
85
+ `allow_credentials=True`.
86
+ - A hard-coded `SECRET_KEY`, API key, or database URL in source instead of
87
+ read through `pydantic-settings`/environment.
88
+ - Password verification skipped on an unknown-username lookup (a username-
89
+ enumeration timing gap), or a token generated with `random` instead of a
90
+ real JWT/`secrets`-based mechanism.
91
+ - SQL built by interpolating a (even Pydantic-validated) field into a raw
92
+ string instead of parameter binding or the ORM's query builder.
93
+
94
+ **Background work**
95
+ - Work that must not be lost (payment capture, an email the user depends
96
+ on) handled with `BackgroundTasks` instead of a real task queue with
97
+ retries.
98
+
99
+ ### Step 3: Report
100
+
101
+ For each finding: file:line, category, what's wrong, and the safe
102
+ alternative (cite the exact pattern, e.g. "declare `response_model=UserRead`
103
+ so `hashed_password` is filtered from the response"). Group by severity — a
104
+ missing auth dependency or an unsafe CORS config outranks a missing
105
+ `Field` constraint.
106
+
107
+ ```
108
+ fastapi-code-review: 3 findings
109
+ [security] routers/users.py:22 — `GET /users/{id}` has no auth
110
+ dependency; add `Depends(get_current_user)`
111
+ [async] routers/orders.py:40 — `requests.get(...)` called directly
112
+ inside `async def create_order`; make the function `def` or use
113
+ `httpx.AsyncClient`
114
+ [response-modeling] routers/users.py:15 — no `response_model` declared;
115
+ the returned `User` carries `hashed_password`, which will leak into
116
+ the response body
117
+ ```
118
+
119
+ ## Rules
120
+
121
+ - NEVER edit the files under review — report findings only.
122
+ - Cite the specific line and the specific safe alternative; a vague "this
123
+ could leak data" finding is not actionable.
124
+ - Do not duplicate a finding the project's own configured `ruff`/`mypy`
125
+ rules already enforce and would catch on their own — focus on what
126
+ static tooling misses (blocking-call placement, response-model gaps,
127
+ auth-dependency omissions, security sinks needing call-site context).
128
+ - Distinguish a real bug from a stylistic preference; a stylistic point
129
+ belongs in `rules/coding-style.mdc`, not a review finding blocking the
130
+ change.
131
+
132
+ ## Red Flags
133
+
134
+ | Rationalization | Why it is wrong |
135
+ |---|---|
136
+ | "The endpoint is `async def` but the blocking call is quick, it's fine" | A "quick" blocking call still runs on the shared event loop and stalls every other concurrent request for its full duration; flag it regardless of expected latency |
137
+ | "No `response_model` needed, the frontend only reads the fields it wants" | The frontend not reading a leaked field doesn't stop it from being present in the response body for anything else (a proxy log, a browser devtools inspection, a different client) to see |
138
+ | "It's just a review, I'll add the missing `Depends(get_current_user)` myself since it's one line" | This skill is read-only; even a trivial fix belongs to the author or `fastapi-build-fix`, not a silent edit during review |
139
+
140
+ ## Verification
141
+
142
+ Do not report the review done until all of the following hold:
143
+
144
+ - Every changed FastAPI file in scope was checked against all six
145
+ categories in Step 2.
146
+ - No finding duplicates something the project's own configured linter/type
147
+ checker already flags and enforces.
148
+ - Every finding names a file:line, the specific problem, and a specific
149
+ fix — no vague findings.
150
+ - No file under review was modified.
@@ -0,0 +1,74 @@
1
+ {
2
+ "triggers": {
3
+ "positive": [
4
+ "Review this FastAPI diff for blocking calls inside async path operations",
5
+ "Check this FastAPI pull request for bugs before I merge it",
6
+ "Before this FastAPI route goes out, can you check whether anyone could hit it without being logged in, or whether our cross-origin setup is too loose?",
7
+ "I'm worried some of these FastAPI handlers might be leaking internal fields back to the client since we didn't always declare an output schema -- can you take a look?",
8
+ "Review this async FastAPI code for blocking database calls",
9
+ "Check this FastAPI code for a request body that skips Pydantic validation"
10
+ ],
11
+ "negative": [
12
+ "Implement a new FastAPI endpoint that fetches order history",
13
+ "Review this plain Python module for mutable default arguments and broad except clauses",
14
+ "Fix the mypy type errors in this FastAPI project so the build passes",
15
+ "Write pytest tests for this FastAPI router",
16
+ "Review this Django view for SQL injection issues",
17
+ "Run review-security-code on our whole repository for OWASP issues"
18
+ ]
19
+ },
20
+ "scenarios": [
21
+ {
22
+ "id": "missing-response-model-finding",
23
+ "prompt": "Review this FastAPI code for bugs:\n\n@router.get(\"/users/{user_id}\")\ndef get_user(user_id: int, db: Session = Depends(get_db)):\n user = db.get(User, user_id)\n if user is None:\n raise HTTPException(status_code=404, detail=\"Not found\")\n return user\n\n# User is a SQLAlchemy model with fields: id, username, email, hashed_password",
24
+ "strictness": "high",
25
+ "expected_behavior": [
26
+ {
27
+ "grader": "judge",
28
+ "rubric": "A correct review flags the missing response_model declaration and explains that without it, the returned User object -- including hashed_password -- serializes straight into the response body, then names the concrete fix, without editing the code itself.",
29
+ "pass_criteria": [
30
+ "identifies that the path operation declares no `response_model` (or equivalent return-type annotation), so FastAPI does not filter the returned `User` object's fields before serializing the response",
31
+ "states specifically that `hashed_password` will leak into the response body as a consequence, not just a generic 'could expose data' remark",
32
+ "names the concrete fix: declare `response_model=UserRead` (or equivalent) using an output schema that excludes `hashed_password`, shown as the fix rather than only described in the abstract -- and does not modify the code itself, since this skill only reports findings"
33
+ ],
34
+ "fail_criteria": [
35
+ "declares the endpoint has no bug or is fine as written, missing the response_model gap and the hashed_password leak entirely"
36
+ ]
37
+ }
38
+ ],
39
+ "calibration": {
40
+ "known_right": "Finding: `get_user` declares no `response_model`, so FastAPI serializes the `User` SQLAlchemy object returned from the function directly, with all of its fields -- including `hashed_password` -- into the JSON response body. There's nothing here filtering the output down to only the fields a client should see; anyone calling this endpoint gets the user's password hash back in the response. Fix: declare `response_model=UserRead` on the path operation, where `UserRead` is a Pydantic model containing only `id`, `username`, and `email` (no `hashed_password`). FastAPI will then serialize through `UserRead` regardless of what extra fields the underlying `User` object carries. This is a real data-exposure bug, so I'm flagging it as the primary finding here rather than editing the code myself, since this review is read-only.",
41
+ "known_wrong": "This endpoint looks fine -- it fetches the user by ID, handles the not-found case with a proper 404, and returns the user object, which is exactly what a `GET /users/{id}` endpoint should do. FastAPI automatically converts the SQLAlchemy object into JSON for the response, so a `response_model` is only strictly required when you actually want to hide fields, and this simple lookup endpoint doesn't need that. No changes needed.",
42
+ "vague": "There's a data exposure risk here -- returning the raw user object without any kind of output schema is generally not a great idea.",
43
+ "subtle_wrong": "Worth a note: this endpoint returns the raw `User` object with no `response_model`, so whatever fields the SQLAlchemy model has will end up in the response. I'd suggest adding a `response_model` at some point, though since the frontend for this app only reads `username` and `email` off the response today, it's more of a minor cleanup than something that needs fixing before merge."
44
+ },
45
+ "anti_patterns": ["response_model"]
46
+ },
47
+ {
48
+ "id": "missing-auth-dependency-finding",
49
+ "prompt": "Review this FastAPI code for bugs:\n\n@router.delete(\"/users/{user_id}\")\ndef delete_user(user_id: int, db: Session = Depends(get_db)):\n user = db.get(User, user_id)\n if user is None:\n raise HTTPException(status_code=404, detail=\"Not found\")\n db.delete(user)\n db.commit()\n return {\"ok\": True}",
50
+ "strictness": "high",
51
+ "expected_behavior": [
52
+ {
53
+ "grader": "judge",
54
+ "rubric": "A correct review flags that the DELETE endpoint has no authentication/authorization dependency, so any caller can delete any user by id, and names Depends(get_current_user) (or an equivalent auth dependency) as the concrete fix, without editing the code itself.",
55
+ "pass_criteria": [
56
+ "identifies that the endpoint has no auth dependency (no `Depends(get_current_user)` or equivalent) despite performing a destructive action (deleting a user)",
57
+ "explains the consequence: any unauthenticated caller can delete any user by guessing/iterating `user_id`, since nothing checks who is making the request or whether they're allowed to delete this particular user",
58
+ "names a concrete fix: add an auth dependency (e.g. `current_user: User = Depends(get_current_user)`) and, ideally, an authorization check that the caller is allowed to delete this specific user -- not just a vague 'add some auth check'"
59
+ ],
60
+ "fail_criteria": [
61
+ "declares the endpoint has no bug or is fine as written, missing the absent auth dependency entirely"
62
+ ]
63
+ }
64
+ ],
65
+ "calibration": {
66
+ "known_right": "Finding: `delete_user` has no authentication or authorization dependency at all -- nothing in this path operation checks who is calling it or whether they're allowed to delete this particular user. As written, any caller who can reach this route can delete any user by iterating `user_id`, with no credential required. Fix: add `current_user: User = Depends(get_current_user)` as a parameter so the endpoint requires a valid authenticated caller, and ideally check `current_user.id == user_id` (or an admin-role check) before deleting, so an authenticated user can't delete someone else's account either. This is a serious authorization gap, so I'm flagging it as the primary finding rather than fixing it myself, since this review is read-only.",
67
+ "known_wrong": "This looks correct -- it fetches the user, returns a proper 404 if missing, deletes it, and commits the transaction, which is exactly the right flow for a delete endpoint. Auth is typically handled at the API gateway or middleware layer in most FastAPI setups, so it's reasonable for the individual path operation not to add its own `Depends(get_current_user)` and duplicate that check itself. No changes needed here.",
68
+ "vague": "This endpoint could probably use some kind of access control before letting a delete go through.",
69
+ "subtle_wrong": "Worth flagging: there's no explicit auth dependency on this DELETE endpoint. That said, since `user_id` is an internal database identifier and not something exposed anywhere publicly, the practical risk of someone guessing valid ids is fairly low, so I'd treat this as a nice-to-have hardening item rather than something blocking the merge."
70
+ },
71
+ "anti_patterns": ["Depends(get_current_user)"]
72
+ }
73
+ ]
74
+ }
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: fastapi-implementation
3
+ description: "Use when implementing or extending a FastAPI path operation, dependency, or Pydantic schema -- covers async vs. sync path operations and FastAPI's threadpool behavior, Depends()-based dependency injection, Pydantic v2 request/response models, response_model filtering, background tasks, and OpenAPI/router conventions. Scoped to FastAPI's own request-handling surface, not general-purpose Python application code with no HTTP layer."
4
+ triggers:
5
+ - "add a FastAPI path operation for..."
6
+ - "implement this route handler in FastAPI"
7
+ - "write a Pydantic model that validates..."
8
+ - "add a FastAPI dependency for the current user"
9
+ - "add background task support to this FastAPI route"
10
+ - "create a new APIRouter for this resource"
11
+ - "implement OAuth2 login in FastAPI"
12
+ - "add response_model filtering to this path operation"
13
+ metadata:
14
+ origin: authored
15
+ category: implement
16
+ version: "1.0.0"
17
+ compatible_harnesses: "claude,codex,cursor,zed,opencode"
18
+ license: "MIT"
19
+ ---
20
+
21
+ # FastAPI implementation
22
+
23
+ Implement or extend a path operation, dependency, or schema in a FastAPI
24
+ service: discovering the project's own router/schema layout and Pydantic
25
+ version before writing code, then applying current-practice async/sync
26
+ path-operation semantics, dependency injection, request/response modeling,
27
+ and background-work patterns. Scoped to FastAPI's own framework layer — for
28
+ generic Python idiom not specific to FastAPI (typing, `asyncio.TaskGroup`,
29
+ context managers, packaging) use `python-implementation`; for tests use
30
+ `fastapi-testing`; for reviewing a diff without editing it use
31
+ `fastapi-code-review`; for fixing a broken build/lint/type-check without
32
+ adding a feature use `fastapi-build-fix`.
33
+
34
+ ## Workflow
35
+
36
+ ### Step 1: Discover the project's own conventions
37
+
38
+ 1. Read `pyproject.toml`/`requirements.txt` for the FastAPI and Pydantic
39
+ versions pinned (Pydantic v1 vs. v2 changes model syntax significantly —
40
+ confirm before assuming `model_config`/`field_validator` v2 syntax
41
+ applies).
42
+ 2. Confirm the project layout: routers under `routers/`/`api/`, schemas
43
+ under `schemas/`/`models/`, a `dependencies.py`, and where `app =
44
+ FastAPI(...)` and `app.include_router(...)` live — place new code
45
+ consistently with what's already there.
46
+ 3. Read 1-2 neighboring routers for: how auth is injected (a shared
47
+ `Depends(get_current_user)`), how DB sessions are obtained, whether
48
+ `Annotated[...]` or bare default-value `Depends()` is the project's own
49
+ style, and the existing `response_model`/status-code conventions.
50
+ 4. Check whether the project uses a real task queue (Celery, arq) already —
51
+ if so, a new "run this after the response" need probably belongs there,
52
+ not in `BackgroundTasks`, unless it's genuinely best-effort/in-process
53
+ work.
54
+
55
+ ### Step 2: Design the change
56
+
57
+ - Decide `async def` vs. plain `def` per `rules/patterns.mdc`: `async def`
58
+ only when the body awaits something async; plain `def` when it calls a
59
+ blocking library, since FastAPI runs a `def` path operation (and `def`
60
+ dependency) in its own threadpool automatically.
61
+ - Design the request/response schema first: what does the client send
62
+ (input model), what does the client get back (output model, via
63
+ `response_model`) — these are usually two different `BaseModel`s, not
64
+ one reused for both.
65
+ - Decide which existing dependency this change reuses (auth, DB session,
66
+ pagination) vs. what new dependency it needs to add, and whether that
67
+ new dependency needs `yield`-based teardown.
68
+
69
+ ### Step 3: Implement
70
+
71
+ 1. Define/extend the Pydantic `BaseModel`(s) for the request body and
72
+ response, with `Field(...)` constraints for anything with a real shape
73
+ constraint, and `field_validator`/`model_validator` (Pydantic v2) for
74
+ cross-field or custom validation — never accept the body as
75
+ `dict`/`Any`.
76
+ 2. Write the path operation with `Annotated[<type>, Depends(...)]`
77
+ parameters (matching the project's existing style from Step 1), a
78
+ declared `response_model`, and the correct `async def`/`def` choice
79
+ from Step 2.
80
+ 3. Add or reuse a `Depends(...)` dependency for anything the path
81
+ operation needs but shouldn't construct itself; use `yield` in the
82
+ dependency if it owns a resource needing teardown.
83
+ 4. For post-response, best-effort work only, inject `BackgroundTasks` and
84
+ call `.add_task(...)`; for anything needing retries or durability past
85
+ the process lifetime, use the project's real task queue instead.
86
+ 5. Register a new router with `app.include_router(...)` (or add to the
87
+ existing router file) with `tags=[...]` and a `summary`/docstring for
88
+ non-trivial endpoints.
89
+ 6. Follow `rules/coding-style.mdc` and `rules/patterns.mdc` for the rest of
90
+ the idiom; check `rules/security.mdc` before touching auth, CORS,
91
+ secrets, or anything building SQL from a validated field. For anything
92
+ not FastAPI-specific (typing, exception chaining, logging), follow
93
+ `python`'s own `rules/coding-style.mdc`/`rules/patterns.mdc`.
94
+
95
+ ### Step 4: Verify
96
+
97
+ ```bash
98
+ ruff check .
99
+ ruff format --check .
100
+ mypy . # or: pyright
101
+ pytest -x -q
102
+ python -c "import <app_module>" # confirms the app still imports/assembles cleanly
103
+ ```
104
+
105
+ Prefix each command with the project's own run prefix (`uv run`, `poetry
106
+ run`) discovered in Step 1. When the project has an app-startup smoke test
107
+ or a `uvicorn <module>:app` check already configured, run that too — a
108
+ router registration or dependency wiring mistake can pass every unit test
109
+ and still fail at app startup.
110
+
111
+ ### Step 5: Report
112
+
113
+ ```
114
+ Implemented: routers/items.py, schemas/item.py
115
+ - added `ItemCreate`/`ItemRead` Pydantic models
116
+ - added `POST /items` path operation with `response_model=ItemRead`
117
+ - ruff/mypy/pytest: all green
118
+ ```
119
+
120
+ ## Rules
121
+
122
+ - ALWAYS discover and match the project's own router/schema layout and
123
+ Pydantic version (Step 1) before assuming a structure or v1/v2 syntax.
124
+ - NEVER put a blocking call (sync DB driver, `requests`, `time.sleep`,
125
+ blocking file I/O) inside an `async def` path operation or dependency —
126
+ use `def` so FastAPI's threadpool handles it, or use an async client.
127
+ - NEVER accept a request body as raw `dict`/`Any`/`await request.json()`
128
+ when a Pydantic `BaseModel` is the correct, validated way to receive it.
129
+ - NEVER skip declaring `response_model` on an endpoint returning a model or
130
+ ORM object that carries any field the response should not expose.
131
+ - Match the project's existing `Annotated[...]` vs. default-value
132
+ `Depends()` style rather than introducing a second one in the same file.
133
+
134
+ ## Red Flags
135
+
136
+ | Rationalization | Why it is wrong |
137
+ |---|---|
138
+ | "I'll make this `async def` since async is the modern way" | If the body calls a blocking library, `async def` blocks the whole event loop for every concurrent request; use plain `def` and let FastAPI's threadpool handle it |
139
+ | "I'll just read `await request.json()` here, adding a Pydantic model feels like overkill for one field" | Skips FastAPI's own validation, error responses, and OpenAPI schema generation for that endpoint; even a one-field body gets a `BaseModel` |
140
+ | "No `response_model` needed, the ORM object already has the right fields" | `response_model` is what filters the response to the declared fields; without it, a field added to the ORM model later (a password hash, an internal flag) leaks straight into the API response |
141
+ | "I'll use `BackgroundTasks` for this, it's simpler than setting up the task queue" | Fine for best-effort, in-process work; wrong for anything that must survive a process restart or needs retries — use the project's real task queue instead |
142
+
143
+ ## Verification
144
+
145
+ Do not report the work done until all of the following hold:
146
+
147
+ - The request body and response are modeled as Pydantic `BaseModel`s (not
148
+ `dict`/`Any`), matching the project's Pydantic version from Step 1.
149
+ - Every new/touched path operation declares `async def` or `def` correctly
150
+ per Step 2, and `response_model` where the return value can carry fields
151
+ the response should not expose.
152
+ - `ruff check .`, `ruff format --check .`, `mypy .`/`pyright`, and
153
+ `pytest -x -q` (or the project's own configured equivalents) exit 0.
154
+ - The app still imports/assembles cleanly (Step 4's import/startup check),
155
+ so a router or dependency wiring mistake doesn't slip past unit tests
156
+ alone.
157
+ - No blocking call introduced inside an `async def`, and no auth/CORS/
158
+ secrets change made without checking `rules/security.mdc`.
@@ -0,0 +1,75 @@
1
+ {
2
+ "triggers": {
3
+ "positive": [
4
+ "I need a FastAPI endpoint that lets a customer place a new order -- how would you wire that up in our router?",
5
+ "Implement this endpoint in FastAPI that returns paginated items",
6
+ "What's the right way to define a Pydantic schema for our signup form's incoming JSON so bad emails or usernames get rejected automatically?",
7
+ "Several of my FastAPI routes need to know who's logged in -- what's the standard way to inject that without repeating auth logic everywhere?",
8
+ "After a user signs up on our FastAPI backend I want to fire off a welcome email without making them wait for it -- how do I do that in this handler?",
9
+ "I'm splitting out the billing endpoints into their own FastAPI router module -- what's the right way to set that up in this project?",
10
+ "How do I set up a login endpoint here that issues a bearer token after checking a username and password, using FastAPI's built-in security tooling?"
11
+ ],
12
+ "negative": [
13
+ "Implement this in Django instead of FastAPI",
14
+ "Write a pytest test for this plain Python function that has no HTTP layer",
15
+ "Review this FastAPI diff for blocking calls inside async def",
16
+ "Fix this ModuleNotFoundError breaking our FastAPI app's import",
17
+ "Implement asyncio.TaskGroup for concurrent fetches in this plain Python script, no web framework involved",
18
+ "Review this Express.js route for security issues"
19
+ ]
20
+ },
21
+ "scenarios": [
22
+ {
23
+ "id": "sync-driver-blocking-call",
24
+ "prompt": "Implement a FastAPI path operation `GET /users/{user_id}` that looks up a user with a synchronous SQLAlchemy session (the project has no async DB driver configured) and returns the user.",
25
+ "strictness": "high",
26
+ "expected_behavior": [
27
+ {
28
+ "grader": "judge",
29
+ "rubric": "A correct answer declares the path operation with plain `def`, not `async def`, so FastAPI runs it in its own threadpool instead of blocking the event loop, since the synchronous SQLAlchemy call cannot be awaited.",
30
+ "pass_criteria": [
31
+ "declares the path operation function with plain `def user_id... -> ...:`, not `async def`, shown in actual code",
32
+ "explains that FastAPI runs a `def` path operation in an external threadpool automatically, which is why a blocking synchronous DB call is safe there but would block the event loop inside `async def`",
33
+ "the synchronous SQLAlchemy session lookup is shown being called directly (no `await`), consistent with a non-async function"
34
+ ],
35
+ "fail_criteria": [
36
+ "declares the path operation `async def` and calls the synchronous SQLAlchemy session directly inside it without wrapping it (e.g. via `asyncio.to_thread` or a real async driver). Mentioning that this would be wrong is not itself a failure."
37
+ ]
38
+ }
39
+ ],
40
+ "calibration": {
41
+ "known_right": "```python\nfrom fastapi import APIRouter, Depends, HTTPException\nfrom sqlalchemy.orm import Session\n\nrouter = APIRouter()\n\n\n@router.get(\"/users/{user_id}\", response_model=UserRead)\ndef read_user(user_id: int, db: Session = Depends(get_db)) -> User:\n user = db.get(User, user_id)\n if user is None:\n raise HTTPException(status_code=404, detail=\"User not found\")\n return user\n```\nThis is declared with plain `def`, not `async def`, because the project's SQLAlchemy session is synchronous and there's no async driver to await. FastAPI runs a `def` path operation in its own external threadpool automatically, so the blocking `db.get(...)` call runs off the main event loop and doesn't stall other concurrent requests. If this were declared `async def` instead, that same blocking call would run directly on the event loop and block every other in-flight request on that worker until it returned.",
42
+ "known_wrong": "```python\nfrom fastapi import APIRouter, Depends, HTTPException\nfrom sqlalchemy.orm import Session\n\nrouter = APIRouter()\n\n\n@router.get(\"/users/{user_id}\", response_model=UserRead)\nasync def read_user(user_id: int, db: Session = Depends(get_db)) -> User:\n user = db.get(User, user_id)\n if user is None:\n raise HTTPException(status_code=404, detail=\"User not found\")\n return user\n```\nMarking the path operation `async def` is the modern, recommended style for FastAPI endpoints and lets the function be awaited by anything that needs to call it directly in tests. The synchronous `db.get(...)` call still works fine here since Python doesn't require `await` on every call inside an `async def` -- only on things that are themselves awaitable -- so this returns the correct user with no errors.",
43
+ "vague": "Make sure the database call doesn't end up blocking the event loop -- pick the path operation style that matches whether the driver is async or not.",
44
+ "subtle_wrong": "```python\nfrom fastapi import APIRouter, Depends, HTTPException\nfrom sqlalchemy.orm import Session\n\nrouter = APIRouter()\n\n\n@router.get(\"/users/{user_id}\", response_model=UserRead)\nasync def read_user(user_id: int, db: Session = Depends(get_db)) -> User:\n user = db.get(User, user_id)\n if user is None:\n raise HTTPException(status_code=404, detail=\"User not found\")\n return user\n```\nKept it `async def` since the rest of the router's endpoints are already async and mixing `def` and `async def` path operations in the same file looks inconsistent -- FastAPI handles both under the hood anyway, so the synchronous `db.get` call here is a minor, low-risk tradeoff for keeping the router's style uniform."
45
+ },
46
+ "anti_patterns": ["async def"]
47
+ },
48
+ {
49
+ "id": "request-body-pydantic-not-dict",
50
+ "prompt": "Write a FastAPI `POST /signup` endpoint that accepts a JSON body with `username` and `email` fields and creates a user.",
51
+ "strictness": "high",
52
+ "expected_behavior": [
53
+ {
54
+ "grader": "judge",
55
+ "rubric": "A correct answer declares the request body as a Pydantic BaseModel parameter so FastAPI validates it before the path operation runs, rather than reading the raw body with `await request.json()` or accepting it as an untyped dict.",
56
+ "pass_criteria": [
57
+ "defines a Pydantic `BaseModel` (e.g. `class SignupRequest(BaseModel): username: str; email: str`) for the request body, shown as actual code",
58
+ "declares the path operation parameter typed as that model (e.g. `payload: SignupRequest`) so FastAPI parses and validates the body automatically before the function body runs",
59
+ "shows the model's fields being used in the function body (e.g. `payload.username`, `payload.email`) rather than manually indexing into a dict"
60
+ ],
61
+ "fail_criteria": [
62
+ "reads the request body via `await request.json()` (or accepts it as a bare `dict`/`Any` parameter) instead of a Pydantic `BaseModel`. Mentioning that this would skip validation is not itself a failure."
63
+ ]
64
+ }
65
+ ],
66
+ "calibration": {
67
+ "known_right": "```python\nfrom fastapi import APIRouter\nfrom pydantic import BaseModel, EmailStr\n\nrouter = APIRouter()\n\n\nclass SignupRequest(BaseModel):\n username: str\n email: EmailStr\n\n\n@router.post(\"/signup\", response_model=UserRead)\ndef signup(payload: SignupRequest) -> User:\n return create_user(username=payload.username, email=payload.email)\n```\nThe body is declared as a `SignupRequest` Pydantic model, so FastAPI parses and validates the incoming JSON -- checking both fields are present and `email` is a well-formed address -- before `signup`'s body ever runs, and returns a `422` automatically on bad input. The function reads `payload.username`/`payload.email` off the validated model rather than indexing into a raw dict, so a typo'd or missing field fails at validation time instead of surfacing as a `KeyError` deep in `create_user`.",
68
+ "known_wrong": "```python\nfrom fastapi import APIRouter, Request\n\nrouter = APIRouter()\n\n\n@router.post(\"/signup\", response_model=UserRead)\nasync def signup(request: Request) -> User:\n body = await request.json()\n return create_user(username=body[\"username\"], email=body[\"email\"])\n```\nReading the body with `await request.json()` is simple and flexible -- it avoids defining a separate Pydantic model for what's just two fields, and the function can grab whatever keys it needs directly off the parsed dict. Since `create_user` will raise if a field is missing anyway, there's no real need for FastAPI's own validation layer here for such a small payload.",
69
+ "vague": "Make sure the incoming username and email get validated before the signup logic runs, using FastAPI's own request-body handling rather than parsing it by hand.",
70
+ "subtle_wrong": "```python\nfrom fastapi import APIRouter, Request\n\nrouter = APIRouter()\n\n\n@router.post(\"/signup\", response_model=UserRead)\nasync def signup(request: Request) -> User:\n body = await request.json()\n username = body.get(\"username\")\n email = body.get(\"email\")\n if not username or not email:\n raise HTTPException(status_code=422, detail=\"username and email are required\")\n return create_user(username=username, email=email)\n```\nThis reads the body manually with `await request.json()` and adds its own presence check that raises a `422`, matching the same status code FastAPI's own validation would return -- so callers see the same error behavior as if a Pydantic model had validated the body, without the overhead of declaring one for just two required strings."
71
+ },
72
+ "anti_patterns": ["await request.json()"]
73
+ }
74
+ ]
75
+ }