# DeckShift Session Backend Handoff Last updated: 2026-07-11. ## Goal Extend DeckShift so its Steam Deck-style gaming mode is not hard-wired to SDDM. The first target is to preserve the existing SDDM behavior for upstream/Omarchy users while adding a DMS/greetd manual backend for our Hyprland/DMS dotfiles. The long-term goal is: - `sddm`: existing seamless auto-login flow for Omarchy users. - `dms-greeter-manual`: select the next session through DMS greeter memory and require normal greeter authentication. - Later: a host-gated one-shot auto-login backend for living-room machines, if it can be made safe and recoverable. ## Repository State Local checkout: ```text /home/anodyine/Projects/deckshift ``` Current work branch: ```text codex/session-backends ``` Remotes: ```text origin ssh://git@tea.kyle-merritt.com:2222/anodyine/deckshift.git github https://github.com/Anodyine/deckshift.git upstream https://github.com/28allday/deckshift.git ``` `origin` is the Gitea working remote. `github` is the public fork. `upstream` is fetch-only for the original DeckShift project. ## What Changed So Far All code changes so far are in: ```text deckshift.sh README.md ``` ### Installer Configuration `deckshift.sh` now accepts these variables: ```sh DECKSHIFT_SESSION_BACKEND=auto DECKSHIFT_DESKTOP_SESSION_ID=hyprland-uwsm.desktop DECKSHIFT_GAMING_SESSION_ID=gamescope-session-steam-nm.desktop ``` Supported backend values right now: ```text auto sddm dms-greeter-manual ``` `auto` detects DMS/greetd when: - `/etc/systemd/system/display-manager.service` resolves to `greetd.service`. - `/etc/greetd/config.toml` contains `dms-greeter`. Otherwise it falls back to `sddm`. ### Generated Backend Config The installer writes: ```text /etc/deckshift/session-backend.conf ``` It records the active backend, desktop/gaming session IDs, the Gamescope session file path, SDDM config path, and DMS greeter memory path. ### Generated Helpers The old SDDM-specific calls are now routed through backend-neutral helpers: ```text /usr/local/bin/deckshift-session-switch /usr/local/bin/deckshift-session-transition ``` `/usr/local/bin/gaming-session-switch` is still generated as a compatibility wrapper that execs `deckshift-session-switch`. Existing generated scripts now call the backend-neutral helpers: ```text /usr/lib/os-session-select /usr/local/bin/switch-to-gaming /usr/local/bin/switch-to-desktop ``` ### SDDM Backend Behavior The SDDM backend preserves the previous model: 1. Write or update `/etc/sddm.conf.d/zz-gaming-session.conf`. 2. `deckshift-session-switch gaming|desktop` changes `Session=...`. 3. `deckshift-session-transition` runs `sudo -n systemctl restart sddm`. This should be behaviorally equivalent to the original DeckShift flow. ### DMS Manual Backend Behavior The DMS manual backend does not create SDDM config. `deckshift-session-switch gaming|desktop`: 1. Resolves the target session file from an allowlist: - desktop: `DECKSHIFT_DESKTOP_SESSION_ID` - gaming: `DECKSHIFT_GAMING_SESSION_ID` 2. Looks in: - `/usr/local/share/wayland-sessions` - `/usr/share/wayland-sessions` 3. Writes DMS greeter memory: ```text /var/cache/dms-greeter/.local/state/memory.json ``` 4. Preserves any existing JSON keys and updates: - `lastSessionId` - `lastSessionDesktopId` `deckshift-session-transition`: 1. If `XDG_SESSION_ID` exists, runs: ```sh loginctl terminate-session "$XDG_SESSION_ID" ``` 2. If there is no current session ID, falls back to: ```sh sudo -n systemctl restart greetd.service ``` This intentionally returns the user to the DMS greeter for normal authentication. It is not a one-shot auto-login implementation. ### Sudoers The generated sudoers file now includes NOPASSWD entries for: ```text /usr/local/bin/deckshift-session-switch /usr/local/bin/deckshift-session-transition /usr/bin/systemctl restart sddm /usr/bin/systemctl restart greetd.service ``` The existing compatibility and NetworkManager/Bluetooth rules remain. ### README The README now documents: - The experimental DMS/greetd manual backend. - The new backend config and helper files. - The backend-neutral session switching flow. - Updated uninstall cleanup for `/etc/deckshift` and the new helper scripts. ## Validation Already Run These checks passed: ```sh bash -n deckshift.sh git diff --check ``` The generated heredoc scripts were also extracted and syntax-checked with `bash -n`: - `deckshift-session-switch` - `deckshift-session-transition` - `switch-to-gaming` - `switch-to-desktop` - `os-session-select` - `gaming-session-switch` compatibility wrapper `shellcheck` was not installed on this machine, so it has not been run yet. No installer run has been performed. No live `/etc`, `/usr/local/bin`, greeter, or display-manager state was changed by this work. ### DMS Greeter Selection Probe After the first code pass, a manual DMS greeter selection test was run outside this checkout. The greeter selected the expected `Deckshift dms test` session. That confirms the core DMS manual backend assumption still holds: writing DMS greeter memory can preselect a non-SDDM session for the next login. This does not yet prove the full DeckShift-generated helper flow or Gamescope session entry, but it is the right green light for implementing and testing the manual DMS backend path before any auto-login work. ### DMS Generated Helper Probe The generated helper path was then tested manually: ```sh sudo -n /usr/local/bin/deckshift-session-switch gaming /usr/local/bin/deckshift-session-transition gaming ``` It behaved as expected: the current session exited, DMS greeter appeared, and the target gaming session was preselected. This proves the first real DMS manual backend flow at the DeckShift helper layer. Remaining DMS validation should focus on the full `switch-to-gaming` script, Gamescope/Steam session startup, and the return path back to the Hyprland UWSM desktop session. ### DMS Manual Round Trip The DMS manual backend was also tested in both directions. It successfully switched the greeter selection away from Hyprland UWSM and then back to the Hyprland UWSM session. The user was able to log back into the UWSM desktop. This proves the non-SDDM manual session-selection loop: ```text Hyprland UWSM -> selected gaming/test session -> DMS greeter DMS greeter/session -> selected Hyprland UWSM -> DMS greeter -> Hyprland UWSM ``` The next layer to test is no longer DMS memory/session preselection. It is the real DeckShift gaming session: `switch-to-gaming`, Gamescope/Steam startup, and `switch-to-desktop` return behavior. ## Important Constraints Do not implement one-shot DMS auto-login yet. Manual DMS switching is the first safe milestone. Do not make this dotfiles-specific inside DeckShift. The DeckShift fork should grow generic backend seams; the dotfiles repo can decide whether and how to install/use the DMS backend. Keep the SDDM behavior stable for existing users. The backend abstraction should be boring and low-risk for the default Omarchy path. ## Known Gaps And Risks ### Not Tested Live The backend helpers have only been syntax-checked. They still need live testing on: - An SDDM/Omarchy machine or VM. - A DMS/greetd machine or VM. - A real target host with Gamescope/Steam. ### DMS Memory Contract The DMS greeter memory write is based on a local proof from the dotfiles repo: writing `lastSessionId` and `lastSessionDesktopId` successfully preselected a test session in DMS greeter. Still verify: - Ownership and permissions after DeckShift writes the file. - Whether DMS ever overwrites the file during greeter startup. - Whether preserving extra JSON keys is sufficient across DMS versions. ### Transition Semantics For DMS manual mode, `loginctl terminate-session "$XDG_SESSION_ID"` is preferred. The fallback `systemctl restart greetd.service` is more disruptive and should be treated as a fallback only. Verify whether `switch-to-desktop` from inside Gamescope has a valid `XDG_SESSION_ID`. If not, returning from gaming may restart greetd. ### Session File Location The installer currently writes the gaming session to: ```text /usr/share/wayland-sessions/gamescope-session-steam-nm.desktop ``` For our dotfiles, `/usr/local/share/wayland-sessions` may be a better long-term owner boundary. Decide whether DeckShift should make this configurable or leave the current upstream-compatible path alone. ### Verification Mode `verify_installation` still treats `/etc/sddm.conf.d/zz-gaming-session.conf` as optional by description only. The verification logic marks missing optional files by checking whether the description contains `(optional)`, so this may need adjustment if verifying a DMS backend install. ### Documentation Still Has Historical SDDM Mentions Some README changelog and troubleshooting sections still mention SDDM because they describe older releases or SDDM-specific recovery. That is probably fine, but before publishing this branch upstream, review the README for places where current behavior should say "session backend" instead. ## Recommended Next Steps 1. Install `shellcheck` on the dev machine or run it in a container/VM: ```sh shellcheck deckshift.sh shellcheck bin/deckshift-settings ``` 2. Test SDDM backend generation without changing behavior: ```sh DECKSHIFT_SESSION_BACKEND=sddm ./deckshift.sh ``` Verify: - `/etc/deckshift/session-backend.conf` - `/etc/sddm.conf.d/zz-gaming-session.conf` - `/usr/local/bin/deckshift-session-switch` - `/usr/local/bin/deckshift-session-transition` - Existing Super+Shift+S / Super+Shift+R behavior. 3. Test DMS backend in the CachyOS/DMS VM or sacrificial host: ```sh DECKSHIFT_SESSION_BACKEND=dms-greeter-manual ./deckshift.sh ``` Verify before switching: - Gaming session appears in the DMS greeter session list. - `deckshift-session-switch gaming` writes the expected DMS memory. - `deckshift-session-switch desktop` restores the Hyprland UWSM session. - File ownership/group/mode allow DMS greeter to read the memory file. 4. Test DMS manual transition without Steam first: ```sh sudo -n /usr/local/bin/deckshift-session-switch gaming /usr/local/bin/deckshift-session-transition gaming ``` Expected result: - Current session exits. - DMS greeter appears. - Gaming session is preselected. - User must authenticate manually. 5. Test return path: ```sh sudo -n /usr/local/bin/deckshift-session-switch desktop /usr/local/bin/deckshift-session-transition desktop ``` Expected result: - Current session exits. - DMS greeter appears. - Hyprland UWSM is preselected. 6. Only after manual DMS mode works, test full Gamescope/Steam entry and return. 7. After both SDDM and DMS manual mode are proven, split large generated helper bodies into clearer functions or files if desired. Avoid refactoring before the behavior is proven. 8. Add Gitea issues for follow-up work: - Prove SDDM backend parity. - Prove DMS manual backend in VM. - Fix verification mode for backend-specific expected files. - Decide session file owner path. - Prototype one-shot DMS/greetd auto-login separately. ## Recovery Notes For DMS Testing If a DMS switch leaves the host at the wrong selected session, switch to a TTY and write DMS memory back to Hyprland UWSM: ```sh sudo python3 - <<'PY' import json path = "/var/cache/dms-greeter/.local/state/memory.json" data = {} try: with open(path) as fh: data = json.load(fh) except Exception: pass data["lastSessionId"] = "/usr/local/share/wayland-sessions/hyprland-uwsm.desktop" data["lastSessionDesktopId"] = "hyprland-uwsm.desktop" with open(path, "w") as fh: json.dump(data, fh, indent=2) fh.write("\n") PY sudo chgrp greeter /var/cache/dms-greeter/.local/state /var/cache/dms-greeter/.local/state/memory.json 2>/dev/null || true sudo chmod 0664 /var/cache/dms-greeter/.local/state/memory.json sudo systemctl restart greetd.service ``` Do not rely on `chezmoi apply` as the only recovery path. The failure mode may be that the graphical desktop is unavailable.