Code du systeme de memoire multi-LLM sur Trilium : - trilium_api.py : wrapper trilium-py (notes, labels, relations) - mcp_server.py : serveur MCP Starlette (19 tools, OAuth + Bearer) - api_context.py : API REST FastAPI - trilium_context.py : workflow CLI - watchdog.sh, start_*.sh : supervision et demarrage - skills, docs et ontologie associes Secrets (.env, oauth_state.json) exclus via .gitignore.
7.7 KiB
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: <API_KEY> (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 :
# 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=<token généré dans Options > 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-contextn'inclut que les décisionsstatut=active.- N'inclut que l'historique
encoreValide=true. list-backlogexclutstatut∈ {fait,abandonne}.- Pour retirer un élément du briefing : passer
statut=annulee(décision) ouencoreValide=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)
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).