Your agent writes bad Vue/Nuxt. This catches it.
A pnpm monorepo of CLIs, oxlint + eslint plugins, and a language server that audit Vue 3 and Nuxt 4 apps for performance, correctness, security, and AI-agent anti-patterns. It does not scaffold or generate. It critiques the code your agent just wrote and gives it a deterministic 0-100 health score. The audit runs fully local and offline: same code in, same score out.
Full docs, rule reference, config, and scoring live at docs.the-doctor.report.
The CLI is the whole product and stays free. If you want the score tracked over time instead of just printed once, the-doctor.report is a hosted dashboard: push a run from CI with --push, and it keeps the score trend, per-rule findings, and per-branch history for each project. It stores rule IDs, severities, and file paths only — never your source, snippets, or messages. Nothing about local CLI usage phones home; the dashboard is opt-in and gated behind your own API key.
| Repo | What | Link |
|---|---|---|
geoql/doctor (this repo) |
OSS CLIs + oxlint rule plugins | github.com/geoql/doctor |
geoql/doctor-action |
GitHub Action wrapper | github.com/geoql/doctor-action |
the-doctor.report |
Hosted SaaS dashboard (private) | app.the-doctor.report |
| Docs | Rules, CLI, scoring reference | docs.the-doctor.report |
| Package | Version | Description |
|---|---|---|
@geoql/vue-doctor |
CLI for Vue 3 projects | |
@geoql/nuxt-doctor |
CLI for Nuxt 4 projects | |
@geoql/doctor-core |
Audit engine: scoring, reporters, hybrid two-pass analysis | |
@geoql/doctor-rule-core |
Linter-neutral rule cores shared by the oxlint/eslint plugins | |
@geoql/oxlint-plugin-vue-doctor |
oxlint JS plugin: Vue 3 rules | |
@geoql/oxlint-plugin-nuxt-doctor |
oxlint JS plugin: Nuxt 4 rules | |
@geoql/eslint-plugin-vue-doctor |
ESLint flat-config plugin: Vue 3 rules | |
@geoql/eslint-plugin-nuxt-doctor |
ESLint flat-config plugin: Nuxt 4 rules | |
@geoql/doctor-language-server |
LSP server for editor integration (npm-only) |
The two CLIs ship at 1.2.2. All nine packages publish to npm with OIDC provenance; the eight library/plugin packages also publish to JSR (the language server is npm-only — it is a stdio binary run via npx, with npm-only vscode-* deps).
# Audit a Vue 3 project (npm)
npx -y @geoql/vue-doctor
# Audit a Nuxt 4 project (npm)
npx -y @geoql/nuxt-doctor
# Run from JSR (Deno)
deno run -A jsr:@geoql/vue-doctor
deno run -A jsr:@geoql/nuxt-doctorBoth CLIs print a health score with grouped diagnostics and exit non-zero when findings breach your --fail-on threshold, so they drop straight into CI.
geoql/doctor/
├── packages/
│ ├── doctor-core/ # @geoql/doctor-core — audit engine
│ ├── doctor-rule-core/ # @geoql/doctor-rule-core — shared rule cores
│ ├── vue-doctor/ # @geoql/vue-doctor — Vue 3 CLI
│ ├── nuxt-doctor/ # @geoql/nuxt-doctor — Nuxt 4 CLI
│ ├── oxlint-plugin-vue-doctor/ # Vue 3 oxlint rules
│ ├── oxlint-plugin-nuxt-doctor/ # Nuxt 4 oxlint rules
│ ├── eslint-plugin-vue-doctor/ # Vue 3 eslint rules
│ ├── eslint-plugin-nuxt-doctor/ # Nuxt 4 eslint rules
│ ├── doctor-language-server/ # LSP server (npm-only)
│ ├── vscode-doctor/ # VS Code extension (not published to npm)
│ └── benchmark/ # perf workspace (not published)
├── apps/docs/ # docs.the-doctor.report (Nuxt)
└── docs/SPEC.md # the locked spec
Both vue-doctor and nuxt-doctor share the same surface. Key flags:
| Flag | Purpose |
|---|---|
--preset <name> |
Base preset: minimal | recommended | strict | all |
--format <kind> |
agent (default) | pretty | json | json-compact | sarif | html | pr-comment |
--fail-on <level> |
Exit non-zero on error | warn | none (default error) |
--threshold <n> |
Minimum passing score 0-100 |
--rule <id:level> |
Override one rule (repeatable), e.g. --rule a/b:off |
--fix |
Auto-fix oxlint-pass findings in place (full scan only) |
--diff / --staged / --full |
Scope to changed, staged, or all files |
--category <cat> / --dimension <dim> |
Score only rules in a category or dimension (repeatable) |
--max-duration <seconds> |
Soft time budget; on timeout, return partial results (incomplete + skippedCheckReasons) |
--score |
Print only the integer score |
--output <file> |
Write the report to a file |
--pr-comment |
Emit a Markdown PR-comment body |
--push |
POST privacy-stripped findings to the SaaS (needs --api-key) |
--push-url <url> |
Findings endpoint (default https://app.the-doctor.report/api/v1/findings) |
--api-key <key> |
the-doctor.report API key (doc_…), sent as the x-api-key header |
--push-project <slug> |
Dashboard project slug, e.g. owner/repo (defaults to the audited dir name) |
Subcommands: list-rules, explain <ruleId>, inspect [dir], init [dir], ci install [dir] (scaffold a CI workflow that runs geoql/doctor-action@v2). Run vue-doctor --help for the complete list. The JSON report's projectInfo.frameworkDetected boolean tells a real Vue/Nuxt audit apart from a scan that found no project.
Internal severities are error, warn, and info with weights 5, 2, and 0.5. The score uses square-root decay: each repeated occurrence of a rule contributes weight × 1/√(i+1), so the first hit costs full weight and repeats cost less. The final score is max(0, round(100 − penalty)). --fail-on accepts error, warn, or none. An invalid value exits 2.
pnpm install
pnpm run lint # vp lint
pnpm run format # vp fmt
pnpm run build # vp pack per package
pnpm run coverage # vitest run --coverage (100% gate)Requires Node >=24.11.0 and pnpm 11.8.0.