§0 — schema-driven, not guessed
Hyprland 0.55 replaced hyprland.conf with a Lua config, and the API underneath it is still evolving. hyprvalidate checks any Hyprland Lua config against Hyprland's real, autogenerated API schema — never a hand-typed table that drifts — and auto-fixes what has exactly one right answer. Migrating an old hyprland.conf? It converts that into modular Lua files first, the way Hyprland's own docs recommend, then validates the result the same way.
Runs the real converter and validator in your browser — the same Python code the CLI ships, checked against a frozen snapshot of Hyprland's schema. Edit the sample below, or paste in your own config.
First run downloads a Python runtime (Pyodide, ~10MB) - subsequent runs are instant. Nothing you type leaves your browser.
The job every existing hyprlang→Lua tool attempts — done by looking things up instead of guessing them.
Dispatcher names, bind flags, and config keys are checked against Hyprland's real API at build and test time — not copied from memory into a table that quietly drifts.
Splits into one file per config area (monitors, keybinds, window rules, appearance, ...) with a hyprland.lua entry point that require()s the rest — matching the pattern Hyprland's own docs recommend, not one 400-line file.
Already on Lua? Point this at your config directly — no other tool checks a Hyprland Lua config against anything real.
-- line)hl.meta.lua, reinstalled on every build{ mouse = true } — a real, implemented flag in Hyprland's own source, just missing from the schema Hyprland itself generates. hyprvalidate can't invent a field the stub doesn't have — flagged here as a known gap, not silently ignored.Unknown symbols, bad config keys, wrong value types, bad call arity, and invalid fields inside hl.monitor/hl.device/hl.bind/etc spec tables.
Point it at a single file or a whole --split output directory — every .lua file inside gets checked in one command.
For the findings with exactly one correct answer, check can just make the correction — never a guess, only what's mechanically unambiguous.
A bare identifier where a string was meant (accel_profile = flat → "flat" — the exact bug that changed a real user's mouse sensitivity after a migration), and a dispatcher factory referenced but never called. Patches the source directly, re-checks, and won't write a fix that turns out to break something else.
An unknown dispatcher or config key (which real name was meant?), a type or arity mismatch, two binds fighting over the same key combo — no single correct fix exists, so --fix leaves them exactly as check reports them.
Hyprland's Lua API is still young — a real config field was renamed one day after Lua config first shipped. diff-impact checks a config against what's changed between two schema versions, so you find out before you update, not after.
Cross-references the schema diff against your config's real usage, not Hyprland's whole API surface — most changes between two versions won't touch anything you wrote.
Exits 0 even when it finds something — a schema diff is evidence of a possible behavior change, not proof of one. --fail-on-impact opts a CI job into treating it as a failure instead.
Requires Hyprland v0.55+ (the Lua config API) and Python 3.10+.
pipx install git+https://github.com/Paritsingla7/hyprvalidate.git hyprvalidate convert ~/.config/hypr/hyprland.conf --split ~/.config/hypr hyprvalidate check ~/.config/hypr
On Arch, install pipx with sudo pacman -S python-pipx — system Python is externally managed (PEP 668).
git clone https://github.com/Paritsingla7/hyprvalidate.git cd hyprvalidate && pip install . hyprvalidate convert ~/.config/hypr/hyprland.conf --split ~/.config/hypr hyprvalidate check ~/.config/hypr
On externally-managed Python, do this inside a venv rather than passing --break-system-packages.