notabene
Référence
note this well
Référence
Référence
Le pendant exhaustif du Guide — tableaux et contrats, une page par surface :
- CLI — chaque commande et flag
notabene. - Clés de configuration — toute la surface de
notabene.config.mjs. - Frontmatter — chaque clé qu’une page peut porter.
- Le contrat du store
.notabene— le schéma JSON versionné que les agents lisent et écrivent. - Le protocole agent — la boucle file-I/O-first que suit n’importe quel agent pour transformer les commentaires en éditions.
- Modèle de sécurité — pourquoi l’API d’écriture ne peut pas vous nuire.
CLI
CLI
Le package npm est scopé (@z29k/notabene) ; la commande installée est simplement
notabene, donc npx notabene … fonctionne tel quel dès lors que le package est
une dépendance de votre repo. Sans installation locale, utilisez toujours le nom scopé —
npx -y @z29k/notabene@latest … — car notabene non scopé n’est pas notre package.
| Commande | Ce qu’elle fait |
|---|---|
notabene doctor | État en lecture seule au format JSON : config/store/port + dossiers de doc détectés — --json |
notabene init | Écrit notabene.config.mjs + crée le store (sans effet s’il existe déjà) ; --detect auto-détecte les dossiers de doc. Écrit aussi le point d’entrée agent : <store>/protocol.md + un bloc borné dans AGENTS.md — désactivables via --no-protocol / --no-agents-md. Idempotent : relancez-le pour rafraîchir les deux |
notabene dev | Démarre le serveur de revue sur les docs de ce repo (rechargement à chaud) ; --detach le lance en démon d’arrière-plan. Avec la dépendance de dev optionnelle pagefind, sa recherche devient plein texte aussi |
notabene status | Le serveur détaché tourne-t-il ? (pid, port, URL) — --json |
notabene stop | Arrête le serveur détaché |
notabene build | Construit le site (Node standalone ; docs prérendues, pas d’API d’écriture dans l’artefact) |
notabene build --public | Site statique en lecture seule pour hébergement public — voir le guide. [--site URL] [--base /sub] [--out DIR]. Avec la dépendance de dev optionnelle pagefind, l’artefact gagne une recherche plein texte statique |
notabene preview | Sert le site construit |
notabene lint | Valide les liens inter-docs contre les routes émises par le dernier build (suggestions « did you mean » ; --json). Après build --public, attrape aussi les liens de pages publiques vers du contenu privé. Exit 1 = liens cassés, 2 = pas encore de build |
notabene pdf | Exporte un PDF via Chromium headless (sommaire de signets + numéros de page) ; --scope doc|space:K|folder:K/P|page:K/I, --locale, --out, --chrome. Nécessite la peer dep optionnelle puppeteer (ou puppeteer-core + --chrome) |
notabene migrate | Convertit le store vers la disposition un-fichier-par-commentaire (estampille schemaVersion 3) |
notabene comments ls | Liste les commentaires — --open --json --page <p> (pour agents/scripts) |
notabene comments done | Marque des commentaires traités : done <id…> [--note <texte>] [--journal <entryId>]. Le statut vient de review (auto → resolved, approve → addressed) — --status force, --force agit sur un commentaire en attente (hold). Écriture atomique ; tous les autres champs préservés |
notabene comments reopen | Renvoie des commentaires à open : reopen <id…> [--reply <texte>] [--author <nom>] — la raison devient une réponse du thread que l’agent lira à la passe suivante (le pendant CLI du rejet sur /review) |
notabene comments verify | Audite le store : statuts, liens commentaire↔journal dans les deux sens, disposition des fichiers, doublons, pages disparues. --json ; exit 1 si erreurs, 2 sans store. À lancer après une passe d’agent, ou en CI |
notabene journal add | Ajoute une entrée de journal JSON lue depuis stdin (écriture atomique ; --json renvoie { id } pour chaîner côté agent) |
notabene protocol | Imprime le protocole agent sur stdout — --path affiche son chemin, --write rafraîchit <store>/protocol.md |
Flags globaux
| Flag | Signification |
|---|---|
--root <path> | Racine du repo consommateur (défaut : cwd) |
--config <path> | Chemin de la config (défaut : <root>/notabene.config.mjs) |
--port <n> | Port du serveur de dev (sinon la config port, sinon un port libre) |
--detach | dev uniquement : démon d’arrière-plan (géré par status/stop) |
--detect | init uniquement : préremplit roots[] avec les dossiers de doc trouvés |
--no-protocol / --no-agents-md | init uniquement : ne pas écrire la copie <store>/protocol.md / le bloc AGENTS.md |
--host | Expose sur le LAN — réseaux de confiance uniquement (sécurité) |
--public / --site / --base / --out | build uniquement : l’artefact de site public |
Clés de configuration
Clés de configuration
notabene.config.mjs est un module ES de données uniquement à la racine de votre
repo ; chaque clé est optionnelle. La version narrative, avec exemples, se trouve dans
le guide de configuration.
| Clé | Défaut | Signification |
|---|---|---|
siteName / tagline | "Docs" / "docs" | Marque de l’en-tête |
locale | "en" | Langue de l’UI + collation du tri de la nav |
format | "mdx" | "mdx" (.mdx strict + .md tolérant) ou "commonmark" (pas de MDX du tout). init génère "commonmark" |
roots[] | [{docs}] | Espaces de doc : { key, label, path, exclude, description, publish }. label/description acceptent une map par locale avec l’i18n ; publish: false garde l’espace hors des builds publics |
store | "docs/.notabene" | Dossier commentaires + journal — committez-le (contrat) |
home | — | Page d’accueil personnalisée : un fichier Markdown relatif au repo (ou une map par locale) rendu au-dessus des cartes d’espaces sur / |
branding | — | Assets d’identité : { logo, logoDark, favicon, socialImage }, fichiers relatifs au repo servis sous /_nb/…. Favicon non défini → une marque par défaut intégrée |
theme | — | Personnalisation du rendu : { tokens, css, assets, code } — surcharges de tokens --nb-* (validées ; une coquille lève une erreur), une feuille de style chargée après celle du renderer (sûre vis-à-vis des cascade layers), un dossier du repo servi sous /_nb/assets/… pour les polices/images (allow-list d’extensions, pas de traversée), un thème Shiki pour le code ("github-light" ou { light, dark } — les deux palettes suivent le sélecteur de schéma), et mermaid: false pour garder la palette de diagrammes propre à Mermaid |
nav | — | Liens sortants : { header[], sidebar: { title, links[] }, footer: { links[], text, poweredBy } }. Une seule forme d’entrée — { label, href, icon, iconOnly, publish } ; label accepte une map par locale, publish: false garde un lien hors des builds publics. Validé au chargement (allow-list de schémas, noms d’icônes, doublons) |
port | 3009 | Port d’astro dev |
host | false | true/NOTABENE_HOST=1/--host expose l’API d’écriture au LAN (sécurité) |
verify[] | [] | Vérifications post-édition que l’agent exécute (le build du renderer s’exécute toujours) |
review | "auto" | "auto" = l’agent résout les commentaires ; "approve" = l’agent propose (addressed), vous validez chacun sur /review avec un diff (boucle de revue) |
author | git user.name | Auteur de commentaire par défaut ; chaque navigateur le remplace par appareil via le dialogue d’identité |
authorEmail | git user.email | E-mail d’auteur par défaut ; intégré façon git (Name <email>) pour garder les identités uniques |
editPattern | — | Lien « Modifier cette page » sous chaque page : une URL avec un placeholder {path} (chemin source relatif au repo), ex. https://github.com/o/r/edit/main/{path}. Placeholder obligatoire — validé au chargement |
pdf | { enabled: true, pageSize: "A4", margin: "18mm" } | Export PDF — enabled active le menu Export + les routes /print ; pageSize/margin définissent la boîte @page |
i18n | — | Doc multilingue : { locales, defaultLocale, strategy: "directory"|"suffix" }. Omettez pour une seule langue |
publish | — | Cible du build public : { site, base, exclude }. site optionnel — omis = artefact agnostique de l’origine |
Surcharges CLI/env
--site/--base surchargent publish.site/publish.base ; NOTABENE_HOST=1 équivaut
à host: true ; la CLI passe l’identité git du repo comme repli pour
author/authorEmail. Rien d’autre n’est configurable hors de ce fichier.
Frontmatter
Frontmatter
Du YAML optionnel tout en haut d’une page. Tout a un défaut raisonnable — un repo sans aucun frontmatter se rend très bien (noms de fichiers humanisés, ordre alphabétique).
---
title: Internal network map # <title> de la page + fil d'Ariane (prime sur le premier H1)
description: Segments and VLANs. # builds publics : meta description + OpenGraph + JSON-LD
publish: false # builds publics : exclut cette page entièrement
lastUpdated: 2026-05-04 # pied de page : prime sur la date git « Mis à jour le »
sidebar:
label: Network map # texte de la sidebar (sinon title, sinon nom de fichier humanisé)
order: 9 # position parmi les pages sœurs (croissant)
indexLabel: Start here # pages d'accueil de dossier : renomme l'entrée « Aperçu »
---
| Clé | Effet |
|---|---|
title | <title> de la page, fil d’Ariane, titre du résultat de recherche. Se replie sur le premier # H1, puis sur le nom du fichier |
description | Builds publics : <meta name="description">, description OpenGraph/Twitter, JSON-LD |
publish: false | Builds publics : la page n’est pas construite — ni route, ni nav, ni recherche, ni llms, ni double, ni sitemap. Les builds dev/normaux la montrent toujours |
lastUpdated | Prime sur la date dérivée de git dans le Mis à jour le du pied de page. Toute date que YAML sait parser. Utile quand l’historique git induit en erreur (contenu importé ou généré) |
sidebar.label | Texte de l’entrée dans la sidebar. Résolution : sidebar.label → title → nom de fichier humanisé |
sidebar.order | Clé de tri parmi les pages sœurs, croissante. Les entrées sans valeur gardent l’ordre alphabétique, après celles qui sont ordonnées. Groupes et pages partagent un seul ordre |
sidebar.indexLabel | Sur la page d’accueil d’un dossier : renomme son entrée Aperçu localisée |
Dossiers
Un dossier est nommé et positionné par sa page d’accueil — <folder>/index.md (ou
readme.md) : son frontmatter sidebar s’applique au groupe entier, et la page
elle-même apparaît comme l’entrée Aperçu du groupe. Labels et ordre se propagent aux
fils d’Ariane et aux couvertures PDF.
Les clés inconnues sont ignorées et préservées — les agents qui éditent une page doivent garder le frontmatter existant intact (le skill de revue le fait).
Le contrat du store .notabene
Le contrat du store .notabene
Le store est un contrat public versionné — committé dans votre repo, lu et écrit par
les agents. Sa forme ne change jamais silencieusement : <store>/meta.json porte
{ "schemaVersion": n } (actuellement 3), et tout changement de forme s’accompagne
d’un migrateur (notabene migrate).
Disposition
<store>/
meta.json # { "schemaVersion": 3 }
journal.json # un tableau d'entrées de journal
protocol.md # le protocole agent (écrit par `init` ; ce n'est pas de la donnée)
<page>/<comment-id>.json # UN FICHIER PAR COMMENTAIRE → merges git sans conflit
meta.json, journal.json et protocol.md sont des noms réservés à la racine du
store ; tout le reste est de la donnée de commentaire. Les lecteurs ne parsent que du
.json, donc protocol.md est inerte — il voyage avec le store pour que la spec soit
toujours à côté des commentaires.
<page> est le chemin logique de la page (docs/guide/setup — avec l’i18n c’est l’id
brut encodant la locale, les commentaires sont donc par langue). Les anciens stores v1
(un tableau par page) sont toujours lus ; toute écriture migre la page concernée.
Un commentaire
{ "id", "space", "page", "scope", // scope : "selection" | "page" | "block"
"anchor": { // selection : citation de texte façon W3C
"quote", "prefix", "suffix", "section" // texte rendu + contexte + titre le plus proche
} | { "kind", "key", "label", // block (diagramme/image) : clé dérivée du contenu
"section", "index" } | null,
"thread": [{ "author", "body", "ts" }], // author peut être façon git "Name <email>"
"status": "open" | "addressed" | "resolved",
"hold": false, // true → l'agent l'ignore (WIP du relecteur)
"resolution": { "note", "journalEntryId" } | null,
"createdAt", "updatedAt" }
addressed est l’état de la revue en deux phases : proposé
par l’agent, en attente de validation humaine sur /review.
Une entrée de journal
{ "id", "date", // YYYY-MM-DD
"title", "summary",
"changes": [{ "page", "commentIds": [], "what", "why" }] }
Un enregistrement changes[] par page réellement touchée — le diff de /review est
construit en inversant le journal, donc une page qui n’y figure pas n’apparaîtra pas
dans le diff du relecteur. Le resolution.journalEntryId de chaque commentaire résolu
pointe vers son entrée.
Règles que les agents doivent honorer
- Les écritures sont atomiques (fichier temporaire + rename) — ne jamais écrire du
JSON partiel à la main. La CLI (
comments done/reopen,journal add) s’en charge ;comments verifyaudite le résultat. - Ne jamais supprimer le store en masse ; supprimez un commentaire précis par id si on vous le demande.
- Ne traiter que
status: "open"ethold: false. - Le protocole complet vit dans
<store>/protocol.md— écrit parnotabene init, committé avec le store, rafraîchi en relançantinit. Pointez-y n’importe quel agent.
Modèle de sécurité
Modèle de sécurité
L’API de commentaires écrit dans votre git — elle est donc cloisonnée, par construction :
- Dev uniquement. Le chemin d’écriture n’existe que sous
notabene dev. Enbuild/previewles mutations renvoient403, et un build public ne contient pas ces routes du tout. - Loopback par défaut. Le serveur se lie à
127.0.0.1; l’API d’écriture n’est pas joignable depuis votre réseau sans opt-in explicite via--host/NOTABENE_HOST=1— réseaux de confiance uniquement. - Chaque écriture est gardée au-delà du bind : les requêtes cross-origin sont
refusées (anti-CSRF), un en-tête
Hostnon-loopback est refusé en mode loopback (anti-DNS-rebinding), et — quand vous définissezNOTABENE_TOKEN— chaque écriture doit porter unx-notabene-tokencorrespondant. Définir un token est recommandé avec--host. - Une identité par personne. Sur un hôte non-loopback, chaque visiteur est invité à renseigner son nom (+ e-mail optionnel) avant de naviguer, pour que les commentaires soient attribués à de vraies personnes plutôt qu’au défaut git du propriétaire du repo.
- L’agent ne committe jamais sans demander et ne supprime jamais le store en masse — cela fait partie du protocole.
- La CLI est une surface distincte. Les règles ci-dessus encadrent l’API d’écriture
HTTP. Les commandes qui écrivent dans le store (
comments done/reopen,journal add) sont des commandes locales que vous — ou un agent dans votre terminal — lancez délibérément : ni serveur, ni port, ni réseau. Écriture atomique, un commentaire à la fois, etcomments verifyaudite le résultat.
L’artefact public est l’image miroir : pas d’API d’écriture, pas de données du store, pas d’identité — rien à garder, parce que rien n’est construit.