Files
deckshift/docs/session-backend-handoff.md
T

424 lines
12 KiB
Markdown
Raw Normal View History

2026-07-11 17:48:08 -04:00
# 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
2026-07-11 17:49:19 -04:00
feature/session-backends
2026-07-11 17:48:08 -04:00
```
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.