Le bouton d'ajout existait mais était introuvable : l'en-tête des
Réglages n'avait ni flex-wrap ni flex-none, donc les commandes
s'écrasaient les unes sur les autres. « + Preset » se retrouvait
compressé sur deux lignes dans 62 px, et le bouton d'enregistrement
chevauchait le texte de description.
- En-tête : les commandes ne se compriment plus (flex-none,
whitespace-nowrap) et passent à la ligne si la largeur manque.
- Le bouton devient « + Nouveau preset », explicite, sur une ligne.
- Le preset appliqué reste sélectionné, avec un bouton de suppression :
deletePreset existait côté API mais n'était appelé nulle part.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Le remaniement précédent avait supprimé le panneau de sessions, et avec
lui le seul bouton pour démarrer une discussion.
- « Demander » devient « Discussion », avec en dessous le bouton
« + Nouvelle discussion » et les 5 discussions les plus récentes,
cliquables (point accent sur celle qui travaille).
- « Fichiers » quitte la barre latérale pour devenir un onglet du
panneau droit, à côté de Code. L'arborescence est extraite en
composant FileTree réutilisable.
- Nettoyage du code devenu mort : LeftPanel, FilesView, WorkspaceTree,
formatSize et la vue « files ».
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Remaniement de la navigation selon « Loki App.dc.html » : le rail
d'icônes de 60 px et le panneau de sessions laissent place à UNE barre
latérale de 264 px — marque, navigation libellée (Demander, Historique,
Fichiers, Outils), section Configuration, état Ollama avec jauge VRAM et
carte de compte. La marque quitte la barre supérieure, qui ne garde que
le contexte de la conversation.
Les sessions restent accessibles par le sélecteur de la barre
supérieure, et les fichiers par la vue Fichiers.
Performance : l'inventaire du workspace n'est plus injecté à CHAQUE
message, seulement quand la demande touche au code ou qu'un travail de
code est en cours. Un simple « bonjour » partait avec des milliers de
jetons de contexte, d'où une longue phase de traitement avant le premier
jeton.
L'attente avant le premier jeton affiche désormais le modèle en cours de
chargement et le temps écoulé, au lieu de rester figée sur « Connexion à
Ollama… » sans distinguer lenteur et blocage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Reprend l'état d'accueil du fichier de design : marque, accroche
« Bienvenue dans Loki », paragraphe sur l'exécution 100 % locale, et les
huit pistes cliquables en pastilles arrondies.
Les pistes pré-remplissent le composer au lieu d'être décoratives, et le
compteur de conversations n'apparaît que s'il y en a.
Remplace l'ancien état vide « PRÊT À TRAVAILLER ».
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Reprend les jetons de « Loki App.dc.html » : fond gris froid #f7f8fa,
surfaces blanches, accent bleu ardoise #2f4a7a (au lieu de l'orange),
filets 1 px #e3e6eb (au lieu des bordures noires 3 px) et ombres douces
diffuses (au lieu des ombres dures décalées).
- tailwind.config.ts : les NOMS de jetons sont conservés, seules leurs
valeurs basculent — toute l'interface suit sans réécrire les
composants. Les jetons historiquement sombres (card-deep, on-dark…)
deviennent la surface sélectionnée claire et son encre.
- Police unique Inter ; l'ex-« font-pixel » devient le kicker de la
maquette (petites capitales espacées de 0.14em), donc les libellés
existants suivent sans modification.
- Conversion mécanique des filets 3 px / 2 px vers 1 px, séparateurs
épais affinés, logo et avatar refaits selon la maquette (carré teinté
à filet accent), couleurs « papier » de l'aperçu passées en jetons.
- Texte blanc corrigé partout où il reposait sur une surface devenue
claire ; conservé sur les fonds accent/warn où il reste lisible.
Vérifié au rendu : body #f7f8fa, encre #1c2536, surface #ffffff, Inter ;
plus aucune trace d'orange, de noir #18181b ni d'ombre dure.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Les deux dernières idées d'AJEAN (github.com/nathaninline/jean).
1. Mémoire en notes Markdown ($DATA_DIR/MEMORY), écrites par l'agent via
deux outils (memory_search / memory_save). Trois modes : off,
ondemand (défaut) et always. Face au RAG vectoriel : aucun modèle
d'embedding requis, notes lisibles et éditables à la main, et rien de
mémorisé à l'insu — la recherche par mots-clés ne rappelle que du
pertinent, là où le RAG ressortait une demande sans rapport.
Le RAG disparaît de l'UI : un seul concept de mémoire.
En mode Plan, seule la consultation est proposée, pas l'écriture.
2. Presets : jeux de réglages nommés, enregistrés et rappelés en un
clic (sélecteur + « + Preset » dans l'en-tête des Réglages).
Au passage, un vrai bug : ConfigPatch ne déclarait ni keep_alive, ni
skills_enabled, ni ponytail — Pydantic ignore les champs non déclarés,
donc ces trois réglages ne se sauvegardaient JAMAIS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Les Réglages exposaient d'un bloc 7 curseurs et 5 interrupteurs
« Intelligence », dont des réglages pointus (Couches GPU, Batch, Top-K)
que l'on ne touche jamais — et Couches GPU est précisément celui qui
avait basculé l'inférence sur le CPU quand on le forçait.
- Génération : ne montre que Température et Contexte ; Top-P, Top-K,
Jetons max, Couches GPU et Batch passent sous « Réglages avancés »,
avec un avertissement explicite sur Couches GPU (laisser auto).
- Intelligence : au premier plan « Code minimal » et « Plan-puis-exécute »
(ce qui change le rendu au quotidien) ; Skills, Auto-critique et
Mémoire entre sessions passent en avancé. Descriptions raccourcies.
- Nouveau repli <details> natif (aucun état à gérer, accessible au
clavier) et ligne ToggleRow réutilisable, qui déduplique le balisage.
Aucune option supprimée : tout reste accessible en un clic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
À vide, l'app chauffait le CPU en continu : trois sondages navigateur
séparés (5/8/10 s) tournaient en permanence, y compris onglet caché, et
chaque tick relançait un sous-processus nvidia-smi (cache TTL 5 s = la
cadence, donc jamais efficace) plus deux connexions vers Ollama.
- Nouveau /api/system/pulse : statut + ressources + modèles chargés en
UNE requête (appels Ollama en parallèle, dégradation propre si muet),
avec un cache court qui absorbe les rafales multi-onglets.
- Front : un seul sondage, SUSPENDU quand l'onglet est caché, cadence
adaptative (4 s pendant un flux, 20 s au repos) et rafraîchissement
immédiat au retour sur l'onglet.
- Panneau Matériel : 5 s -> 15 s et rien onglet caché.
- Caches serveur alignés sur la cadence : nvidia-smi mis en cache 12 s,
et _all_local_gpus (vue Matériel) n'était pas caché du tout.
Effet au repos : ~25 requêtes/min et ~12 nvidia-smi/min -> ~3 et ~3
onglet visible, et ZÉRO onglet caché. Le serveur n'a aucune boucle de
fond : sans navigateur ouvert, il ne consomme plus rien.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
L'agent termine son tour pour attendre la validation, donc le streaming
s'arrête aussitôt — or la carte de confirmation n'était affichée que
pendant le streaming, elle disparaissait avant qu'on puisse cliquer.
- La carte de validation shell s'affiche tant que `pendingShell` existe,
indépendamment de l'état de streaming (approbation/refus déjà gérés
hors flux).
- Changer de session efface une validation en attente (elle appartenait
à la session quittée).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Adapte github.com/DietrichGebert/ponytail (philosophie anti
sur-ingénierie) en méthode transverse de Loki, remède direct aux rendus
trop ambitieux qui cassent (ex. « moteur IA » dans un jeu d'échecs).
- Échelle de décision injectée pour toute tâche de code (YAGNI ->
réutiliser -> natif -> minimum de code), sur les DEUX chemins : dans
le contexte de l'agent ET dans la consigne du moteur code (Aider ne
voit pas convo).
- Nouvel interrupteur « Ponytail (code minimal) » dans Réglages >
Intelligence, activé par défaut (fusionne sans migration).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Le plan s'affichait mais restait figé — on ne voyait pas le modèle
avancer. Désormais :
- Le modèle annonce chaque étape accomplie (« ✅ Étape N terminée »),
demandé dans la consigne de plan.
- L'agent détecte ces annonces dans le flux et émet des événements
plan_step, sans jamais recompter deux fois la même étape.
- Le panneau PLAN coche les étapes en temps réel : ✓ vert + barré pour
les faites, sablier sur l'étape en cours, compteur « n/N validées ».
Chemin agent uniquement (le moteur code tourne de bout en bout). Les
messages passés restent affichés tels quels.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
La mémoire long-terme rappelait des échanges d'AUTRES sessions dans la
discussion en cours : demander « un jeu d'échecs » ressortait une « appli
sport » demandée ailleurs, et déroutait les petits modèles.
- rag_enabled désactivé par défaut : chaque discussion ne se souvient que
d'elle-même (résumé + messages récents, déjà en place).
- Migration v7 : désactive le RAG une fois sur les installs existantes
(la valeur persiste en base /data) ; réactivable dans Réglages.
- Rappel plus strict quand le RAG est activé : seuil de similarité 0.45 -> 0.6.
- Réglages : libellé clarifié (« Mémoire entre sessions »).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Le chip modèle du composer était décoratif (pastille orange fixe) alors
que le TopBar montrait le vrai état de chargement. Le sélecteur complet
(liste + pastille GPU/CPU/à charger/préchargement) vit maintenant dans
la carte du chat, menu vers le haut.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ollama reloaded the chat model mid-message because plan/summary/router
calls sent divergent runner options (no num_ctx/num_batch) and omitted
keep_alive — the main cause of perceived slowness.
- share one keep-alive httpx.AsyncClient for all Ollama calls
- unify runner options (runner_options) + keep_alive on every model
call, embeddings included
- drop the blocking LLM routing fallback (pure lexical heuristic)
- run RAG recall + plan + code-model pick in parallel inside the SSE
stream, after the start event
- RAG cosine scoring off the event loop; cache /api/tags 30s and
nvidia-smi 5s; frontend polls 2s->5s, warm poll backoff, dedup
config fetch
feat: working session menu in TopBar (switch/create/rename/delete)
feat: workspace file deletion (DELETE /api/files + UI trash buttons)
docs: recommended Ollama env vars (KEEP_ALIVE, MAX_LOADED_MODELS...)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Modes d'exécution (composer) :
- routes/chat : champ mode ; _apply_mode adapte la config —
plan = outils lecture seule + plan forcé ; yolo = confirm_shell off ;
build = comportement normal.
- Frontend : ModeSelector dans le composer, mode dans le store + requête chat.
Panneau Git & Diff (le workspace est un dépôt git, Aider commite) :
- routes/git : /api/git/log (commits), /api/git/diff (commit ou working),
/api/git/revert (git revert --no-edit, confiné au workspace).
- Frontend : onglet Git dans le PreviewPanel — liste des commits, diff
colorisé, bouton Annuler (revert) avec rafraîchissement de l'arbo.
Bonus : le panneau Matériel explique que « GPU déclaré 12 Go » vient de
GPU_VRAM_MB (valeur manuelle) — à corriger en 16000 pour une 16 Go.
Tests : git log/diff/revert, modes plan/yolo/build via la route chat, builds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Recherche : un modèle plus gros que la VRAM (ex. qwen3.6:35b-a3b ~20 Go sur
16 Go) déborde sur le CPU et charge lentement ; et le préchargement chargeait
un runner aux options par défaut, aussitôt rechargé par le 1er message avec un
num_ctx différent — double chargement d'un gros modèle.
- ollama_client.warm : accepte et transmet les options de génération.
- routes/models : start_model_warm calcule les options depuis la config du
modèle (ollama_options) et les passe au warm -> runner identique au chat,
plus de rechargement. Après chargement, détecte le placement via /api/ps
(gpu/cpu/mixte + %) et l'expose dans l'état de warm.
- Frontend : warmModel renvoie l'état ; si le modèle se charge sur CPU/mixte,
message d'alerte clair (trop gros pour la VRAM, choisir plus petit/quant).
Tests : options transmises au warm, placement 'mixte 65%' détecté, builds OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
- routes/system : /api/system/hardware — liste les GPU vus par le conteneur
(nvidia-smi, multi-GPU) ou l'override GPU_VRAM_MB, et le placement réel des
modèles chargés côté Ollama (GPU/CPU/mixte + VRAM) via /api/ps.
- config : réintègre gpu_vram_mb / gpu_name (perdus lors d'une fusion).
- UI : carte MATÉRIEL dans Configuration (rafraîchie toutes les 5 s) montrant
les deux points de vue et si Ollama est local ou distant.
Répond à « l'appli est-elle réservée à la 3060 ? » (non) et permet de voir
tout de suite si Ollama charge un modèle sur CPU faute de support GPU.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
- config/main : LOKI_VERSION (git sha), exposé via /api/health et /api/version ;
affiché dans la barre du haut. Permet de vérifier que l'image déployée est
bien à jour (cause fréquente de 'les nouveautés n'apparaissent pas').
- Dockerfile : ARG/ENV LOKI_VERSION ; workflow : build-arg = github.sha.
- bench : corrige un bug de précédence d'opérateur dans l'épreuve JSON
(le tuple de retour était malformé quand l'extraction était partielle).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Évite le rechargement lent quand Ollama a déchargé le modèle de la VRAM :
- ollama_client.warm() : précharge un modèle (/api/generate sans prompt) ;
chat() accepte keep_alive (durée de rétention en VRAM).
- agent.run_agent transmet keep_alive ; route chat le passe depuis la config.
- config : champ keep_alive (défaut 30m) par profil de modèle.
- routes/models : POST /api/models/warm, GET /api/models/loaded (placement
GPU/CPU via /api/ps).
- main : préchargement du modèle par défaut au démarrage (arrière-plan,
best-effort — n'empêche pas le démarrage si Ollama est absent).
- Frontend : préchargement automatique à la sélection d'un modèle, poll des
modèles chargés (8s), pastille verte (GPU) / orange (CPU) / blanche (à
charger) dans le sélecteur, réglage 'Maintien en VRAM' dans Configuration.
Tests : warm/loaded routes, keep_alive transmis, démarrage résilient sans
Ollama, build front.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
1. Plan-puis-exécute (enhance.make_plan) : les demandes complexes sont
décomposées en 3-5 étapes (event SSE 'plan', carte PLAN dans le fil,
meta.plan persisté) ; le plan guide l'agent et le moteur code.
2. Auto-critique « Qualité + » (enhance.self_review, toggle Intelligence) :
critique éclair puis révision de la réponse (event 'revision').
3. Mémoire long-terme RAG (rag.py) : échanges vectorisés via /api/embed
(modèle d'embedding auto-détecté), rappel cosinus top-3 inter-sessions
injecté en contexte, indexation en arrière-plan, élagage à 2000 souvenirs.
4. Vérification HTML (tools.check_html) : références locales cassées et
balises déséquilibrées ; branchée sur l'auto-vérification des outils ET
sur le moteur code avec une passe d'auto-correction Aider.
5. Benchmark intégré (bench.py + /api/bench) : 5 épreuves notées /100
(appel d'outil, code exécuté en sous-processus isolé, consignes, JSON,
format), streaming SSE, scores stockés ; carte BENCHMARK dans l'UI.
Config : plan_mode / self_review / rag_enabled / embed_model + carte
Intelligence (3 toggles). Client SSE : events plan/revision ; PlanCard.
Tests : heuristique+parsing du plan, révision, index/rappel RAG (exclusion
de la session courante), html_check, bench 100/100 sur modèle simulé,
intégration chat HTTP (event plan + meta persisté), build front.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Faire d'un petit modèle un bon agent :
- memory.py : contexte = invite + résumé des anciens tours + 10 derniers
messages ; résumé régénéré en arrière-plan après chaque réponse (colonne
summary sur sessions, migration douce). Contexte court = modèle concentré
et qui tient sur le GPU.
- tools.py : edit_file (recherche/remplacement exact, erreurs pédagogiques,
unicité exigée), grep_search (regex bornée, dossiers ignorés), et
vérification syntaxique auto (.py/.json) après chaque écriture — l'erreur
revient au modèle qui se corrige dans le même tour.
- coder.pick_code_model : les tâches de code vont au meilleur modèle code
installé (qwen-coder, deepseek-coder…) via config code_model=auto.
- Branché dans la route chat (mémoire + résolution du modèle code) et la
boucle agent (code_task) ; UI : descriptions et glyphes des nouveaux outils.
Tests : edit/grep/vérification, compression mémoire (19 msgs -> 12 dont
résumé), pick auto/explicite, chat HTTP de bout en bout, build front.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Favicon now matches the LokiMark topbar icon instead of an unrelated
arrow glyph. New /api/system/stats endpoint (psutil + nvidia-smi)
polled every 2s and shown in the topbar next to the Ollama status.
Le bloc de code avait un texte gris fonce (text-ink-2) sur fond sombre apres
le passage au theme clair -> illisible. Texte repasse en clair (on-dark),
bordure noire 3px + ombre dure pour coller au theme neo-brutaliste.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Certains modèles « thinking » ne renvoyaient que du raisonnement, sans reponse
finale -> erreur. Nouvel interrupteur global `think` (Reglages > Generation) :
- think=false envoie `think:false` a Ollama pour desactiver le raisonnement
- repli automatique si le modele refuse le parametre (does not support thinking)
- message d'erreur mis a jour pour pointer vers l'interrupteur
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
UI : reskin complet vers un theme neo-brutaliste clair (bordures noires 3px,
ombres dures, accent orange, polices Press Start 2P + DM Mono).
- tailwind.config / index.css / index.html : palette, polices, ombres, scrollbars
- TopBar, ActivityBar, LeftPanel, ChatPanel, PreviewPanel, SettingsView,
ToolCard, ModelSelector, Icon : restyle complet
Chat : panneau « Raisonnement » repliable et redimensionnable affichant le
thinking de l'agent en direct (diffuse depuis le backend, persiste dans meta).
Robustesse Ollama : les echecs de generation de parseur d'outils
(« Unable to generate parser for this template ») declenchent desormais le
repli automatique en conversation simple sans outils, au lieu d'un 400.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Frontend
- MessageContent: rendu Markdown complet (react-markdown + remark-gfm) avec
blocs de code dans un cadre + bouton Copier, et styles thematises (titres,
listes, gras, liens, tableaux, citations).
- ChatPanel: affiche sous chaque reponse de l'agent la vitesse (tokens/s) et le
nombre de jetons generes / en entree.
- PreviewPanel: iframe en sandbox="allow-scripts" pour que le JS des pages
generees s'execute (animations, canvas) tout en gardant une origine opaque.
- Icon: ajout CopyIcon / CheckIcon.
Backend
- agent: cumule les metriques Ollama (eval_count, eval_duration,
prompt_eval_count) et calcule les tokens/seconde, emis dans l'evenement final.
- chat: persiste les stats dans meta et les renvoie au client.
- agent_config: l'invite systeme par defaut demande un formatage Markdown.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend :
- agent_config : num_ctx dans la config, envoyé à Ollama (0 = défaut modèle)
- ollama_client : méthode ps() (placement GPU/CPU via /api/ps)
- autotune : placement() lit size vs size_vram pour savoir si le modèle est sur GPU
- routes/config : POST /api/config/auto (détecte GPU + modèle, calcule et applique
num_ctx/max_tokens, renvoie la détection et le placement)
Frontend :
- client/store : autoTune(), état tuning + résultat
- SettingsView : bouton ⚡ Réglage auto, bannière de détection (GPU/VRAM,
contexte, placement GPU/CPU), slider Contexte (num_ctx)
Config :
- GPU_VRAM_MB / GPU_NAME pour déclarer la VRAM si Ollama est distant
Tests : recommandation (8B sur 12 Go -> ctx 32768), route /auto + persistance,
transmission num_ctx aux options Ollama, placement via /api/ps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
Backend :
- tools.py : web_search (DuckDuckGo HTML sans clé, ou SearxNG via SEARX_URL) et
run_shell (confiné au workspace, sortie bornée, timeout)
- agent.py : run_shell sensible -> émet tool_confirm et ne s'exécute pas tant que
l'utilisateur n'a pas validé (confirm_shell)
- agent_config.py : web_search/run_shell désactivés par défaut, flag confirm_shell
- routes/shell.py : POST /api/shell/run exécute une commande validée
- routes/chat.py : relaie l'événement tool_confirm, passe confirm_shell
Frontend :
- streamChat : événement tool_confirm
- store : pendingShell + approveShell/rejectShell (réinjecte le résultat à l'agent)
- ChatPanel : carte de validation de commande (Approuver / Refuser)
- SettingsView : toggles web_search/run_shell, marqueur sensible, switch confirm_shell
- ToolCard : glyphes web_search/run_shell, statut 'à valider', aperçu d'argument
Tests : run_shell confiné, gate de confirmation (commande dangereuse non exécutée),
route shell, parser DuckDuckGo.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N