Baikal MCP pour la gestion des agendas perso et NEXTE et de l'observatoire des tâches
1-l'infrastructure Baikal et Infcloud sur le vps personnel - juxjux.ovh
Cas à part de la gestion des contacts et du calendrier -
Non pas sur alteris.ovh mais sur juxjux.ovh car primauté de l'infrastructure personnelle de JUlien pour la gestion des agendas et des contacts.
la solution contacts et calendrier
Solution d'unification des contacts et du calendrier de Julien.
État au 3 août 2026 — déployé et opérationnel de bout en bout. Seul vdirsyncer (agrégation Google/Infomaniak) reste à faire.
1. Objectif
Unifier la base de contacts et de calendriers, dispersée entre plusieurs sources (Google, Infomaniak, téléphone), autour d'un point central auto-hébergé sur le VPS juxjux.ovh, synchronisé vers tous les clients existants.
Baïkal est la source de vérité unique. Roundcube, InfCloud et DAVx5 en sont des clients ; vdirsyncer sera le seul composant qui écrit depuis l'extérieur vers Baïkal.
2. Architecture réellement déployée
| Composant | Rôle | Emplacement | État |
|---|---|---|---|
| Baïkal | Serveur CardDAV + CalDAV, stockage central | Docker, VPS juxjux | En service |
| InfCloud | Agenda et contacts web | Statique, servi par nginx | En service |
| Roundcube | Interface web des contacts | Docker, VPS juxjux | En service |
| Nginx | Reverse proxy HTTPS | Hôte VPS | En service |
| DAVx5 | Pont de synchronisation vers Android | Téléphone | Opérationnel |
| Fossify Agenda | Client calendrier | Téléphone (via DAVx5) | Opérationnel |
| vdirsyncer | Agrège Google et Infomaniak vers Baïkal | VPS, cron | Non déployé |
| Thunderbird | Client mail, indépendant de ce circuit | Téléphone | Inchangé |
3. Accès
| Service | URL | Identifiant |
|---|---|---|
| Agenda + contacts web | https://baikal.juxjux.ovh/infcloud/ | Julien (compte Baïkal) |
| Contacts web (Roundcube) | https://secretariat.juxjux.ovh | julien.bertrand@ik.me (compte mail Infomaniak) |
| Administration Baïkal | https://baikal.juxjux.ovh/admin/ | compte admin Baïkal |
| Découverte DAV (DAVx5) | https://baikal.juxjux.ovh/dav.php/ |
Julien |
Utilisateur Baïkal : Julien — avec un J majuscule. La casse compte dans les URLs DAV.
- Principal :
https://baikal.juxjux.ovh/dav.php/principals/Julien/ - Contacts :
https://baikal.juxjux.ovh/dav.php/addressbooks/Julien/default/ - Calendrier :
https://baikal.juxjux.ovh/dav.php/calendars/Julien/default/
Certificats Let's Encrypt valides jusqu'au 1er novembre 2026 pour les deux domaines. Celui de baikal.juxjux.ovh existait déjà mais avait expiré le 8 février 2026 (vestige d'une tentative antérieure) ; il a été renouvelé le 3 août.
4. Déploiement
Stack sur le VPS : /home/debian/baikal/docker-compose.yml, projet compose baikal. Sources versionnées : Syncthing/Jux_univers/Jux-scripts/Baikal-Contacts/.
| Fichier | Rôle |
|---|---|
docker-compose.yml |
Stack Baïkal + Roundcube |
baikal.juxjux.ovh.conf |
Vhost Baïkal (.well-known forcés en HTTPS + service d'InfCloud) |
secretariat.juxjux.ovh.conf |
Vhost Roundcube |
infcloud-config.js |
Configuration InfCloud |
finaliser_tls.sh |
Vérifie le DNS puis lance certbot |
vps_backup.sh |
Script de sauvegarde complet, Baïkal inclus |
push_bookstack.py |
Publication de cette page via l'API BookStack |
| Service | Image | Port local | Base | RAM |
|---|---|---|---|---|
| baikal | ckulka/baikal:nginx |
127.0.0.1:8088 | SQLite | ~38 Mo |
| roundcube | roundcube/roundcubemail:latest (1.7.2) |
127.0.0.1:8083 | SQLite | ~32 Mo |
| InfCloud | fichiers statiques (13 Mo sur disque) | — | aucune | 0 |
Les deux containers pèsent environ 70 Mo au total, contre environ 600 Mo avec l'architecture MariaDB initialement prévue. Ce choix était important : le VPS était en pression mémoire au moment du déploiement (swap à 3,8/4,0 Go).
5. Écarts avec le plan initial
Le plan préparé prévoyait une configuration qui ne pouvait pas fonctionner en l'état. Écarts constatés et corrigés :
| Point | Prévu | Réel | Raison |
|---|---|---|---|
| Port Baïkal | 8081 | 8088 | 8081 est occupé par FreshRSS. 8088 correspond au vhost baikal.juxjux.ovh préexistant |
| Port Roundcube | 8082 | 8083 | 8082 est ciblé par un vhost nextcloud mort |
| Domaine Roundcube | mail.juxjux.ovh |
secretariat.juxjux.ovh |
Aucun DNS n'existait ; mail. prêtait à confusion avec les MX OVH du domaine |
| Base Roundcube | MariaDB | SQLite | ~400 Mo de RAM économisés, suffisant en mono-utilisateur |
| Vhost Baïkal | À créer | Déjà présent | Le fichier baikal.conf préparé n'a pas servi |
| Agenda web | Plugin calendar Roundcube | InfCloud | Plugin inutilisable, voir §6.2 |
6. Pièges rencontrés
6.1 Les plugins carddav et calendar ne sont pas dans l'image Roundcube
L'image officielle ne fournit ni carddav ni calendar. Les déclarer dans ROUNDCUBEMAIL_PLUGINS ne fait que les activer — s'ils sont absents, Roundcube part en erreur fatale.
Il faut les faire installer par composer au démarrage, via ROUNDCUBEMAIL_COMPOSER_PLUGINS (et non ROUNDCUBEMAIL_INSTALL_PLUGINS, qui n'existe pas dans cette image) :
Le premier démarrage est alors plus long (téléchargement composer).
6.2 Le plugin calendar de Roundcube est une impasse
Trois obstacles successifs, testés le 3 août :
a) Il casse le tout premier démarrage. Le script d'initialisation de base de kolab/calendar s'exécute avant que l'entrypoint n'écrive la configuration Roundcube : il tombe sur le DSN MySQL par défaut et échoue en SQLSTATE[HY000] [2002] No such file or directory. Cette erreur fatale empêche la régénération de l'autoloader composer, ce qui casse aussi le plugin carddav :
Symptôme : HTTP 500 permanent, alors que les fichiers du plugin sont bien présents sur le disque — c'est vendor/composer/autoload_psr4.php qui ne contient aucune entrée carddav.
b) Ce premier obstacle est contournable. Réinstallé après que Roundcube ait été initialisé une première fois, la configuration existe déjà dans le volume et l'initialisation aboutit (Creating database schema... [OK]). Vérifié.
c) Mais le plugin ne sait pas parler à Baïkal. La seule version installable, kolab/calendar 3.2.9.1, ne livre que les pilotes database, kolab et ldap — aucun pilote caldav. Il ne créerait qu'un agenda local dans Roundcube, sans lien avec Baïkal ni le téléphone : pire qu'inutile, on pourrait y saisir des rendez-vous en croyant qu'ils se synchronisent.
Les versions qui embarquent le pilote CalDAV (3.5.7, 3.6.1) dépendent de kolab/libkolab, qui réclame pear/http_request2 — paquet bloqué par composer pour faille de sécurité (PKSA-jrt3-xndd-g4sz). Ne pas contourner ce garde-fou sur un service exposé sur internet.
Conclusion : agenda web assuré par InfCloud (§7), plugin calendar définitivement écarté.
6.3 Baïkal ignore X-Forwarded-Proto — fuite HTTP sur la découverte
Baïkal ne tient pas compte de X-Forwarded-Proto et générait ses redirections de découverte en HTTP nu :
C'est exactement le risque identifié dès la conception : CardDAV et CalDAV envoient les identifiants à chaque synchronisation. Un client suivant cette redirection part sur du HTTP.
Corrigé en court-circuitant Baïkal directement dans le vhost :
À vérifier après tout reload nginx : le rechargement n'est pas instantané, un test lancé dans la foulée peut encore montrer l'ancien comportement.
6.4 Roundcube exige un serveur IMAP pour authentifier
Roundcube n'a pas de base d'utilisateurs propre : son écran de login valide les identifiants contre le serveur IMAP configuré. Sans IMAP joignable, aucune connexion n'est possible — donc aucun accès aux contacts non plus.
L'idée d'un Roundcube « contacts et agenda seulement, sans IMAP » n'est pas réalisable. La configuration retenue pointe vers ssl://mail.infomaniak.com:993, ce qui couvre le compte julien.bertrand@ik.me (le domaine ik.me est servi par l'infrastructure Infomaniak).
Si un jour le compte passe en double authentification, il faudra générer un mot de passe d'application Infomaniak.
6.5 Baïkal doit être installé en SQLite
L'installeur Baïkal propose MySQL ou SQLite. Choisir SQLite : la stack ne contient aucun serveur MySQL, cocher « Enable MySQL » mène à une impasse. Base à /var/www/baikal/Specific/db/db.sqlite, dans le volume baikal-data.
7. InfCloud — l'agenda web
Client CalDAV/CardDAV entièrement côté navigateur : aucun backend, aucune base, du HTML/JS servi en statique par nginx. Affiche agenda et contacts.
- Source officielle :
https://www.inf-it.com/InfCloud_0.13.1.zip(3,9 Mo, sha2569fa95edd2dcc2b864a10b503ab9220895ea28d4c5541ab02117de1511d5464d4) - Installé dans
/home/debian/baikal/infcloud, propriétairewww-data - Servi sur le même domaine que Baïkal (
/infcloud/) et non sur un sous-domaine dédié : InfCloud interroge/dav.php/en direct depuis le navigateur ; depuis une autre origine il aurait fallu ouvrir du CORS sur les méthodes DAV de Baïkal, ce qui est fragile et l'affaiblirait. Même origine = aucun CORS. - Dossier
auth/supprimé : module PHP d'authentification par proxy inutilisé ici. nginx ne traite pas le PHP à cet emplacement — servis en statique, ces fichiers.incauraient exposé leur contenu en clair.
Réserve assumée : projet figé depuis 2015, interface datée, embarque jQuery 2.1.4. Acceptable parce qu'il n'a aucun composant serveur : rien à maintenir, rien à patcher. La seule alternative maintenue serait SOGo, au prix d'environ 500 Mo de RAM et d'une base PostgreSQL.
7.1 Les trois pièges d'InfCloud
a) Le bloc regex du vhost avale tous les JS. Le vhost Baïkal contient déjà :
En nginx, un bloc regex ~* a priorité sur un bloc préfixe ordinaire. Tous les fichiers JavaScript d'InfCloud auraient donc été proxifiés vers Baïkal. Comme InfCloud est presque intégralement du JavaScript, la page serait restée blanche — symptôme difficile à diagnostiquer. Il faut ^~, qui passe devant les regex :
b) L'endpoint par défaut vise DAViCal. Le config.js livré pointe /caldav.php/ ; Baïkal expose /dav.php/.
c) Le href doit viser les principals, pas la racine DAV. InfCloud accole le nom d'utilisateur au href. Avec /dav.php/ il demandait /dav.php/Julien/ → 404. La documentation du fichier le précise : « globalNetworkCheckSettings : principal URL WITHOUT the USER/ part ». Chez Baïkal, la bonne valeur est donc :
Après toute modification de config.js, rechargement forcé du navigateur (Ctrl+Maj+R) : le fichier est mis en cache.
7.2 Digest → Basic : le blocage d'authentification
Baïkal était configuré en dav_auth_type: Digest et annonçait WWW-Authenticate: Digest realm="BaikalDAV".
InfCloud ne sait faire que du Basic. Ses requêtes partaient donc en 401 en boucle, alors que DAVx5 — qui gère Digest — fonctionnait parfaitement avec le même compte. Le symptôme prêtait à confusion : les identifiants étaient bons.
Diagnostic par les logs nginx, où le champ utilisateur est renseigné mais la réponse reste 401 :
Correctif : dav_auth_type: Basic dans /var/www/baikal/config/baikal.yaml, puis docker restart baikal.
Ce n'est pas un pis-aller. Digest repose sur MD5, est considéré comme obsolète, et impose au serveur de stocker une empreinte exploitable ; Basic sur TLS est aujourd'hui la recommandation, et tout est en HTTPS ici, y compris les redirections de découverte (§6.3).
Les mots de passe restent valides : Baïkal calcule la même empreinte md5(username:auth_realm:password) dans les deux modes (Baikal\Core\PDOBasicAuth::validateUserPass), avec auth_realm: BaikalDAV conservé en interne — même si le serveur annonce désormais realm="sabre/dav" côté client. Rien à redéfinir, DAVx5 bascule tout seul.
Sauvegarde : /var/www/baikal/config/baikal.yaml.bak-260803-digest (dans le container).
8. Sauvegarde
Baïkal a été ajouté à /opt/backups/vps_backup.sh le 3 août 2026 (cron quotidien à 2h UTC).
- Dossier kDrive de destination : 1467771 (
SYNC-pour_VPS/backups/baikal) - Le bilan de fin de log passe de 5 à 6 services (le total est calculé dynamiquement, pas codé en dur)
- Sauvegarde de l'ancien script :
/opt/backups/vps_backup.sh.bak-260803
La fonction archive deux volumes, via un tar intermédiaire puis 7z :
Specific/— la basedb.sqlite(contacts et calendriers)config/—baikal.yaml(paramètres et empreinte du mot de passe admin)
Sans le second, la restauration est incomplète. Testée le 3 août : upload HTTP 200, aucun résidu temporaire.
InfCloud n'a pas besoin d'être sauvegardé (fichiers statiques réinstallables), mais son config.js est versionné dans Jux-scripts/Baikal-Contacts/.
9. Vérifications effectuées le 3 août 2026
| Test | Résultat |
|---|---|
GET /dav.php/ |
HTTP 401 — authentification bien exigée |
PROPFIND /dav.php/ |
HTTP 401 et non 405 — nginx laisse passer les méthodes DAV étendues |
.well-known/carddav et caldav |
301 vers HTTPS |
| Installation Baïkal | Utilisateur Julien, carnet et calendrier default créés |
| Login Roundcube | IMAP Infomaniak accepté |
| Découverte CardDAV Roundcube | Carnet résolu à .../dav.php/addressbooks/Julien/default/ |
| Écriture d'un contact | vCard 3.0 écrite par RCMCardDAV v5.1.3, relue dans Baïkal, accents UTF-8 préservés |
| Synchronisation DAVx5 | 5 rendez-vous d'août écrits dans Baïkal par DAVx5/4.5.18-ose, synctoken du calendrier à 6 |
| InfCloud | 32 ressources servies en 200 ; PROPFIND sur principals, addressbooks et calendars tous en 207 |
| Dotfiles InfCloud | .htaccess bloqué en 403 |
| Sauvegarde Baïkal | Archive uploadée sur kDrive, HTTP 200 |
Note : dans la table carddav_addressbooks de Roundcube, une seconde ligne nommée %N avec une URL vide n'est pas une erreur — c'est le template de rcmcarddav v5, qui porte les réglages appliqués aux carnets découverts.
10. Reste à faire
10.1 vdirsyncer — agrégation Google et Infomaniak
Seule brique du plan initial encore absente. Objectif : faire remonter dans Baïkal les contacts existants sur Google et Infomaniak, pour que Baïkal devienne le point central réel et pas un silo de plus.
- Google Contacts : CardDAV via
https://www.google.com/carddav/v1/principals/EMAIL/— nécessite un mot de passe d'application (compte en 2FA) - Infomaniak : CardDAV natif, identifiants standards du compte mail
- vdirsyncer : outil CLI léger, une paire de synchronisation par source, exécuté par cron sur le VPS
Décision à prendre avant déploiement :
- one-way (Google/Infomaniak → Baïkal, lecture seule) : sans risque, mais les modifications faites dans Baïkal ne remontent pas vers Google
- two-way : tout reste aligné, mais un conflit ou une erreur de configuration peut propager des suppressions dans les deux sens
Recommandation : démarrer en one-way le temps de vérifier que l'import est fidèle, puis basculer si besoin.
10.2 Nettoyage
Quatre vhosts morts traînent dans /etc/nginx/sites-enabled/, vestiges des tentatives précédentes : radicale, agendav, infcloud, nextcloud. Le dernier cible le port 8082, ce qui a contraint le choix du port de Roundcube. Attention : le vhost nommé radicale.juxjux.ovh sert en réalité Readeck — ne pas le supprimer sans vérifier.
11. Checklist sécurité
- Aucun mot de passe
CHANGE_ME_...en production — la bascule vers SQLite a supprimé les identifiants MariaDB du compose - HTTPS forcé sur les deux vhosts (redirection 80 vers 443)
- Certificats Let's Encrypt valides, renouvellement automatique certbot en place
- Découverte DAV forcée en HTTPS (§6.3)
- Authentification Basic uniquement sur TLS (§7.2)
- Les deux containers n'écoutent que sur
127.0.0.1— seul nginx les expose - Module PHP
auth/d'InfCloud supprimé, dotfiles bloqués - Sauvegarde quotidienne des volumes Baïkal vers kDrive
- Mot de passe d'application dédié pour l'accès CardDAV Google — à faire au moment de vdirsyncer
12. Commandes utiles
13. Choix d'architecture — pourquoi ces outils
Radicale écarté : stockage fichier brut, pas de vraie gestion. La stack Radicale/InfCloud initialement envisagée n'a pas été mise en place — seul InfCloud a finalement été retenu, en client de Baïkal.
Nextcloud écarté : trop lourd pour l'usage visé (PHP-FPM + base + Redis + écosystème complet), alors que le VPS fait déjà tourner PostGIS, Metabase, BookStack, FreshRSS.
Baïkal retenu : léger, CardDAV et CalDAV natifs, interface d'administration suffisante. Développé par des bénévoles sous l'organisation sabre-io (mainteneurs de SabreDAV, la librairie sous-jacente) — pas de société commerciale derrière, mais communauté active et outil robuste pour un usage personnel sur la durée.
Roundcube retenu comme interface de saisie des contacts, Baïkal n'ayant pas de vraie UI de consultation : léger, traduit en français, projet actif (version 1.7.2 en août 2026). A rejoint la famille Nextcloud en 2023 tout en restant indépendant, sous licence GPL. Réserves constatées à l'usage : il impose une authentification IMAP (§6.4) et ne couvre pas l'agenda (§6.2).
InfCloud retenu pour l'agenda web : sans backend, donc sans coût mémoire ni surface d'attaque serveur, et couvre agenda et contacts. Ancien mais fonctionnel.
SOGo envisagé et écarté : suite complète et maintenue, mais environ 500 Mo de RAM et une base PostgreSQL sur un VPS déjà en pression mémoire, et il aurait fait doublon avec Roundcube.
Thunderbird containerisé (VNC/noVNC) envisagé puis écarté : fonctionnel mais plus lourd et moins adapté au multi-accès qu'un vrai webmail.
2-MCP CalDAV pour Claude Code — un agenda Baïkal partagé par les deux PC
MCP CalDAV pour Claude Code
État au 15 septembre 2026 — opérationnel sur le PC NEXTE. Cycle complet validé : création de calendrier, écriture d'un événement, relecture, visibilité sur le téléphone (DAVx5 → Fossify) et dans InfCloud, suppression. Installation sur le PC perso à faire (§7).
Prérequis : l'infrastructure Baïkal décrite en page 1 de ce chapitre (Baïkal en Docker sur juxjux.ovh, Basic auth sur TLS, utilisateur DAV Julien).
1. Décision d'architecture
Un seul Baïkal, sur juxjux.ovh, partagé par les deux Claude Code (PC perso et PC NEXTE). C'est la seule exception assumée à l'étanchéité entre l'univers Jux et l'univers Alteris/NEXTE.
Pourquoi ne pas dupliquer Baïkal sur le VPS Alteris :
Pourquoi l'exception est acceptable : l'étanchéité protège les fichiers et données de mission. Un agenda n'est pas une donnée de mission, c'est un service de la personne, comme le téléphone. Le PC NEXTE devient un client CalDAV de plus, au même titre que DAVx5 ; aucune donnée Jux n'entre sur NEXTE, aucune donnée Alteris ne sort vers juxjux. Seul l'identifiant Baïkal traverse — il est dans le Vault 2603.
2. Modèle : un utilisateur, deux calendriers
Default calendar
https://baikal.juxjux.ovh/dav.php/calendars/Julien/default/
Personnel (Julien)
(installeur)
PC perso
NEXTE
https://baikal.juxjux.ovh/dav.php/calendars/Julien/nexte/
Professionnel NEXTE (pas Alteris)
#1E88E5 bleu
PC NEXTE
Même compte Julien pour les deux, donc les deux calendriers apparaissent ensemble dans DAVx5, Fossify et InfCloud, chacun avec sa couleur.
Règle de lecture/écriture du MCP : chaque PC écrit dans son calendrier par défaut (CALDAV_DEFAULT_CALENDAR) mais lit les deux — sinon Claude placerait un rendez-vous pro sur un créneau perso. L'écriture dans l'autre calendrier reste possible en le nommant explicitement (calendar="Default calendar").
Le calendrier NEXTE a été créé le 15/09/2026 par le MCP lui-même (MKCALENDAR, outil create_calendar). Dans DAVx5, il faut ensuite rafraîchir la liste des calendriers du compte et le cocher pour qu'il se synchronise. Dans InfCloud, il faut l'inscrire dans les réglages stockés sur le serveur — voir §5.7, c'est désormais fait automatiquement par create_calendar.
3. Le serveur MCP
Aucun serveur MCP CalDAV communautaire mûr : serveur maison, ~400 lignes de Python.
C:\Users\nexte\Nexte Claude\MCP CalDAV\260915-mcp_caldav_server.py
Script autonome PEP 723 : dépendances déclarées en tête de fichier, résolues par uv run --script. Aucune installation Python système nécessaire (il n'y en a pas sur NEXTE, seulement celui de QGIS) — uv est déjà là pour le MCP QGIS.
Dépendances : mcp>=1.2,<2 (FastMCP), caldav (3.3 au 15/09), icalendar, python-dateutil.
Configuration par variables d'environnement, passées par claude mcp add -e :
CALDAV_URL
https://baikal.juxjux.ovh/dav.php/
racine DAV de Baïkal
CALDAV_USER
Julien
utilisateur DAV — J majuscule, la casse compte
CALDAV_PASSWORD
Vault 2603
mot de passe de l'utilisateur DAV (pas celui de l'admin Baïkal)
CALDAV_DEFAULT_CALENDAR
NEXTE
calendrier d'écriture par défaut (default sur le PC perso)
CALDAV_TZ
Europe/Paris (défaut)
fuseau des heures saisies sans fuseau, et fuseau posé sur les calendriers créés
Le script ne journalise jamais le mot de passe ; s'il manque, il le signale sur stderr sans en dire plus.
Outils exposés
list_calendars
calendriers du compte, avec marquage du calendrier par défaut
create_calendar(name, cal_id, color)
MKCALENDAR, puis pose calendar-color / calendar-order / calendar-timezone (palette par défaut) et inscrit le calendrier dans les réglages InfCloud (§5.7) ; refuse si le nom existe déjà
infcloud_sync_collections
inscrit dans les réglages InfCloud tous les calendriers du compte qui n'y figurent pas — pour un calendrier créé ailleurs (DAVx5, admin Baïkal)
list_events(start, end, calendar, all_calendars)
événements sur une période (défaut : aujourd'hui → +14 j), tous calendriers sauf si calendar est nommé ; occurrences récurrentes développées
search_events(text, calendar)
recherche plein texte (résumé, lieu, description), fenêtre −6/+12 mois
get_event(uid, calendar)
détail + iCalendar brut
create_event(summary, start, end, calendar, all_day, location, description, rrule)
end absent → +1 h (ou +1 jour en journée entière) ; heures sans fuseau = Europe/Paris ; dates ISO ou jj/mm/aaaa, heures 16:00 ou 16h00
update_event(uid, …)
ne modifie que les champs fournis ; incrémente SEQUENCE et LAST-MODIFIED
delete_event(uid, calendar)
suppression définitive — uniquement après confirmation explicite de Julien
free_slots(start, end, duration_minutes, day_start, day_end, weekdays_only)
créneaux libres tous calendriers confondus, dans la plage horaire quotidienne indiquée
4. Enregistrement dans Claude Code (PC NEXTE)
Portée utilisateur (-s user), comme le MCP QGIS. À lancer dans un terminal, en remplaçant <MDP> par le mot de passe de l'utilisateur DAV Julien (Vault 2603) :
Puis :
qui doit afficher caldav: … - ✔ Connected.
Pour refaire l'enregistrement (mot de passe changé, mauvais calendrier par défaut) : claude mcp remove -s user caldav puis la commande add.
Où va le secret : claude mcp add l'écrit en clair dans C:\Users\nexte\.claude.json — même niveau de protection que le MCP postgres. Le mot de passe reste archivé dans le Vault 2603 ; il n'a pas à figurer dans une conversation ni dans BookStack.
5. Pièges rencontrés le 15/09/2026
5.1 Les chevrons du gabarit ne font pas partie du mot de passe
Une commande donnée avec CALDAV_PASSWORD=<MDP> a été lancée telle quelle, puis avec <vrai-mdp> chevrons compris. Dans les deux cas Baïkal répond 401. Vérification sans afficher le secret : longueur de la valeur stockée, premier caractère, présence des caractères spéciaux attendus.
5.2 Mot de passe admin ≠ mot de passe utilisateur DAV
Baïkal a deux comptes distincts : l'admin (/admin/) et l'utilisateur DAV (Julien). Le premier essai a été fait avec le mot de passe admin → 401 systématique, avec Julien comme avec julien, alors que le serveur annonçait bien Basic realm="sabre/dav". Le bon mot de passe est celui saisi dans DAVx5 et InfCloud. Test de référence qui distingue « serveur joignable » de « identifiants acceptés » :
401 sans identifiants = normal ; 401 avec identifiants = mauvais couple utilisateur/mot de passe.
5.3 Caractères spéciaux dans PowerShell
Le mot de passe contient % et @ : passer la variable entre apostrophes simples ('CALDAV_PASSWORD=…'), pas entre guillemets. Vérifié : la valeur stockée est intacte.
5.4 SDK mcp 2.x
La 2.x du SDK Python a renommé FastMCP en MCPServer et cassé l'import mcp.server.fastmcp. Le script épingle mcp<2. À revoir si on migre un jour vers la 2.x.
5.5 Reprise de session ≠ nouvelle session
Un serveur MCP est chargé au démarrage de la session. Après claude mcp add, une session reprise dans l'app ne voit pas le nouveau serveur alors que claude mcp list le donne connecté. Il faut une nouvelle session. Entre-temps, le script peut être piloté directement (import du module + lecture de l'env dans .claude.json) — c'est ainsi que le calendrier NEXTE et l'événement test ont été créés.
5.6 Rappels de la page 1 qui s'appliquent au MCP
/dav.php/, pas /caldav.php/.
Julien en majuscule dans les URLs.
Basic sur TLS : la bibliothèque caldav gère la négociation 401 → Basic toute seule.
5.7 Un calendrier créé hors InfCloud n'apparaît jamais dans InfCloud
Symptôme : NEXTE visible dans DAVx5 et Fossify, mais absent d'InfCloud, même après déconnexion, Ctrl+Maj+R et reconnexion.
Fausse piste écartée en premier : le calendrier créé par MKCALENDAR nu n'avait ni calendar-color, ni calendar-order, ni calendar-timezone (404 sur ces trois propriétés, alors que le calendrier de l'installeur les a). Elles ont été posées par PROPPATCH — nécessaire pour l'homogénéité, mais insuffisant.
Cause réelle : config.js d'InfCloud a settingsAccount: true. InfCloud stocke alors ses réglages sur le serveur, dans la propriété {http://inf-it.com/ns/dav/}settings du principal (/dav.php/principals/Julien/), sous forme de JSON. Ce JSON contient loadedcalendarcollections et activecalendarcollections (idem pour les tâches), figés à la première session — donc réduits à default/. InfCloud ne charge que les collections de cette liste ; un nouveau calendrier n'y entre jamais tout seul.
Diagnostic (avec identifiants) :
puis lire loadedcalendarcollections dans le JSON retourné.
Correctif : relire le JSON, ajouter l'URL du calendrier aux quatre listes (loadedcalendarcollections, activecalendarcollections, loadedtodocollections, activetodocollections), réécrire la propriété par PROPPATCH, puis déconnexion/reconnexion InfCloud (les réglages sont lus au login). Sauvegarde du JSON d'origine : MCP CalDAV\260915-infcloud_settings_backup.json.
Depuis le 15/09, create_calendar fait tout cela d'emblée, et infcloud_sync_collections rattrape un calendrier créé ailleurs. Le config.js lui-même n'est pas en cause (additionalResources: [], pas de liste figée).
5.8 Le parseur de dates lisait 2026-10-02 comme le 10 février
dateutil.parser.parse(..., dayfirst=True) — voulu pour accepter 02/10/2026 — inverse aussi jour et mois d'une date ISO quand les deux valeurs sont ≤ 12 : 2026-10-02 devient le 10 février, 2026-10-09 le 10 septembre, 2026-10-12 le 10 décembre. 2026-10-13 passe, ce qui rend le bug intermittent et sournois.
Constaté lors du premier blocage de créneaux (6 dates, 3 fausses). Correctif dans _parse_dt : datetime.fromisoformat d'abord, dateutil en jour-premier seulement en repli ; 16h00 / 14h sont normalisés en 16:00 / 14:00. Les trois événements erronés ont été supprimés et recréés.
Règle : toujours relire les dates renvoyées par create_event (le résultat affiche start/end en ISO avec fuseau) avant d'annoncer qu'un créneau est bloqué.
6. Vérifications effectuées le 15/09/2026
PROPFIND /dav.php/ sans identifiants
401, Basic realm="sabre/dav"
list_calendars
Default calendar visible
create_calendar("NEXTE", cal_id="nexte")
créé, URL …/calendars/Julien/nexte/
list_events 14 jours, tous calendriers
1 événement perso lu
create_event dans NEXTE (16/09 10:00–10:30, Europe/Paris)
écrit, relu par get_event avec fuseau +02:00
Synchronisation DAVx5 → Fossify
événement visible sur le téléphone après avoir coché NEXTE
delete_event par UID
supprimé, calendrier NEXTE vide
PROPPATCH couleur/ordre/fuseau sur NEXTE
200, relu
Inscription de NEXTE dans les réglages InfCloud
200 ; NEXTE visible dans InfCloud après reconnexion
infcloud_sync_collections après correction
added: [] — idempotent
create_calendar("NEXTE") une seconde fois
refusé, « existe déjà »
claude mcp list
caldav … ✔ Connected
6 créneaux « Tourrettes PLU (validation en attente) » dans NEXTE (02→16/10)
créés, relus aux bonnes dates après correctif §5.8 ; aucun conflit perso
7. Installation sur le PC perso
Objectif : que le Claude Code du PC perso lise les deux calendriers et écrive dans l'un ou l'autre, avec le même serveur Baïkal et le même compte Julien. Aucune configuration côté Baïkal : le compte voit déjà les deux calendriers. Tout se passe sur le PC perso.
7.1 Copier le script
Source (PC NEXTE) : C:\Users\nexte\Nexte Claude\MCP CalDAV\260915-mcp_caldav_server.py — prendre la version courante, elle contient les correctifs du 15/09 (§5.7 InfCloud, §5.8 dates).
Destination recommandée : Syncthing/Jux_univers/Jux-scripts/Baikal-Contacts/260915-mcp_caldav_server.py, à côté d'infcloud-config.js — c'est le dossier où sont déjà versionnés les fichiers Baïkal (page 1, §4). Le script est autonome : un seul fichier, pas de dépendance à copier.
Point d'attention : le fichier ne doit pas être dans un coffre Cryptomator — un MCP se lance au démarrage de Claude Code, coffre fermé ou non (règle « aucun script ne dépend d'un coffre déverrouillé »).
7.2 Vérifier uv
Si absent :
puis rouvrir le terminal. uv télécharge lui-même un Python et les dépendances au premier lancement (~50 paquets, une dizaine de secondes) ; aucune installation Python système n'est nécessaire.
Repérer le chemin complet de uv.exe ((Get-Command uv).Source en PowerShell) — l'utiliser en absolu dans la commande d'enregistrement, comme sur NEXTE, évite les surprises de PATH au lancement par Claude Code.
7.3 Choisir le calendrier par défaut
CALDAV_DEFAULT_CALENDAR
Comportement
Recommandé
default
le PC perso écrit dans le calendrier perso sauf mention contraire ; symétrique de NEXTE sur le PC pro
Variante
NEXTE
le PC perso se comporte exactement comme le PC NEXTE
Dans les deux cas, la lecture porte sur les deux calendriers, et l'écriture dans l'autre calendrier reste possible en le nommant (« ajoute ça dans NEXTE »).
7.4 Enregistrer le MCP
Dans un terminal (PowerShell), en remplaçant <MDP> par le mot de passe de l'utilisateur DAV Julien (Vault 2603) et <chemin> par le dossier de destination :
Rappels des pièges §5 :
Julien, pas celui de l'admin Baïkal (§5.2) ;
sans chevrons autour de la valeur (§5.1) ;
apostrophes simples autour de CALDAV_PASSWORD=… à cause des % et @ (§5.3) ;
Julien avec un J majuscule (§5.6).
Vérifier :
→ caldav: … - ✔ Connected. Si Failed to connect : lancer à la main uv run --script "<chemin>\260915-mcp_caldav_server.py" dans le terminal pour voir l'erreur (dépendance, chemin, Python).
Pour corriger une valeur : claude mcp remove -s user caldav puis relancer la commande add.
7.5 Nouvelle session et test
list_calendars : les deux calendriers doivent apparaître, Default calendar marqué par défaut.
Écrire un événement test dans NEXTE (« crée un test demain 10 h dans NEXTE »), le vérifier sur le téléphone ou dans InfCloud, puis le faire supprimer.
7.6 Ce qui n'est PAS à faire
.claude.json du PC.
7.7 Entretien à deux PC
Le script existe en deux exemplaires (NEXTE et perso). Toute correction faite sur l'un doit être recopiée sur l'autre — c'est le prix d'un serveur maison hors dépôt. Convention : le fichier daté reste 260915-… tant que l'API des outils ne change pas ; une refonte produit un nouveau fichier daté et une mise à jour des deux enregistrements MCP.
8. Règles d'usage pour Claude
list_events sans calendar, ou free_slots).
Écrire dans le calendrier par défaut du PC ; n'écrire dans l'autre que sur demande explicite.
Ne jamais appeler delete_event sans confirmation explicite de Julien dans la conversation.
Ne jamais afficher, journaliser ni répéter CALDAV_PASSWORD ; diagnostiquer sur les longueurs et les codes HTTP.
Si un calendrier manque dans InfCloud : infcloud_sync_collections, puis déconnexion/reconnexion — avant toute autre hypothèse.
Relire les dates renvoyées par create_event avant d'annoncer un créneau bloqué (§5.8).
3 - gestionnaires de tâches - Tasks.org sur Baikal - Infcloud et DAVx5
Gestionnaire de tâches — Tasks.org sur Baïkal, InfCloud et DAVx5
État au 15 septembre 2026 — opérationnel de bout en bout. Cycle validé dans les deux sens : une tâche créée par le MCP est apparue dans Tasks.org, y a été cochée, et le MCP l'a relue COMPLETED ; une tâche saisie dans Tasks.org a été lue par le MCP ; les deux sont visibles dans InfCloud (§6).
Décision : on valorise au maximum l'existant — Baïkal, InfCloud, DAVx5. Les tâches vivent dans les mêmes collections que les événements, aucun composant serveur n'est ajouté. Seul ajout : Tasks.org sur le téléphone, comme écran des tâches que DAVx5 lui dépose.
1. Ce que l'existant sait déjà faire
VTODO)
Constat
Baïkal
oui, nativement
les deux collections default/ et nexte/ annoncent VEVENT et VTODO (vérifié par PROPFIND supported-calendar-component-set)
InfCloud
oui, onglet Tâches
les réglages serveur contiennent déjà loadedtodocollections / activetodocollections avec les deux calendriers (page 2, §5.7)
DAVx5
oui, synchronise les VTODO
mais Android n'a pas de fournisseur de tâches natif : DAVx5 ne peut les déposer que dans une appli tierce — Tasks.org, jtx Board ou OpenTasks. Sans elle, l'option « Tâches » n'apparaît même pas dans le compte
MCP CalDAV
oui depuis le 15/09
7 outils *_task ajoutés au script (§3)
2. Choix du client Android
Fossify Calendar — écarté
La fonction « Tâche » de Fossify est locale : c'est un événement d'un type particulier dans sa propre base, jamais écrit en VTODO, jamais synchronisé (héritage de Simple Calendar, dont la synchro CalDAV ne couvre que les événements). Une tâche saisie là n'atteint ni Baïkal, ni InfCloud, ni le MCP — et on croirait qu'elle est synchronisée. Même famille de piège que le plugin calendar de Roundcube (page 1, §6.2).
Fossify reste le client événements ; il n'affiche pas les tâches — chaque appli dans son rôle.
Tasks.org (F-Droid, 15.x) — retenu
VTODO complet : échéance, priorité, récurrence, rappels, sous-tâches, étiquettes ; CalDAV direct ou via DAVx5
deux chemins possibles → en choisir un seul (§4)
Fonctionnel
vraie appli de tâches : listes = collections CalDAV, filtres, widgets, tri par échéance
plus riche que nécessaire pour un usage simple — d'où le §5
Projet
actif, GPL, version F-Droid sans services Google
pas de synchro Google Tasks sur F-Droid — sans importance ici
Cohérence
les tâches apparaissent dans InfCloud et sont lisibles/écrites par le MCP
—
Alternative connue : jtx Board (bitfire, même éditeur que DAVx5) — tâches + journaux (VJOURNAL), intégration DAVx5 très propre, mais moins de fonctions de gestion de tâches. À garder en tête si les notes datées deviennent un besoin ; Baïkal gère VJOURNAL.
Branchement : via DAVx5, pas en CalDAV direct
Tasks.org sait parler CalDAV tout seul, mais on le branche comme fournisseur de tâches de DAVx5 : un seul compte Baïkal sur le téléphone, une seule planification de synchro, un seul mot de passe stocké. DAVx5 détecte Tasks.org à l'installation et fait apparaître « Tâches » dans le compte. Rien à saisir dans Tasks.org : ni compte, ni URL, ni mot de passe.
Emplacement des tâches : dans les calendriers existants
Pas de collection dédiée aux tâches. La séparation perso/pro est portée par la collection (Default calendar / NEXTE), InfCloud est déjà configuré ainsi, et Tasks.org montre deux listes portant ces noms. L'échéance d'une tâche reste visible à côté des rendez-vous dans InfCloud.
3. Outils tâches du MCP CalDAV
Ajoutés le 15/09/2026 au script 260915-mcp_caldav_server.py (page 2, §3). Même mécanique que les événements : écriture dans le calendrier par défaut du PC, lecture des deux.
list_tasks(calendar, include_completed, due_before)
tâches ouvertes de tous les calendriers (ou d'un seul) ; include_completed ajoute terminées/annulées ; due_before filtre sur l'échéance ; tri échéance puis priorité
get_task(uid, calendar)
détail + iCalendar brut
create_task(summary, due, calendar, priority, description, start, categories, rrule)
due = date seule (journée) ou date-heure (Europe/Paris) ; priority 0 aucune / 1 haute / 5 moyenne / 9 basse (convention Tasks.org) ; rrule ex. FREQ=WEEKLY;BYDAY=MO
update_task(uid, …)
ne modifie que les champs fournis ; due="" retire l'échéance ; status ∈ NEEDS-ACTION / IN-PROCESS / COMPLETED / CANCELLED ; percent_complete
complete_task(uid, calendar)
STATUS COMPLETED, COMPLETED = maintenant, 100 % ; une tâche récurrente est close pour l'occurrence courante et la suivante est générée
reopen_task(uid, calendar)
retour à NEEDS-ACTION, COMPLETED et pourcentage retirés
delete_task(uid, calendar)
suppression définitive — uniquement après confirmation explicite de Julien
Champs renvoyés : calendar, uid, summary, status, due, start, priority, percent_complete, completed, description, categories, rrule, last_modified.
4. Configuration du téléphone — faite le 15/09
NEXTE et Default calendar (DAVx5 récent les montre dans le même onglet, avec une icône différente — il faut cocher les deux entrées de chaque collection).
Tasks.org → Paramètres → Synchronisation : le compte « DAVx5 » est actif. Aucun compte CalDAV ajouté dans Tasks.org lui-même — ce serait le second chemin de synchro qu'on a écarté.
5. Utiliser Tasks.org au quotidien
Tasks.org intimide parce qu'il s'ouvre sur un filtre (« Ma journée » ou « Boîte de réception »), pas sur les listes. Une tâche due demain n'y apparaît pas ; il faut aller la chercher dans sa liste ou dans « Toutes les tâches ». Le vocabulaire à connaître :
5.1 Listes et filtres
NEXTE et Default calendar
menu ≡ (icône en bas à gauche, ou balayage depuis le bord gauche), bloc au nom du compte DAVx5
Filtre
une vue transversale sur toutes les listes
menu ≡, en haut
« Toutes les tâches »
l'ensemble des tâches ouvertes, perso + pro, dans une seule vue — la vue du quotidien
filtre
« Ma journée »
échues aujourd'hui ou en retard, tous calendriers — l'équivalent de list_tasks(due_before=aujourd'hui)
filtre
« Récemment modifiées »
ce qui a bougé, utile après une synchro
filtre
Filtre personnalisé
composition de critères : listes, étiquettes, priorité, échéance (« cette semaine »), état
menu ≡ → Filtres → + ; devient une entrée du menu
Widget
un widget d'écran d'accueil par liste ou par filtre — « Toutes les tâches » en widget montre donc les deux calendriers
appui long sur l'écran d'accueil
Pour distinguer perso et pro dans la vue commune : Paramètres → Apparence → regrouper par liste (ou afficher le nom de la liste sous chaque tâche), et une couleur par liste (appui long sur la liste → couleur), affichée en pastille. La couleur est locale à Tasks.org ; celle d'InfCloud est la calendar-color de la collection (page 2, §5.7).
5.2 Le déclenchement — quand une tâche se rappelle à toi
C'est la partie à comprendre avant de s'en remettre à l'appli :
DUE;VALUE=DATE)
à l'heure d'échéance par défaut de Tasks.org (Paramètres → Échéances / Notifications → « heure par défaut », à régler — souvent 18 h d'origine)
Échéance date + heure
à cette heure, si le rappel « à l'échéance » est actif dans les réglages de la tâche (il l'est par défaut pour les tâches créées dans Tasks.org ; pour une tâche créée par le MCP, voir §7.3)
Rappels supplémentaires (dans la tâche → Rappels)
« au début », « à l'échéance », « aléatoire », « personnalisé » (x heures/jours avant ou après), et « quand dépassée » qui relance périodiquement tant que la tâche n'est pas cochée
Tâche cochée
plus aucune notification, elle passe dans les terminées (masquées ou non selon Paramètres → Apparence → « afficher les terminées »)
Une notification peut être reportée (snooze) depuis la notification elle-même. Les rappels sont écrits en VALARM dans le VTODO et donc synchronisés vers Baïkal ; InfCloud les affiche, le MCP les lit dans get_task (iCalendar brut) mais ne les crée pas encore.
5.3 Ce que porte une tâche, et sa correspondance CalDAV
VTODO
Vu par le MCP
Titre
SUMMARY
summary
Échéance (date, ou date + heure)
DUE
due
Date de début (« masquer jusqu'à »)
DTSTART
start
Priorité (aucune / basse / moyenne / haute)
PRIORITY 0 / 9 / 5 / 1
priority
Notes
DESCRIPTION
description
Étiquettes (tags)
CATEGORIES
categories
Répétition
RRULE
rrule
Sous-tâches
RELATED-TO (tâche parente)
non exposé — à ajouter si l'usage vient
Rappels
VALARM
iCalendar brut seulement
Coché
STATUS:COMPLETED + COMPLETED + PERCENT-COMPLETE:100
status, completed, percent_complete
Pièces jointes, lieux, minuteur
locaux, jamais synchronisés
—
Piège constaté : une tâche saisie dans Tasks.org sans toucher à la priorité arrive avec PRIORITY:9 (basse), pas 0. Ne pas lire « basse » comme un choix de Julien.
5.4 Trois gestes utiles
Default calendar pour que le perso soit le réflexe et que NEXTE soit un choix).
Forcer la synchro : balayage vers le bas dans une liste, ou DAVx5 → Synchroniser maintenant. Sinon, périodicité DAVx5 (120 s dans InfCloud, celle de DAVx5 pour le téléphone).
6. Vérifications effectuées le 15/09/2026
6.1 MCP → Baïkal (script seul)
supported-calendar-component-set sur default/ et nexte/
VEVENT, VTODO sur les deux
create_task échéance 18/09/2026, priorité 1, catégorie
créée dans NEXTE, DUE;VALUE=DATE
create_task échéance 2026-09-20 17h00, priorité 5
créée, DUE horodaté +02:00
list_tasks(calendar="NEXTE")
les deux, triées par échéance
list_tasks(due_before="19/09/2026")
une seule (la première)
update_task IN-PROCESS, 50 %, échéance décalée au 19/09
relu conforme
complete_task
COMPLETED, 100 %, horodatage COMPLETED posé
list_tasks sans / avec include_completed
0 / 1
reopen_task
NEEDS-ACTION, 0 %, COMPLETED retiré
update_event (régression §7.1)
description posée sur un créneau Tourrettes, date inchangée
delete_task ×2
NEXTE vide
claude mcp list après modification
caldav … ✔ Connected
6.2 Bout en bout, avec le téléphone
create_task « TEST MCP → Tasks.org », échéance 16/09, priorité 5, dans NEXTE
créée
Synchro DAVx5 → Tasks.org, liste NEXTE
visible, avec échéance et priorité
Cochée dans Tasks.org, synchro
list_tasks(include_completed=True) : COMPLETED 100 %, completed 15/09 17:02
Tâche « reprendre des fruits » saisie dans Tasks.org (liste NEXTE)
lue par le MCP : NEEDS-ACTION, sans échéance, PRIORITY:9
InfCloud → onglet Tâches
les deux visibles
Les deux tâches sont laissées en place à la demande de Julien, pour observer le comportement des rappels (§5.2).
7. Pièges rencontrés le 15/09/2026
7.1 icalendar.walk() renvoie une liste
Avec icalendar 6, Calendar.walk("VTODO") renvoie une liste, pas un itérateur : next(ic.walk(...)) échoue en TypeError. Le même code dormait dans update_event depuis la création du script — jamais exercé jusque-là. Corrigé aux deux endroits (ic.walk(...)[0]).
7.2 Todo.complete() ne pose pas le pourcentage
La bibliothèque caldav pose STATUS:COMPLETED et COMPLETED:<horodatage> mais laisse PERCENT-COMPLETE à sa valeur précédente (50 % dans le test). Certains clients affichent alors une tâche « terminée à 50 % ». complete_task force 100 %.
7.3 Une tâche créée par le MCP n'a pas de rappel
Le MCP écrit DUE mais aucun VALARM. Dans Tasks.org, la tâche a une échéance mais son rappel « à l'échéance » dépend du réglage par défaut de l'appli pour les tâches importées (Paramètres → Notifications). Si Julien veut être notifié des tâches créées depuis Claude, deux options : régler Tasks.org pour appliquer les rappels par défaut aux nouvelles tâches synchronisées, ou ajouter un VALARM côté MCP (paramètre reminder sur create_task). À trancher à l'usage.
7.4 Échéance : date seule vs date-heure
Une échéance 18/09/2026 doit produire DUE;VALUE=DATE:20260918 (journée entière), et 2026-09-20 17h00 un DUE horodaté en Europe/Paris. Les deux formes sont gérées ; due_before compare une date seule à la fin de journée, pour ne pas exclure une tâche échue le jour même.
7.5 Priorité 9 par défaut côté Tasks.org
Voir §5.3 : « basse » n'est pas un choix, c'est le défaut de l'appli.
8. Règles d'usage pour Claude
delete_task uniquement après confirmation explicite de Julien. Terminer ≠ supprimer : une tâche faite se termine (complete_task), on ne l'efface pas — l'historique reste consultable avec include_completed.
Priorités : n'en poser une que si Julien la donne ; par défaut 0. Ne pas interpréter un 9 venant de Tasks.org.
Une tâche sans échéance ne notifiera jamais : si Julien veut « être rappelé », demander une date.
Ne jamais annoncer qu'une tâche est créée sans relire due dans le résultat (même règle que pour les dates d'événements, page 2 §5.8).
4 - intégration des contacts personnels et professionnels de Julien
Intégration des contacts personnels et professionnels de Julien
Statut au 15 septembre 2026 : en discussion. Rien n'est construit. Cette page contient le plan en trois actes posé par Julien, puis les retours de Claude. Les décisions prises seront consignées en §5 au fur et à mesure.
1. Le plan de Julien (15/09/2026)
Sources actuelles, dispersées :
julien.bertrand@ik.me) ;
contacts téléphone qui se baladent dans le Xiaomi (compte local / Mi Cloud) ;
contacts Gmail perso.
Trois actes :
Procédure hébergée sur le VPS perso juxjux.ovh, comme le reste de la stack (page 1).
2. Retours de Claude
2.1 L'acte 1 existe déjà : Baïkal est la base SQLite
Baïkal stocke ses contacts dans une base SQLite (/var/www/baikal/Specific/db/db.sqlite, table cards, une vCard par ligne — page 1 §6.5 et §12). Construire une seconde SQLite « unificatrice » à côté, c'est créer deux sources de vérité pour le même objet, avec un synchroniseur maison entre les deux à écrire et à maintenir. C'est précisément le problème que Baïkal a été installé pour résoudre (page 1 §1 : « Baïkal est la source de vérité unique »).
Ce que le plan attend de la base « versatile dans sa lecture » — être vue par Thunderbird, par le téléphone, par un répertoire web — c'est exactement ce qu'un serveur CardDAV fournit. Une SQLite nue ne le fournit pas : il faudrait un connecteur par client. Baïkal est la SQLite plus la couche de lecture universelle.
Proposition : fusionner les actes 1 et 2. Baïkal est la base ET le catalyseur. Ce qui manque n'est pas une base, ce sont trois choses :
Le tri, le sériage, l'ancrage et l'archivage se font dans le vocabulaire vCard, pas dans un schéma SQL à inventer : CATEGORIES pour les étiquettes (mairie, bureau d'études, famille, …), NOTE ou un champ X-PROVENANCE pour l'origine, ORG/TITLE pour l'ancrage professionnel, et plusieurs carnets pour les grands compartiments. Tous les clients relisent ces champs.
2.2 Les sources ne sont pas de même nature
Le plan les traite comme quatre « foyers de création » équivalents. Elles ne le sont pas :
.vcf une fois, import dans un carnet de transit, puis triage. Synology Contacts n'est ensuite plus alimenté
Infomaniak (pro)
source vivante, CardDAV natif
vdirsyncer, prévu depuis août (page 1 §10.1), en sens unique vers Baïkal pour commencer
Gmail (perso)
source vivante, CardDAV Google (mot de passe d'application, compte en 2FA)
idem, vdirsyncer sens unique vers Baïkal
Xiaomi
pas une source distante : ce sont des contacts dans le compte « Téléphone » ou « Mi Cloud » de l'appareil, invisibles de tout serveur
export .vcf une fois depuis l'appli Contacts, import en transit, triage ; puis réglage du compte par défaut pour les nouveaux contacts = compte Baïkal de DAVx5, et désactivation de la synchro contacts Mi Cloud / Google pour tarir la fuite
Point important : une fois le compte DAVx5 défini comme compte par défaut sur le téléphone, le téléphone n'est plus un foyer de création à synchroniser — il écrit directement dans Baïkal. Même chose pour InfCloud, Roundcube et Claude (via le futur MCP CardDAV). Restent deux vrais flux entrants : Infomaniak et Gmail.
2.3 Sur le « reçoit les mises à jour » de l'acte 2 : le sens du flux est la décision structurante
Deux modèles possibles, à trancher avant de configurer vdirsyncer :
Modèle A — Baïkal devient l'unique foyer de création. Gmail et Infomaniak sont vidés dans Baïkal une fois (sens unique), puis on cesse d'y créer des contacts : nouveaux contacts saisis sur le téléphone (compte DAVx5), dans InfCloud, ou par Claude. Gmail et Infomaniak deviennent des vestiges, ou reçoivent une copie descendante (Baïkal → Google) si l'autocomplétion Gmail compte.
Modèle B — synchronisation bidirectionnelle permanente avec Gmail et Infomaniak.
Recommandation : modèle A, avec vdirsyncer en sens unique le temps de la migration, puis à l'arrêt. C'est aussi la recommandation déjà posée en page 1 §10.1. Si l'autocomplétion Gmail manque, ajouter plus tard un flux descendant Baïkal → Google (sens unique aussi) — pas de remontée.
2.4 Espace de tri : des carnets de transit dans Baïkal
Plutôt que de trier dans une base à part, créer dans Baïkal, sous le même utilisateur Julien :
default
contacts personnels de référence
oui
nexte
contacts professionnels de référence (mairies, DDTM, bureaux d'études, …)
oui
archive
contacts conservés mais sortis de l'usage (anciens clients, personnes décédées, …)
non — visible dans InfCloud seulement
transit-synology, transit-gmail, transit-infomaniak, transit-xiaomi
chaque source importée telle quelle, sans modification
non
Les carnets de transit sont éphémères : une fois vidés par le triage, on les supprime. Tout ce qui est décidé s'exprime par un déplacement d'un carnet à un autre — ce qui est tracé par Baïkal (horodatage, synctoken) et sauvegardé chaque nuit (page 1 §8).
Deux carnets de référence (default / nexte) plutôt qu'un seul : même logique que pour les calendriers (page 2 §1) — le PC NEXTE n'écrit que dans nexte, les contacts personnels ne transitent par une conversation Alteris que si Julien le demande, et DAVx5 permet de n'exposer que l'un des deux à une appli donnée. Une mairie qui est « les deux » va dans nexte avec une CATEGORIES explicite ; on ne duplique pas.
2.5 L'outil de triage : c'est là que Claude a une valeur
Le triage manuel de quatre sources est ce qui a fait échouer toutes les tentatives de rangement de contacts depuis vingt ans. Ce que le MCP CardDAV (à écrire, comme pour les tâches — page 3) permettrait :
+33 6 …), même nom à casse/accent près, entre carnets ;
fusion assistée : Claude propose la fiche fusionnée (union des e-mails et téléphones, ORG le plus complet, NOTE avec provenance), Julien valide, la fiche entre dans default ou nexte et les fiches sources sont retirées du transit ;
classement par lots : « tous les contacts dont l'e-mail est en .gouv.fr ou mairie- → nexte, catégorie collectivité » ;
archivage : déplacement vers archive avec date et motif en NOTE.
Rien de tout cela ne demande une base à part : ce sont des opérations CardDAV (REPORT addressbook-query, PUT, DELETE, MOVE) sur des vCards 3.0 — le format que Roundcube écrit déjà et que tout le monde relit (page 1 §9).
2.6 Acte 3 — InfCloud, Roundcube, Thunderbird, Synology
loadedaddressbookcollections), même piège qu'en page 2 §5.7 ; on a d'ailleurs vu dans ces réglages une entrée activeaddressbookcollections: ["https://undefined"] à corriger au passage.
Roundcube : il n'a plus de rôle propre pour les contacts dès qu'InfCloud les couvre. Il ne se justifie que comme webmail du compte ik.me. Si Julien ne l'utilise pas comme webmail, il peut être arrêté : un container, un vhost, ~32 Mo et une surface d'attaque de moins (page 1 §6.4 pour ses contraintes IMAP). À décider — pas dans l'urgence.
Thunderbird sur le téléphone : il ne gère pas de carnet ; il lit les contacts Android, qui viennent de DAVx5. Rien à faire de plus. Thunderbird sur PC (s'il y en a un) parle CardDAV nativement : URL du carnet + identifiants, et il voit default/nexte.
Synology Contacts : à ma connaissance, l'application Synology expose du CardDAV (elle est serveur) et importe des comptes Google/Microsoft, mais ne consomme pas un CardDAV tiers. À vérifier sur le DSM. Si c'est confirmé, le NAS n'est pas un client à alimenter mais une source à vider (§2.2), et il n'a plus de rôle après la migration — sauf comme archive figée de l'existant, ce qui est très bien.
2.7 Ordre de chantier proposé
Chaque étape est réversible et laisse la stack en état de marche. Rien n'est lancé sans validation de Julien.
.vcf, comptage
1
Gel des sources : arrêt de la création de contacts dans Gmail et le webmail Infomaniak ; compte DAVx5 par défaut sur le Xiaomi ; synchro contacts Mi Cloud/Google coupée
téléphone, discipline
réglages Android
2
Carnets : création de nexte, archive et des carnets de transit ; inscription dans InfCloud
Baïkal
admin Baïkal ou MCP
3
Imports morts : Synology et Xiaomi → carnets de transit
VPS
.vcf + PUT CardDAV
4
Imports vivants : vdirsyncer sens unique Gmail → transit, Infomaniak → transit ; cron le temps de la migration
VPS
vdirsyncer (page 1 §10.1)
5
Triage : inventaire, doublons, fusions validées, classement default/nexte/archive
MCP CardDAV
Claude + Julien
6
Vérification clients : téléphone (DAVx5), InfCloud, Thunderbird PC
clients
—
7
Fin de migration : suppression des carnets de transit, arrêt de vdirsyncer (modèle A), sort de Roundcube
VPS
—
Le MCP CardDAV (outils *_contact) est un préalable à l'étape 5 et sert dès l'étape 0 pour compter. Il se construit comme celui des tâches, dans le même script.
3. Ce que Claude ne recommande pas
4. Questions à trancher
default/nexte, ou un seul avec catégories ? — §2.4
Le pro, c'est NEXTE ou Alteris, ou les deux avec une catégorie ? (même question que pour le calendrier, tranchée « NEXTE » le 15/09)
Roundcube : webmail utilisé, ou à arrêter ? — §2.6
Synology Contacts : confirmer qu'il ne peut pas être client CardDAV ; sinon, souhaite-t-on qu'il reste alimenté ?
L'autocomplétion Gmail manque-t-elle si Gmail cesse d'être alimenté ? (déclenche ou non un flux descendant Baïkal → Google)
Ordre de grandeur : combien de contacts au total, toutes sources confondues ? (change la méthode de triage : 300 se font en une séance, 3 000 par lots)
5. Décisions
(à compléter au fil des échanges)