Procédure de mise à jour du portefeuille « à chaque trade » à partir des relevés
Revolut, sans IA (exact).
- finlab/revolut.py : reconstruit les positions depuis le « trading account
statement » (toutes transactions) par COÛT MOYEN (achats − ventes, PRU pondéré),
mappe les tickers Revolut→Yahoo (ASME→ASML.AS, TOTB→TTE.PA, BNP→BNP.PA, AXA→CS.PA,
FTE→ORA.PA, AIR1→AI.PA) et vérifie les cours. Idempotent, ne touche qu'un compte,
préserve les autres comptes/cash/commentaires (round-trip ruamel.yaml)
- CLI : python -m finlab.cli import-revolut <csv> [--write] [--account]
- Dashboard : le bouton « Importer un relevé » accepte les CSV → endpoints
/api/revolut/preview (aperçu) + /api/revolut/apply (écrit), avec garde anti-évasion
de chemin ; le front affiche les positions + bouton « Appliquer »
- portfolio.yaml : compte Revolut reconstruit depuis l'historique complet → ajoute
AMAT (achetée le 29/06, manquait) ; valeurs alignées au centime
- requirements : + ruamel.yaml ; persona console + admin/ia/finlab.md documentés
Validé sur l'historique réel : 11 positions reconstruites = portfolio.yaml existant
(cours vérifiés, 0 warning) + AMAT. Flux dashboard upload→preview→apply testé
(TestClient), JS OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Permet de configurer des alertes « préviens-moi par mail quand NVDA atteint 200$ »
depuis la Console IA. Un sidecar surveille les cours en continu.
- finlab/watcher.py : boucle toutes les 5 min, lit price_alerts.yaml (workspace),
évalue les seuils above/below, envoie un email au franchissement. Anti-spam
(1 mail/seuil, état .watcher-state.json, ré-armé en ré-éditant). Modes --once / --test
- Email via le relais postfix du lab (storage-01:25, SMTP_HOST) qui réécrit
l'expéditeur en Gmail — AUCUN secret (pods k8s dans mynetworks)
- price_alerts.yaml : config seedée dans le workspace (email_to + rules), éditée
par la Console IA sur demande
- deployment : conteneur sidecar `watcher` (boucle 5 min, ressources minimes)
- Dockerfile : seed price_alerts.yaml ; persona console + admin/ia/finlab.md documentés
Logique testée en local (SMTP mocké) : franchissement → envoi, anti-spam au 2e run,
seuil non atteint → rien.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Process dédié pour actualiser le portefeuille à partir d'une capture de relevé :
- Dashboard : bouton « 📥 Importer un relevé » (panneau Mes comptes) → upload de
l'image vers le workspace (imports/) via POST /api/import ; une modale donne la
phrase exacte à dire à la console + un lien direct
- Backend : endpoints /api/import (UploadFile, refuse les non-images) et /api/imports
(listing), dossier imports/ sous FINLAB_HOME (workspace, persistant)
- Persona console (CLAUDE.md) : workflow « Import d'un relevé » — lire l'image,
extraire compte/positions, mapper vers tickers Yahoo en VÉRIFIANT les cours,
confirmer, puis mettre à jour portfolio.yaml
Le scan vision se fait dans la Console IA (abonnement, pas de clé API). Le dashboard
n'est que le pont d'upload. Testé : POST image→200 + listing OK, non-image→400 ;
JS node --check OK.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Permet de suivre plusieurs comptes (courtiers/banques) côte à côte, avec vue par
compte et agrégée. Ajoute le PEA BNP Paribas à côté de Revolut.
- portfolio.yaml : nouveau format `accounts` (name/type/cash/positions par compte).
Compat ascendante : ancien format (cash/positions à la racine) lu comme compte
unique « Principal »
- data.py : load_accounts(), base_currency(), portfolio_tickers() (union dédupliquée)
- tracker.py : build_account / build_all (par compte + agrégat global) ; build()
reste la vue globale (digest/report) ; report() multi-comptes
- scanner/technical/alerts : helpers « portfolio » → union de tous les comptes
- dashboard /api/portfolio : renvoie accounts[] (positions+agg par compte) + global
- dashboard front : onglets de comptes (Tous / Revolut / BNP Paribas), KPI + positions
+ secteurs qui suivent le périmètre sélectionné, badge de type par ligne en vue Tous
- BNP Paribas (PEA) saisi depuis la capture : AI/PAEEM/DCAM/PCEU/PSP5/BNP/ENGI/TTE .PA
(tickers Yahoo vérifiés, cours conformes à la capture)
Vérifié : totaux conformes à la capture BNP (6 395,49 € ; P&L -39 €), global 22 444 € ;
bascule d'onglet OK au navigateur (Playwright) ; compile + JS + CLI report OK.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- Dashboard : la console Claude Code (/console/) est désormais embarquée en iframe
sous le graphique (boutons reconnecter / plein écran), en plus du lien topbar
- Nouvelle vue pleine largeur « Chaîne de valeur IA — par couche » : regroupe les
watchlists par couche de l'électron au logiciel (⚡ énergie → 🔧 puces →
🏢 datacenter → 🔌 câbles/optique → ☁️ software), tickers cliquables colorés
par biais (haussier/baissier), tooltip cours/RSI/MACD
- Backend : endpoint /api/layers (scan groupé par thème, ordre des couches)
Vérifié au navigateur (Playwright, instance locale) : layout complet OK —
portefeuille + graphique chandeliers MM50/200 + console embarquée + alertes +
5 cartes de couches colorées. Endpoints et JS validés.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute une interface graphique à finlab, en plus de la console Claude Code (les
deux cohabitent sur finance.lab.local) :
- dashboard/ : backend FastAPI (sans LLM/clé) exposant les données finlab en JSON
(/api/portfolio, /api/scan, /api/ohlc, /api/plan, /api/alerts) + front statique
(lightweight-charts) : graphiques chandeliers MM50/200 + volume, portefeuille
(P&L/poids/secteurs), watchlists thématiques scannées, alertes, plan de trade R:R
- Découplage code/data : finlab lit ses configs depuis FINLAB_HOME si défini
(workspace persistant) ; repli sur le dossier du package en dév local
- Image double usage (un build, deux conteneurs) : code → /opt/app, seed minimal
(configs + persona + MCP) → workspace
- Fix seed NFS (cause racine du workspace vide) : WORKDIR n'est plus sur le volume
(le runtime le créait en root sur NFS) ; seed déplacé dans un initContainer
robuste (recrée le dossier s'il est non-inscriptible)
- Deployment : initContainer seed + 2 conteneurs (console ttyd -b /console, dashboard
uvicorn) ; Service 2 ports ; IngressRoute 2 routes (/console + dashboard), basicAuth
Validé en local (podman) : seed OK, dashboard /api/portfolio → 16k€/10 positions
via FINLAB_HOME, endpoints ohlc/scan/plan/alerts OK, ttyd/claude/finlab présents.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(finlab): console Claude Code finance in-cluster + toolkit d'analyse
Intègre finlab (ex-projet Projets/Finance) au lab comme une console Claude Code
web spécialisée finance — l'esprit OpenAlice, mais c'est le vrai Claude Code sur
l'abonnement (login persisté, pas d'API facturée), agentique, avec la boîte à
outils finlab (Yahoo Finance) branchée en MCP.
- tools/finlab/ : source finlab rapatriée + Dockerfile (Python 3.12 + Node +
claude-code + ttyd) + persona workspace/CLAUDE.md + branchement MCP + entrypoint
(seed du workspace no-clobber sur le PVC)
- .github/workflows/build-finlab.yml : build GHCR funk-finlab + bump manifest (main)
- k8s/apps/finlab/ : Deployment/Service/PVC/IngressRoute (finance.lab.local) +
Middleware basicAuth (shell web protégé) ; PVC = HOME (login) + workspace
- k8s/apps-of-apps/apps/finlab.yaml : Application ArgoCD
- .mcp.json (racine) : outils finlab dans les sessions Claude Code du lab
- admin/ia/finlab.md + READMEs + CLAUDE.md : doc + enregistrement
Analyse/aide à la décision uniquement — aucun ordre réel (paper trading Alpaca
fictif seul exécutable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(finlab): ttyd absent des dépôts bookworm → binaire statique GitHub
Le build amont échouait (`E: Package 'ttyd' has no installation candidate`) :
ttyd n'est pas packagé dans Debian bookworm. On récupère le binaire statique
(musl, pin TTYD_VERSION=1.7.7) depuis les releases GitHub. Build complet validé
en local (podman) : ttyd 1.7.7, claude-code 2.1.195, import finlab + seed OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Asa peut AGIR sur le homelab (l'autre moitié de la vision), via le vrai agent Hermes,
profil par défaut, tous ses outils — avec confirmation et jeton.
Découverte : Hermes n'a pas d'API HTTP (appli TUI), mais un mode one-shot `hermes -z
"<prompt>" --yolo`. On s'appuie dessus.
storage-01 — exécuteur :
- tools/hermes-exec/server.py : service HTTP qui lance `hermes -z --yolo` en user hermes,
derrière un jeton Bearer (compare_digest), timeout + audit, une action à la fois.
- rôle Ansible hermes_exec : systemd (User=hermes, env hermes-agent), jeton via
EnvironmentFile 0640 (Vault vault_hermes_exec_token) ; ajouté au playbook storage-01.
STT-server (0.5.0 → 0.6.0) :
- agent.py : pont vers hermes-exec (jeton) + détection confirme/annule.
- contexts.py : contexte « agent » (court-circuite le LLM).
- app.py : flux dédié — handshake 2 temps par session (pending action) → sur « confirme »,
appelle hermes-exec ; « annule » annule. /v1/contexts masque « agent » si désactivé.
- config : STT_ACTIONS_ENABLED (opt-in, défaut false) + URL + jeton (secret k8s).
- deployment : env actions + secret stt-server-secrets/hermes-exec-token (optionnel).
Sécurité : opt-in désactivé par défaut ; jeton obligatoire (sinon contexte caché + exécuteur
refuse tout) ; --yolo atteint seulement jeton+confirmation en main ; audit storage-01.
Client : AUCUN changement (le contexte « agent » apparaît tout seul dans le sélecteur).
Validé en local : exécuteur (401 sans/mauvais jeton, exec avec bon jeton via echo),
handshake serveur (TestClient : confirme→exécute, annule→annule, agent masqué si OFF).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- Ajout systemd timer hermes-auto-improve-daily.timer (22h00, Persistent=true)
- Service oneshot : --all puis --daily-pr (TimeoutSec=7200 pour 28 fichiers)
- auto-improve.py : flag --all qui bypass MAX_FILES et traite tout admin/
- trigger-server.py : timeout 600s → 7200s pour les runs --all via HTTP
La rotation par batch (MAX_FILES=5) reste active pour les triggers n8n
à la demande. Le workflow n8n 30-min doit être désactivé manuellement.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Le script n'écrase plus les docs existants. Pour chaque fichier admin/ :
- Inspecte le cluster en read-only (systemctl, kubectl, nft, etc.)
- Demande à Hermes d'écrire UNIQUEMENT une section "## État vérifié — DATE"
- Appende cette section au doc (ou remplace la précédente)
- Commit local dans hermes/daily-work, pas de push
- rag-ingest Qdrant à la fin du batch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GitHub repo configuré squash-only (allow_merge_commit=false, allow_rebase_merge=false)
- create_github_pr() vérifie si une PR hermes/daily-work est déjà ouverte :
si oui → met à jour titre+body (pas de PR dupliquée)
si non → crée une nouvelle PR
- Supprime le bug de silence sur "a pull request for branch X already exists"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Script hermes-doc-rewrite : inspecte l'état réel du cluster (read-only)
et demande à Hermes de réécrire chaque fichier admin/ avec des infos exactes.
Commit local dans hermes/daily-work, pas de push automatique.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Le run Hermes prend ~3min (5 appels LLM). Le serveur retourne maintenant
{"started": true} immédiatement. n8n attend 5min via Wait node puis GET /status.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Plus besoin de GITHUB_TOKEN dans le vault ni dans le service systemd.
gh auth login root une seule fois sur s01 suffit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pipeline complet dans feature/hermes-auto-improve :
- auto-improve.py : analyse admin/ avec hermes --profile funk-ai, applique
les améliorations, committe dans la branche, ré-ingère dans Qdrant
- trigger-server.py : HTTP 9095 (POST /trigger, /trigger/all, /trigger/subdir,
/trigger/dry-run) pour déclenchement depuis n8n ou manuellement
- Ansible role hermes_auto_improve : déploie scripts + service systemd sur s01
- n8n workflow "Hermes Auto-Improve" (ID: CX72UUOempE1YtNL) : schedule
hebdo dimanche 09h + webhook manuel → analyse → résumé LLM → email
Tout reste dans cette branche — rien ne touche main avant review.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Réécriture complète pour une expérience chat naturelle :
- Mode VEILLE : écoute "Ok Hermès" → active la conversation
- Mode CONVERSATION : 60s de parole libre sans répéter le wake word
- webrtcvad mode=3 (remplace détection énergie) — fini les faux déclenchements
- Single large-v3 (supprime la détection 2 niveaux peu fiable)
- VOICE_INJECT prefix pour forcer des réponses courtes
- Mots de sortie : "au revoir", "bonne nuit", "stop hermes", "fin"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- VAD mode : Whisper small (~0.3s) pour détecter "ok hermes", large-v3 uniquement pour transcrire la commande
- PTT mode : large-v3 direct (inchangé)
- install-service.sh : installe hermes-voice comme service utilisateur systemd (auto-start à la session)
- doc mise à jour
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tools/hermes-voice/ : pipeline VAD → faster-whisper → LiteLLM → piper TTS
- mot-clé "hermes" détecté dans la transcription Whisper (pas de wake word model)
- modes : VAD continu + push-to-talk + --no-tts pour debug
- nftables : ouvrir port 4000 LiteLLM vers LAN domestique (192.168.1.0/24)
- admin/ia/hermes-voice.md : documentation installation et utilisation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>