The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Task tracking (sessions, ETA, dashboard) listing page.
English summary. Local-first tracking of long-running tasks: an MCP server for Claude or Lyra, a small HTTP API on 127.0.0.1:8765 and a Textual terminal dashboard. Sessions have items, progress, logs and templates (download, machine, free, lyra_task, movie); pollers feed qBittorrent and Bazarr sessions automatically. Install: pip install . then mcp-tracking, mcp-tracking-api, mcp-tracking-ui. No cloud, no telemetry.
Serveur MCP de suivi en temps reel avec dashboard terminal. Permet a Claude/Lyra de tracker n'importe quelle operation longue ET alimente automatiquement les sessions depuis le media-server (qBittorrent, Bazarr, conversion DV).
Un agent LLM (grand modèle de langage) qui lance une tâche longue (conversion, clone de VM, téléchargement) ne peut pas rester bloqué à la regarder, et il ne voit rien de ce qui se passe entre deux de ses tours. Ce serveur lui sert de mémoire de travail partagée :
tracking_get.metrics.py) : l'agent reçoit des chiffres au lieu d'extrapoler lui-même.running sans mise à jour depuis 10 minutes
est marquée stale : l'agent distingue « encore en cours » de « processus mort ».pid de son processus ;
l'heure de démarrage relevée dans /proc évite de signaler un pid réutilisé par un
autre programme. tracking_stop envoie SIGTERM et garde la session, tracking_kill
envoie SIGKILL et la supprime.flock et réécrit de façon atomique (storage.py) : plusieurs agents et scripts peuvent
écrire en même temps.download, machine, movie, lyra_task, free)
pour que chaque agent décrive son travail de la même façon.Local-first et self-hosted : aucun cloud, aucune télémétrie, tout reste sur la machine (on-prem). Utilisé par Lyra, l'assistant vocal French-first, et par n'importe quel client MCP (Claude Code, Claude Desktop...).
![]()
Enregistree avec docs/demo/record.sh : server.py --test alimente quatre sessions simulees dans un repertoire d'etat temporaire (TRACKING_STATE_DIR), puis server.py --ui ouvre le dashboard dessus. Les sessions reelles ne sont pas touchees.
| Fichier | Emplacement | Surcharge |
|---|---|---|
tracking_state.json | ~/.local/state/tracking/ | TRACKING_STATE_DIR |
poller_state.json | ~/.local/state/tracking/ | TRACKING_STATE_DIR |
templates.json (templates utilisateur, optionnel) | ~/.config/tracking/ | TRACKING_TEMPLATES_FILE |
credentials/*.cred (qBittorrent, Bazarr) | a cote du code, gitignore | -- |
Un ancien tracking_state.json a cote du code est migre automatiquement au premier
demarrage (copie, jamais supprime).
Variables d'environnement de retention :
| Variable | Defaut | Role |
|---|---|---|
TRACKING_TTL_DAYS | 7 | Purge des sessions done / error / paused |
TRACKING_TTL_RUNNING_H | 24 | Purge des sessions running orphelines (plus mises a jour) |
Le fichier d'etat est ecrit a chaque modification via ecriture atomique (os.replace) sous verrou
fichier (tracking_state.lock). Tous les processus (MCP, API, poller, dashboard) partagent cet
unique fichier ; chaque lecture verifie le mtime pour invalider son cache.
Toute mutation (HTTP ou MCP) passe par mutations.py, qui garantit le meme comportement sur les
deux chemins : started_at / finished_at poses sur les items et la session, historique de
progression (fenetre glissante de 40 points), niveaux de log info / warn / error,
auto-completion quand tous les items sont termines.
GET /sessions et tracking_get renvoient un bloc metrics calcule a la volee par metrics.py :
| Champ | Sens |
|---|---|
percent | progression (plafonnee a 100) |
rate, rate_str | vitesse sur les 120 dernieres secondes (2.0 MB/s, 30.0 u/min) |
eta_seconds, eta_str | temps restant estime (session running uniquement) |
elapsed_seconds, elapsed_str | depuis created_at jusqu'a finished_at ou maintenant |
idle_seconds, stale | stale = running sans mise a jour depuis 10 min (affiche dans le TUI) |
Configuration Claude Desktop / Claude Code (mcpServers) :
Le MCP est enregistre dans Claude Code (scope user) :
Pour reenregistrer :
Deux services tournent en permanence et se lancent au boot :
| Service | Role | Port |
|---|---|---|
tracking-api.service | API HTTP locale pour scripts externes | 127.0.0.1:8765 |
tracking-poller.service | Poll qBittorrent (10s) + Bazarr (60s) | -- |
Les instances MCP server.py deja ouvertes par des sessions Claude Code ne sont pas
redemarrees par deploy.sh : reconnecter tracking via /mcp dans ces sessions.
Cherche "MCP Tracking" dans wofi/launcher. Lance le dashboard dans Kitty.
Simule 4 sessions en parallele : download, machine (12 noeuds), free, movie (pipeline DV complet).
| Icone | Statut | Couleur |
|---|---|---|
[ ] | pending | gris |
[>] | running | cyan |
[ok] | done | vert |
[!] | error | rouge |
| Couleur | Statut |
|---|---|
| cyan | running |
| vert | done |
| rouge | error |
| jaune | paused |
| Touche | Action |
|---|---|
f | Filtre suivant (cycle dynamique par template) |
e | Basculer filtre erreurs uniquement |
r | Refresh manuel |
s | Stop propre d'une session (saisir l'ID) -> status paused |
k | Kill force d'une session (saisir l'ID) -> suppression |
q | Quitter |
| Fleches / Molette | Scroll |
Appuyer sur s ou k ouvre un modal avec un champ de saisie pour l'ID de session.
s marque la session en paused et ajoute un logk supprime definitivement la session du dashboardEchap annuleLe cycle de filtres est construit automatiquement depuis les sessions presentes :
all toujours presenterrors n'apparait que si au moins une session a une erreurfiltre: movie | 2/5 session(s)allLe poller interroge http://localhost:8080/api/v2/torrents/info toutes les 10 secondes.
[DOWNLOAD] avec nom, taille, vitesse, ETAcredentials/qbt-password.cred (chiffre systemd-creds --user, genere par media-server/scripts/secrets/rotate-secrets.sh)Le poller interroge l'API Bazarr toutes les 60 secondes.
[SUBTITLES] unique liste tous les episodes/films sans sous-titres FRSous-titres manquants (151)credentials/bazarr-api-key.cred (meme mecanisme). Sans credential, le poll concerne est simplement desactive.Declenche par dv-webhook.service quand Radarr/Sonarr importent un film DV Profile 4 ou 7.
Flux :
Les 6 etapes trackees avec leurs metriques :
| Etape | Outil | Metriques affichees |
|---|---|---|
| 1/6 extraction HEVC | ffmpeg | frame / speed / size / time |
| 2/6 demux BL/EL | dovi_tool | frames X/Y (%), bl: X GB, el: X GB |
| 3/6 extraction RPU + conv P8 | dovi_tool | frames X/Y (%), RPU: X KB |
| 4/6 injection RPU P8 dans BL | dovi_tool | frames X/Y (%), P8 HEVC: X GB |
| 5/6 reconstruction timestamps | ffmpeg | frame / fps / size |
| 6/6 remuxage MKV final | ffmpeg | frame / speed / size |
La barre de progression globale avance en continu pendant chaque etape (pas par sauts de 1/6 a la fin de chaque etape).
Mode manuel :
En mode manuel, la session tracking est creee automatiquement dans process_file.
Scripts externes peuvent creer/modifier des sessions directement :
Corps PUT complet (tous les champs optionnels) :
tracking_createtracking_updatetracking_logAjoute un log sans modifier la progression.
tracking_completeMarque done a 100%.
tracking_errorMarque en erreur (prefixe "ERREUR:" auto, remonte dans colonne Erreurs).
tracking_stopArrete proprement une session (status -> paused). Reste visible dans le dashboard.
tracking_killSupprime une session en force. Disparait immediatement du dashboard.
tracking_getRetourne l'etat complet formate d'une session.
tracking_listtracking_deleteSupprime une session (equivalent de tracking_kill).
tracking_templatesAffiche la liste des templates et leurs champs.
open_tracking_uiOuvre le dashboard dans un terminal Kitty.
downloadTelechargement de fichiers. Alimente automatiquement par qBittorrent via le poller.
machineOperations sur des machines (update, clone, snapshot, deploy). Utilise par Lyra pour les operations VM/cluster.
freeFormat libre. Utilise par le poller pour les sous-titres Bazarr manquants.
lyra_taskOperations Lyra (VM clone, backup, update, snapshot).
moviePipeline complet d'un film : telechargement -> conversion Dolby Vision. Alimente automatiquement par dv_convert.py quand Radarr/Sonarr importent un fichier DV P4/P7.
Deux attaquants realistes sur une machine de bureau :
127.0.0.1:8765. Sans protection, elle pourrait creer des
sessions, en supprimer, et surtout demander l'envoi d'un signal a un processus.api.py ecoute uniquement sur 127.0.0.1:8765 -- inaccessible depuis le reseau$XDG_RUNTIME_DIR/tracking/token (droits 0600, donc illisible par un autre utilisateur), exige
en Authorization: Bearer ... sur POST, PUT et DELETE. Une page web ne peut pas le lire.Origin donne un 403, meme avec le jeton.Host verifie (boucle locale uniquement) et Content-Type: application/json exige
en ecriture.pid annonce existe et appartient au meme utilisateur, puis releve son
heure de demarrage. /stop et /kill refusent d'agir si cette empreinte a change (numero de
processus recycle par un autre programme) ou si le pid n'a jamais ete enregistre. Le pid ne
peut plus etre modifie par un PUT. Chaque signal envoye est journalise.ProtectSystem=strict, ProtectHome=read-only avec le seul etat
en ecriture, PrivateTmp, SystemCallFilter=@system-service, CapabilityBoundingSet= vide,
UMask=0077. Verifiable avec systemd-analyze security tracking-api.service.lyra-daemon garde un sudo NOPASSWD pour piloter la machine (services,
VMs, audio). Ce n'est pas le tracking qui l'accorde, et le durcir releve du projet Lyra ; tant
que ce daemon existe, un attaquant qui obtiendrait l'execution de code sous cet utilisateur
disposerait de ce pouvoir, independamment des protections ci-dessus.127.0.0.1:5678 dans docker-compose.ymldv_webhook_server.py ecoute sur 0.0.0.0:8787 (necessaire pour recevoir les webhooks Docker) -- proteger ce port avec un firewall si la machine est exposeeNoNewPrivileges=truepoller.py lit $CREDENTIALS_DIRECTORY (service user) ou dechiffre credentials/*.cred via systemd-creds decrypt --user (service systeme), avec repli sur les variables QBT_PASSWORD / BAZARR_KEY pour le debugtemplates.py et ajouter une entree dans TEMPLATES :_sim_mon_template() dans sim.py.Le template est immediatement disponible sans autre modification.
Sans toucher au code, un template peut aussi etre declare dans ~/.config/tracking/templates.json
(meme structure, cle = nom du template) ; il est charge au demarrage.
La fixture autouse de conftest.py redirige la persistence vers un tmp_path : les tests ne
touchent jamais l'etat de production.
| Dépôt | Rôle |
|---|---|
| lyra | French-first voice assistant : assistant DevOps vocal, local par défaut (AGPL-3.0) ; le français familier est compris par des règles avant même d'appeler un modèle, ce qui lui suffit d'un modèle de 0.5B |
| fedora-agents | MCP : machines virtuelles KVM et sauvegardes |
| mcp-tracking | MCP + API + tableau de bord des tâches longues |
| neutroncore | hub PWA du homelab |
| hue-mcp | MCP Philips Hue (fork de ThomasRohde/hue-mcp) |
| pylips-mcp | MCP TV Philips |
| denon-mcp | MCP ampli Denon |
| catt-mcp | MCP Chromecast et DLNA |