Contexte
Listik est né d'une frustration simple : une idée arrive pendant qu'on travaille sur autre chose, et le temps d'ouvrir une application de tâches, de trouver le bon projet et de remplir les champs, elle est perdue ou on a perdu le fil. Je voulais un outil où noter une chose à faire prend une seconde, depuis n'importe quelle fenêtre, sans changer d'application.
C'est un projet personnel, mené seul depuis l'été 2025 : une application de bureau complète, de la base de données à la page de téléchargement, en passant par la mise à jour automatique et l'identité visuelle. Côté ergonomie, je me suis inspiré de Things 3 : peu d'écrans, des vues qui répondent à une question précise (« quoi aujourd'hui ? », « quoi plus tard ? »), et un clavier qui suffit pour tout faire.
Deux principes ont guidé les choix techniques : les données restent sur l'ordinateur, dans une base SQLite locale, sans compte ; et l'IA est une option, branchée sur l'outil que l'utilisateur a déjà installé plutôt que sur un service imposé.


Le geste au centre
Tout part d'un raccourci global, Alt+Q. Une petite fenêtre flottante s'ouvre par-dessus le travail en cours ; on écrit comme on parle, on valide avec Entrée, et la fenêtre disparaît.

Le texte est analysé pendant la frappe : « Réserver l'hôtel vendredi #lisbonne ! » devient une tâche planifiée vendredi, rangée dans le projet Lisbonne, en priorité haute ; le « ! » ne reste pas dans le titre. Les dates relatives (« lundi », « dans 3 jours »), les projets et les tags sont surlignés au fil de la saisie, pour que l'on voie ce que l'application a compris avant de valider.
La même fenêtre a trois modes : une tâche pour le planificateur, une pensée pour la page du jour du journal, une question pour l'assistant.
Fonctionnalités
Le planificateur
- Vues inspirées de Things 3 : Boîte de réception, Aujourd'hui, À venir, Quand je peux, Un jour, Historique
- Domaines et projets avec progression, tags, sous-tâches
- Date planifiée et échéance distinctes, récurrences (tous les jours, certains jours de la semaine, le dernier vendredi du mois…), rappels par notification système
- Clavier d'abord : navigation, sélection multiple, réordonnancement, recherche globale (Ctrl+K)
- Annulation de la dernière action pendant quelques secondes, suppressions comprises


Le journal
- Une page par jour, écrite au fil des heures, dans un éditeur riche
- Pièces jointes : photos, PDF et notes vocales enregistrées au micro
- Recherche plein texte sur tout le journal et export Markdown


L'assistant
L'assistant peut lire et organiser les tâches en langage naturel (« qu'est-ce qui est en retard ? », « déplace tout ce qui concerne le salon à la semaine prochaine »). Plutôt que d'embarquer une clé d'API, Listik détecte les outils en ligne de commande déjà installés et connectés par l'utilisateur — Claude Code, Codex CLI, OpenCode, Antigravity CLI — et leur ouvre l'accès aux données via un serveur MCP local, protégé par un jeton éphémère. Les suppressions ne sont pas exposées à l'assistant.
Et autour
- Sauvegarde complète (JSON et pièces jointes) et restauration
- Personnalisation : thème clair, sombre ou OLED, six couleurs d'accent, navigation en barre latérale ou en dock flottant
- Accueil du premier lancement qui fait faire le vrai geste (Alt+Q) plutôt que de l'expliquer
Stack technique
- Tauri 2
- Application de bureau (Windows, macOS), fenêtres et raccourcis système
- Rust
- Cœur de l'application : données, rappels, serveur MCP, commandes
- SQLite · sqlx
- Base locale, requêtes vérifiées, migrations, recherche plein texte (FTS5)
- axum
- Serveur MCP local exposé aux assistants en ligne de commande
- Next.js 15
- Interface, exportée en statique et servie par la webview
- TypeScript
- Typage du front ; types générés depuis les structures Rust (ts-rs)
- SWR
- Cache et synchronisation des données côté interface
- Tailwind CSS
- Styling (v4), design system maison
- Lexical
- Éditeur de la capture et du journal
- Motion · Remotion
- Animations d'interface ; logo animé rendu en vidéo
- Vitest · cargo test
- 264 tests côté interface, 128 côté Rust
- GitHub Actions
- Tests, compilation Windows et macOS, publication et mises à jour signées
Architecture
L'interface ne touche jamais la base de données. Au début du projet, la webview exécutait elle-même ses requêtes SQL ; je les ai toutes déplacées côté Rust, derrière une cinquantaine de commandes typées. Le front appelle une commande, Rust écrit dans SQLite, puis émet un événement (todos:changed) que toutes les fenêtres écoutent pour se rafraîchir — la fenêtre de capture et la fenêtre principale restent ainsi synchronisées sans se parler directement.
Fenêtre principale Capture (Alt+Q) Assistant CLI
│ │ │
└──── invoke ────────┘ MCP + jeton
│ │
▼ ▼
Rust : commandes · rappels · serveur MCP local
│
▼
SQLite (sqlx, migrations, FTS5)
│
▼
événement « todos:changed » → toutes les fenêtres
Les types partagés sont écrits une seule fois, en Rust, et exportés en TypeScript : un champ renommé côté données casse la compilation du front au lieu de casser l'application à l'exécution.
La distribution est entièrement automatisée : un tag de version déclenche la compilation des installateurs Windows et de l'application macOS, la publication sur GitHub et un manifeste de mise à jour signé. Au démarrage, Listik vérifie la signature avant de proposer la nouvelle version.
Identité et page de téléchargement
J'ai voulu que Listik ait une vraie identité plutôt qu'un logo générique. Le logotype, L!stik, est composé dans la police Fraunces : le premier « i » est remplacé par une plume de stylo-plume dont la goutte d'encre forme un point d'exclamation. Le clin d'œil est aussi fonctionnel : dans la saisie, « ! » rend une tâche prioritaire.
L'animation du logo est rendue image par image avec Remotion (React) : les lettres font leur mise au point, la plume se pose à la place du « ! », puis la goutte tombe. La même composition produit l'écran d'ouverture de l'application, le sting vidéo et les formats pour les réseaux.
Le film de présentation, en haut de cette page, est construit de la même façon : l'interface y est recréée en React à partir de vraies captures, et chaque plan est calé sur la musique, dont j'ai d'abord extrait le tempo et les temps forts.
La page de téléchargement reprend cette identité, montre de vraies captures de l'application et dit franchement ce qui se passe au premier lancement (l'installateur n'étant pas encore signé par un certificat Microsoft).
Ce que j'ai appris
Listik est le projet le plus complet que j'aie mené : plus de 140 commits, environ 9 000 lignes de Rust et 28 000 de TypeScript. Il m'a surtout appris à penser en produit — chaque fonctionnalité commence par la question « qu'est-ce que la personne essaie de faire à ce moment-là ? » avant celle de l'implémentation.
Côté technique, la frontière entre la webview et Rust a été la leçon principale. Déplacer l'accès aux données côté Rust a demandé de réécrire une bonne partie de l'application, mais a rendu le reste plus simple : une seule source de vérité, des types partagés, des fenêtres synchronisées par événements.
Une application de bureau oblige aussi à composer avec le système : Alt+Espace est réservé par Windows (d'où Alt+Q), WebView2 ne donne pas l'accès au micro sans un gestionnaire de permissions écrit en Rust, et une app lancée depuis le Finder sur Mac ne voit pas le PATH du terminal. La version macOS a été portée sans Mac sous la main : l'intégration continue sur GitHub Actions a été le seul moyen de la compiler, de la lancer et d'en voir une première capture.
Enfin, livrer, c'est aussi la chaîne autour du code : signature des mises à jour, pipeline de publication, page de téléchargement, onboarding. C'est souvent là que se joue la différence entre un projet qui fonctionne et un produit que quelqu'un d'autre peut installer et adopter.
