Would .xinitrc work?
Systemd units with After=graphical.target and properly configured User=, Display=, Session=, Seat=, and/or whatever else might be necessary. Or maybe user-mode systemd units. https://wiki.archlinux.org/index.php/Systemd/User
Or maybe rc.local with `systemctl is-system-running --wait` before your commands - I often have to use this with qvm-run. Running from rc.local though, commands might not be running as the right user/session/seat/slice/scope/whatever, I don't know.
> The systemd route does seem promising. Thanks.
>
> If I edited the template vm, I could just put my unit file in
> /etc/systemd/system and it would work fine.
>
> However I'd like to do this for a specific AppVm, so I dropped the unit
> file in /usr/local/lib/systemd/system. This file persists across boots
> as expected, however systemd doesn't load units from it until I
> daemon-reload after boot.
>
> I suppose this is because /usr/local is symlinked from /rw/usrlocal
> sometime after systemd has loaded its units.
>
> Is there anyway to get systemd to load units from
> /usr/local/lib/systemd/system as part of appvm boot?
>
> ~abel
Try putting `systemctl daemon-reload` in rc.local. I haven't tried it, but this should work, as rc.local itself resides on /rw, so /rw has to be available by that time. (Arguably the stock rc.local in Qubes templates should be preinstalled with this line. But then, arguably, systemd should always automatically reload units any time it mounts something.)