Magento
heimdall
Read-only diagnostic checks for Magento 2, over a CLI, a local web UI and JSON.
When a working storefront hides a broken installation
Some Magento faults leave the homepage working and the logs unhelpful. A queue accepts a message that reaches no consumer. An indexer reports itself valid while its changelog stops receiving updates. A session configuration typo sends customers to local file sessions when the deployment expected Redis. The visible symptom can sit several systems away from the mistake.
I built heimdall to connect those symptoms to evidence. It starts with orientation: heimdall about identifies the platform, effective configuration, installed stack and local modifications. Knowing a payment package is installed is different from knowing it takes payments here. Knowing which theme packages exist is different from knowing which theme a store actually renders. Those distinctions change where I look next.
Observe before changing anything
The diagnostic checks are read-only. I want an explanation I can assess before deciding what to change, particularly on an unfamiliar installation. Each failure carries a remedy, but the check leaves that remedy for the person investigating to apply.
Requirements are split into filesystem, bootstrap and database tiers. A store that cannot boot still has files and Composer metadata worth reading. An unreachable database should prevent the checks that need it from running while leaving the other evidence available. Heimdall itself requires PHP 8.1 or newer; checks that must execute inside Magento use the installation's own PHP through the yphp shim.
That separation also limits what a result can mean. A failed database query becomes a skip with a reason. An earlier config reader returned the same empty result for an absent setting and an unreadable table, producing a reassuring answer against a database with no schema. The tool now preserves that distinction rather than turning an inability to inspect into a pass.
Follow the failure across the boundary
One deployment fault captures the kind of reasoning I wanted to preserve. Magento's Composer installer copies files from packages into the project root. On an affected installer, a dangling symlink at a destination confuses the existence check: file_exists() follows the link and reports its missing target, then mkdir() tries to create a directory where the link itself already exists.
The copy aborts for that package, later map entries never run and Composer can still exit successfully. A link under pub/media/ can therefore explain a missing setup/ directory. Heimdall reports the obstructing link alongside the entries that would never be copied. It checks the installed code for the corrective is_link() guard, since a locally patched package can carry the fix without changing its version number.
The same attention to context matters for quieter faults. Cron checks use the database's latest execution as their reference clock, because a copied database is naturally as old as its copy. Cache settings are judged against deployment mode: disabling a cache during development is ordinary, while the same setting in production adds work to requests. A rule that repeatedly accuses healthy installations soon stops being useful.
Keep the evidence attached to the verdict
Every check returns structured evidence for the terminal, local web interface and JSON output. Terminal tables announce any row limit. The web interface shows the full payload, and a self-contained HTML report lets me take the findings away from a host reached over SSH. Filtering a report leaves the whole-run counts visible, including outcomes omitted from view.
The web server binds only to loopback because its reports contain installation paths and file contents. For unattended checks, cron --level=fail emails only failures. The chosen level controls the message contents, whether it is sent and the findings exit code. Failure to hand the message to sendmail gets a separate exit code: once the reporting path breaks, a quiet inbox no longer tells me whether the checks were clear.