
Console de contrôle auto-hébergée et bureau à distance pour postes de travail Linux via Tailscale, avec streaming WebRTC, contrôle vocal avec LLM local, macros de scène, entrée virtuelle, transfert de fichiers et télémétrie système en direct.
Transformez un téléphone Android de rechange (ou tout appareil avec un navigateur) en un panneau de contrôle auto-hébergé et en bureau à distance pour votre station de travail Linux — via votre réseau privé Tailscale, sans applications tierces.
Tout a commencé par « que faire d'un vieux téléphone ? » et est devenu un plan de contrôle pour une configuration Hyprland : contrôle des fenêtres/espaces de travail, macros de scène, routeur vocal push-to-talk avec un assistant LLM local, contrôles contextuels dans l'application, streaming audio + écran bidirectionnel, un bureau à distance tactile, un clavier/souris virtuel, transfert de fichiers + partage téléphone→PC, et télémétrie en direct — le tout servi comme une PWA installée avec un aspect terminal phosphor.
Note sur la portabilité. Ceci a été construit pour une configuration spécifique : Linux basé sur Arch (Garuda) + Hyprland + PipeWire + NVIDIA + Tailscale, avec les dotfiles end-4 / illogical-impulse. L'architecture est générique, mais plusieurs intégrations sont spécifiques à l'environnement (noms de moniteurs, liaisons d'espaces de travail, chemin du thème matugen,
cpupower/nvidia-smi). Considérez-le comme une référence de travail à adapter, pas un package clé en main.
L'UI est une application web sombre, paysage, à onglets (synchronisée avec le thème de votre bureau) :
| Onglet | Ce qu'il fait |
|---|---|
| Espaces | Grille d'espaces de travail en direct par écran (taper pour changer), liste des fenêtres en direct (taper pour focaliser), bascule DPMS par écran + luminosité ddcutil |
| Distant | Pavé tactile à l'écran (glisser/taper/deux doigts) + clavier virtuel avec modificateurs et combinaisons, via un périphérique uinput du noyau |
| Modes | Macros de scène en un tap — lancer/fermer/agencer des dispositions d'applications complètes sur plusieurs écrans (ex. « Travail » / « Loisirs ») |
| Voix | Routeur vocal push-to-talk (faster-whisper, CPU) : voies de mot-clé — macro (exécuter un mode/une commande), type (dicter), input (phrase → combinaison de touches) — avec confirmation avant exécution, plus « friday », un répondeur LLM local en lecture seule (Ollama + Qwen) avec recherche web auto-hébergée et connaissance de l'état système en direct |
| Audio | Sourdine micro/haut-parleur, volume, sélecteurs de périphériques de sortie et d'entrée, transport playerctl + couverture d'album (suit le lecteur MPRIS actif) |
| Stream | Audio WebRTC bidirectionnel (PC↔téléphone, avec micro du téléphone et sortie téléphone uniquement) + vidéo d'écran, et taper pour contrôler l'écran streamé = un véritable bureau à distance |
| Système | Bascule du mode de performance, changement de thème en direct, statut Tailscale, principaux processus (taper pour tuer), verrouillage, redémarrage de NetworkManager, mise en veille/redémarrage/extinction |
| Fichiers | Capture d'écran d'un moniteur → visualisation/téléchargement sur le téléphone ; déposer un fichier téléphone→PC |
| Config | Modifier la configuration commands.json / modes.json (et voix/contexte) depuis le téléphone (validé JSON) |
Toujours présent, au-dessus des onglets — une bande contextuelle qui affiche ce qui se passe en ce moment : un appel actif (sourdine / aller à), média en cours de lecture + transport, et contrôles de clavier dans l'application pour l'application focalisée (YouTube / Brave / Teams), fournis sans voler le focus.
Deux autres, au-delà des onglets :
Plus : connexion par code PIN numérique, verrouillage de l'écran, PWA plein écran paysage, et verrouillage par force brute sur la connexion.
téléphone / ordinateur portable (PWA navigateur)
│ HTTPS + WSS (Tailscale uniquement)
▼
tailscale serve ──► Application web FastAPI ── Socket Unix ──► deckd
(certificat TLS réel) (exécutée en tant que votre utilisateur) (noms d'actions) (exécutée en tant que root)
│ │
hyprctl · pactl · ddcutil · grim · liste d'autorisation fixe
wf-recorder · uinput · WebRTC de commandes privilégiées
(cpupower, nvidia-smi,
systemctl, …)
Deux processus :
app/ — l'application web s'exécute en tant que votre utilisateur normal. Elle fait tout ce qui ne nécessite pas root : contrôle Hyprland, audio, luminosité, capture d'écran, entrée virtuelle, streaming WebRTC, transfert de fichiers.deckd/ — un petit assistant root (stdlib uniquement, aucune dépendance) pour les quelques actions privilégiées. L'application web ne lui envoie jamais de chaînes shell — seulement des noms d'actions d'une liste d'autorisation fixe (governor_performance, gpu_power_limit, suspend, …), validée dans deckd/actions.py avant toute exécution. Même si l'application web était complètement compromise, le rayon d'impact est exactement les actions autorisées, sans injection d'arguments. Le socket est root:<groupe> mode 0660.tailscale serve l'expose sur votre nom MagicDNS avec un vrai certificat Let's Encrypt ; il ne se lie jamais à 0.0.0.0.L'application web peut exécuter vos commandes shell configurées et injecter des entrées en tant que votre utilisateur — c'est, par conception, une télécommande pour votre machine. Gardez-la sur votre tailnet, derrière le PIN, et ne l'exposez pas publiquement.
pactl/PulseAudio)hyprctl, pactl / pw-record / pw-play, playerctl, ddcutil,
wf-recorder, grim, cpupower, nvidia-smi, kitty (ou votre terminal)input (pour /dev/uinput) et le groupe i2c (pour ddcutil)aiortc + PyAV (installés via uv) pour le streaming audio/vidéogit clone <votre-url-de-repo> phone-deck
cd phone-deck
uv sync # crée .venv et installe les dépendances
uv run python -m app.set_pin # définissez votre PIN de déverrouillage
deckd)Modifiez systemd/deckd.service d'abord — définissez les chemins et DECK_SOCKET_GROUP à un groupe auquel votre utilisateur appartient (généralement votre groupe principal) :
sudo cp systemd/deckd.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now deckd