Outil de notes / Outil web

SelixyBrain

Second cerveau : notes reliées, graphe 3D et notes volantes

Vue 3TypeScriptNodeCodeMirrorGraphePodman

Je prends mes notes dans SelixyBrain : idées, lectures, expérimentations, matière du mémoire. Je l’ai commencé fin mai 2026 comme une interface Vue pour un vault SilverBullet, puis le dépôt a absorbé mes deux projets précédents (l’interface seule et un hub). Il est en ligne sur brain.selixy.dev, et l’essentiel du travail a eu lieu entre fin septembre et début octobre, au moment où je l’ai repris pour le rendre sûr à partager.

Graphe et éditeur

Les notes sont des fichiers Markdown reliés par des liens [[...]], et l’interface les montre en graphe 3D (3d-force-graph et three). L’éditeur est CodeMirror ; sous chaque note, il liste les rétroliens, c’est-à-dire les notes qui la citent. Les tags (#tag) alimentent l’autocomplétion et un filtre du graphe, et Ctrl+K sert à sauter d’une note à l’autre.

Graphe 3D et éditeur avec rétroliens, sur un vault de démonstration

Les liens se résolvent en un seul endroit du code, pour le graphe, le clic, l’autocomplétion et la suppression : chemin exact, puis même chemin sans la casse, puis nom court, avec la note du même dossier en cas d’ambiguïté. Sur téléphone, un seul panneau est visible à la fois, et le graphe choisit lui-même le nœud le plus proche du doigt, parce que la bibliothèque désigne un nœud périmé au toucher.

Ne jamais perdre de texte

C’est la règle de conception que j’ai posée en premier. L’éditeur a un état séparé par note, donc Ctrl+Z ne traverse pas deux notes. La frappe en attente est envoyée dès qu’on change de note, qu’on cache l’onglet ou qu’on quitte la page.

Si l’enregistrement échoue, il est retenté (après 2 s, 5 s, 10 s, puis toutes les 30 s) et un bouton permet de réessayer. Le texte non enregistré est aussi gardé dans le navigateur, et la note propose de le restaurer à sa réouverture. Chaque note garde enfin ses versions, que l’administrateur peut restaurer, y compris pour une note supprimée.

Notes volantes

Explorateur des notes volantes (section « À ranger »), sur un vault de démonstration

Les notes volantes servent à capturer vite : texte, voix, photo, fichier, liens. Une volante est un dossier .note dans volantes/, avec ses médias rangés par type dans des sous-dossiers, et elle se range ensuite dans des dossiers libres. Elles sont réservées à l’administrateur, sortent du graphe, et se trient dans un explorateur (récentes ou A à Z, avec une section « À ranger »). Elles se promeuvent ensuite en vraies notes. La section de transcription vocale est prévue dans le format, mais rien ne la remplit encore.

Couche d'accès et droits

Les notes vivent dans un vault tenu par SilverBullet, que je n’expose pas. Entre lui et l’interface, j’ai écrit une couche d’accès en Node 22 et TypeScript strict, sans dépendance d’exécution. Elle sert aussi l’interface, gère comptes, rôles et sessions (mots de passe hachés en scrypt, cookie signé), et relaie les appels vers SilverBullet avec son propre jeton, que l’interface ne voit jamais.

  • trois rôles : administrateur, spectateur en lecture seule, et invité qui peut créer et modifier sans supprimer ;
  • les droits sont appliqués côté serveur dans une table unique, l’interface ne fait que masquer les actions ;
  • une note est visible par défaut. L’administrateur peut la réserver, et elle disparaît alors des listes et du graphe, avec une erreur 404 en accès direct, comme si elle n’existait pas ; il peut aussi seulement la masquer aux spectateurs ;
  • ces marqueurs sont tenus dans un registre à part : rien n’est écrit dans les notes, et changer un marqueur ne modifie pas le vault d’un octet (un test le prouve) ;
  • si le registre est perdu ou corrompu, les comptes non administrateurs ne voient plus rien tant que je n’ai pas restauré la sauvegarde ;
  • une note peut aussi être partagée par un lien à jeton, qui ouvre cette seule note sans session et se révoque.

Une limite reste ouverte : le texte d’une note visible peut citer le nom d’une note réservée. Le serveur ne réécrit jamais une note, donc ce nom reste lisible. Le graphe, lui, ne montre que des nœuds visibles. C’est à moi d’y veiller.

Agents et MCP

Le dépôt contient un panneau agent, réservé à l’administrateur : une conversation avec un agent branché sur le coffre, qui montre ses appels d’outils sur une piste d’exécution et demande mon accord avant d’agir. Un serveur sans agent configuré répond « Agent non configuré », et le README du dépôt dit qu’il n’y a ni IA ni chat pour l’instant. Je le traite donc comme une piste, pas comme une fonction livrée.

À côté, un serveur MCP (extensions/vault-mcp) permet à un agent comme Claude Code de chercher, lire et écrire dans le vault. Il passe par la couche d’accès avec un compte ordinaire, donc avec les mêmes rôles, le même registre et les mêmes versions restaurables qu’un humain.

Déploiement et tests

L’interface (Vue 3, Vite, CodeMirror) et la couche d’accès sont livrées dans un conteneur unique, sans droits particuliers, avec un système de fichiers en lecture seule et 256 Mo. J’ai choisi un seul conteneur parce que l’interface n’est que du statique, que Node sert en une centaine de lignes, et qu’un nginx de plus aurait demandé un réseau interne et une seconde image sans rien ajouter à la sécurité. Un git push vers le VPS lance la livraison.

Le dépôt compte des tests unitaires et des parcours Playwright. Un test construit l’interface avec de faux identifiants et échoue si l’un d’eux apparaît dans le code livré. Un audit modulaire vérifie les règles que je me suis données : 200 lignes par fichier, cinq fonctions au plus, aucun commentaire dans le code, le pourquoi vivant dans le README de chaque module.

Où j'en suis

L’outil me sert, mais il reste en chantier. Le panneau agent n’est pas branché, la transcription des vocaux n’existe pas, et la migration des anciennes notes vers le format en dossier .note n’est pas terminée en production.

Liens

Note-taking / Web tool

SelixyBrain

Second brain: linked notes, 3D graph and quick-capture notes

Vue 3TypeScriptNodeCodeMirrorGraphePodman

I take my notes in SelixyBrain: ideas, readings, experiments, material for my thesis. I started it in late May 2026 as a Vue interface for a SilverBullet vault, then the repository absorbed my two earlier projects (the interface alone and a hub). It is online at brain.selixy.dev, and most of the work happened between late September and early October, when I took it up again to make it safe to share.

Graph and editor

Notes are Markdown files linked with [[...]], and the interface shows them as a 3D graph (3d-force-graph and three). The editor is CodeMirror; under each note it lists the backlinks, meaning the notes that cite it. Tags (#tag) feed autocompletion and a graph filter, and Ctrl+K jumps from one note to another.

3D graph and editor with backlinks, on a demonstration vault

Links are resolved in a single place in the code, for the graph, clicks, autocompletion and deletion: exact path, then same path ignoring case, then short name, with the note in the same folder winning when it is ambiguous. On a phone only one panel shows at a time, and the graph picks the node closest to the finger itself, because the library reports a stale node on touch.

Never lose text

This is the design rule I set first. The editor has a separate state per note, so Ctrl+Z does not cross two notes. Pending keystrokes are sent as soon as I switch notes, hide the tab or leave the page.

If saving fails, it is retried (after 2 s, 5 s, 10 s, then every 30 s) and a button lets me retry by hand. Unsaved text is also kept in the browser, and the note offers to restore it when reopened. Each note also keeps its versions, which the administrator can restore, deleted notes included.

Floating notes

Floating notes explorer ("To file" section), on a demonstration vault

Floating notes are for fast capture: text, voice, photo, file, links. A floating note is a .note folder inside volantes/, with its media sorted by type in subfolders, and it can then be filed into free-form folders. They are reserved to the administrator, stay out of the graph, and are sorted in an explorer (recent or A to Z, with a “To file” section). They are later promoted into proper notes. A voice transcription section is planned in the format, but nothing fills it yet.

Access layer and permissions

The notes live in a vault run by SilverBullet, which I do not expose. Between it and the interface, I wrote an access layer in Node 22 and strict TypeScript, with no runtime dependency. It also serves the interface, handles accounts, roles and sessions (scrypt-hashed passwords, signed cookie), and relays calls to SilverBullet with its own token, which the interface never sees.

  • three roles: administrator, read-only viewer, and guest who can create and edit but not delete;
  • permissions are enforced server-side in a single table, the interface only hides the actions;
  • a note is visible by default. The administrator can reserve it, and it then disappears from lists and from the graph, with a 404 on direct access, as if it did not exist; they can also just hide it from viewers;
  • these markers are kept in a separate registry: nothing is written into the notes, and changing a marker does not alter the vault by a single byte (a test proves it);
  • if the registry is lost or corrupted, non-administrator accounts see nothing until I restore the backup;
  • a note can also be shared through a token link, which opens that single note without a session and can be revoked.

One limit remains open: the text of a visible note can quote the name of a reserved note. The server never rewrites a note, so that name stays readable. The graph only shows visible nodes. It is up to me to watch for it.

Agents and MCP

The repository contains an agent panel, reserved to the administrator: a conversation with an agent plugged into the vault, which shows its tool calls on an execution track and asks for my approval before acting. A server with no agent configured answers “Agent not configured”, and the repository README says there is no AI or chat for now. I treat it as a lead, not as a shipped feature.

Next to it, an MCP server (extensions/vault-mcp) lets an agent such as Claude Code search, read and write in the vault. It goes through the access layer with an ordinary account, so with the same roles, the same registry and the same restorable versions as a human.

Deployment and tests

The interface (Vue 3, Vite, CodeMirror) and the access layer ship in a single container, unprivileged, with a read-only filesystem and 256 MB. I chose a single container because the interface is only static files, which Node serves in about a hundred lines, and one more nginx would have needed an internal network and a second image without adding any security. A git push to the VPS triggers delivery.

The repository has unit tests and Playwright journeys. One test builds the interface with fake credentials and fails if any of them shows up in the shipped code. A modular audit checks the rules I set myself: 200 lines per file, five functions at most, no comments in the code, the why living in each module’s README.

Where it stands

The tool serves me, but it is still a work in progress. The agent panel is not wired up, voice transcription does not exist, and the migration of old notes to the .note folder format is not finished in production.

Links