Let me update here, sorry about the delay to answer you. i will share here a script for an easy app workflow. Just bind a key to run the script and make your life easy.
Problem: In Qubes, launching apps in specific qubes requires either:
- Memorizing commands like
qvm-run -a appvm app
. - Manually opening a terminal in the target qube first.
Solution: This script provides a GUI menu (via Zenity) to:
- Detect the active qube automatically (no need to type its name).
- Launch apps with one click (e.g., Browser, Terminal, File Manager)
Secure and easy way to screenshot sharing between Qubes
Problem: Sharing screenshots between qubes is combersome
- Manual steps: save → qvm-copy → Open in target qube.
Solution: Automated Screenshot feature:
- Captures a region (xfce4-screenshooter -r).
- Automatically sends to a user-selected qube (e.g., work or personal).
- Opens the file manager in the target qube for instant access.
This script can reduce human error, avoid mistakes like:
- Launching apps in the wrong qube (e.g., opening a browser in personal instead of work vm)
- Typos in commands
It validates the qube name and uses a predefined list of trusted apps (no accidental risky commands). it makes your workflow faster, you can save time, no need to switch to dom0 terminal to run qvm-run, that way the user has no need to remember app-specific commands (e.g., qubes.StartApp for browsers).
Example: Launching a browser in work-vm takes 2 clicks instead of 5+ keystrokes.
Flexibility:
- Easily add/remove apps by editing the APPS dictionary in source code (e.g., add
["Signal"]="signal-desktop"
). - Extend with new functions (e.g., _open_vpn to start a VPN in a qube).
Ideal for Non-Technical Users (everybody needs a start, we can make it easy for then so they can have a better experience trying Qubes)
Example Workflow:
You’re in a work qube editing a document.
Need to open a browser in work-web?
Run script → select "Browser" → done.
Need to send a screenshot to personal qube?
Run script → "Automated Screenshot" → select personal → crop region → file appears in personal’s QubesIncoming.
This script simplifies secure, compartmentalized workflows — perfect for Qubes OS’s philosophy.
To make sure everything works
-
dom0:
sudo qubes-dom0-update zenity xorg-xprop xfce4-screenshooter
-
in VMs: you need the apps and your prefered browser
sudo dnf install xfce4-terminal thunar geany yourbrowser # Fedora
sudo apt install xfce4-terminal thunar geany yourbrowser # Debian
Menu images:
Install example:
You are in vm personal and saved the script in /Downloads/ named as action-flow.sh
Go to dom0 terminal and type:
mkdir -p ~/scripts
cd scripts/
qvm-run -u root -p personal 'cat /home/Downloads/action-flow.sh' >> action-flow.sh
chmod +x action-flow.sh
bind a key to run the script:
> 1. Start Menu -> System Settings -> Keyboard
> 2. Select "Application Shortcuts" menu
> 3. Click "+Add"
> 4. Browse to Scripts/action-flow.sh
> 5. Bind your shortcut key to run the script
Done!
SOURCE CODE: action-flow.sh
#!/bin/bash
declare -r LOG_FILE="/var/log/qubes/app_launcher.log"
declare -A APPS=(
["XTerm"]="xterm"
["Terminal"]="xfce4-terminal"
["Geany"]="geany"
["Thunar"]="thunar"
["Browser"]="qubes.StartApp+xfce4-web-browser"
["Automated Screenshot"]="_take_screenshot"
)
_get_qube_name() {
local active_win=$(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2)
xprop -id "$active_win" _QUBES_VMNAME 2>/dev/null | awk -F'"' '{print $2}'
}
_validate_qube() {
[[ "$1" =~ ^[a-zA-Z0-9_-]+$ ]] && qvm-check "$1" &>/dev/null
}
_launch_app() {
local qube="$1" app="$2"
if [[ "$app" == "Browser" ]]; then
qvm-run -q -a --service "$qube" "${APPS[$app]}" >/dev/null 2>&1 &
elif [[ "${APPS[$app]}" == _* ]]; then
"${APPS[$app]}"
else
qvm-run -q -a "$qube" "${APPS[$app]}" >/dev/null 2>&1 &
fi
}
_take_screenshot() {
local RUNNING_VMS=$(qvm-ls --running --raw-list | grep -v "dom0" | grep -v "sys" | grep -v "vpn")
if [[ -z "$RUNNING_VMS" ]]; then
zenity --error --text="No VMs are running!" --width=300
return 1
fi
local VM_LIST=$(echo "$RUNNING_VMS" | tr ' ' '\n')
local TARGET_VM=$(zenity --list \
--title="Automated screenshot" \
--text="Which VM would you like to send the file to:" \
--column="Active VMs" $VM_LIST \
--width=400 --height=300 2>/dev/null
) || return 1
if [[ -z "$TARGET_VM" ]]; then
zenity --error --text="No VM selected!" --width=300
return 1
fi
xfce4-screenshooter -r -o "qvm-copy-to-vm $TARGET_VM" || {
zenity --error --text="Failed to capture/send to $TARGET_VM!" --width=300
return 1
}
zenity --notification --text="Screenshot sent to $TARGET_VM!" 2>/dev/null
qvm-run -q -a "$TARGET_VM" 'thunar ~/QubesIncoming/dom0/' &
}
main() {
echo "$(date) - Starting app launcher" >> "$LOG_FILE"
qube_name=$(_get_qube_name) || {
zenity --error --text="Cannot identify Qube!" --width=300
exit 1
}
_validate_qube "$qube_name" || {
zenity --error --text="Invalid Qube: $qube_name" --width=300
exit 1
}
IFS=$'\n' sorted_apps=($(sort <<<"${!APPS[*]}"))
selected_app=$(zenity --list \
--title="Apps - $qube_name" \
--text="Select an app:" \
--column="Applications" \
"${sorted_apps[@]}" \
--width=350 --height=300 2>/dev/null
) || exit 0
_launch_app "$qube_name" "$selected_app"
zenity --notification --text="Launched $selected_app in $qube_name" 2>/dev/null &
}
main "$@"