424 lines
12 KiB
Markdown
424 lines
12 KiB
Markdown
# 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.
|