# Troubleshooting Shubbak is built to answer "why did it do that?" rather than leave you guessing. This page is the order to try things in. ## The one command ``` shubbak diagnose -o report.md ``` Produces a single file containing the environment, your config as loaded, the live window tree drawn as indented text, and the last few thousand log entries. **Recent log entries are kept in memory even at the default log level**, so this is usually worth running *after* something has already gone wrong. You do not need to have enabled logging in advance. **It works with the window manager dead, too** — which is when a report is most wanted. With nothing running it says so at the top and reports from what is on disk instead: the binaries and their dates, the config as every one of the four loaders reads it with each diagnostic rendered, the tails of every program's log and of the run before, the session as last saved, and any crash report from the last week, the newest one whole. Start the window manager and run it again for the live half, and attach both. Attach that file to a bug report. ## "This window isn't being tiled" The most common question, and the one Shubbak can answer directly: ``` shubbak inspect ``` Click the window, wait three seconds. You get every matchable attribute, the manageability verdict **with its reason**, and which of your rules and app definitions matched — including, for each app that did not match, the specific matcher that failed. Common verdicts and what they mean: | Reason | What is happening | |---|---| | `window has WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW` | The app declares itself a palette or utility window. Usually correct to skip. | | `window is cloaked by the shell` | A suspended UWP app. It reports as visible but is not composited; tiling it would reserve space for nothing. | | `window is owned by another window` | A dialog. Its parent gets the tile — otherwise a save prompt would shrink the document behind it. | | `window has no title` | Splash screens and message-only helpers. | | `window belongs to an elevated process` | Install the MSI (`winget install MoaidHathot.Shubbak`): from `Program Files`, signed, Shubbak may move these. From a portable copy, run Shubbak elevated. | If the verdict is `manageable: yes` but a rule matched, the rule is why. ## "It is not loading my config" ``` shubbak doctor ``` goes through the install as a checklist and names the config in effect, whether it parses, and whether the window manager and its three companions are running. For the config question alone: ``` shubbak config-path ``` Prints the file in effect and how it was found. If nothing was found it lists **every location it looked in**, which is usually enough on its own — "no config file" is a useless thing to be told when the file is sitting right there and the search looked somewhere else. A window manager started with no config anywhere writes the starter to the first user location and loads that - so if your file is somewhere the search does not reach, the symptom is the starter's keys working rather than yours, and `config-path` says which file won. Search order, first match wins: 1. `--config ` 2. `$SHUBBAK_CONFIG` — a file, or a directory containing `shubbak.kdl` 3. `$XDG_CONFIG_HOME/shubbak/shubbak.kdl` 4. each entry of `$XDG_CONFIG_DIRS` 5. `%USERPROFILE%\.config\shubbak\shubbak.kdl` 6. `%APPDATA%\shubbak\shubbak.kdl` An explicit `--config` is used even when the file does not exist, so you get "that file is missing" rather than a silent fallback to a different config. On Windows, `XDG_CONFIG_DIRS` is separated with `;` rather than `:` — a colon would split `C:\Users\me` at the drive letter. ## "My keybinding does nothing" ``` shubbak check-config ``` Reports unknown commands with a suggestion, unknown keys, and — the one that catches people out — **duplicate bindings**, naming the line that shadows yours. Every code it prints is in the [diagnostics catalogue](diagnostics.md). If the config is clean, watch the binding fire: ``` shubbak log-level debug ``` Then press the key. Every resolved binding is logged with the commands it ran. If nothing appears, the keystroke never reached a binding; if it appears but nothing happens, the command was rejected and the reason is logged. ## "A rule never fires" `shubbak inspect` lists each app definition with the matcher that failed. The classic mistake, which Shubbak warns about at load time: ``` title regex="/[Pp]ower[Pp]oint.*/" # wrong - the slashes are matched literally title regex="[Pp]ower[Pp]oint.*" # right ``` ## "Windows have disappeared" They are almost certainly **cloaked**, not closed. Windows on inactive workspaces are concealed with a DWM cloak, which removes them from the screen, Alt+Tab and the taskbar while leaving the process running. The important property is that this is **recoverable**: a cloaked window still reports as visible to Win32, so simply starting Shubbak again adopts it and un-cloaks it when its workspace becomes active. ``` shubbak-wm # restart; concealed windows come back ``` Shubbak also un-cloaks everything on a clean exit. If it was killed outright, the restart above is the recovery. If cloaking misbehaves with a particular application, fall back: ```kdl general { hide-method "hide" } ``` Be aware that `hide` is genuinely unrecoverable - a hidden window is rejected by the filter as invisible and cannot be re-adopted - so only use it if cloaking is broken in your environment, which mainly means remote sessions with no compositor. ## "Dragging a window did the wrong thing" Dropping a tiled window is resolved against the tree: | Where you drop | What happens | |---|---| | middle of another window | the two swap places | | near its left/right edge | inserted beside it - in a manual split, horizontally | | near its top/bottom edge | inserted beside it - in a manual split, stacked vertically | | far from any window | nothing; it snaps back | The edge zone is the outer quarter of each side, leaving the middle half as the swap zone. A drop landing in the gap between two tiles still resolves to the nearest one. The edge means what it says only in `splith` and `splitv`, where the tree is the layout and a drop across the split's axis nests a new one. In an automatic layout - `fibonacci`, `grid`, `master-*` - the layout decides the geometry and the edge decides only the order: the leading edge puts the dropped window before the target, the trailing edge after it. So a window dropped onto a `fibonacci-v` monitor lands stacked, because that is how `fibonacci-v` places a second window, whichever edge the cursor was nearest; the layout you set for that monitor stays in charge. Dragging a **border** resizes instead, converting the new size back into the tree's ratios. A move of fewer than 8px, or a size change of fewer than 4px, is ignored - otherwise clicking a title bar would rearrange the layout. Run with `--log-level debug` to see each drop resolved. ## "Windows jump around" / "the layout is wrong" The window tree in the diagnostic report shows the nesting, the layout on each container and each node's size ratio. When a window is the wrong size, the nesting is almost always the answer, and an indented drawing shows it at a glance: ``` workspace "1" [active] layout=splith (4,26 3832x2130) window 0x8D088C "Firefox" (firefox) Tiling ratio=0.500 (4,26 1916x2130) container layout=splitv ratio=0.500 (1920,26 1916x2130) window 0x4009FE "Code" (code) Tiling ratio=0.500 (1920,26 1916x1065) ``` ## "Everything scattered after a reboot" Session state lives in `%LOCALAPPDATA%\Shubbak\session.json`. Windows are matched by process, class and a title hash — deliberately tolerant, because a browser's title changes constantly. If restoration puts things in the wrong place, delete that file to start clean. If it puts *nothing* back, check the log for `session loaded` at startup. ## Capturing an intermittent problem ``` shubbak log-level trace ``` Changes the level on the **running** window manager — no restart, so you do not lose the state that was about to trigger the problem. Trace records every window event and every command. It is verbose (a busy desktop produces well over a hundred entries a second), which is precisely what makes a misbehaviour reproducible from a log alone. Reproduce, then: ``` shubbak diagnose -o report.md ``` For a problem that occurs during startup, tracing has to be on from the start: ``` shubbak-wm --foreground --log-level trace --log-file ``` `--foreground` is what attaches it to your terminal. Without it the daemon has no console at all — it is a GUI-subsystem binary so that starting it at logon does not leave a window on the desktop — and the trace would go only to the file. That is often what you want; add `--foreground` when you want to watch it happen. ## Reading a trace Filter by category: ```powershell Select-String -Path report.md -Pattern " Window " # window lifecycle Select-String -Path report.md -Pattern " Hook " # keystrokes and bindings Select-String -Path report.md -Pattern " Command " # what ran, what was rejected Select-String -Path report.md -Pattern " Rule " # rule matches Select-String -Path report.md -Pattern " Layout " # placement passes ``` `EVENT_OBJECT_LOCATIONCHANGE` is deliberately **not** traced. It fires around 120 times a second from a single dragged window; logging it would drown everything else and slow down the thing being diagnosed. ## If it crashes A crash writes `%LOCALAPPDATA%\Shubbak\crash-.md` containing the same report, including the log entries leading up to it. Attach that. Each program's log is beside it - `shubbak.log`, `taj.log`, `dalil.log`, `ayn.log` - and the three sessions before the current one are kept as `.1` (the most recent) to `.3`, so a start that had the answer is not lost to the restart that followed it. ## The bar Taj logs separately: ``` taj --log-level debug --log-file ``` - **Blank bar** — check `connected to the window manager` appears. Taj retries indefinitely, so a missing WM shows as repeated connection attempts. - **Windows tile over the bar** — the bar is still there and still working; nothing has reserved room for it. Look for `the shell restarted; reserving bar N's strip again`, which is Taj recovering by itself, or `the shell refused bar N's reservation`, which is Explorer not being ready. Restarting Explorer is the usual cause. If it stays that way, restart Taj: `shubbak taj-exit` and start it again. - **A widget shows nothing** — a widget whose value is empty hides itself, which is deliberate: an empty box with padding looks like a rendering fault. Check the source name in your template matches a declared source. - **A widget shows `!`** — the source threw. For a `command` source, run the command by hand. ## After an upgrade **The window manager did not come back.** A `winget upgrade` asks the running window manager to leave and starts it again once the files are in place. If it did not return - the machine was mid-logoff, or something force-closed it before it could register - start it with `shubbak-wm` or the Start Menu entry; the bar, the palette and the watcher follow from the config. Scoop stops everything before an update and does not start it again; that one is by design, run `shubbak-wm`. **"Another window manager took the desktop first" in a console at logon.** Two things tried to start it: the Run key and something else, usually an older shortcut or a second `autostart enable` from a different copy. `shubbak autostart status` says which copy is registered. **The bar is missing after an upgrade or a move.** The window manager looks for `taj` beside its own executable and then on `PATH`, so a bar that fails to start means neither place has one. `shubbak-wm --foreground` shows the `shell-exec failed` line naming what was tried. ## Uninstalling `shubbak autostart disable`, then `winget uninstall MoaidHathot.Shubbak` or `scoop uninstall shubbak`. Your config (`%USERPROFILE%\.config\shubbak`) and the session, logs and crash reports (`%LOCALAPPDATA%\Shubbak`) are left for you to delete or keep. ## Known limitations These are design constraints, not bugs: - **No whole-desktop workspace transitions.** Windows gives no compositor access. Per-window move, resize and fade animations work; sliding the entire desktop does not. Komorebi has the same ceiling. - **Drag-to-swap has no live preview.** The drop is resolved when you release the mouse, so there is no highlight showing where the window will land while you drag. - **Elevated windows need the installed Shubbak, or an elevated one.** Windows lets a program move windows above its own integrity level only if it is signed, asks for `uiAccess` in its manifest, and runs from `Program Files` - which is what the MSI provides. A portable copy detects and reports them but cannot move them unless it is itself run elevated. - **A window cannot be on two workspaces at once.** Tags relocate a window to whichever tagged workspace you last activated. A Windows window has one position on one monitor; anything else would be a promise the platform cannot keep. - **Windows' own virtual desktops (Win+Ctrl+Left/Right) do not mix with Shubbak's workspaces.** Switching desktop makes Windows cloak every window on the one you left, which Shubbak reads as those windows going away, and uncloak them when you return, which it reads as new windows arriving on the focused workspace. Use Shubbak's workspaces for what virtual desktops did; they are the same idea with the keyboard, the bar and the rules attached. - **`resize` needs a split to resize within.** In `splith`, `splitv` and the master-stack layouts a window's edges are ratios, and that is what `resize` moves. `fibonacci`, `grid` and `monocle` decide the geometry from the order of the windows alone, so there is no ratio for the key to act on and it says so.