Files
promptkey/docs/architecture-prompt-manager-autohotkey.md
Spark 258287b2ea
ci / verifier-pack (push) Successful in 1m29s
feat(pack,docs): pack de démarrage 20 prompts, README, tests, CI, build
- packs/essentiels : 20 prompts en 4 catégories (Général, Écriture, Code,
  Analyse), en-têtes conformes au parseur, variables déclarées = utilisées
- tests/run_tests.ahk : suites Frontmatter, Variables, JSON, Recherche,
  encodage UTF-8 (à exécuter sous Windows avec AutoHotkey v2)
- scripts/check_pack.py + .gitea/workflows/ci.yml : cohérence du pack
- build.ps1 : tests puis compilation Ahk2Exe et zip portable
- docs : document d'architecture et de conception v1.0
2026-10-11 10:17:30 -04:00

72 KiB
Raw Permalink Blame History

PromptKey — Gestionnaire de prompts pour IA sous AutoHotkey

Architecture et conception — v1.0 — 2026-10-11 Statut : document de conception, à valider avant implémentation Nom de travail : PromptKey (à confirmer, §20-Q1) Environnement cible : Windows 10 / 11, AutoHotkey v2.0 (64 bits)


Table des matières

  1. Résumé décisionnel
  2. Le problème et les cas d'usage
  3. Périmètre : ce que PromptKey fait, et ce qu'il ne fait pas
  4. Pourquoi AutoHotkey — et ses limites assumées
  5. Décisions structurantes (D1 à D8)
  6. Architecture d'ensemble
  7. Modèle de données : un prompt = un fichier Markdown
  8. Le Quick Picker : la surface principale
  9. Le Gestionnaire et l'Éditeur
  10. Le moteur de variables
  11. Le moteur d'injection : livrer le prompt à l'IA
  12. Profils de destination (les « IA cibles »)
  13. Raccourcis globaux et hotstrings
  14. Recherche : index en mémoire et classement flou
  15. Historique, favoris et statistiques d'usage
  16. Import, export et packs de prompts
  17. Paramètres, portabilité et synchronisation
  18. Sécurité et vie privée
  19. Architecture du code AutoHotkey v2
  20. Maquettes des écrans (ASCII)
  21. Packaging, installation et mises à jour
  22. Tests et critères de qualité
  23. Plan d'implémentation en phases (tickets)
  24. Risques et mitigations
  25. Alternatives écartées
  26. Décisions ouvertes pour Bruno
  • Annexe A — Exemple complet d'un fichier prompt
  • Annexe B — Algorithme de classement de la recherche
  • Annexe C — Séquence d'injection, pas à pas
  • Annexe D — Pack de démarrage proposé (20 prompts)

1. Résumé décisionnel

PromptKey est une petite application Windows, écrite en AutoHotkey v2, qui vit dans la zone de notification (tray) et qui répond à un seul besoin, partout dans Windows, en moins de deux secondes :

« Je suis dans ChatGPT / Claude / Gemini / Qwen / un éditeur / un courriel. Je veux insérer le bon prompt, adapté à ce texte-ci, sans quitter le clavier ni fouiller dans un fichier de notes. »

Le geste central tient en trois touches et quelques frappes :

Ctrl+Alt+Espace  →  taper « résu… »  →  Entrée  →  remplir 1-2 variables  →  le prompt est collé, prêt à envoyer

Les cinq choix qui structurent tout le reste du document :

# Décision En une phrase
D1 AutoHotkey v2 uniquement Pas de v1 : syntaxe moderne, classes, Map, meilleure maintenabilité.
D2 Un prompt = un fichier .md Source de vérité en fichiers Markdown avec en-tête structuré : lisibles, éditables partout (dont Obsidian), versionnables sous Git/Gitea, jamais enfermés dans un format propriétaire.
D3 Index en mémoire, pas de base de données en v1 Chargement complet au démarrage + cache JSON ; suffisant et rapide jusqu'à ~5 000 prompts, zéro DLL externe.
D4 Injection par presse-papiers restauré, par défaut Coller via Ctrl+V après sauvegarde du presse-papiers, restauration après délai ; SendText en repli configurable pour les champs récalcitrants.
D5 Aucun appel réseau, aucun envoi automatique PromptKey insère du texte dans le champ actif ; il n'appelle aucune API d'IA et n'appuie jamais sur « Envoyer » à la place de l'utilisateur (option explicite par profil, désactivée par défaut).

Conséquence directe : PromptKey est agnostique de l'IA. Il sert aussi bien une page web ChatGPT qu'une application de bureau, un terminal, Hermes, un client courriel ou un document Word — partout où un champ texte accepte un collage. Changer d'IA ne change rien à la bibliothèque de prompts ; seuls des profils de destination (§12) ajustent la forme (longueur, format, langue, touche d'envoi).

Livrable visé à la fin du plan (§23) : un PromptKey.exe portable compilé (Ahk2Exe), un dossier Prompts\ de départ (Annexe D), et ce document comme cahier des charges.


2. Le problème et les cas d'usage

2.1 Le problème, concrètement

Travailler avec plusieurs IA au quotidien produit le même cycle coûteux :

  1. Dispersion. Les bons prompts vivent dans des notes, des courriels, des fichiers texte, la mémoire — rarement retrouvés au moment voulu.
  2. Retapage. Le même prompt « résume ce texte en 5 points, ton neutre » est retapé, réadapté, dégradé à chaque usage.
  3. Perte du contexte. Le prompt idéal dépend du texte sélectionné, du presse-papiers, de la date, du projet — recopiés à la main.
  4. Friction de changement d'outil. Un prompt taillé pour une IA (format, longueur, consignes) est réécrit pour l'autre.
  5. Aucune mémoire d'usage. Impossible de savoir quels prompts servent vraiment, lesquels sont des doublons morts.

Le coût n'est pas le temps de frappe : c'est l'interruption de flux — quitter l'application, chercher, copier, revenir, recoller, réadapter.

2.2 Cas d'usage nominaux

# Cas Déroulement cible
U1 Prompt simple Dans Claude (web), Ctrl+Alt+Espace → « traduis » → Entrée → le prompt de traduction est collé avec le texte sélectionné déjà incorporé.
U2 Prompt à variables « Revue de code » demande {{langage}} (liste : Python / JS / AHK…) et {{niveau}} (liste : rapide / strict) dans un mini-formulaire, puis colle le prompt résolu.
U3 Prompt sur sélection Sélectionner un paragraphe dans Word → raccourci → choisir « Reformuler » → le texte sélectionné est capturé automatiquement et injecté dans {{selection}}.
U4 Prompt favori sans recherche Ctrl+Alt+1 colle directement le prompt épinglé n° 1, sans ouvrir aucune fenêtre.
U5 Abréviation tapée Taper ::resu; dans n'importe quel champ le remplace par le prompt « Résumer » (hotstring, §13.2).
U6 Bibliothèque qui grandit Nouveau prompt créé depuis le Gestionnaire en 30 s, ou depuis la sélection (« Enregistrer la sélection comme prompt »), classé par catégorie et étiquettes.
U7 Changement d'IA Le même prompt « Explique » est utilisé dans Qwen avec le profil Qwen (consignes resserrées, réponse en français) et dans ChatGPT avec le profil par défaut — le corps du prompt ne change pas, le profil ajoute son préambule.
U8 Partage / sauvegarde Exporter une catégorie en un fichier .zip de .md (ou la versionner dans un dépôt Gitea) ; l'importer sur un autre poste en glisser-déposer.

2.3 Personnes et contexte d'usage

Utilisateur unique, poste Windows personnel, usage au clavier d'abord. L'application doit rester utile hors ligne, sans compte, sans serveur — y compris quand l'IA cible est elle-même locale ou dans un terminal.


3. Périmètre : ce que PromptKey fait, et ce qu'il ne fait pas

3.1 Dans le périmètre (v1 visée par ce document)

  • Bibliothèque locale de prompts : créer, modifier, dupliquer, supprimer, classer (catégories + étiquettes), épingler.
  • Recherche instantanée floue (titre, étiquettes, catégorie, corps) et navigation 100 % clavier.
  • Variables typées dans les prompts, résolues par mini-formulaire ou automatiquement (sélection, presse-papiers, date…).
  • Injection du prompt résolu dans l'application active, par presse-papiers ou par frappe simulée.
  • Profils de destination (préambule, format, option « envoyer après insertion » désactivée par défaut).
  • Raccourcis globaux personnalisés par prompt + hotstrings.
  • Historique d'usage local, favoris, compteurs (pour le classement « fréquents »).
  • Import/export Markdown et JSON ; packs de prompts.
  • Paramètres : raccourci principal, délais d'injection, thème, dossier de bibliothèque, démarrage avec Windows.

3.2 Hors périmètre (explicitement)

  • Appeler une API d'IA. PromptKey ne parle à aucun modèle ; il prépare et insère du texte. (Une extension « envoyer à l'API et coller la réponse » est discutée en phase optionnelle §23.7, hors v1.)
  • Gérer des conversations ou l'historique des réponses des IA.
  • Synchroniser tout seul : la synchro passe par le dossier (Git, OneDrive, dossier partagé) — PromptKey détecte les changements de fichiers, il ne transporte rien (§17.3).
  • Mac / Linux : AutoHotkey est Windows seulement (§4.2).
  • Multi-utilisateur, partage en temps réel, permissions.
  • Stocker des secrets : les prompts ne doivent pas contenir de clés d'API ; les variables de type « masqué » existent pour la saisie ponctuelle, jamais persistées (§18).

4. Pourquoi AutoHotkey — et ses limites assumées

4.1 Ce qu'AutoHotkey v2 apporte, exactement pour ce besoin

  • Raccourcis globaux et hotstrings natifs, fiables dans presque toutes les applications Windows — c'est le cœur du besoin, et c'est la spécialité historique d'AHK.
  • Manipulation du presse-papiers (A_Clipboard, ClipWait) et envoi de frappes (Send, SendText) intégrés, sans dépendance.
  • GUI native (Gui, ListView, TreeView, Edit) suffisante pour un sélecteur rapide et un gestionnaire en trois volets.
  • Exécutable autonome via Ahk2Exe : un seul .exe, aucun runtime à installer chez l'utilisateur final (AHK v2 reste requis seulement pour développer).
  • Démarrage rapide, empreinte mémoire faible, processus tray discret — adapté à un outil invoqué 50 fois par jour.

4.2 Limites assumées (et leur traitement dans ce document)

Limite Traitement
Windows seulement Assumé (§3.2). La bibliothèque en .md reste portable : si un équivalent Mac/Linux naît un jour, il relira les mêmes fichiers.
Applications élevées (administrateur) : un AHK non élevé ne peut pas leur envoyer de frappes Détection + message clair (§11.5) ; option « relancer en administrateur » documentée, jamais forcée.
Champs riches (éditeurs web, contenteditable) où le collage formate ou échoue Profils par application avec méthode d'injection dédiée (§12) ; repli SendText.
Les .exe compilés AHK déclenchent parfois des faux positifs antivirus Distribution du .ahk source en parallèle, compilation reproductible documentée (§21.3) ; pas de comportement réseau qui aggraverait le score.
GUI native limitée (pas de « beau » framework) Design fonctionnel : Picker minimal et rapide plutôt que joli ; soin porté à la typographie, au thème sombre et au clavier (§20).
Pas de vrai YAML ni de SQLite intégrés Sous-ensemble d'en-tête strictement défini et parsé par un module dédié (§7.3) ; index en mémoire (§14).
Raccourcis déjà pris par d'autres applications Détection de conflit à l'enregistrement et rapport dans les Paramètres (§13.3).

5. Décisions structurantes (D1 à D8)

D1 — AutoHotkey v2.0 64 bits uniquement

Toute la base de code cible la syntaxe v2 : classes, Map(), fonctions fléchées, Gui orienté objet. Aucun code v1, aucune double compatibilité : mélanger les dialectes est la première source de bogues AHK. Version minimale épinglée : v2.0.10+ (correctifs ListView / DPI).

D2 — Un prompt = un fichier Markdown

Chaque prompt est un fichier Nom-du-prompt.md dans le dossier de bibliothèque :

  • En-tête (frontmatter délimité par ---) : métadonnées structurées (§7.2).
  • Corps : le texte du prompt, avec ses variables {{…}}.

Avantages décisifs pour l'usage visé : éditable dans n'importe quel éditeur (dont le Gestionnaire intégré, mais aussi VS Code ou Obsidian), cherchable par grep, versionnable sous Git (un dépôt Gitea privé fait une sauvegarde et un historique parfaits), partageable fichier par fichier. Le coût — un parseur d'en-tête maison — est borné par un sous-ensemble strict (§7.3) et couvert par des tests (§22).

Rejeté : base SQLite comme source de vérité (opaque, non éditable à la main, DLL externe) ; fichier JSON unique géant (conflits de fusion, illisible dès 100 prompts). Le JSON reste utilisé pour le cache d'index (§14.2) et l'export, jamais comme source.

D3 — Index en mémoire reconstruisible

Au démarrage, PromptKey lit tous les .md, construit l'index en mémoire et le met en cache (index-cache.json, invalidé par date/taille des fichiers). La recherche travaille sur l'index, pas sur le disque. Plafond de conception : 5 000 prompts, recherche < 100 ms. Au-delà, une phase ultérieure pourra adosser SQLite sans changer le format source (D2 reste intact).

D4 — Injection : presse-papiers restauré par défaut, frappe en repli

Comparatif tranché (§11 donne le détail) :

Méthode Vitesse Fidélité (Unicode, sauts de ligne) Risques
Presse-papiers + Ctrl+V Instantanée Excellente Écrase brièvement le presse-papiers → sauvegarde/restauration obligatoires
SendText (frappe simulée) Lente sur longs prompts Bonne, mais sensible à la disposition clavier Interférences (IMEs, champs qui interceptent), focus perdu = texte dans le vide

Défaut : presse-papiers, avec restauration après un délai configurable (1,5 s par défaut) et abandon de la restauration si l'utilisateur a copié autre chose entre-temps (§11.3).

D5 — Insérer, ne pas envoyer

Après injection, le curseur reste chez l'utilisateur : il relit, ajuste, envoie lui-même. L'option « Entrée automatique après insertion » existe par profil de destination, désactivée par défaut, avec un délai de grâce de 800 ms annulable par Échap (§12.3). Principe : un mauvais prompt collé se corrige ; un mauvais prompt envoyé — éventuellement au mauvais fil — ne se rattrape pas.

D6 — Processus tray unique, aucune fenêtre au repos

Instance unique (#SingleInstance Force), icône tray, aucune fenêtre visible tant qu'on n'invoque pas PromptKey. Fermer une fenêtre = la masquer, jamais quitter (quitter se fait par le menu tray).

D7 — Zéro réseau en v1

Aucun appel sortant : ni télémétrie, ni vérification de mise à jour en ligne, ni « amélioration IA du prompt ». Cela simplifie la sécurité (§18), les antivirus (§4.2) et la confiance. Les mises à jour sont manuelles (§21.4).

D8 — Clavier d'abord, souris en appoint

Chaque action du Picker et du Gestionnaire a un chemin clavier complet ; les listes se naviguent aux flèches, Entrée valide, Échap ferme et rend le focus à l'application d'origine (§11.2 — le retour de focus est une fonction de premier rang, pas un détail).


6. Architecture d'ensemble

6.1 Vue logique

┌────────────────────────────────────────────────────────────────────┐
│                        PromptKey.exe (AHK v2)                      │
│                                                                    │
│  ┌──────────────┐   ┌───────────────┐   ┌───────────────────────┐  │
│  │  Entrées     │   │  Surfaces GUI │   │  Services (classes)   │  │
│  │              │   │               │   │                       │  │
│  │ Raccourcis   │──▶│ Quick Picker  │──▶│ PromptStore  (fichiers)│  │
│  │ globaux      │   │ Gestionnaire  │   │ Index/Recherche        │  │
│  │ Hotstrings   │   │ Éditeur       │   │ VariableEngine         │  │
│  │ Menu tray    │   │ Formulaire    │   │ Injector               │  │
│  │ Clic tray    │   │  variables    │   │ ClipboardGuard         │  │
│  │              │   │ Paramètres    │   │ HotkeyManager          │  │
│  └──────────────┘   └───────────────┘   │ UsageStats             │  │
│         ▲                               │ Settings               │  │
│         │                               └──────────┬────────────┘  │
└─────────┼──────────────────────────────────────────┼───────────────┘
          │                                        │
   Clavier/souris                          Disque (local uniquement)
   (toutes applications)           ┌───────────────────────────────┐
                                   │ Bibliothèque\  *.md (source)  │
                                   │ config.ini / index-cache.json │
                                   │ usage.json     / promptkey.log│
                                   └───────────────────────────────┘

6.2 Flux principal (le « chemin heureux »)

1. L'utilisateur travaille dans l'application X (focus sur X).
2. Raccourci global → PromptKey mémorise la fenêtre active (hwnd X) et son titre.
3. Le Picker s'ouvre (déjà chargé : l'index est en mémoire), focus sur la recherche.
4. Frappe + flèches → le prompt choisi ; aperçu du corps à droite.
5. Si le prompt a des variables manuelles → mini-formulaire (les variables
   automatiques — sélection, presse-papiers — sont déjà capturées, §10.3).
6. VariableEngine produit le texte final (corps + préambule du profil actif).
7. Le Picker se ferme, le focus revient sur X, Injector colle le texte.
8. UsageStats enregistre l'usage (id, horodatage) — jamais le contenu résolu (§18).

Étape critique : 2 → 7, la capture et la restitution du focus. Si le focus ne revient pas exactement dans le champ d'origine, l'injection part dans le vide. Le module Injector (§11) est donc isolé, testé à part, et toutes les surfaces passent par lui — aucun Send dispersé dans les GUI.

6.3 Démarrage et cycle de vie

  • Lancement (manuel ou démarrage Windows) → chargement des paramètres → scan de la bibliothèque → construction/vérification du cache d'index → enregistrement des raccourcis globaux et hotstrings → icône tray → attente.
  • Un surveillant de dossier (sondage léger toutes les 5 s sur les dates de modification, ou WM_DEVICECHANGE-like par minuteur) détecte les .md ajoutés/modifiés/supprimés hors de l'application (édition dans VS Code, git pull…) et rafraîchit l'index sans redémarrage.
  • Arrêt propre par le menu tray : libération des raccourcis, vidage du cache vers le disque, restauration du presse-papiers si une restauration était en attente.

7. Modèle de données : un prompt = un fichier Markdown

7.1 Arborescence de la bibliothèque

Bibliothèque\
├─ _packs\                 ← packs importés, non édités directement (optionnel)
├─ Code\
│  ├─ revue-de-code.md
│  └─ expliquer-une-erreur.md
├─ Écriture\
│  ├─ reformuler.md
│  └─ resumer-en-5-points.md
├─ Général\
│  └─ expliquer-simplement.md
└─ Sans catégorie\         ← dossier réel ou implicite (fichiers à la racine)

La catégorie = le dossier de premier niveau. Choix délibéré : la structure est visible et manipulable dans l'Explorateur Windows, aucun champ à maintenir en double. Sous-dossiers au-delà du premier niveau : ignorés en v1 (organisation plate par étiquettes pour le reste). Renommer un dossier = renommer la catégorie, détecté par le surveillant (§6.3).

7.2 L'en-tête du fichier (métadonnées)

---
id: 7f3a2c1e-…            # GUID stable, généré à la création, ne change jamais
title: Résumer en 5 points
tags: [résumé, synthèse, court]
targets: [défaut, claude, qwen]     # profils de destination conseillés (§12)
favorite: true
pinned: 2                            # rang dans les raccourcis directs (0 = non épinglé)
hotkey: ^!r                          # raccourci propre (syntaxe AHK), optionnel
hotstring: resu;                     # abréviation ::resu; , optionnelle
profile: défaut                      # profil appliqué si targets ne tranche pas
send_after: false                    # surcharge du profil (§12.3)
sensitive: false                     # si true : presse-papiers vidé après injection (§18, point 6)
created: 2026-10-11
updated: 2026-10-11
variables:
  - name: ton
    label: Ton de la réponse
    type: enum
    choices: [neutre, formel, amical, direct]
    default: neutre
  - name: longueur
    label: Longueur max
    type: enum
    choices: ["5 points", "1 paragraphe", "détaillé"]
    default: "5 points"
---

Résume le texte suivant en {{longueur}}, ton {{ton}}.
Réponds en français, sans reformuler la première phrase.

Texte :
{{selection}}

Le corps commence après le second ---. Tout ce qui suit est le prompt, verbatim, y compris ses propres --- éventuels (le parseur ne coupe qu'aux deux premiers délimiteurs).

7.3 Le sous-ensemble d'en-tête accepté (contrat strict)

AHK n'a pas de parseur YAML : PromptKey définit donc un sous-ensemble ligne par ligne, documenté ici comme contrat — tout le reste est une erreur de fichier signalée, jamais devinée :

  • Clés scalaires : clé: valeur (chaîne, true/false, nombre, date AAAA-MM-JJ).
  • Listes en ligne : [a, b, c] — virgules, éléments éventuellement entre guillemets doubles.
  • Bloc variables: : liste d'objets indentés de 2 espaces, clés parmi name, label, type, choices, default, required, multiline.
  • Commentaires # en fin de ligne, lignes vides ignorées.
  • Interdits (erreur explicite avec n° de ligne) : ancres YAML, listes multi-lignes hors variables, tableaux imbriqués, valeurs multi-lignes |.

Un fichier en erreur n'est jamais exclu silencieusement : il apparaît dans le Gestionnaire sous « Fichiers en erreur » avec le message et la ligne, et double-cliquer l'ouvre dans l'éditeur de texte par défaut. Un prompt sans en-tête du tout est accepté : titre = nom du fichier, corps = tout le fichier (import de notes existantes sans friction).

7.4 Identité et renommage

L'id (GUID dans l'en-tête) est l'identité ; le nom de fichier est libre (renommer le fichier ne casse ni les statistiques ni les raccourcis). L'historique et les compteurs (§15) sont indexés par id. À la première lecture d'un fichier sans id, PromptKey le génère et réécrit l'en-tête (avec sauvegarde .bak unique).

7.5 Champs calculés (jamais stockés dans le fichier)

usage_count, last_used, score de récence : dérivés de usage.json (§15), pas du fichier prompt — pour que versionner la bibliothèque sous Git ne produise pas un diff à chaque usage.


8. Le Quick Picker : la surface principale

Le Picker est l'écran que l'utilisateur verra 95 % du temps. Ses exigences sont des exigences de vitesse perçue :

Exigence Cible
Raccourci → fenêtre visible et focus prêt < 150 ms (fenêtre pré-créée, masquée/montée)
Frappe → liste filtrée < 50 ms par touche (recherche sur index en mémoire)
Ouverture → prompt collé (cas sans variable) ≤ 4 frappes + Entrée, par défaut
Abandon (Échap) Focus rendu à l'application d'origine, zéro effet de bord

8.1 Composition (voir maquette §20.1)

  • Champ de recherche (focus initial, texte sélectionné au retour).
  • Liste de résultats : titre, catégorie, étiquettes, marqueurs (★ favori, 📌 épinglé, raccourci propre). Tri par défaut : épinglés → favoris → fréquents récents → pertinence de recherche.
  • Panneau d'aperçu : corps du prompt avec les variables surlignées, et — si une sélection a été capturée — son début, tronqué proprement.
  • Barre de statut : profil de destination actif, méthode d'injection qui sera utilisée, nombre de résultats.

8.2 Interactions clavier (contrat)

Touche Effet
↑ / ↓, Ctrl+N / Ctrl+P Naviguer
Entrée Utiliser le prompt (formulaire de variables si requis, sinon injection directe)
Ctrl+Entrée Utiliser sans formulaire : valeurs par défaut pour toutes les variables
Ctrl+C (sur un résultat) Copier le prompt résolu dans le presse-papiers, sans injecter
Ctrl+E Ouvrir le prompt dans l'Éditeur
Alt+1…9 Basculer le profil de destination pour cette injection seulement
Échap Fermer, rendre le focus, ne rien faire d'autre
Frappe directe Filtrer (la recherche est toujours active, pas de mode séparé)

8.3 Listes par défaut (recherche vide)

À l'ouverture sans frappe : Épinglés, puis Récents (7 derniers jours, dédupliqués), puis Fréquents. C'est ce qui rend l'outil rapide pour les 5 prompts du quotidien : la plupart des usages ne nécessitent aucune recherche.


9. Le Gestionnaire et l'Éditeur

9.1 Gestionnaire (fenêtre principale, §20.2)

Ouvert par le menu tray, par Ctrl+Alt+M ou depuis le Picker (Ctrl+E sur la bibliothèque). Trois volets :

  1. Arbre : catégories (dossiers), Favoris, Récents, Épinglés, Fichiers en erreur — avec compteurs.
  2. Liste : prompts de la sélection, triables (titre, modifié, usage), recherche locale.
  3. Détail / aperçu : métadonnées et corps, boutons Utiliser / Modifier / Dupliquer / Exporter / Supprimer.

Actions de masse : déplacer vers une catégorie (glisser-déposer ou menu), ajouter/retirer une étiquette, exporter la sélection. Suppression = corbeille Windows (pas de suppression définitive directe) — un prompt est un texte précieux, souvent le fruit d'itérations.

Création express, trois chemins :

  • Nouveau (formulaire vide + modèle de corps commenté) ;
  • Depuis la sélection : le texte sélectionné dans l'application courante devient le corps (déjà vu en U6) ;
  • Depuis le presse-papiers : idem, contenu courant du presse-papiers.

9.2 Éditeur (§20.3)

Éditeur intégré volontairement simple — champ texte multiligne à tabulations conservées, panneau de métadonnées à droite (titre, catégorie, étiquettes, profils, favori/épinglé, raccourci, hotstring), et trois aides qui le distinguent d'un bloc-notes :

  • Insertion de variable (Ctrl+J ou bouton) : insère {{nom}} et, si la variable n'existe pas encore dans l'en-tête, propose de la déclarer (type, libellé, défaut) — la déclaration et l'usage restent synchronisés.
  • Validation en direct : variables utilisées non déclarées, variables déclarées inutilisées, en-tête en erreur (ligne fautive), raccourci en conflit — affichés sous l'éditeur, sauvegarde bloquée seulement pour les erreurs d'en-tête, jamais pour les avertissements.
  • Tester (Ctrl+T) : ouvre le formulaire de variables puis montre le prompt résolu final (avec profil) dans une fenêtre de prévisualisation, sans rien injecter.

Enregistrer écrit le fichier en UTF-8 explicite (jamais l'encodage ANSI par défaut d'AHK, voir le piège détaillé en §19.4) et rafraîchit l'index immédiatement.

9.3 Ce que l'Éditeur n'essaie pas d'être

Pas de coloration syntaxique avancée, pas de markdown riche : pour l'édition lourde, le bouton « Ouvrir dans l'éditeur externe » (paramétrable : VS Code, Notepad++, Obsidian…) ouvre le .md, et le surveillant de dossier répercute les changements au retour.


10. Le moteur de variables

10.1 Syntaxe

{{nom}} dans le corps. Noms : [a-z0-9_]+, insensibles à la casse à la résolution. Aucune logique (pas de conditions, pas de boucles) en v1 : ce sont des emplacements à remplir, pas un langage de gabarit — la complexité est renvoyée au prompt lui-même, qui est fait pour une IA.

10.2 Types de variables déclarées

Type Contrôle du formulaire Exemple
text Champ ligne {{sujet}}
multiline Champ multiligne {{contexte}}
enum Liste déroulante (choices obligatoire) {{ton}}
number Champ + validation numérique {{nb_points}}
date Sélecteur de date, rendu AAAA-MM-JJ ou format du default {{echeance}}
bool Case à cocher, rend default si coché / texte alternatif choices: [oui, non] {{avec_exemples}}
password Champ masqué, jamais persisté ni journalisé jeton ponctuel

Variable utilisée mais non déclarée : traitée comme text avec libellé = nom, demandée au formulaire (aucun blocage — un prompt copié-collé depuis le web doit fonctionner tel quel).

10.3 Variables automatiques (jamais demandées)

Variable Source Précision
{{selection}} Texte sélectionné dans l'application d'origine, capturé à l'invocation (§11.2) Chaîne vide si rien n'est sélectionné ; le formulaire le signale
{{clipboard}} Contenu texte du presse-papiers avant toute manipulation Capturé avant que l'Injector ne touche au presse-papiers
{{date}} / {{datetime}} / {{time}} Horloge locale Formats AAAA-MM-JJ, AAAA-MM-JJ HH:mm, HH:mm
{{app}} Nom du processus / titre de la fenêtre d'origine Utile pour « je suis dans {{app}}… »
{{cursor}} Marqueur de position : après injection, le curseur est replacé ici et le marqueur est retiré du texte Pour les prompts-gabarits à compléter à la main

Règle de capture : les variables automatiques sont figées au moment de l'invocation (raccourci/hotstring), pas à la validation du formulaire — sinon la sélection d'origine serait perdue dès que le Picker prend le focus.

10.4 Le formulaire de variables (§20.4)

  • Un contrôle par variable manuelle, dans l'ordre de déclaration ; valeurs par défaut pré-remplies ; Tab navigue, Entrée (hors champ multiligne) valide tout, Échap annule toute l'injection.
  • Les required vides bloquent la validation avec surlignage, jamais avec une boîte de dialogue.
  • Les choix faits sont mémorisés par prompt (usage.json, §15) comme nouveaux défauts proposés — un prompt « revue de code » retient que le langage habituel est Python. Les password sont exclus de cette mémorisation, sans exception.

10.5 Ordre de résolution

corps du fichier
  → substitution des automatiques (capturées à l'invocation)
  → substitution des manuelles (formulaire ou défauts, Ctrl+Entrée)
  → résolution de {{cursor}} (position mémorisée, marqueur retiré)
  → préambule + séparateur + postambule du profil actif (§12.2)
  → texte final remis à l'Injector

Aucune variable inconnue ne subsiste silencieusement : un {{…}} non résolu après ces étapes (ex. faute de frappe dans une automatique) est laissé tel quel et signalé dans la prévisualisation du formulaire ; en injection directe sans formulaire, un bip discret + infobulle tray « variable non résolue : X » après collage. Mieux vaut un défaut visible qu'un texte silencieusement faux.


11. Le moteur d'injection : livrer le prompt à l'IA

C'est le module le plus délicat du système. Il concentre toutes les interactions avec le focus, le presse-papiers et la frappe simulée.

11.1 Interface

Injector.Deliver(texte, options) → résultat {ok, méthode, erreur?}
  options : { hwndCible, profil, méthode: auto|clipboard|sendtext,
              sendAfter: bool, restaurerPressePapiers: bool }

Aucun autre module n'appelle Send, A_Clipboard ou ControlFocus directement (règle vérifiable par recherche dans le code, §22).

11.2 Capture du contexte d'invocation

À chaque invocation (raccourci global, hotstring exclue) :

  1. hwnd et titre de la fenêtre active, nom du processus.
  2. Tentative de capture de la sélection : sauvegarde du presse-papiers → Ctrl+C simulé → ClipWait court (250 ms) → lecture → restauration immédiate du presse-papiers. Si le presse-papiers n'a pas changé ou ne contient pas de texte, sélection = vide. Cette capture est best-effort : son échec ne bloque jamais l'ouverture du Picker.
  3. Ces données vivent dans un objet InvocationContext transmis au Picker, au formulaire puis à l'Injector.

11.3 Méthode « presse-papiers » (défaut)

1. Sauvegarder le presse-papiers complet (tous formats, via ClipboardAll).
2. Poser le texte final dans le presse-papiers (format texte Unicode).
3. Rendre le focus à hwndCible (WinActivate + attente active ≤ 500 ms).
4. Send "^v" ; attendre le délai de collage (par défaut 150 ms).
5. Planifier la restauration à +1,5 s (paramétrable) :
   - si le presse-papiers contient encore EXACTEMENT le texte injecté → restaurer la sauvegarde ;
   - sinon (l'utilisateur a copié autre chose) → abandonner la restauration sans rien écraser.
6. Si sendAfter (profil) : attendre 800 ms annulables, puis Send "{Enter}".

L'étape 5 est la différence entre un outil propre et un outil qui « mange » le presse-papiers de l'utilisateur : elle est obligatoire, pas optionnelle.

11.4 Méthode « frappe simulée » (SendText)

Utilisée quand : le profil de l'application la demande, le collage a échoué (détection best-effort), ou l'utilisateur la choisit pour cette fois (Ctrl+Alt+V dans le Picker bascule la méthode). SendText plutôt que Send : pas d'interprétation des caractères spéciaux (+^!#{}), indispensable pour du texte de prompt arbitraire. Vitesse plafonnée et documentée : au-delà de ~4 000 caractères, un avertissement propose de repasser en presse-papiers.

11.5 Échecs et cas limites traités explicitement

Cas Comportement
Fenêtre d'origine fermée entre-temps Injection annulée, texte final copié dans le presse-papiers + infobulle « fenêtre disparue — prompt copié »
Application cible élevée (admin), PromptKey non élevé Message clair nommant l'application et l'option (relancer PromptKey en admin, ou copier plutôt qu'injecter) — détecté par comparaison d'intégrité du processus cible quand c'est possible, sinon par échec de WinActivate
Le champ cible n'accepte pas le collage (détecté : presse-papiers revenu inchangé n'est pas un signal fiable → pas de détection prétendue) Aucune fausse promesse : le repli est un choix de profil par application (§12), pas une détection magique
Échap pendant le compte à rebours d'envoi Envoi annulé, texte laissé en place
Texte final vide (prompt vide) Refus avec message, aucune injection
PromptKey invoqué alors qu'il est déjà ouvert Le Picker reprend le focus (instance unique) ; jamais deux fenêtres

11.6 Journalisation

promptkey.log (rotation, 1 Mo) : horodatage, action, id du prompt, méthode, durée, erreur éventuelle. Jamais le contenu des prompts, des variables ou de la sélection (§18).


12. Profils de destination (les « IA cibles »)

12.1 Principe

Un profil décrit comment adapter la livraison à une destination, pas un autre prompt. La bibliothèque reste unique ; les profils évitent les doublons « Résumer (pour Claude) », « Résumer (pour Qwen) »…

12.2 Contenu d'un profil

; config.ini — section [Profil.claude]
Nom=Claude
Preambule=Réponds en français, en Markdown, sans préambule de politesse.\n---
Postambule=
Methode=clipboard
SendAfter=false
DelaiCollageMs=250
AppMatch=chrome.exe, msedge.exe        ; indices d'auto-détection (optionnel)
TitreMatch=Claude                      ; expression dans le titre de fenêtre
  • Préambule / postambule : texte ajouté avant/après le corps résolu (avec \n interprétés). C'est l'endroit des consignes transversales : langue, format, concision.
  • Méthode, délais : surcharge de l'injection pour cette destination.
  • SendAfter : voir §12.3.
  • Profils livrés : défaut (neutre), claude, chatgpt, gemini, qwen, deepseek, hermes-terminal, courriel — tous modifiables, liste ouverte.
  • Un profil peut aussi être générique par type de champ : terminal (pas de Markdown, lignes courtes), texte-brut.

12.3 Sélection du profil

Dans l'ordre : (1) choix manuel dans le Picker (Alt+n°, mémorisé pour la session) ; (2) targets/profile du prompt (§7.2) ; (3) auto-détection par AppMatch + TitreMatch de la fenêtre d'origine ; (4) profil défaut. Le profil actif est toujours visible dans la barre de statut du Picker — jamais d'adaptation invisible.

12.4 SendAfter : garde-fous

Désactivé dans tous les profils livrés. Activation = case explicite dans les Paramètres par profil. Quand il est actif : compte à rebours visible dans une mini-fenêtre non bloquante (800 ms par défaut, paramétrable jusqu'à 3 s), Échap annule, et la première activation déclenche un avertissement unique rappelant le risque d'envoi au mauvais fil de discussion.


13. Raccourcis globaux et hotstrings

13.1 Raccourcis par défaut

Raccourci Action Remarque
Ctrl+Alt+Espace Ouvrir le Quick Picker Le raccourci. Espace évite la plupart des conflits applicatifs
Ctrl+Alt+M Ouvrir le Gestionnaire M = manager
Ctrl+Alt+N Nouveau prompt (depuis la sélection si elle existe)
Ctrl+Alt+1…9 Injecter l'épinglé n° 1…9 pinned: de l'en-tête (§7.2)
Ctrl+Alt+V Injecter le dernier prompt utilisé, à nouveau Rejoue avec un contexte frais (nouvelle sélection capturée)
(par prompt) Raccourci propre (hotkey:) Priorité aux conflits signalés (§13.3)

Tous reassignables dans les Paramètres ; la modification ré-enregistre à chaud, sans redémarrage.

13.2 Hotstrings

Déclarée par hotstring: resu; → l'abréviation ::resu; est active partout. Convention recommandée : terminer par ; (ou un autre signe distinctif) pour éviter les déclenchements en pleine frappe normale — le document de l'utilisateur final le dira, et le modèle de création propose ce suffixe par défaut.

Différences assumées vs raccourcis : pas de capture de contexte riche (la sélection environnante n'est pas récupérable au milieu d'une frappe) — les variables automatiques disponibles sont {{clipboard}}, {{date}}… mais pas {{selection}} ; si le prompt en contient une, elle est résolue comme vide et l'utilisateur est averti une fois par session. Les variables manuelles d'un prompt déclenché par hotstring ouvrent le même formulaire, puis l'injection se fait à l'endroit du curseur.

Attention documentée : une hotstring se déclenche aussi dans les mots de passe et les terminaux ; la liste des hotstrings est visible d'un coup d'œil dans le Gestionnaire (filtre dédié) et chacune peut être désactivée sans supprimer le prompt.

13.3 Conflits

À l'enregistrement (démarrage, modification, création), tout échec de Hotkey()/Hotstring() est consigné et présenté dans Paramètres → Raccourcis en conflit, avec le prompt/raccourci concerné et trois issues : réassigner, désactiver, ignorer (consigné). Aucun conflit silencieux : un raccourci qui ne répond pas sans explication détruit la confiance dans l'outil.


14. Recherche : index en mémoire et classement flou

14.1 Champs indexés

Par prompt : title, tags, catégorie, corps (tronqué aux 2 000 premiers caractères pour l'index), id. Normalisation : minuscules, suppression des accents (é→e) des deux côtés (requête et index) — « resu » doit trouver « Résumer ».

14.2 Construction et cache

Scan des .md → pour chacun : mtime + taille comparés à index-cache.json ; seuls les fichiers changés sont re-parsés. Démarrage cible : < 300 ms pour 1 000 prompts, cache chaud < 80 ms. Le cache est un détail d'optimisation jetable : le supprimer ne perd rien.

14.3 Classement (détail en Annexe B)

Score = pertinence textuelle (sous-séquence floue, bonus préfixe/mots entiers/titre) × pondérations d'usage (épinglé, favori, fréquence, récence). La recherche vide n'utilise que les pondérations (§8.3). L'algorithme tient en une fonction pure, testable unitairement avec des jeux fixes (§22) — le classement ne doit jamais devenir une boîte noire capricieuse entre deux versions.


15. Historique, favoris et statistiques d'usage

usage.json (à côté de la bibliothèque, exclu de la synchro Git recommandée — §17.3) :

{
  "7f3a2c1e-…": {
    "count": 42, "last_used": "2026-10-11T09:32:11",
    "last_values": { "ton": "direct", "langage": "Python" }
  }
}
  • count / last_used : alimentent le classement (§14.3) et le tri du Gestionnaire.
  • last_values : derniers choix du formulaire → nouveaux défauts proposés (§10.4). Jamais de password, jamais {{selection}}/{{clipboard}} (ce sont des contextes, pas des préférences).
  • Favoris et épinglés vivent dans l'en-tête du prompt (ils font partie de sa définition partageable), les statistiques dans usage.json (elles sont personnelles et volatiles). Cette séparation est intentionnelle et cohérente avec D2/§7.5.
  • « Réinitialiser les statistiques » dans les Paramètres ; historique détaillé (liste des usages horodatés) non conservé : seuls les compteurs servent le classement, le reste serait de la surveillance de soi sans bénéfice.

16. Import, export et packs de prompts

Opération Format Comportement
Export d'une sélection / catégorie .zip de .md (+ pack.json de manifeste) Les fichiers restent de simples .md : le zip n'est qu'un transport
Export « texte brut » Un .md unique découpé par ## Titre Pour partager dans un courriel ou une note ; réimportable
Import .md, dossier de .md, .zip, .json (schéma §16.1) Prévisualisation : nouveaux / doublons (même id) / conflits (même titre, autre id) — choix par ligne : importer, remplacer, dupliquer, ignorer
Import du presse-papiers Texte quelconque Crée un prompt dont le corps est le contenu, titre à saisir
Pack de démarrage Dossier _packs\essentiels\ Livré avec l'application (Annexe D), installable/ignoré au premier lancement

16.1 Schéma JSON d'échange (pour l'interopérabilité)

{ "promptkey_export": 1,
  "prompts": [ { "title": "…", "category": "Code", "tags": ["…"],
                 "body": "… {{selection}} …", "variables": [ { "name": "ton", "type": "enum", "choices": ["…"] } ] } ] }

L'import JSON génère des fichiers .md conformes à §7 (D2 reste la loi : aucun prompt ne vit durablement en JSON).


17. Paramètres, portabilité et synchronisation

17.1 config.ini (à côté de l'exécutable ou de la bibliothèque, mode portable)

Sections : [General] (dossier bibliothèque, langue d'interface du Picker — FR par défaut, thème, démarrage Windows), [Injection] (méthode par défaut, délais, restauration), [Raccourcis], [Editeur] (éditeur externe), [Profil.*] (§12.2). INI plutôt que JSON pour les paramètres : éditable à la main sans casse, natif en AHK (IniRead/IniWrite).

17.2 Mode portable intégral

Si PromptKey.exe trouve un dossier Bibliothèque\ à côté de lui, il l'utilise et écrit tout (config, cache, stats) dans son propre dossier : la totalité de l'outil — programme + prompts + réglages — tient sur une clé USB ou dans un dossier synchronisé. Sinon, défaut : %USERPROFILE%\Documents\PromptKey\.

17.3 Synchronisation (par le dossier, jamais par le code)

  • Git/Gitea (recommandé pour Bruno) : la bibliothèque est un dépôt ; usage.json et index-cache.json dans .gitignore. Historique, retour arrière, partage entre postes.
  • OneDrive / dossier partagé : fonctionne tel quel ; le surveillant de dossier (§6.3) absorbe les arrivées de fichiers.
  • Conflits : PromptKey ne fusionne rien. Un fichier modifié des deux côtés relève de Git ou de l'Explorateur ; l'application relit ce qui est sur disque, point. Ce non-objectif est écrit ici pour ne jamais être « ajouté vite fait » plus tard.

18. Sécurité et vie privée

  1. Zéro réseau (D7) : vérifiable — le code ne contient aucun WinHttp, curl ou socket. C'est aussi l'argument antivirus.
  2. Aucun contenu journalisé : ni prompts résolus, ni sélections, ni valeurs de variables dans promptkey.log (§11.6).
  3. Variables password : masquées, non persistées (§10.4), exclues de last_values, et le texte final qui les contient n'est jamais mis dans le presse-papiers plus longtemps que le délai d'injection — préférer SendText pour ces prompts (réglage automatique proposé à la déclaration d'une telle variable).
  4. Secrets dans les prompts eux-mêmes : déconseillés par conception (fichiers en clair, versionnés). La documentation utilisateur le dira en première page ; un avertissement de l'Éditeur signale les motifs évidents (sk-…, api_key=, Bearer …) — avertissement, pas censure.
  5. Injection ≠ exécution : PromptKey colle du texte. Si le texte collé dans un terminal est une commande, c'est l'affaire de l'utilisateur — d'où D5 (pas d'envoi automatique par défaut), particulièrement sensible pour le profil terminal.
  6. Presse-papiers restauré (§11.3) : ne pas laisser le dernier prompt — possiblement sensible — traîner dans l'historique du presse-papiers Windows (Win+V) plus que nécessaire. Limite honnête : Windows peut avoir déjà archivé la valeur ; le paramètre « ne pas restaurer mais vider après injection » est offert pour les prompts marqués sensitive: true dans l'en-tête (champ ajouté au contrat §7.2).

19. Architecture du code AutoHotkey v2

19.1 Arborescence du projet source

PromptKey\
├─ PromptKey.ahk            ← point d'entrée, #Include, bootstrap, tray
├─ lib\
│  ├─ Settings.ahk          ← config.ini (lecture/écriture, défauts)
│  ├─ PromptStore.ahk       ← scan dossier, parse/write des .md (§7)
│  ├─ Frontmatter.ahk       ← parseur du sous-ensemble §7.3 (+ tests)
│  ├─ Index.ahk             ← index mémoire, cache, recherche floue (§14)
│  ├─ VariableEngine.ahk    ← résolution §10.5, captures automatiques
│  ├─ ClipboardGuard.ahk    ← sauvegarde/restauration sûre (§11.3)
│  ├─ Injector.ahk          ← SEUL module autorisé à Send / coller (§11.1)
│  ├─ HotkeyManager.ahk     ← enregistrement, conflits (§13)
│  ├─ UsageStats.ahk        ← usage.json (§15)
│  └─ Util.ahk              ← dates, normalisation accents, GUID, log
├─ gui\
│  ├─ Picker.ahk            ← §8 / §20.1
│  ├─ Manager.ahk           ← §9.1 / §20.2
│  ├─ Editor.ahk            ← §9.2 / §20.3
│  ├─ VarForm.ahk           ← §10.4 / §20.4
│  └─ SettingsGui.ahk       ← paramètres, conflits, profils
├─ assets\  (icônes .ico : clair/sombre, épinglé…)
├─ packs\essentiels\        ← Annexe D
├─ tests\                   ← §22 (scripts AHK autonomes, sortie console)
├─ build.ahk / build.ps1    ← compilation Ahk2Exe + zip de distribution
└─ README.md

19.2 Principes de code

  • Une classe par module, état passé explicitement ; pas de variables globales hors Settings et App (contexte courant).
  • Les GUI ne touchent ni au disque ni au presse-papiers : elles appellent les services. L'Injector ne connaît pas les GUI : il reçoit un texte et des options.
  • Erreurs : les modules lèvent/retournent des résultats typés {ok, erreur} ; les messages utilisateur sont en français, centralisés dans Util.Msg* pour une éventuelle traduction.
  • Aucune dépendance externe en v1 (pas de DLL, pas de librairie tierce) : le .ahk doit tourner sur une installation AHK v2 propre.

19.3 Concurrence et minuteries

Processus à un fil : tout est événementiel (raccourcis, minuteries AHK). Le scan initial de grosses bibliothèques est le seul travail long : chargement par lots avec SetTimer pour ne pas geler l'icône tray, barre de progression discrète dans le Gestionnaire si > 1 000 fichiers. Aucun travail de fond pendant qu'un Picker est ouvert (le surveillant est suspendu, repris à la fermeture).

19.4 Encodage — le piège n° 1 en AHK

Règle unique : les fichiers prompts sont lus et écrits en UTF-8 explicite (FileEncoding positionné et restauré, ou FileOpen avec encodage nommé), jamais dans l'encodage ANSI par défaut. Les prompts contiennent des accents, des « — », des émojis : un seul aller-retour ANSI les détruit. Tests dédiés (§22) : aller-retour d'un corps contenant é à — ‘’ « » 😀 et {{variables}} doit être bit à bit identique. Les fins de ligne sont normalisées en CRLF à l'écriture sous Windows, tolérées en LF à la lecture.

19.5 Fenêtres et DPI

Gui créés avec prise en charge DPI (-DPIScale évité, dimensions en unités relatives, polices Segoe UI 10/11). Picker : largeur fixe confortable (~720 px à 100 %), centrée sur l'écran de la fenêtre d'origine (pas forcément l'écran principal). Le retour de focus (§6.2) cible le hwnd capturé, jamais « la fenêtre sous la souris ».


20. Maquettes des écrans (ASCII)

20.1 Quick Picker

┌─ PromptKey ──────────────────────────────────────────── [profil: Claude ▾] ─┐
│ Rechercher : résu█                                                          │
├──────────────────────────────────┬──────────────────────────────────────────┤
│ ★ Résumer en 5 points   [Général]│ Résume le texte suivant en {{longueur}}, │
│ 📌 Revue de code         [Code]  │ ton {{ton}}. Réponds en français…        │
│   Résumer un courriel    [Écrit.]│                                          │
│   Résumé exécutif (1 page)[Gén.] │ Texte :                                │
│                                  │ {{selection}}                            │
│                                  │                                          │
│                                  │ Sélection capturée : « Le rapport du    │
│                                  │ troisième trimestre montre… » (1 240 c.) │
├──────────────────────────────────┴──────────────────────────────────────────┤
│ Entrée Utiliser · Ctrl+Entrée Défauts · Ctrl+E Modifier · 12 résultats     │
│ Méthode : presse-papiers · Envoi auto : non                                 │
└─────────────────────────────────────────────────────────────────────────────┘

20.2 Gestionnaire

┌─ PromptKey — Gestionnaire ──────────────────────────────────────────────────┐
│ Fichier  Prompt  Outils                       Rechercher : [____________]   │
├───────────────┬──────────────────────────────────┬──────────────────────────┤
│ ▾ Bibliothèque│ Titre              Modifié  Usage│ Résumer en 5 points      │
│   Code     (4)│ ★ Résumer 5 points  10-09     42  │ Catégorie : Général      │
│   Écriture (6)│ 📌 Revue de code    10-10     31  │ Étiquettes : résumé, …   │
│   Général  (9)│   Traduire FR→EN    09-28     18  │ Raccourci : —  Hotstring │
│ ★ Favoris  (5)│   Expliquer erreur  10-11      3  │ : resu;                  │
│ ◷ Récents     │                                  │                          │
│ 📌 Épinglés(3)│                                  │ [Utiliser] [Modifier]    │
│ ⚠ En erreur(1)│                                  │ [Dupliquer] [Exporter]   │
│               │                                  │ [Supprimer]              │
├───────────────┴──────────────────────────────────┴──────────────────────────┤
│ [+ Nouveau] [Depuis sélection] [Importer]        20 prompts · index à jour │
└─────────────────────────────────────────────────────────────────────────────┘

20.3 Éditeur

┌─ Modifier — Revue de code ───────────────────────┬─ Métadonnées ────────────┐
│ Tu es un relecteur de code senior.               │ Titre : Revue de code    │
│                                                  │ Catégorie : [Code     ▾] │
│ Relis le {{langage}} suivant (niveau {{niveau}}) │ Étiquettes : code, revue │
│ et signale :                                     │ ★ Favori  📌 Épinglé n°2 │
│ 1. les bogues probables…                         │ Raccourci : [Ctrl+Alt+R] │
│                                                  │ Hotstring : [revue;    ] │
│ Code :                                           │ Profils : [claude, qwen] │
│ {{selection}}                                     │                          │
│                                                  │ Variables déclarées :    │
│                                                  │  • langage (enum)        │
│                                                  │  • niveau (enum)         │
│ [Insérer variable Ctrl+J]                        │ [+ Déclarer]             │
├──────────────────────────────────────────────────┴──────────────────────────┤
│ ⚠ « niveau » utilisé mais non déclaré — [Déclarer]      [Tester Ctrl+T]     │
│                                          [Ouvrir externe] [Annuler] [OK]  │
└─────────────────────────────────────────────────────────────────────────────┘

20.4 Formulaire de variables

┌─ Revue de code — paramètres ──────────────┐
│ Langage :  [Python            ▾]          │
│ Niveau :   (•) Strict  ( ) Rapide         │
│ Contexte : [___________________________]  │
│            [___________________________]  │
│                                           │
│ Sélection incluse : 1 240 caractères ✓    │
│              [Échap Annuler] [Entrée OK]  │
└───────────────────────────────────────────┘

21. Packaging, installation et mises à jour

21.1 Formes de distribution

  1. Source .ahk (pour qui a AHK v2) — la forme de référence, lisible et auditable.
  2. PromptKey.exe compilé par Ahk2Exe (base AHK v2 64 bits, icône intégrée) — pour l'usage quotidien.
  3. Archive portable .zip : exe + packs\ + README + bibliothèque d'exemple ; aucune installation, mode portable (§17.2) actif par la présence du dossier Bibliothèque\.

Pas d'installeur en v1 : décompresser, lancer, éventuellement cocher « Démarrer avec Windows » (raccourci dans le dossier Démarrage, créé par l'application sur demande — pas d'écriture registre cachée).

21.2 Premier lancement

Assistant en trois écrans maximum : (1) choisir/créer le dossier de bibliothèque ; (2) proposer le pack de démarrage (Annexe D) — installé seulement sur accord ; (3) montrer LE raccourci, avec bouton « Tester maintenant » qui ouvre le Picker. Toute la valeur de l'outil tient à ce premier test réussi en moins d'une minute.

21.3 Compilation reproductible

build.ps1 : vérifie la version AHK, lance les tests (§22), compile, produit le zip et un SHA256. La recette est dans le README : n'importe qui peut recompiler et comparer — réponse directe au problème des faux positifs antivirus (§4.2).

21.4 Mises à jour

Manuelles en v1 (D7) : remplacer l'exe. Les formats de fichiers (.md, config.ini, usage.json) portent un numéro de version interne ; une migration de format, si un jour nécessaire, se fait à la lecture avec sauvegarde préalable, et est annoncée dans le journal.


22. Tests et critères de qualité

Pas de framework lourd : des scripts AHK autonomes dans tests\, exécutables en ligne de commande, sortie OK/ÉCHEC — lancés par build.ps1 avant toute compilation.

Suite Ce qui est vérifié
Frontmatter Le contrat §7.3 : fichiers valides parsés au champ près ; chaque interdit produit l'erreur et la ligne attendues ; fichier sans en-tête accepté
Encodage Aller-retour UTF-8 bit à bit (§19.4), fins de ligne LF/CRLF
Variables Résolution §10.5, automatiques, {{cursor}}, inconnues signalées, password jamais dans last_values
Recherche Jeux fixes titre/requête → ordre attendu (Annexe B), insensibilité aux accents
Injection (manuel assisté) Script ouvrant le Bloc-notes : collage, restauration du presse-papiers, abandon si copie intermédiaire, SendText, retour de focus — à exécuter sur le poste réel, cases cochées dans le rapport de test
Raccourcis Enregistrement des défauts sans conflit sur une machine propre ; rapport de conflit simulé

Golden tasks (parcours complets, chronométrés à la main avant chaque version) :

  1. Démarrage froid → Picker → prompt sans variable collé dans le Bloc-notes : < 3 s, presse-papiers d'origine intact après coup.
  2. Prompt à 3 variables dont une enum : formulaire → collage correct dans un navigateur (page de test locale).
  3. Hotstring resu; dans Word : remplacement + variables résolues.
  4. Édition d'un .md dans un éditeur externe pendant que PromptKey tourne : index à jour sans redémarrage.
  5. Bibliothèque de 2 000 prompts générés : démarrage < 1 s cache chaud, frappe dans le Picker sans latence visible.

23. Plan d'implémentation en phases (tickets)

Convention : chaque ticket est livrable et testable seul ; les critères d'acceptation sont des comportements observables, pas des intentions. Estimation en demi-journées (dj) pour un développeur AHK v2 à l'aise — à titre d'ordre de grandeur.

Phase 0 — Socle et preuve du geste central (≈ 2 dj)

Objectif : prouver le risque n° 1 — capture du focus, collage propre, presse-papiers restauré — avant tout le reste.

Ticket Contenu Acceptation
P0-1 Squelette : PromptKey.ahk, tray, instance unique, Settings (INI) L'exe démarre, icône tray, quitter fonctionne, aucun résidu
P0-2 ClipboardGuard + Injector (méthode presse-papiers seule) Golden task 1 réussie sur Bloc-notes et navigateur
P0-3 Raccourci global + capture du contexte (hwnd, sélection best-effort, §11.2) La sélection d'un paragraphe est récupérée 9 fois sur 10 dans Word/Chrome ; échec = sélection vide, jamais blocage
P0-4 Picker minimal : liste fixe de 5 prompts codés en dur, recherche naïve, Entrée/Échap Le geste §1 complet fonctionne de bout en bout

Phase 1 — Bibliothèque réelle (≈ 3 dj)

Ticket Contenu Acceptation
P1-1 Frontmatter : parseur du contrat §7.3 + écriture (aller-retour) Suite Frontmatter verte ; erreurs avec n° de ligne
P1-2 PromptStore : scan, catégories-dossiers, génération d'id, surveillant de dossier §6.3 : un .md déposé à la main apparaît sans redémarrage
P1-3 Index + cache + recherche floue (Annexe B) Suite Recherche verte ; 1 000 prompts, < 50 ms/frappe
P1-4 Picker complet (§8) : aperçu, tris par défaut, barre de statut Golden tasks 1 et 5
P1-5 Gestionnaire (§9.1) : arbre, liste, détail, CRUD, corbeille Créer → utiliser → modifier → supprimer sans quitter l'outil

Phase 2 — Variables et profils (≈ 3 dj)

Ticket Contenu Acceptation
P2-1 VariableEngine : types §10.2, automatiques §10.3, {{cursor}}, ordre §10.5 Suite Variables verte
P2-2 Formulaire de variables (§20.4) + mémorisation des derniers choix Golden task 2 ; password absent de usage.json (vérifié)
P2-3 Profils (§12) : préambule, méthode, sélection auto/manuelle, SendAfter gardé Même prompt, deux profils → deux textes finaux conformes en prévisualisation
P2-4 Éditeur (§9.2) : métadonnées, insertion/déclaration de variables, validation, Tester Un prompt créé de zéro dans l'Éditeur fonctionne au Picker sans retouche du fichier
P2-5 Injection SendText + bascule par profil/par frappe Un champ où le collage échoue reçoit le prompt en frappe, texte exact

Phase 3 — Raccourcis avancés, import/export (≈ 2 dj)

Ticket Contenu Acceptation
P3-1 HotkeyManager : raccourcis par prompt, épinglés 1…9, rapport de conflits (§13.3) Conflit provoqué → visible et explicable dans Paramètres
P3-2 Hotstrings (§13.2) + filtre de gestion Golden task 3 ; désactivation unitaire respectée
P3-3 UsageStats complet : tris Fréquents/Récents, réinitialisation §8.3 vérifié après usages simulés
P3-4 Import/export (§16) + pack de démarrage (Annexe D) + premier lancement (§21.2) Export d'une catégorie réimporté sur une bibliothèque vierge = prompts identiques
P3-5 Paramètres complets (§17.1), mode portable, démarrage Windows Le zip portable fonctionne depuis un dossier neuf, sans trace ailleurs

Phase 4 — Durcissement et distribution (≈ 2 dj)

Ticket Contenu Acceptation
P4-1 Suites de tests complètes (§22) intégrées à build.ps1 Build refusé si un test échoue
P4-2 Compilation Ahk2Exe, zip portable, sommes SHA256, README utilisateur (français) Une machine sans AHK utilise le zip de bout en bout
P4-3 Cas limites §11.5 passés en revue un par un sur poste réel Tableau §11.5 coché ligne par ligne
P4-4 Prompts marqués sensitive : vidage du presse-papiers après injection (§18, point 6) Après injection d'un tel prompt, Win+V ne montre pas le texte injecté comme entrée PromptKey restaurée

Phase 5 — Extensions optionnelles (hors v1, à décider séparément)

  • P5-A — Pont API : profil spécial qui, au lieu d'injecter, envoie le prompt résolu à une API (OpenAI-compatible) et colle la réponse — change la nature de l'outil (réseau, clés, coûts) : décision explicite requise, contraire à D7.
  • P5-B — Chaînes de prompts : un prompt dont une variable est la sortie d'un autre (composition), sans langage de gabarit complet.
  • P5-C — Bibliothèque SQLite : si la bibliothèque dépasse ~5 000 prompts (D3 à réviser, D2 inchangé).
  • P5-D — Snippets système : réponses types courriel/support gérées dans le même outil (mêmes mécanismes, autre bibliothèque).

24. Risques et mitigations

Risque Prob. Mitigation (section)
Le retour de focus échoue dans certaines applications → texte perdu ou au mauvais endroit Moyenne Module isolé et testé (§11), fenêtre disparue = copie de secours, jamais d'envoi auto par défaut (D5)
Presse-papiers de l'utilisateur écrasé ou historique pollué Moyenne ClipboardGuard + restauration conditionnelle (§11.3), mode sensitive (§18, point 6)
Faux positifs antivirus sur l'exe compilé Élevée Source distribuée, build reproductible (§21.3), zéro réseau (D7)
Le sous-ensemble d'en-tête devient un faux YAML frustrant Moyenne Contrat écrit (§7.3), erreurs avec ligne, fichiers sans en-tête acceptés, Éditeur qui génère l'en-tête pour l'utilisateur
Conflits de raccourcis avec les applications du quotidien Élevée Défaut peu conflictuel (Ctrl+Alt+Espace), détection et rapport (§13.3)
L'utilisateur empile 300 prompts et ne retrouve rien Moyenne Classement par usage (§14.3), épinglés/favoris, Annexe D comme modèle de nommage
Verrouillage format : les prompts deviennent prisonniers de PromptKey Faible D2 : des .md lisibles restent exploitables même sans l'application — c'est un argument de conception, pas un risque résiduel

25. Alternatives écartées

Alternative Pourquoi pas (pour ce besoin)
Espanso / Beeftext / PhraseExpress (extenseurs de texte) Excellents pour des snippets figés ; pas de bibliothèque de prompts cherchable avec aperçu, profils par IA, ni formulaire de variables riche au centre du geste
PowerToys / lanceurs (Flow Launcher, Raycast-like) Bons lanceurs, mais l'injection fine (capture de sélection, restauration du presse-papiers, profils) y serait un plugin à écrire quand même — AHK la donne nativement
Les bibliothèques intégrées des IA (prompts enregistrés ChatGPT/Claude…) Enfermées par outil : le besoin est justement une bibliothèque pour toutes les IA (§2.1-4)
Gestionnaire de presse-papiers (Ditto…) Retrouve des textes collés, ne gère ni variables, ni catégories, ni profils
Application Electron/web maison Surdimensionné : installation, empreinte, et l'accès global au clavier/presse-papiers sous Windows y est plus indirect qu'en AHK
Simples hotstrings AHK sans application Le point de départ de beaucoup d'usages réels — mais sans Picker ni gestion, la bibliothèque cesse d'être retrouvable dès ~20 prompts ; PromptKey les conserve comme un mode d'accès parmi d'autres (§13.2)

26. Décisions ouvertes pour Bruno

Aucune ne bloque la Phase 0 ; Q2 et Q3 influencent la Phase 1.

  • Q1 — Nom. « PromptKey » est un nom de travail. Alternatives : PromptDeck (écho à Flowdeck), Prompto, TouchePrompt… Le nom décide du dossier par défaut et de l'icône.
  • Q2 — Bibliothèque initiale. Dossier neuf dédié, ou adosser la bibliothèque à un vault/dossier existant (les .md y côtoieraient d'autres notes — le parseur tolère les fichiers sans en-tête, mais le Gestionnaire ne montrera que le dossier choisi) ?
  • Q3 — Synchro entre postes. Git/Gitea dès le départ (recommandé, §17.3) ou dossier local simple en v1 ?
  • Q4 — Langue d'interface. Français seulement en v1 (hypothèse de ce document) ou FR/EN dès le départ ? Le code centralise les messages (§19.2) pour garder la porte ouverte.
  • Q5 — SendAfter. Le conserver comme option gardée (§12.4), ou le retirer complètement de la v1 pour ne jamais risquer un envoi involontaire — quitte à le réintroduire plus tard ?

Annexe A — Exemple complet d'un fichier prompt

Fichier : Bibliothèque\Code\expliquer-une-erreur.md

---
id: 9d41b7aa-3c2f-4e01-9a55-1f0c2d77e810
title: Expliquer une erreur
tags: [débogage, erreur, pédagogie]
targets: [défaut, claude, qwen, deepseek]
favorite: false
created: 2026-10-11
updated: 2026-10-11
variables:
  - name: niveau
    label: Mon niveau sur ce sujet
    type: enum
    choices: [débutant, intermédiaire, avancé]
    default: intermédiaire
---

Explique l'erreur ci-dessous à un niveau {{niveau}} :
1. ce qu'elle signifie, en une phrase simple ;
2. la cause la plus probable dans ce code ;
3. la correction minimale, avec le code corrigé seulement.

Message d'erreur et code :
{{selection}}

Utilisation type : copier un message d'erreur (ou le sélectionner dans l'IDE) → Ctrl+Alt+Espace → « erreur » → choisir le niveau → le prompt complet est collé dans l'IA ouverte.

Annexe B — Algorithme de classement de la recherche

Fonction pure Score(prompt, requêteNormalisée) :

  1. Correspondance floue : la requête (sans accents, minuscules) est cherchée en sous-séquence dans titre, puis étiquettes, puis catégorie, puis corps. Bonus : correspondance en début de mot (×2), mot entier (×3), dans le titre (×4).
  2. Requête multi-mots : chaque mot doit correspondre quelque part (ET logique) ; le score est la somme des mots.
  3. Pondérations multiplicatives : épinglé ×1,5 · favori ×1,3 · fréquence 1 + log10(1+count) × 0,2 · récence : ×1,2 si utilisé < 7 jours.
  4. Tri : score décroissant, égalité tranchée par last_used puis titre alphabétique — déterminisme total, testable (§22).

Le but n'est pas la sophistication : c'est que les 5 prompts quotidiens remontent en ≤ 3 frappes, et que le comportement soit prévisible.

Annexe C — Séquence d'injection, pas à pas

Utilisateur        Application X        PromptKey             Presse-papiers
    │                    │                  │                        │
    │── Ctrl+Alt+Esp ────┼─────────────────▶│ capture hwnd, titre    │
    │                    │                  │ capture sélection ──────▶│ (sauvegarde,
    │                    │                  │                        │  Ctrl+C, lecture,
    │                    │                  │◀───────────────────────│  restauration)
    │                    │   Picker ouvert  │                        │
    │── frappe+Entrée ───┼─────────────────▶│ résolution variables   │
    │                    │                  │ texte final (profil)   │
    │                    │                  │ sauvegarde complète ──▶│
    │                    │                  │ pose le texte ────────▶│
    │                    │◀─ WinActivate ───│                        │
    │                    │◀─ Ctrl+V ────────│                        │
    │                    │   (texte collé)  │ minuterie +1,5 s       │
    │                    │                  │ si PP inchangé : ─────▶│ restauration
    │                    │                  │ sinon : abandon propre │

Annexe D — Pack de démarrage proposé (20 prompts)

Livrés dans packs\essentiels\, chacun conforme à §7, avec variables déclarées — ils servent aussi d'exemples du format.

Général : Expliquer simplement · Expliquer une erreur (Annexe A) · Résumer en 5 points · Plan d'action à partir d'un texte · Questions de clarification avant de répondre. Écriture : Reformuler (ton variable) · Corriger sans changer le style · Raccourcir de moitié · Courriel poli à partir de notes brutes · Traduire FR↔EN en gardant la mise en forme. Code : Revue de code (niveau variable) · Écrire un test pour cette fonction · Expliquer ce code ligne par ligne · Convertir dans un autre langage · Message de commit à partir du diff ({{clipboard}}). Analyse : Pour / contre structuré · Extraire les décisions et tâches d'un compte rendu · Comparer deux options selon mes critères ({{contexte}}) · Résumé exécutif d'une page · Transformer en tableau Markdown.


Fin du document — PromptKey, architecture et conception v1.0.