◎hyprvalidate

§0 — schema-driven, not guessed

Keep your Hyprland Lua config working.

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.


§1 Try it

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.

old hyprland.conf
loading…
Converted files will appear here.

First run downloads a Python runtime (Pyodide, ~10MB) - subsequent runs are instant. Nothing you type leaves your browser.


§2 The converter

The job every existing hyprlang→Lua tool attempts — done by looking things up instead of guessing them.

$ hyprvalidate convert old.conf --split ~/.config/hypr

Schema-derived, not hand-typed

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.

bindr = SUPER, Q, killactive
  ↳ hl.bind("SUPER + Q", hl.dsp.window.close(), { release = true })

Modular output

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.

  • Statement order is preserved within each file
  • Every emitted file is checked before anything is written
  • Low-confidence conversions become a comment, never a guess

§3 The validator

Already on Lua? Point this at your config directly — no other tool checks a Hyprland Lua config against anything real.

51
real dispatchers in Hyprland's own stub
53 / 12 / 2
dispatcher-table sizes across 3 existing converters
0
schema entries a fourth tool's own parser extracts (skips every -- line)
1
source of truth: hl.meta.lua, reinstalled on every build
HL.BindOptions, the installed stub
Real-world configs (Garuda Linux's distribution settings, the sea-shell project) use { 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.
$ hyprvalidate check config.lua

Checks the whole shape

Unknown symbols, bad config keys, wrong value types, bad call arity, and invalid fields inside hl.monitor/hl.device/hl.bind/etc spec tables.

hl.monitor({ resolution = "1920x1080" })
  ↳ 'resolution' is not a field of HL.MonitorSpec

Runs on directories too

Point it at a single file or a whole --split output directory — every .lua file inside gets checked in one command.

$ hyprvalidate check ~/.config/hypr
3 file(s) checked, no issues found.

§4 The fixer

For the findings with exactly one correct answer, check can just make the correction — never a guess, only what's mechanically unambiguous.

$ hyprvalidate check config.lua --fix

Two corrections, both provably safe

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.

[possible_missing_quotes] 'input.accel_profile' is set to the bare
  identifier 'flat' — did you mean the string "flat"?

Everything else stays reported, not guessed

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.


§5 Stay working through the next update

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.

$ hyprvalidate diff-impact config.lua --from old.json --to new.json

Only what your config actually uses

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.

[possible_rename] 'allow' on HL.PermissionSpec no longer exists
  ↳ possibly renamed to 'mode' (heuristic guess, not confirmed)

Warns by default, never claims certainty

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.


§6 Install

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).