# SKILL — Référence technique : APIs Trilium & serveur MCP Référence d'implémentation du système Context Continuity. À sortir pour débugger, étendre ou appeler directement les APIs. Le « quand/pourquoi » comportemental est dans le skill de réflexe de continuité ; ici c'est le « comment » technique. Trois voies d'accès à Trilium coexistent : **API REST FastAPI** (distante, HTTPS), **ETAPI via wrapper Python** (locale, sur GrosseBertha), **MCP** (pour agents Mistral). --- ## 1. API REST FastAPI — accès distant (recommandé pour un LLM) Couche créée pour exposer Trilium en HTTPS (pallie l'absence d'accès direct). | Paramètre | Valeur | |---|---| | Base URL | `https://api-trilium.bertha-cloud.fr` | | Auth header | `Authorization: ` (clé brute, **sans** `Bearer`) | | Clés | Clé Claude / clé Le Chat — demander à Bastien ou lire dans `.env` | | Doc Swagger | `https://api-trilium.bertha-cloud.fr/api/docs` | **Endpoints essentiels :** | Action | Appel | |---|---| | Lire le contexte projet | `GET /api/contexte/{projet}?llm_cible=NomLLM` | | Voir le backlog | `GET /api/backlog/{projet}` | | Enregistrer une décision | `POST /api/decisions` | | Enregistrer un historique | `POST /api/historique` | | Créer une conversation | `POST /api/conversations` | | Clôturer une session | `PATCH /api/conversations/{id}` | | Marquer un backlog item | `PATCH /api/backlog/{id}` | **Exemples curl :** ```bash # Lire le briefing de reprise curl -s -H "Authorization: CLE" \ "https://api-trilium.bertha-cloud.fr/api/contexte/SlidingAutomation?llm_cible=Le+Chat+Large" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['briefing'])" # Enregistrer une décision curl -s -X POST -H "Authorization: CLE" -H "Content-Type: application/json" \ -d '{"projet":"SlidingAutomation","enonce":"Décision prise","justification":"Raison"}' \ https://api-trilium.bertha-cloud.fr/api/decisions # Marquer un backlog item comme fait curl -s -X PATCH -H "Authorization: CLE" -H "Content-Type: application/json" \ -d '{"statut":"fait"}' \ https://api-trilium.bertha-cloud.fr/api/backlog/NOTE_ID ``` --- ## 2. ETAPI via wrapper Python — accès local (sur GrosseBertha) TriliumNext 0.95+ a restructuré ses routes : `POST /etapi/notes` retourne *Router not found*. **Solution validée : `trilium-py 1.3.9`**, encapsulé dans `~/App/Context_continuity/trilium_api.py`. ``` pip install trilium-py python-dotenv ``` `.env` : ``` TRILIUM_URL=http://localhost:4292 TRILIUM_TOKEN= ETAPI> ``` Header d'auth : `Authorization: token` (**sans** `Bearer` ; Bearer accepté depuis 0.93 mais non requis). **Fonctions du wrapper `trilium_api.py` :** | Fonction | Note | |---|---| | `check_api()` | Lève SystemExit si Trilium inaccessible | | `create_note(parent_id, title, content=" ", note_type="text")` | `content=" "` obligatoire — jamais vide | | `get_note_id(result)` | Extrait `noteId` du résultat de `create_note` | | `get_note(note_id)` / `get_note_content(note_id)` | Récupère note / contenu HTML | | `update_note_content(note_id, content)` | Met à jour le contenu | | `search_notes(query, limit=50)` | Recherche **sans guillemets** autour du terme | | `search_by_label(label, value="")` | Syntaxe interne `#label=value` | | `find_note_by_title(title, parent_id="")` | Retourne `noteId` ou `None` | | `set_label(note_id, name, value="")` | `isInheritable=False` requis en interne | | `get_label_value(note_id, name)` | Retourne la valeur ou `None` | **Erreurs connues et fixes :** | Erreur | Cause | Fix | |---|---|---| | `Router not found POST /etapi/notes` | Routing TriliumNext 0.95 | Utiliser `trilium-py` | | `missing argument isInheritable` | `create_attribute()` trilium-py | Passer `isInheritable=False` | | `Note content must be set` | Contenu vide refusé | Passer `content=" "` | | Recherche avec guillemets → `[]` | Parser 0.95 | Chercher sans guillemets | | `{status,code,message}` sur create | Note existe déjà / contenu vide | `find_note_by_title` avant + `content=" "` | IDs des dossiers : `trilium_ids.json` (généré par `trilium_init.py`). Clés : `root, Projets, Conversations, Backlog, Decisions, Historique, Glossaire, ContextesReprise`. --- ## 3. Serveur MCP — pour agents Mistral `mcp_server.py` — serveur MCP pur Starlette (compatible Python 3.9), transport Streamable HTTP sur `/mcp`, écoute `127.0.0.1:8766`, exposé via `https://mcp-trilium.bertha-cloud.fr`. Protocole `2025-06-18`. **Authentification : Bearer token statique** (`API_KEY_CLAUDE` / `API_KEY_LECHAT` depuis `.env`). C'est ce qui le rend **utilisable par Le Chat mais PAS par Claude** : les connecteurs distants de Claude.ai exigent OAuth (endpoints de découverte `/.well-known/oauth-authorization-server`, flux d'autorisation), absents de ce serveur. Pour activer Claude, il faudrait ajouter une couche OAuth devant le serveur. **11 tools exposés :** `get_backlog`, `get_decisions`, `get_historique`, `get_glossaire`, `get_contexte`, `add_decision`, `add_history`, `add_backlog`, `update_backlog`, `new_conversation`, `close_session`. --- ## 4. Structure des données Trilium Note racine **Context Continuity** → 8 sous-dossiers : `Projets`, `Conversations`, `Backlog`, `Decisions`, `Historique`, `Glossaire`, `Contextes Reprise`, `Skills`. **Types de notes et labels obligatoires :** | Type (`type=`) | Labels obligatoires | |---|---| | `projet` | `projet` (sans espaces), `statut` (actif\|en-pause\|archive) | | `conversation` | `projet`, `llm`, `statut` (en-cours\|clos), `date` (YYYY-MM-DD HH:MM) | | `backlogItem` | `projet`, `statut` (a faire\|en cours\|bloque\|fait\|abandonne), `priorite` (haute\|moyenne\|basse) | | `decision` | `projet`, `statut` (active\|revisee\|annulee) | | `historiqueItem` | `projet`, `typeHistorique`, `encoreValide` (true\|false) | | `termeGlossaire` | `projet`, `definition` | | `contexteReprise` | `projet`, `llmCible`, `version` | `typeHistorique` ∈ { `Fait etabli`, `Test effectue`, `Hypothese invalidee`, `Contrainte decouverte` }. **Filtres des briefings** (pièges) : - `generate-context` n'inclut que les décisions `statut=active`. - N'inclut que l'historique `encoreValide=true`. - `list-backlog` exclut `statut` ∈ { `fait`, `abandonne` }. - Pour retirer un élément du briefing : passer `statut=annulee` (décision) ou `encoreValide=false` (historique) — ne pas supprimer la note. **Pièges d'écriture récurrents :** | Erreur | Conséquence | Fix | |---|---|---| | Statut avec majuscule (`Actif`) | Le filtre rate la note | Toujours minuscules | | Nom projet avec espaces | `search_by_label` échoue | `SlidingAutomation` | | `encoreValide="True"` | Filtre cherche `true` | Minuscules | | `definition` absent sur glossaire | Briefing affiche « (voir note) » | Ajouter le label | --- ## 5. Workflow CLI (sur GrosseBertha) ```bash cd ~/App/Context_continuity && source venv/bin/activate # Début python trilium_context.py new-conversation --projet SlidingAutomation --llm "Claude Sonnet" --titre "..." # Reprise python trilium_context.py generate-context --projet SlidingAutomation --llm-cible "Claude Sonnet" --note-id ID --version N # Au fil de l'eau python trilium_context.py add-decision --projet SlidingAutomation --enonce "..." --justification "..." python trilium_context.py add-history --projet SlidingAutomation --type "Test effectue" --enonce "..." --detail "..." # Clôture python trilium_context.py close-session --note-id ID --summary "..." # État python trilium_context.py list-backlog --projet SlidingAutomation python trilium_context.py list-projects ``` Fichiers du système : `trilium_api.py` (wrapper, ne pas modifier), `trilium_init.py` (init unique), `trilium_context.py` (workflow quotidien), `trilium_logger.py` (intégration pipeline Sliding), `trilium_ids.json`, `mcp_server.py`, `api_context.py` (API FastAPI).