Skip to content

Load workspace layout saves from the layouts directory - #9889

Open
fresh3nough wants to merge 3 commits into
omacom:quattrofrom
fresh3nough:fix/9664-workspace-layout-path
Open

Load workspace layout saves from the layouts directory#9889
fresh3nough wants to merge 3 commits into
omacom:quattrofrom
fresh3nough:fix/9664-workspace-layout-path

Conversation

@fresh3nough

Copy link
Copy Markdown

Summary

Fixes #9664.

After omarchy-hyprland-workspace-layout-toggle writes ~/.local/state/omarchy/workspace-layouts/<id>.lua, every Hyprland reload could raise:

module 'omarchy.workspace-layouts.N' not found

workspace-layouts.lua required a nested module prefix while bootstrap only puts HOME/.local/state/?.lua on package.path. That fails when XDG_STATE_HOME diverges from HOME/.local/state (and is fragile even when they match). toggles.lua already avoids this by putting its directory on package.path and requiring bare filenames.

The toggle script also always wrote under $HOME/.local/state, ignoring XDG_STATE_HOME, so saves could miss the directory paths.state_home uses to load.

Change

  • default/hypr/workspace-layouts.lua: prepend layouts_dir/?.lua and require_all.files(..., nil, ...) (same pattern as toggles.lua)
  • bin/omarchy-hyprland-workspace-layout-toggle: write under ${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/workspace-layouts

Test plan

  • Extended test/shell.d/hyprland-workspace-layout-test.sh
    • toggle still saves/applies under default HOME state
    • toggle respects XDG_STATE_HOME and does not dual-write under HOME
    • layouts load via workspace-layouts after bootstrap
    • layouts load via production toggles.lua when XDG_STATE_HOME diverges from HOME
  • bash test/shell.d/hyprland-workspace-layout-test.sh — all pass
  • Confirmed pre-fix: with XDG_STATE_HOME set, require("default.hypr.workspace-layouts") failed with module-not-found; post-fix loads the rule
ok - workspace layout toggle persists and applies the selected layout
ok - workspace layout toggle ignores broken hyprctl output
ok - workspace layout toggle respects XDG_STATE_HOME
ok - saved workspace layouts load into Hyprland configuration
ok - saved workspace layouts load via toggles when XDG_STATE_HOME diverges from HOME

workspace-layouts.lua required omarchy.workspace-layouts.N while only
HOME/.local/state was on package.path. With XDG_STATE_HOME set, or when
bootstrap's HOME entry does not resolve the nested module, every Hyprland
reload after a layout toggle raised module-not-found.

Mirror toggles.lua: put the layouts directory on package.path and require
bare filenames. Point the toggle script at XDG_STATE_HOME so saves match
paths.state_home. Extend the workspace-layout shell test for both.

Fixes omacom#9664

Signed-off-by: fresh3nough <anonwurcod@proton.me>
omarchybot and others added 2 commits September 3, 2026 05:24
… default

The toggle now derives its directory from XDG_STATE_HOME, and paths.lua always
did, so a developer with that variable set in their own environment made the
first case write into their real state directory and then fail on the tmpdir
path it had just asserted. Clearing it is how agent-usage-update-test.sh keeps
the same script hermetic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e fails

lua reading a bare heredoc exits 0 even when the chunk raises: with the fix
reverted, both loader checks printed the module-not-found error from omacom#9664 and
still reported ok, so neither one proved the change it was added for. lua - and
an explicit fail are how hyprland-qconsole-test.sh already handles this.

Co-Authored-By: Codex XHigh <noreply@openai.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@omarchybot

Copy link
Copy Markdown
Collaborator

Reviewed by Claude Opus 5 in Claude Code and by Codex at xhigh reasoning, on a disposable Omarchy 4.0.0 worker with a real Hyprland session. Two defects found, both in the test file; both fixed and pushed to this branch. The production change is correct and I reproduced the bug and the fix on a live compositor.

This does fix #9664, and the mechanism is not quite the one the PR describes.

I reproduced it on a real compositor with $OMARCHY_PATH pointed at this branch:

  • Base code + the current config/hypr/hyprland.lua: hyprctl reload is clean. The old prefixed require("omarchy.workspace-layouts.1") resolves fine, because default/hypr/bootstrap.lua:33 puts $HOME/.local/state/?.lua on package.path.
  • Base code + a ~/.config/hypr/hyprland.lua from before bootstrap.lua was extracted (it set package.path to ~/.config/?.lua and $OMARCHY_PATH/?.lua, with no state root): the exact error from workspace-layouts.lua: saved layouts fail to load (module 'omarchy.workspace-layouts.N' not found) #9664, and the search list matches the one in the issue line for line — toggles dir, ~/.config, $OMARCHY_PATH, and no ~/.local/state entry.
  • This branch + that same legacy hyprland.lua: clean reload, and hyprctl activeworkspace reports the saved scrolling layout restored.

So the affected population is people whose ~/.config/hypr/hyprland.lua predates the bootstrap extraction — that file is user-owned and updates do not rewrite it — not people with XDG_STATE_HOME set. Putting the layouts directory itself on package.path is the right fix precisely because it stops depending on what the user's entrypoint happens to have set up. Worth correcting the comment at default/hypr/workspace-layouts.lua:3-5, which currently attributes the failure to XDG divergence; the next person to read it will be looking for the wrong thing.

[high] The two loader checks could not fail. lua reading a bare heredoc exits 0 even when the chunk raises, and base-test.sh does not set -e, so a failed require still reached the pass on the next line. With the fix reverted, the suite printed the full module-not-found traceback and then ok - saved workspace layouts load into Hyprland configuration, ok - saved workspace layouts load via toggles ..., and exited 0. Neither new check proved the change it was added for. Fixed in 69c21da by switching both to lua - <<'LUA' || fail ..., which is the shape test/shell.d/hyprland-qconsole-test.sh:13 already uses for the same reason. Re-running the mutation now gives not ok on the toggles case and exit 1. Codex found this one; I had not reasoned about it, and it is the finding that mattered most here.

[medium] The suite was not hermetic once the toggle started following XDG_STATE_HOME. The cases that assert the $HOME default at lines 34 and 65 inherited the developer's own XDG_STATE_HOME, so on a machine that sets it the first toggle wrote into the real ~/omarchy/workspace-layouts/3.lua — outside $tmpdir, so the trap did not clean it up — and then failed on the tmpdir path it had just asserted. Confirmed: XDG_STATE_HOME=/tmp/... bash test/shell.d/hyprland-workspace-layout-test.sh gave not ok - workspace layout toggle saves a workspace rule and left the file behind. Fixed in fd4f4a7 by pinning XDG_STATE_HOME="" on those invocations, matching test/shell.d/agent-usage-update-test.sh:38. Both Codex and I found this independently, though Codex can read this session's transcript so its independence is not currently guaranteed.

[low] Bare module names resolve outside the layouts directory. With a nil prefix, require_all turns each basename into a bare require(), and a name containing a dot becomes a path searched across the whole of package.path rather than under omarchy/workspace-layouts/ as before. I put an empty pr9889probe.payload.lua in the layouts directory and a real ~/.config/pr9889probe/payload.lua next to it; the reload silently executed the one in ~/.config and applied its rule, with no config error. Not a privilege boundary — anyone who can write the layouts directory can write ~/.config too — and toggles.lua has had the identical exposure since it was written, so this is a note rather than a blocker. The toggle only ever writes names matching ^-?[0-9]+$.

Two things for the maintainer rather than for you, since they are judgement calls and I did not touch them:

  • The XDG_STATE_HOME change to the toggle script is a second, separable fix, and it is incomplete on its own: there is no migration for saves already under $HOME/.local/state. Those were already not loading for anyone with a divergent XDG_STATE_HOME — the reader has always used paths.state_home — so this is not a regression, but the preferences stay stranded until every workspace is toggled again. migrations/1787618700.sh is the precedent for moving them.
  • It also puts this feature on the opposite side of a convention that is written down three times: bin/omarchy-toggle-input-device:26-28 ("hardcoded to ~/.local/state like the sibling toggle tools, so it keeps working when XDG_STATE_HOME diverges"), default/hypr/disabled-input-device.lua:7-10, and bin/omarchy-hyprland-toggle:17. Reader and writer now agree with each other but not with the siblings sharing that state tree. Whether the tree moves to XDG or this one moves back is the maintainer's call.

One coverage gap left, if you want it: no test exercises the failure that was actually reported. The first loader check passes with or without the fix, because it runs the current bootstrap. Only the XDG_STATE_HOME-divergence case discriminates. A case that loads with a package.path lacking a state root would pin the regression this PR is named after.

Tests: test/shell.d/hyprland-workspace-layout-test.sh (5 passed), plus hyprland-paths-test.sh, toggle-input-device-test.sh, toggle-test.sh, hyprland-default-config-test.sh, hyprland-reload-guard-test.sh and ./test/cli (116 passed) — all on the worker, after the pushed commits, and re-run with XDG_STATE_HOME both set and unset.

Waiting on the maintainer for the migration and convention questions above; nothing else blocking from me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

workspace-layouts.lua: saved layouts fail to load (module 'omarchy.workspace-layouts.N' not found)

2 participants