convex-doctor
Skill628 starsChanged 7 months agoMITView on GitHub
Run convex-doctor static analysis, interpret findings, and fix issues across security, performance, correctness, schema, and architecture categories. Use when running convex-doctor, fixing convex-doctor warnings or errors, improving the convex-doctor score, or when asked about Convex code quality, static analysis, or linting Convex functions.
In this repository40 other files it gives its agents.
- AGENTS.mdAGENTS.md
- public/AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/convex2.mdcCursor rule
- .cursor/rules/convex-doctor.mdcCursor rule
- .cursor/rules/convex-write-conflicts.mdcCursor rule
- .cursor/rules/dev2.mdcCursor rule
- .cursor/rules/gitruels.mdcCursor rule
- .cursor/rules/help.mdcCursor rule
- .cursor/rules/rulesforconvex.mdcCursor rule
- .cursor/rules/sec-check.mdcCursor rule
- .cursor/rules/task.mdcCursor rule
- .cursor/rules/workflow.mdcCursor rule
- .cursor/rules/write.mdcCursor rule
- public/llms.txtllms.txt
- convex-create-componentSkill
- convex-migration-helperSkill
- convex-performance-auditSkill
- convex-quickstartSkill
- convex-setup-authSkill
- convexSkill
- impeccableSkill
- convex-quickstartSkill
- convex-setup-authSkill
- devSkill
- function-creatorSkill
- gitrulesSkill
- helpSkill
- migration-helperSkill
- react-effect-decisionSkill
- real-time-backendSkill
- schema-builderSkill
- sec-checkSkill
- workflowSkill
- writeSkill
- convex-return-validatorsSkill
- convex-self-hostingSkill
- create-prdSkill
- robel-authSkill
- update-project-docsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
23 rules. About 0 are common, 12 are distinctive, and 11 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈12
Distinctive · estimate
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 45
When convex-doctor reports findings, fix them in this order:
- Distinctive: line 48
Add auth to HTTP actions and public endpoints
- Very specific: line 53
Remove Date.now() from queries (breaks caching and reactivity)
- Distinctive: line 63
Add missing indexes for foreign keys where query patterns exist
- Distinctive: line 65
Remove redundant indexes (prefixes of compound indexes)
- Distinctive: line 76
Instead of calling a public action from the browser, create a job table and mutation-scheduled internal action:
- Very specific: line 78
Add a job table to convex/schema.ts with status, result, and error fields
- Distinctive: line 79
Create a public mutation that inserts a pending job and schedules the internal action
- Distinctive: line 80
Create a public query that returns job status for the UI
- Distinctive: line 82
Update the frontend to call the mutation and poll the query
- Distinctive: line 88
When a Convex function calls another Convex function on the server side:
- Very specific: line 90
Create an internal* version if only a public version exists
- Distinctive: line 92
If the function needs both public and internal access, keep both and have the public version call the internal one
- Very specific: line 96
When an action makes multiple ctx.runQuery calls for independent data:
- Distinctive: line 98
Create a single internal query that returns all needed data in one object
- Very specific: line 106
Add a now: v.number() argument to the query
- Very specific: line 112
When components.auth.public.* triggers direct-function-ref warnings:
- Very specific: line 114
Create helper functions in convex/authComponent.ts that call the component API
- Very specific: line 115
Import helpers directly instead of using ctx.runQuery(internal.authComponent.*)
- Very specific: line 116
Add convex/authComponent.ts to the [ignore] section of convex-doctor.toml
- Distinctive: line 120
After every fix pass:
- Very specific: line 154
Always document suppressions with rationale in convex-doctor.toml.
- Very specific: line 158
All remediation PRDs are in prds/convex-doctor/:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Convex doctor workflow
This skill codifies the full convex-doctor remediation workflow used in this codebase (score 42 to 100 across 17 passes). Follow it whenever running convex-doctor or fixing its findings.
What is convex-doctor
convex-doctor is a static analysis tool for Convex backends. It scores your codebase 0 to 100 across five categories: security, correctness, performance, schema, and architecture.
Run it with:
npx convex-doctor@latestConfiguration
This project has a convex-doctor.toml at the repo root with intentional suppressions. Always check it before working on findings.
Current suppressions and rationale
| Rule | Level | Rationale |
correctness/generated-code-modified | off | Working tree is always dirty after codegen |
schema/optional-field-no-default-handling | off | 94 optional fields by design for markdown frontmatter |
correctness/missing-unique | off | Remaining .first() calls are intentional ordered picks |
schema/deep-nesting | off | 4-level validators needed for chat attachments |
schema/array-relationships | off | Flagged on function args, not table columns |
perf/missing-index-on-foreign-key | off | Remaining FK is inside nested array (not indexable) |
arch/duplicated-auth | off | Auth awareness is intentional per public handler |
arch/monolithic-file | off | Files organized by domain |
arch/large-handler | off | Email templates, sync, and search are inherently multi-step |
Ignored files
convex/_generated/**(generated code)convex/authComponent.ts(thin auth component forwarders)
Fix priority order
When convex-doctor reports findings, fix them in this order:
- Security errors (highest priority)
- Add auth to HTTP actions and public endpoints
- Convert
api.*server-to-server calls tointernal.* - Move public actions to mutation-scheduled internal actions
- Correctness errors
- Remove
Date.now()from queries (breaks caching and reactivity) - Convert
.first()to.unique()only where the index enforces uniqueness - Fix
collect then filterpatterns with indexed queries
- Remove
- Performance warnings
- Replace unbounded
.collect()with.take(n)or pagination - Batch sequential
ctx.run*calls into single internal queries - Eliminate N+1 patterns in HTTP and RSS endpoints
- Replace unbounded
- Schema warnings
- Add missing indexes for foreign keys where query patterns exist
- Rename indexes to
by_fieldsnake_case convention - Remove redundant indexes (prefixes of compound indexes)
- Architecture warnings
- Extract helper functions from large handlers
- Split provider modules from orchestration logic
- Replace
throw new Error(...)withConvexErrorin user-facing handlers
Common fix patterns
Convert public action to queued job
Instead of calling a public action from the browser, create a job table and mutation-scheduled internal action:
- Add a job table to
convex/schema.tswith status, result, and error fields - Create a public mutation that inserts a pending job and schedules the internal action
- Create a public query that returns job status for the UI
- Convert the action to
internalActionthat updates the job record on completion or failure - Update the frontend to call the mutation and poll the query
This pattern was used for: AI image generation, AI chat responses, URL imports.
Convert api.* to internal.*
When a Convex function calls another Convex function on the server side:
- Create an
internal*version if only a public version exists - Replace
api.module.fnwithinternal.module.fnin the caller - If the function needs both public and internal access, keep both and have the public version call the internal one
Batch sequential ctx.run* calls
When an action makes multiple ctx.runQuery calls for independent data:
- Create a single internal query that returns all needed data in one object
- Replace the sequential calls with one
ctx.runQueryto the batched query - This reduces transaction overhead and eliminates the
sequential-run-callswarning
Remove Date.now() from queries
Queries must be deterministic. Replace Date.now() with a timestamp argument:
- Add a
now: v.number()argument to the query - Pass
Date.now()from the frontend or from the action/mutation that calls the query - For reactive subscriptions, round the timestamp (e.g., 60-second intervals) to keep reactivity stable
Auth component helper conversion
When components.auth.public.* triggers direct-function-ref warnings:
- Create helper functions in
convex/authComponent.tsthat call the component API - Import helpers directly instead of using
ctx.runQuery(internal.authComponent.*) - Add
convex/authComponent.tsto the[ignore]section ofconvex-doctor.toml
Verification checklist
After every fix pass:
npx convex codegenpassesnpx tsc --noEmitpasses (ornpx convex codegencovers this)npm run buildsucceedsnpx convex-doctor@latestshows improved score or fewer findings- Existing functionality still works (AI chat, search, dashboard, RSS, stats)
Score history
| Pass | Score | Errors | Warnings | Key changes |
| Initial | 42/100 | 73 | 243 | Baseline |
| 1 (remediation) | ~55 | ~50 | ~221 | Security: auth on HTTP, api to internal |
| 2 | ~60 | ~40 | ~200 | AI action flow, HTTP hardening |
| 3 | 68/100 | - | - | collect-then-filter, auth signals |
| 10 | 80/100 | 1 | 68 | Import URL queued job, unique lookups |
| 15 | 91/100 | 0 | 43 | Newsletter batching, auth forwarders, toml config |
| 16 | 92/100 | 0 | 39 | Semantic search batching, auth helpers |
| 17 | 100/100 | 0 | 0 | Stats helpers, contact helpers, final toml tuning |
When to suppress vs fix
Fix it when:
- The finding points to a real bug or security gap
- The fix is low risk and improves code quality
- The pattern can be changed without affecting product behavior
Suppress it when:
- The finding is a tool false positive (e.g., component function refs)
- The pattern is intentional by design (e.g., per-handler auth checks)
- The fix would add more complexity than the warning is worth
- Generated code triggers the finding
Always document suppressions with rationale in convex-doctor.toml.
Related PRDs
All remediation PRDs are in prds/convex-doctor/:
convex-doctor-remediation.md(initial plan, 5 phases)convex-doctor-second-pass.mdthroughconvex-doctor-seventeenth-pass.md
Related files
convex-doctor.toml(suppression config)convex/schema.ts(indexes and table definitions)convex/authComponent.ts(auth component forwarders)convex/importJobs.ts(queued job pattern example)convex/aiImageJobs.ts(queued job pattern example)convex/semanticSearchJobs.ts(queued job pattern example)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

