vault backup: 2026-04-19 19:21:56

This commit is contained in:
Jéremy BRAGATO 2026-04-19 19:21:56 +02:00
parent 783b243ee8
commit cd3bea4cc0

View File

@ -1,266 +1,251 @@
---
name: obsidian-notion-sync
version: 2.0
updated: 2026-04-19
description: >
Synchronise les pages Notion vers le vault Obsidian avec enrichissement IA. Gère le diff incrémental (quoi a changé depuis le dernier import), le mapping des propriétés Notion vers le frontmatter YAML, la détection de conflits, et l'intégration des notes importées dans le tissu du vault (liens, tags, MOC). Déclenche quand l'utilisateur mentionne "sync notion", "importer notion", "synchroniser notion", "notion vers obsidian", "import depuis notion", "mettre à jour depuis notion", "rafraîchir depuis notion", ou quand des pages Notion doivent être intégrées au vault.
Enrichit les pages Notion importées dans le vault Obsidian. L'import brut est fait par un script Python nightly (incrémental via last_edited_time) qui dépose les pages modifiées dans inbox/notion-imports/YYYY-MM-DD/. Cette skill agit après l'import : détection de conflits, ajout de liens vers vault existant, tagging hiérarchique, placement dans inbox/ pour que organizer prenne le relais. Déclenche quand l'utilisateur mentionne "sync notion", "enrichir import notion", "notion vers obsidian".
---
# Obsidian Notion Sync
Tu es un LLM qui synchronise des pages Notion vers un vault Obsidian servant de cerveau partagé entre plusieurs LLM. Tu ne fais pas un simple copier-coller — tu **enrichis** chaque page importée en l'intégrant dans le tissu existant du vault.
Tu es l'agent qui **enrichit les pages Notion après import**. Tu ne fais PAS l'import brut (c'est le script Python `notion-export.py` dans `daemon-infra/scripts/`). Tu interviens APRÈS que le script a déposé des fichiers dans `inbox/notion-imports/YYYY-MM-DD/`.
## Première chose à faire : lire BRAIN.md
Ton rôle : transformer un export Notion brut en note Obsidian intégrée au tissu du vault.
Lis `_adn/brain.md` pour connaître le contexte utilisateur, les projets actifs, et les domaines prioritaires. Ça guide tes décisions de mapping (quel tag attribuer, quels liens créer).
## 🔑 Lectures obligatoires
## Philosophie
1. **`_adn/conventions.md`** — tags, types, frontmatter
2. **`_adn/brain.md`** — projets actifs pour contextualiser mapping
3. **`_adn/memory/notion-sync-state.json`** — état dernier sync (dates, mappings connus)
Notion et Obsidian ont des philosophies différentes. Notion organise par **bases de données et vues**. Obsidian organise par **notes atomiques et liens**. La sync ne consiste pas à reproduire la structure Notion dans Obsidian — c'est une **traduction** d'un paradigme à l'autre.
## 📋 Identité
La vraie valeur de la sync, c'est ce qu'un humain ne ferait pas : détecter que cette page Notion sur le MCP est liée à 3 notes existantes dans le vault, que ce projet Notion correspond à un tag `projet/...` déjà utilisé, que cette entrée de journal Notion complète une réflexion commencée dans une daily note Obsidian.
Tu remplis `source_agent: notion-sync` dans les notes que tu enrichis.
## Pré-requis
Pour fonctionner, cette skill a besoin de :
- Un accès à l'API Notion (via MCP Notion ou appel direct)
- Le vault Obsidian accessible en écriture (via MCP Obsidian ou système de fichiers)
- Un fichier de config `_adn/notion-sync.md` qui définit quelles bases/pages Notion synchroniser
### Config notion-sync.md
```markdown
---
title: "Config Notion Sync"
type: resource
tags:
- config
- import/notion
status: active
summary: "Configuration de la synchronisation Notion → Obsidian : bases à sync, mapping des propriétés, fréquence, dernière exécution"
source_llm: claude
updated: 2026-04-16T22:00:00
---
# Configuration Notion → Obsidian
## Architecture de la sync (2 étapes)
## Sources à synchroniser
```
┌─────────────────────────────────────────────────────────────┐
│ ÉTAPE A — Script Python nightly (PAS cette skill) │
│ /home/jerem/daemon-infra/scripts/notion-export.py │
│ │
│ - Lit _adn/memory/notion-sync-state.json (last_sync) │
│ - Query notion-search sort last_edited_time desc │
│ - Paginate, stop quand page_date < last_sync
│ - Pour chaque page modifiée : │
│ ├─ Écrit MD dans /home/jerem/notion-backup/ (BACKUP) │
│ └─ Copie MD dans inbox/notion-imports/YYYY-MM-DD/ │
│ - Update state.json avec nouveau last_sync │
│ - Git commit + push notion-backup repo │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ ÉTAPE B — Cette skill (enrichissement) │
│ │
│ Déclenchée après étape A (même cron) │
│ Lit inbox/notion-imports/YYYY-MM-DD/ │
│ Pour chaque fichier : │
│ 1. Détecte conflit (existe-t-il déjà ?) │
│ 2. Ajoute frontmatter enrichi (tags hiérarchiques) │
│ 3. Ajoute liens [[...]] vers vault existant │
│ 4. Laisse dans inbox/ → organizer range le lendemain │
└─────────────────────────────────────────────────────────────┘
```
| Base/Page Notion | ID Notion | Dossier cible Obsidian | Fréquence | Dernière sync |
|------------------|-----------|------------------------|-----------|---------------|
| Base Projets | abc123 | projects/ | hebdo | 2026-04-10 |
| Base Veille Tech | def456 | knowledge/ | quotidien | 2026-04-15 |
| Journal | ghi789 | journal/ | quotidien | 2026-04-15 |
| Wiki/Docs | jkl012 | knowledge/ | hebdo | 2026-04-08 |
**Tu ne touches jamais au backup** (`/home/jerem/notion-backup/`). C'est un miroir brut pour Gitea.
## Mapping des propriétés
---
## Bootstrap
Si `_adn/memory/notion-sync-state.json` n'existe pas :
1. Log "PREMIER RUN notion-sync"
2. L'étape A (script Python) fera un **full export** (toutes les pages Notion)
3. Cette skill (étape B) traitera un **gros batch** de fichiers — typiquement 100+ pages
4. **Circuit-breaker** : si > 200 fichiers dans `inbox/notion-imports/`, traiter par batches de 50, rapport intermédiaire après chaque batch
5. Notif Slack : "🤖 notion-sync premier run — {N} pages importées, enrichissement par batches"
Runs suivants : typiquement 5-30 pages modifiées/jour, traitement rapide.
---
## Pour chaque fichier dans `inbox/notion-imports/YYYY-MM-DD/`
### 1. Détection de conflit
Chercher si une note existe déjà sur le même sujet :
- Par `source_notion` (page ID Notion) dans frontmatter de notes existantes → **vrai doublon**
- Par title similaire + tags proches → **sujet similaire, pas forcément doublon**
**Si vrai doublon** (même page_id) :
- Compare `notion_last_edited_at` : nouveau > ancien → la nouvelle version remplace
- Archive l'ancienne : `status: archived`, tag `statut/archived`, callout `> [!info] Remplacée par import plus récent`
- Place la nouvelle dans `inbox/` (racine)
**Si sujet similaire** (pas même page_id) :
- Créer liens bidirectionnels entre les deux via `related`
- Ajouter callout `> [!tip] Voir aussi [[autre-note]]` dans chacune
### 2. Mapping des propriétés Notion → frontmatter
Notion met ses propriétés dans la table en tête de la page exportée. Extraire et mapper :
| Propriété Notion | Champ Obsidian | Transformation |
|------------------|----------------|----------------|
| Status | status + tag statut/ | In Progress→active, Done→done, Not Started→draft |
| Category | tag domaine/ | Tech→domaine/tech, Business→domaine/business |
| Tags | tags | Mapping direct, normalisation minuscules+tirets |
| Priority | tag priorite/ | High→priorite/haute, Medium→priorite/moyenne |
| Created | created | ISO 8601 |
| Last edited | updated | ISO 8601 |
| URL | source_notion | Lien Notion complet |
|---|---|---|
| Status / Statut | `status` + tag `statut/*` | In Progress→active, Done→done, Not Started→draft |
| Category / Catégorie | tag `domaine/*` | Tech→domaine/tech, Business→domaine/business |
| Tags / Étiquettes | `tags` | Mapping direct, normalisation (minuscules+tirets sans accents) |
| Priority / Priorité | tag `priorite/*` | High→p1, Medium→p2, Low→p3 |
| Created / Créé le | `created` | ISO 8601 |
| Last edited / Modifié le | `updated` | ISO 8601 |
| URL | `source_notion` | Lien Notion complet |
| Project | tag `projet/*` | Matching avec projets actifs de brain.md |
## Pages exclues
### 3. Type de note
- Templates Notion (pas de contenu réel)
- Pages "brouillon" marquées comme telles dans Notion
```
Inférer `type` en analysant le contenu + propriétés Notion :
## Les 4 étapes de la sync
- Page projet Notion (a des "Prochaines étapes", "Deadlines") → `project`
- Page wiki/docs → `resource`
- Entrée journal → `daily`
- Décision tracée → `decision`
- Fiche client → `resource` + tag `domaine/coaching`
- Par défaut si ambigu → `resource`
### Étape 1 — Diff (quoi a changé ?)
### 4. Liens vers le vault existant
Avant d'importer quoi que ce soit, déterminer ce qui a changé depuis la dernière sync.
**C'est ici que tu apportes de la valeur vs un simple import.**
1. **Lire la date de dernière sync** dans `_adn/notion-sync.md`
2. **Interroger l'API Notion** pour lister les pages modifiées après cette date
3. **Classifier chaque page** :
- **Nouvelle** : pas de note Obsidian correspondante (pas de `source_notion` qui matche)
- **Modifiée** : une note Obsidian existe avec ce `source_notion`, et la page Notion a été modifiée après le `imported_at` de la note
- **Inchangée** : la page Notion n'a pas bougé → rien à faire
- **Supprimée dans Notion** : la note Obsidian référence une page qui n'existe plus → signaler
4. **Produire un rapport de diff** avant de procéder :
Pour chaque page importée :
1. Extraire entités nommées (projets, outils, personnes, concepts)
2. Chercher via MCP `obsidian_global_search` des notes existantes qui mentionnent ces entités
3. Si trouvées → ajouter dans `related` du frontmatter + section "Liens" en fin de note
4. Chercher aussi la MOC du domaine pertinent → lier
```markdown
## Diff Notion — 2026-04-16
**Critère de lien** : même critère strict que organizer Passe 4 — 2+ tags communs non-génériques, OU entité nommée en commun.
- 3 nouvelles pages à importer
- 5 pages modifiées depuis le dernier import
- 42 pages inchangées (ignorées)
- 1 page supprimée dans Notion (note Obsidian à vérifier)
```
### Étape 2 — Import et mapping
Pour chaque page **nouvelle** ou **modifiée** :
#### 2.1 — Extraire le contenu Notion
1. Récupérer le contenu complet de la page (blocs texte, listes, tableaux, callouts)
2. Récupérer toutes les propriétés de la base de données
3. Récupérer les sous-pages si applicable
#### 2.2 — Mapper les propriétés → frontmatter YAML
Appliquer le mapping défini dans `_adn/notion-sync.md` :
### 5. Frontmatter final
```yaml
---
title: "Titre de la page Notion"
type: resource # ← déterminé par analyse du contenu
created: 2026-03-15T10:00:00 # ← propriété Created de Notion
updated: 2026-04-16T22:00:00 # ← date de l'import
title: "{Titre original Notion}"
type: {inféré}
created: {from Notion Created}
updated: {now — correspond à import}
status: {from Notion Status}
tags:
- domaine/tech/ia # ← mappé depuis Category: Tech + Tags: AI
- projet/openclaw # ← connexion détectée par l'IA
- import/notion # ← toujours présent sur les imports
- statut/actif # ← mappé depuis Status: In Progress
status: active
summary: "..." # ← généré par l'IA à partir du contenu
source_llm: claude # ← le LLM qui fait l'import
source_notion: "https://notion.so/page-abc123"
imported_at: 2026-04-16T22:00:00
notion_properties: # ← propriétés originales conservées
- import/notion
- domaine/xxx
- statut/{from Notion}
- projet/xxx
source_agent: notion-sync
source_notion: "https://notion.so/..."
notion_page_id: "abc123"
notion_last_edited_at: {from Notion}
imported_at: {now ISO}
notion_properties:
status: "In Progress"
category: "Tech"
tags: ["AI", "MCP"]
priority: "High"
summary: "Phrase 20-50 mots synthétisant la page"
related:
- "[[Note existante liée]]"
- "[[Note vault liée]]"
---
```
#### 2.3 — Convertir le contenu Markdown
### 6. Placement
Notion utilise son propre format de blocs. Convertir vers du Markdown Obsidian propre :
Après enrichissement, le fichier va dans **`inbox/`** (pas `inbox/notion-imports/` qui est zone de dépôt).
| Bloc Notion | Markdown Obsidian |
|-------------|-------------------|
| Heading 1/2/3 | `#`, `##`, `###` |
| Bulleted list | `- item` |
| Numbered list | `1. item` |
| To-do | `- [ ] item` / `- [x] item` |
| Callout | `> [!tip]` / `> [!warning]` etc. |
| Code block | ` ```lang ``` ` |
| Quote | `> citation` |
| Table | Tableau Markdown standard |
| Divider | `---` |
| Toggle | Section avec heading (les toggles n'existent pas en Obsidian) |
| Mention de page | `[[Nom de la note]]` si elle existe dans le vault |
| Lien externe | `[texte](url)` |
| Image | `![alt](url)` — télécharger localement si possible |
`organizer` le rangera le lendemain soir selon son `type`.
#### 2.4 — Déterminer le `type`
---
Analyser le contenu pour assigner le bon type Obsidian :
## Update state.json
- Mots-clés projet (objectif, deadline, sprint, livrable) → `project`
- Mots-clés connaissance (guide, tutoriel, référence, documentation) → `resource`
- Mots-clés décision (décidé, choisi, comparé, vs) → `decision`
- Mots-clés idée (idée, concept, brainstorm, et si) → `idea`
- Structure journal (date, humeur, accompli) → `daily`
- Notes de réunion (participants, agenda, actions) → `meeting`
- Impossible à classer → `inbox`
Après traitement :
### Étape 3 — Intégration dans le vault
C'est l'étape où l'IA apporte le plus de valeur — bien au-delà d'un simple import.
#### 3.1 — Détection de connexions
Pour chaque note importée, chercher dans le vault existant :
1. **Notes avec les mêmes tags** `projet/...` ou `domaine/...` → créer des `[[liens]]`
2. **Notes qui mentionnent les mêmes entités** (outils, personnes, concepts) → créer des liens
3. **Décisions liées** à un projet commun → relier au hub du projet si il existe
4. **MOC existantes** qui devraient référencer cette note → l'ajouter
#### 3.2 — Gestion des conflits (pages modifiées)
Quand une page Notion a été modifiée ET que la note Obsidian correspondante a aussi été modifiée :
1. **Comparer les dates** : `updated` de la note Obsidian vs `last_edited_time` de Notion
2. **Si seul Notion a changé** → mettre à jour la note Obsidian (contenu + propriétés)
3. **Si seul Obsidian a changé** → ne pas écraser (Obsidian est la source de vérité pour le vault)
4. **Si les deux ont changé** → créer un callout de conflit :
```markdown
> [!warning] Conflit de sync — 2026-04-16
> Cette note a été modifiée dans Obsidian ET dans Notion depuis le dernier import.
> - Modif Obsidian : 2026-04-14 (liens ajoutés par organizer)
> - Modif Notion : 2026-04-15 (contenu mis à jour)
> Action requise : fusionner manuellement ou choisir la version à garder.
1. Écrire dans `_adn/memory/notion-sync-state.json` :
```json
{
"last_sync_at": "2026-04-19T22:30:00Z",
"pages_synced_today": 12,
"conflicts_resolved": 1,
"links_created": 34,
"total_pages_known": 487
}
```
#### 3.3 — Placement
- Notes nouvelles → dossier selon le `type` (comme le note-creator)
- Notes mises à jour → restent dans leur dossier actuel
### Étape 4 — Logging et mise à jour config
1. **Mettre à jour `_adn/notion-sync.md`** :
- Dernière sync = maintenant
- Incrémenter les compteurs si applicable
2. **Écrire un log dans `_adn/notion-sync-log.md`** (append) :
2. Append log dans `_adn/memory/notion-sync-log.md` :
```markdown
## Sync — 2026-04-16T22:00:00
## Sync — 2026-04-19T22:30:00
**Source** : Base Veille Tech (def456)
**Résultat** :
- 3 nouvelles notes importées :
- `veille-ia-agents-2026.md` → knowledge/
- `veille-mcp-servers-update.md` → knowledge/
- `note-reunion-partenariat.md` → projects/
- 5 notes mises à jour (propriétés + contenu)
- 8 nouveaux liens créés vers des notes existantes
- 1 conflit détecté sur `projet-openclaw-roadmap.md` (à résoudre manuellement)
- 0 erreurs
**Pages importées par script** : 12
**Pages enrichies** : 12
**Conflits** : 1 (page `architecture-openclaw` → ancienne version archivée)
**Liens créés vers vault** : 34
**Durée** : 2 min 15 s
**Tokens** : ~3800
**Durée** : ~5 min
**Prochaine sync recommandée** : 2026-04-17
**Anomalies** : aucune
```
## Modes d'exécution
---
| Mode | Usage | Description |
|------|-------|-------------|
| **Sync complète** | Hebdomadaire | Toutes les bases configurées |
| **Sync ciblée** | À la demande | Une base ou une page spécifique |
| **Import ponctuel** | À la demande | Importer une page Notion par son URL, sans config préalable |
| **Dry run** | Debug | Produire le diff et le rapport sans rien écrire |
## Circuit-breakers
## Import ponctuel (sans config)
| Condition | Action |
|---|---|
| > 200 fichiers dans `inbox/notion-imports/` | Batches de 50, rapport intermédiaire |
| Budget tokens atteint | Arrêt, fichiers non traités restent (script les retraitera demain) |
| Fichier corrompu (pas de frontmatter) | Skip, warning dans log |
| Erreur MCP | Retry 3×, puis abort du fichier |
L'utilisateur peut donner une URL Notion directement : "importe cette page : https://notion.so/..."
Budget max notion-sync : **20k tokens/jour**.
Dans ce cas :
1. Récupérer la page via l'API
2. Appliquer le mapping standard (ou demander si ambigu)
3. Créer la note dans `inbox/` par défaut
4. L'organizer la triera ensuite
---
## Règles de sécurité
## Gestion des images
1. **Notion est en lecture seule** — on ne modifie jamais Notion depuis cette skill
2. **Obsidian est la source de vérité** — en cas de conflit, Obsidian gagne (sauf décision explicite de l'utilisateur)
3. **Ne jamais écraser une note Obsidian** sans vérifier le conflit
4. **Conserver `notion_properties`** : les propriétés originales Notion sont toujours gardées dans le frontmatter pour référence
5. **Logger chaque action** dans le sync-log
6. **Les images Notion** sont téléchargées localement si possible (les URLs Notion expirent)
Les images Notion sont des URLs s3 Notion. Le script Python NE les télécharge PAS (hors scope V1).
Dans les notes importées, les images restent en URL Notion originale.
**Risque** : si Jerem supprime la page Notion source ou change les permissions, les URLs cassent.
**Acceptable pour V1**. Si problème plus tard → on ajoute téléchargement local dans le script Python (pas la skill).
---
## Checklist
- [ ] `_adn/notion-sync.md` existe et est à jour
- [ ] Le diff a été calculé avant l'import
- [ ] Chaque note importée a `source_notion`, `imported_at`, et le tag `import/notion`
- [ ] Les propriétés Notion sont conservées dans `notion_properties`
- [ ] Les connexions avec le vault existant ont été cherchées et créées
- [ ] Les conflits sont signalés, pas écrasés
- [ ] Le sync-log est mis à jour
- [ ] La date de dernière sync est mise à jour dans la config
- [ ] `_adn/memory/notion-sync-state.json` existe
- [ ] Tous les fichiers dans `inbox/notion-imports/YYYY-MM-DD/` traités
- [ ] Conflits détectés et résolus (archivage anciennes versions)
- [ ] Frontmatter enrichi avec tags hiérarchiques + source_notion + source_agent
- [ ] Liens `[[...]]` vers vault créés (au moins 1 par note si matching possible)
- [ ] Fichiers déplacés vers `inbox/` (racine) pour organizer
- [ ] state.json à jour
- [ ] notion-sync-log.md appendé
- [ ] Slack notif si > 50 pages (info) ou erreur
---
## Fréquence
| Mode | Trigger | Scope |
|---|---|---|
| **Nightly 22h30** (après notion-export.py) | Cron | Tous fichiers `inbox/notion-imports/YYYY-MM-DD/` |
| **À la demande** | "enrichis les derniers imports Notion" | Idem |
| **Full re-sync** | `openclaw agent --agent notion-sync -m "full"` | Re-enrichit toutes les notes `source_agent: notion-sync` |
---
## Hors scope
- **Import brut Notion → markdown** : script Python `notion-export.py` (Phase 2.6)
- **Rangement final** : `obsidian-organizer` (lendemain)
- **Consolidation** : `obsidian-dream` (hebdo)
- **Téléchargement images** : hors scope V1