A browser-based inspector for Magento 1 / Maho / OpenMage module trees.
Point it at an app/code directory and it parses every module's config.xml, then
shows you what the platform is actually going to do at runtime: which rewrites collide,
which module wins, which observers pile onto the same event, which declared classes
don't exist, and which database tables no longer belong to anything.
It runs entirely in your browser. Nothing is uploaded anywhere.
config.xml is a distributed system pretending to be configuration. Three modules can
rewrite catalog/product and Magento will silently pick one based on code-pool
precedence and load order. Seven modules can observe checkout_cart_save_after and
you'll never know until one of them is slow. A module can declare a rewrite to a class
that was deleted two refactors ago and fail only on the code path nobody tests.
None of that is visible by reading one module at a time. This tool reads all of them at once and cross-references them.
Conflict detection. Groups every rewrite by target alias, applies the real
precedence rule (core < community < local, last one loaded wins) and shows you the
winner, the losers, and a side-by-side diff of the competing classes. A conflict is
flagged critical when every participant is enabled, warning when a disabled module is
involved.
Static analysis. Seven issue types across the whole install: rewrite conflicts, missing rewrite targets, rewrite chains (A rewrites B which rewrites C), shared observers, inactive modules that still declare rewrites, and local-pool modules overriding community ones — laid over an interactive dependency graph.
Module detail. Per module: overview, full file tree, rewrites, observers, layout handles, routes, cron jobs, declared tables, and dependencies colour-coded as satisfied / disabled / missing. Files open in an embedded Monaco editor and can be saved back to disk.
Event index. Every event in the install with its observers, searchable and filterable by area.
Database analysis. Connects to your Magento database and classifies every table as declared-and-present, declared-but-missing, a known Maho/Magento system table, or an orphan — present in the database but claimed by no installed module. Orphans are selectable and droppable.
Module removal. Generates a removal plan: the files it would delete, the tables it
would drop, and a downloadable package containing a shell script, a .sql file and a
README — so you can review it before anything happens, or execute it directly.
Remote inspection over SSH. Inspect a staging or production install without checking anything out locally. See Remote hosts below.
Export. Any module as a ZIP, or copied directly into another directory.
git clone https://github.com/postadelmaga/maho-inspector.git
cd maho-inspector
npm install
npm run devOpen http://127.0.0.1:3000, then either:
- click Open project… and pick your Magento/Maho root (or its
app/code), or - drag the folder onto the window, or
- click or try the demo store to explore a bundled synthetic install — no Magento needed.
Directory picking uses the File System Access API (Chrome/Edge 86+). Drag-and-drop works in any browser, but is read-only: saving edits requires the picker.
Point it at the store root rather than app/code where you can. Only from the root
can it read app/etc/modules/*.xml — which is what actually decides whether a module is
enabled — and app/etc/local.xml for the database connection.
examples/demo-store/ is a small fake install (13 modules across all three code pools)
that deliberately contains one of everything: a critical rewrite conflict with a real
diff, a rewrite chain, a missing class, a disabled module that still declares rewrites,
an event with seven observers, a missing table, and dependencies that are satisfied,
disabled and missing. It is what the screenshots in this README show, and it's the
fastest way to see what the tool does. See
examples/demo-store/README.md for the full map of
which module demonstrates which finding.
Conflicts — who wins, who is silently overridden, and the suggested fix:
Analysis — every detected issue laid over the module dependency graph:
Events — every observer in the install, grouped by event:
Dark theme — follows your OS by default, with a light/dark/system toggle:
The browser can't speak the MySQL wire protocol, so database features are proxied through a small server-side bridge. It is disabled by default and must be turned on explicitly:
MAHO_INSPECTOR_DB=1 npm run devConnection details are read from app/etc/local.xml when available, or entered by hand.
Inspect a remote install directly, using the SSH setup you already have:
MAHO_INSPECTOR_SSH=1 npm run devClick Remote. Hosts are discovered from your ~/.ssh/config and known_hosts — pick
one, or type in an IP, user and source directory directly. The server walks the remote
app/code and streams it back. Database queries are tunnelled through the same SSH
connection, reading the remote app/etc/local.xml so you never retype credentials.
Authentication, tried in order: ssh-agent, then a key from ~/.ssh, then a
password if you supply one. Key auth is the better option where you have it; the password
field is there for hosts that don't. A password is kept in server memory only, for the
life of the session — never written to disk, never stored in the browser, never logged.
After connecting, the browser holds only an opaque session token (15-minute idle TTL), so
the password isn't resent on later calls. If a key needs a passphrase, ssh-add it.
Host keys are verified against known_hosts. A host you've never connected to shows
its fingerprint for confirmation, the same way ssh does on first contact — verify it
with ssh-keygen -lf and accept, optionally recording it in known_hosts. Accepting is
bound to the fingerprint you were shown: the server re-derives it from the key actually
presented and refuses anything else, so the prompt can't be waved through. A host whose
key has changed (HOST_KEY_MISMATCH) is refused outright with no override — that's
the case worth taking seriously, and it belongs in your SSH config, not in this tool.
Other constraints:
- Read-only. A remote scan never writes to the remote host.
- The remote
local.xmlreaches the browser with its<password>redacted; the real value is re-read server-side per query. - Scans are bounded (file count, per-file size, total bytes). If a limit is hit you get an explicit truncation warning — a partial module list is never presented as complete.
Run this on your own machine, against installs you administer. It is a developer tool, not a service to deploy.
Both bridges are off unless their env var is set, and when on they are guarded by a
same-origin (CSRF) check, a Host allowlist against DNS rebinding, and a JSON
content-type requirement. Both servers bind loopback only by default. Table names are
validated against information_schema and quoted with escapeId() rather than
interpolated. Driver errors are logged server-side and reduced to a short code for the
client.
Full threat model and configuration: server/README.md.
To reach it from another machine, prefer an SSH tunnel over widening the bind address:
ssh -L 3000:127.0.0.1:3000 user@hostAll optional; see .env.example.
| Variable | Default | Purpose |
|---|---|---|
MAHO_INSPECTOR_DB |
(off) | Enable the MySQL bridge |
MAHO_INSPECTOR_SSH |
(off) | Enable remote SSH inspection |
HOST |
127.0.0.1 |
Production bind address — widening it is unsafe |
PORT |
3000 |
Production port |
MAHO_INSPECTOR_ALLOWED_HOSTS |
(unset) | Extra hostnames for the Host check, behind a reverse proxy |
npm run dev # Vite dev server with hot reload
npm run check # TypeScript — kept at zero errors
npm run format # Prettier
npm run build # production build (frontend + bundled server)
npm start # run the production buildArchitecture. Almost everything is client-side: there is no router and no application
server. client/src/utils/fs.ts unifies three filesystem backends behind one interface —
the File System Access API, the legacy drag-and-drop entry API, and an in-memory tree —
so the demo store and remote SSH scans reuse the exact same traversal and parsing code as
a local directory. server/ exists only to serve the production build and host the two
optional bridges.
See CLAUDE.md for a map of the codebase and the non-obvious invariants
(code-pool precedence, app/etc/modules overriding config.xml, why file handles can't
be persisted).
Magento 1.x, OpenMage LTS, and Maho. It reads the config.xml
conventions common to all three and never writes to your install except through the
explicit save, export and delete actions.
Issues and pull requests welcome. Please keep npm run check at zero errors and run
npm run format before submitting.
MIT — see LICENSE.




