This project is not covered by Drupal’s security advisory policy.
Site Doctor helps you answer a simple question that gets harder as a Drupal site ages: "is my site healthy — and is it getting better or worse?"
It runs read-only diagnostic checks (pending updates, configuration drift, permission risks, dormant accounts, unused leftovers) on a schedule and — unlike a one-time audit — remembers what it finds: every finding carries a stable fingerprint, so the built-in report shows what appeared this week, what stopped being found, what got worse, and what has been quietly degrading for months. It is not a database/query monitor (see Site Health) and not a per-request developer profiler (see Webprofiler) — Site Doctor tracks site-level diagnostic findings over time.
Every result is a projection of the same structured schema: a plain-language report page with history and trends; CLI commands on both Drupal core's new dr CLI and Drush, with CI-friendly output and exit codes for your deployment pipeline; and machine-readable output that automation and AI agents can consume. Site Doctor never mutates site configuration or content — it writes only to its own reporting tables, with configurable retention. There is no auto-fix: it diagnoses and reports; fixing remains a deliberate human decision.
Features
The report page and results store (new in 1.0.0-alpha2):
- Scheduled check-ups via cron (frequency configurable, default daily); CLI runs are stored too, with a per-run opt-out.
- The report at
/admin/reports/site-doctor, in plain language: current problems with an age breakdown, a filterable "what changed" timeline (new / no longer found / got worse / improved, with fix guidance), severity trends charted over time, and an Inventory — facts on file about the site (every permission grant, configuration overrides, the declared workflow) with their own change history, kept apart from problems. Every filtered view is a bookmarkable URL. - Honest history: disabling a check is recorded, never silent — frozen findings say why and since when; a category-filtered run declares itself partial and can never fabricate "resolved".
- Configurable retention with the horizons printed on the views they bound; the store monitors its own purging as a check like any other.
Checks:
- Pending updates (system) — pending database/post-deployment updates (code deployed ahead of the database, or a deploy script that swallowed a failure) and mismatched entity/field definitions — the chronic class that
drush updbdoes not fix. - Maintenance mode (system) — the site was left in maintenance mode.
- Permission risk audit (security) — permissions flagged "restrict access" granted to the anonymous role (Error) or to authenticated/other non-admin roles (Warning); admin roles are exempt by contract.
- Permission grants inventory (security, new in alpha2) — the full (role, permission) inventory as memory rather than judgment: the report's Inventory answers "when did this role gain that permission?" with a stored date, for every grant — not only the risky ones. Never gates CI.
- Dormant privileged accounts (security) — active accounts holding admin or restricted-permission roles with no login past a configurable threshold (default 180 days); never-logged-in accounts included.
- Configuration drift classifier (config) — compares active configuration against your sync directory and frames each difference by consequence: what the next
config:importwould delete, revert, or re-create. Severity follows your declared workflow (sync,active, orauto): sync-disciplined sites get CI-gating Warnings; recipe-era and site-builder sites that treat active storage as the source of truth get a never-nagging Info inventory instead. Also aggregates all runtime config overrides (settings.php / modules) site-wide, reporting the overridden key paths — never the values, which is where secrets live. - Entropy checks (advisory — never gate CI) — unused image styles, orphaned view modes, roles with no users, unused text formats.
- Results store health (new in alpha2) — Site Doctor applies its own machinery to itself: a stalled retention purge is a Warning like any other finding.
- Extensible by design: drop a check plugin in any module — site-specific business rules become first-class findings on every surface, history included. See CONTRIBUTING.md and AGENTS.md in the repository.
Query commands (answers, not checks):
site-doctor:who-can PERMISSION— which roles hold a permission and through which path (explicit grant, admin role, user-1 super-user policy), with user counts — the questions ad-hoc reasoning (human or LLM) reliably gets wrong.site-doctor:role-diff ROLE_A ROLE_B— compare the explicit permission sets of two roles.- Roadmap: read commands over the stored history ("what changed since last week?" from the CLI), and pluggable queries — define a site-specific lookup as one Query plugin and it derives a CLI command on both dr and Drush and a typed MCP tool, giving AI agents safe, bounded answers about your site instead of improvised database queries.
Checks (roadmap):
- Cron and queue health (a stuck queue with 40k items is invisible today).
- Dangling entity reference auditor (references to deleted targets, media pointing at missing files).
- Extension risk report (release age, security coverage, unused-module signals).
- Route latency sampler (production-safe p50/p95 per route, week-over-week regressions — zero external infrastructure).
- Runtime deprecation telemetry (which deprecated code paths actually execute in production, ranked by hit count — prioritize your next major upgrade by real impact).
- Content model export (Mermaid/JSON description of your bundles, fields, and references — documentation and agent context).
Surfaces:
- The report page at
/admin/reports/site-doctorand a settings form at/admin/config/development/site-doctor, each behind its own restrict-flagged permission. - CLI on both Drupal core's
dr(11.4+) and Drush 13+ from one implementation:site-doctor:check [category] --format=table|json|junit|llm. Exit codes are a frozen contract: 0 ok/info, 1 warnings, 2 errors, 3 the diagnosis itself failed (a crashed check never aborts the run — the rest still report). Machine envelopes declare their scope: a category-filtered run can never be mistaken for full coverage. --format=llm— self-describing, bounded output for AI agents: embedded severity semantics and exit-code map, truncation markers on long evidence, staleness fields on every result.- Status report summary line at /admin/reports/status, including collection staleness.
- Tool API integration (roadmap): each check and query exposed as a tool so AI agents and MCP clients can query site health instead of guessing.
Use cases:
- Pre-deployment CI gate ("fail the pipeline on dangerous config drift"), post-deploy verification ("did updates actually run?"), monthly maintenance review with the "what changed" timeline, incident forensics ("when did that role gain that permission?"), upgrade planning, security/permission audits, handover audits of inherited sites, and giving AI agents accurate structured facts about the site.
- And the part only your own code can supply: site-specific checks encode your business rules ("every product needs a hero image", "this role must never gain that permission") as one small plugin class in your custom module, and it automatically gets every surface: both CLIs, all output formats, CI exit codes that can gate your deployments, and the full trend history. Agencies can ship one internal check pack across every client site.
Post-Installation
Enable the module, then:
- Run
drush site-doctor:check(ordr site-doctor:checkon Drupal 11.4+) for the first check-up, and open/admin/reports/site-doctor. With cron running, check-ups collect on a schedule from here on (default daily). - Visit
/admin/config/development/site-doctorto declare your configuration workflow (so drift severity matches your reality), set the check-up frequency and retention, and switch off any checks you don't want — switching off is always recorded, never silent. - For CI: run
drush site-doctor:check --format=junitin your pipeline and gate on the exit code.
No content types, fields, or front-end output are created. All checks are read-only toward your site: Site Doctor writes only to its own four reporting tables, and retention keeps them bounded.
Additional Requirements
None beyond Drupal core (Drupal 11, PHP 8.3+). Drush 13+ is optional — core's dr CLI (11.4+) is fully supported. Individual checks degrade gracefully: a check whose subject doesn't exist on your site reports "not applicable", never a false pass.
Recommended modules/libraries
Site Doctor deliberately does not duplicate established tools — it complements them and links to them from findings where relevant:
- Upgrade Status — static deprecation analysis (Site Doctor's runtime telemetry will tell you which of those findings matter in production).
- Security Review — security best-practice checklist (Site Doctor's security category covers what a checklist can't: reverse lookups, grant-path analysis, account dormancy).
- Linkchecker — external/content link checking (Site Doctor will cover entity-reference integrity only).
- Site Audit — use it today for one-shot scored audit reports; see also Similar projects below.
- Tool API / MCP Server — enables the agent-facing tool surface (roadmap).
Similar projects
- Site Audit — point-in-time static best-practice checks via Drush. Site Doctor differs in its design around recorded history/trends (in development), production runtime telemetry (roadmap), and results exposed to CI and AI agents (available now: severity-mapped exit codes, junit, and an agent-oriented output format).
- Healthcheck — similar plugin-based concept from the Drupal 8 era, including historical reports. Site Doctor is a Drupal 11-native take with runtime telemetry and an agent/automation surface.
- Webprofiler — per-request developer profiling: deep, dev-only, heavyweight. Site Doctor's roadmap latency sampler is the inverse instrument: production-safe 1-in-N sampling, p50/p95 per route trended over time. The sampler finds which route regressed; webprofiler dissects why, in dev.
- Site Health — database query monitoring (slow queries, per-statement statistics). Site Doctor is route- and site-level over time, not a query profiler.
- Monitoring — sensor integration with external monitoring stacks (Icinga, etc.). Site Doctor is self-contained with no external infrastructure.
- health_check / health_check_url and similar — uptime ping endpoints for load balancers; a different problem entirely.
Supporting this Module
Issues, reviews, and merge requests are welcome — the check plugin API is
designed so a new check is a small, self-contained contribution: one plugin
class implementing collect(), one kernel test extending the provided
CheckKernelTestBase, and it automatically appears on every surface.
Community Documentation
The README ships with the module: usage on both CLIs, CI integration with
exit-code semantics, configuration guide (including how to choose your
config workflow), and a writing-your-own-check guide. GitHub Actions
examples and a fuller tutorial are planned as the module matures.
AI-assisted development disclosure: this module is developed with AI
coding assistance under human direction and review. All code is
human-reviewed before commit; every check ships with kernel tests that
encode its expected behavior, and CI (phpcs, phpstan, phpunit, cspell,
code coverage) gates every merge request.
Project information
- Project categories: Administration tools, Developer tools, Performance
- Created by amangrover90 on , updated
This project is not covered by the security advisory policy.
Use at your own risk! It may have publicly disclosed vulnerabilities.
Releases
Site Doctor gets a memory: scheduled check-ups, a results store, and a report page showing what changed over time — plus a settings UI and a permission grants inventory. Run updb after updating.
Development version: 1.x-dev updated 10 Jul 2026 at 12:41 UTC
