Aller au contenu

Référence CLI

Toutes les commandes disponibles via grimoire [commande].

Auto-complétion

Installez l'auto-complétion : grimoire completion install --shell bash (ou zsh, fish).

Raccourcis

Des aliases courts sont disponibles : i=init, d=doctor, s=status, v=validate, l=lint, ck=check, u=up, c=config, r=registry.

Commandes principales

grimoire init

Initialise un nouveau projet Grimoire.

grimoire init [PATH] [OPTIONS]
Option Description Défaut
--name TEXT Nom du projet Nom du répertoire
--archetype, -a Archétype d'agents minimal
--backend, -b Backend mémoire (auto, local, lexical, qdrant-local, qdrant-server, weaviate-server, mempalace, ollama) auto
--memory-profile, -m Composition mémoire : lexical, standard, graphe, complet déduite
--memory-collection TEXT Nom explicite de la collection, pour un backend partagé déduit du nom du projet
--force, -f Écraser la config existante false
--dry-run Afficher le plan sans écrire false
--output, -o Format de sortie : text ou json text

La mémoire se choisit comme une composition, pas comme un backend : le profil fixe les sept couches du Memory OS d'un coup (mémoire courte, sémantique, sidecar structuré, graphes, mémoire chaude, visualisation).

--backend auto (le défaut, y compris avec -y) n'attache jamais silencieusement le projet à un service mémoire trouvé sur la machine : il résout toujours vers lexical, isolé, et se contente de signaler dans le rapport ce qui a été détecté (issue #496). Sur un backend partagé choisi explicitement, la collection est nommée d'après le projet (son slug) ; pour s'attacher à une collection déjà peuplée, --memory-collection est requis. Voir Système de mémoire.

Profil Composition
lexical BM25 SQLite seul — aucun modèle, aucun service, aucun réseau
standard Sémantique + BM25 fusionnés (RRF) et sidecar structuré
graphe Standard + graphes Neo4j : connaissances, souvenirs, code, tâches
complet Graphe + mémoire chaude Redis (TTL, baux, coordination multi-agents)

grimoire doctor

Diagnostique la santé du projet (8 vérifications).

grimoire doctor [PATH] [--fix]
Option Description
--fix Auto-correction des répertoires manquants

Vérifie : config YAML, répertoires, archétype, backend, validation sémantique, dépendances optionnelles, version Python. Avec --fix, les répertoires manquants sont créés automatiquement.

grimoire status

Affiche le statut du projet (agents, mémoire, config).

grimoire status [PATH]

grimoire validate

Valide project-context.yaml contre le schéma Grimoire.

grimoire validate [PATH]

grimoire lint

Lint avancé : valide structure, types, contraintes et références dans le YAML config.

grimoire lint [PATH] [OPTIONS]
Option Description Défaut
--format, -f Format de sortie : text ou json text

Accepte un chemin vers un fichier .yaml/.yml ou un répertoire (cherche project-context.yaml).

# Lint du projet courant
grimoire lint .

# Lint d'un fichier spécifique
grimoire lint configs/project-context.yaml

# Sortie JSON (pour CI)
grimoire lint . --format json

grimoire up

Amène le projet à la version du kit installé — c'est la commande de mise à jour.

grimoire up [PATH] [--dry-run]

Sur un projet neuf, elle initialise. Sur un projet existant, elle régénère les artefacts appartenant au kit (_grimoire/kit/, wrappers d'agents, prompts, instructions) et rafraîchit les artefacts du standard que le projet n'a pas modifiés. Ce que le projet possède — project-context.yaml, .mcp.json, la mémoire, les décisions de conformité, tout _grimoire/overrides/ — n'est jamais réécrit.

Le profil du standard suit la même règle : les --needs passés à l'installation sont persistés dans _grimoire/standard/install-manifest.yaml et réutilisés à chaque up sans argument — un up nu ne rétrograde jamais un profil vers starter (#344). Si le profil déjà en place est plus large que celui qu'un up nu résoudrait, il est préservé et l'étape rapporte skipped. Seul un --needs explicite qui réduit le périmètre est honoré, et il est alors rapporté comme un changement de profil, jamais comme done.

L'écriture est différentielle : sans nouvelle version du kit, aucun fichier n'est touché et le rapport indique kit artifacts already up to date. La commande est donc sûre à lancer à tout moment.

grimoire migrate

Fait passer un projet créé avant la frontière kit/overrides sur cette frontière. Opération unique : une fois faite, grimoire up suffit.

grimoire migrate [PATH]              # montre ce qui bougerait, n'écrit rien
grimoire migrate [PATH] --apply      # exécute, après snapshot
grimoire migrate [PATH] --adopt-kit  # reprend la version du kit sur les fichiers qui la masquaient
grimoire migrate [PATH] --restore 20260826T193210Z

Chaque fichier de l'ancien emplacement est classé par son contenu : s'il correspond à quelque chose que le kit a livré un jour (catalogue d'empreintes embarqué), il est régénéré dans _grimoire/kit/ ; sinon il est considéré comme étant celui du projet et déplacé dans _grimoire/overrides/. Un contenu non reconnu n'est jamais supprimé.

Le plan signale les fichiers qui vont masquer un fichier du kit : ceux-là cesseront de recevoir les mises à jour. S'ils ne contiennent aucune customisation, --adopt-kit les remet sous la responsabilité du kit.

grimoire diff

Affiche les différences entre la config actuelle et les défauts de l'archétype.

grimoire diff [PATH]
Option Description
--output, -o Format de sortie : text ou json

grimoire env

Affiche les informations d'environnement (version, Python, dépendances, OS).

grimoire env
Option Description
--output, -o Format de sortie : text ou json

grimoire version

Affiche des informations étendues sur la version (grimoire, Python, plateforme, projet actif).

grimoire version
Option Description
--output, -o Format de sortie : text ou json

grimoire schema

Exporte le JSON Schema (Draft 2020-12) pour project-context.yaml.

grimoire schema

Utile pour l'autocomplétion YAML dans les IDE (VS Code, JetBrains) et la validation CI.

grimoire check

Exécute lint + validate + vérification de structure en une seule passe.

grimoire check [PATH]

Phases :

  1. Lint — validation du schéma YAML
  2. Validate — vérification de la config chargée (GrimoireConfig.validate())
  3. Structure — vérification des répertoires requis (_grimoire/, _grimoire/_memory/, _grimoire-output/)

Code de sortie 1 si un problème est détecté.


Surfaces hôtes

Le groupe grimoire host projette le projet sur ce que chaque hôte sait exécuter. Détail et dégradations par hôte : Surfaces hôtes.

Commande Description
grimoire host list Hôtes connus, surfaces natives de chacun, hôte détecté
grimoire host surface Description host-neutre du projet
grimoire host sync --host all Générer les surfaces (--dry-run, --force)
grimoire host status Écart entre ce que le projet déclare et ce que l'hôte exécute
grimoire host run <slug> Corps d'une commande, pour un hôte sans commandes natives
grimoire host hook --host <h> --event <e> Point d'entrée des hooks générés (stdin vers stdout)

grimoire init, grimoire up --fix et grimoire standard init synchronisent automatiquement ; l'appel manuel sert après l'ajout ou la modification d'une persona.

host list remonte aussi ce qu'un hôte ne sait pas exécuter, avec le substitut retenu — dont l'ouverture d'une session dans un agent, qu'aucun hôte ne sait faire : la persona d'entrée est alors remise à la boucle principale par le hook session_start. Voir Persona d'entrée.

Fournisseurs LLM

Le groupe grimoire providers croise le registre déclaratif (llm-provider-registry.yaml, voir Compatibilité multi-provider) et l'état de refroidissement/audit runtime pour répondre à : quel fournisseur appeler maintenant, pour quel palier de coût (cheap/mid/strong) ?

Commande Description
grimoire providers status [--json] Fournisseurs activés, modèles par palier, disponibilité (refroidissement + dernier audit), prochain choix
grimoire providers audit [--json] Sonder chaque fournisseur activé sans dépenser (PATH, --version, modèles Ollama) et journaliser available/models_seen/probe_note dans l'état
grimoire providers cooldown <id> --reason rate_limit\|timeout\|overloaded Enregistrer un échec à la main (429, timeout, 529)
grimoire providers probe [<id>] [--json] Sonder (comme audit) puis rouvrir les fournisseurs fermés par une date de forfait illisible (unknown) ; une suspension à date n'est jamais levée
grimoire providers quota [--json] Fenêtre de forfait lue dans les flux d'appel : lower_bound (minorant daté) ou unknown, jamais 0
grimoire providers history [--ledger-root <chemin>] [--json] Historique des dispatchs par couple (type de tâche, classe) et palier de départ recommandé

providers audit ne fait jamais l'appel réel : présence du premier mot de invocation sur le PATH, --version pour un exécutable reconnu (claude, gemini, copilot, codex, ollama), et pour un fournisseur local (invocation ollama ... ou provider_type: local) la liste des modèles via GET /api/tags (hôte surchargeable par OLLAMA_HOST, timeout 3 s). Un fournisseur jugé available: false est écarté par choose/candidates jusqu'au prochain audit qui le retrouve — l'audit n'active ni ne désactive jamais un fournisseur, enabled reste une décision de gouvernance.

providers history (issue #312) lit les événements task.dispatched du Mission Ledger et compte, par couple (type de tâche, classe de vérifiabilité) : le nombre de dispatchs et le taux d'escalade depuis cheap et depuis mid (part des dispatchs où le palier de départ n'a pas suffi). Pas de classifieur, pas d'entraînement — des compteurs. Avec au moins 5 observations pour un couple, un taux d'escalade dépassant 40 % depuis cheap fait recommander mid, dépassant 40 % depuis mid fait recommander strong ; un couple monté à mid dont les 5 dernières observations à ce palier n'ont plus escaladé, et qui n'a pas retenté cheap depuis autant d'observations, voit cheap recommandé à nouveau (re-sondage) — jamais sous le plancher qu'impose la classe (mid reste le plancher d'une tâche V1). La colonne « départ recommandé » est exactement ce que grimoire task dispatch retient par défaut pour ce couple.

Comptabilité du dispatch : coût par tâche résolue et pass^k

grimoire dispatch stats est la sœur de providers history : même idée (compter, ne pas classifier), autre source et un autre angle. providers history lit le Mission Ledger au grain de la tentative et compte des taux d'escalade par couple (type de tâche, classe) ; dispatch stats lit le journal de traces au grain de la cascade entière (un événement dispatch.outcome par grimoire task dispatch ou par node de grimoire flow run --executor dispatch réellement exécuté — jamais pour un refus avant tout appel ni un --dry-run) et répond à deux questions que seules des campagnes d'évals manuelles répondaient jusque-là (issue #442, point 5 de l'audit de positionnement du 2026-09-12) : combien coûte une tâche résolue, et à quel point une même tâche rejouée plusieurs fois réussit-elle systématiquement ?

Commande Description
grimoire dispatch stats [--since 30d] [--json] Coût par tâche résolue, taux d'escalade, part d'inexécutable — pour l'ensemble, par classe de vérifiabilité, par fournisseur et par flow — et pass^k sur les nœuds rejoués

Coût par tâche résolue : le coût total de toutes les tentatives (vertes et rouges confondues, un check rouge a quand même coûté un appel) divisé par le nombre de dispatchs résolus — jamais divisé par le nombre total de tentatives, qui sous-estimerait le coût réel d'un succès quand la cascade a dû escalader. None sans aucun dispatch résolu, jamais une division par zéro qui se lirait à tort comme un coût nul.

pass^k : quand un même nœud (le node d'un blueprint de flow, identifié par blueprint + id de node — ou, hors flow, directement l'identifiant de la tâche) a été dispatché au moins deux fois, cette répétition forme une « série ». Une série compte comme entièrement verte seulement si toutes ses exécutions ont résolu la tâche — la fiabilité au sens strict (k exécutions, toutes réussies), pas une moyenne de taux de réussite individuels. Le taux affiché est la part de séries entièrement vertes parmi celles observées au moins deux fois ; une tâche jamais rejouée n'entre dans aucun dénominateur.

--since 30d (ou 12h) ne garde que les dispatchs dont l'horodatage est plus récent que cette ancienneté. Sans journal de traces sous _grimoire-output/traces/, la commande n'échoue jamais : elle affiche qu'il n'y a rien à montrer ({"overall": null} en JSON).

Le contrôle du standard dispatch.cost_slo (voir Contrôles gouvernés) lit exactement les mêmes agrégats — cette commande en est la vue humaine, jamais un second calcul.

Routeur de LLM : une politique déclarative, tracée avant d'être activée

grimoire task dispatch choisit un palier de départ par la classe de vérifiabilité et l'historique d'escalade, puis prend le premier modèle du palier que le forfait n'a pas fermé. Le routeur (épopée #705, lot K9, issue #774) y ajoute une décision déclarative et rejouable, sans rien changer à ce chemin tant qu'on ne l'active pas : route(task, history, provider_state) choisit un modèle d'après la tâche seule (classe, type, difficulté), l'historique de réussite par modèle et la disponibilité du fournisseur. Il ne lit jamais le quota, le budget ni les tokens restants, et ne change jamais de modèle pour économiser : ces notions relèvent de l'admission, pas du choix. Un fournisseur suspendu par son forfait y figure comme indisponible, jusqu'à sa date de réouverture, comme un fournisseur injoignable.

Commande Description
grimoire route explain <tâche> [--json] Rejoue la dernière décision task.routed à partir de ses entrées et de inputs_digest ; sortie 1 si le rejeu diffère, 2 sans décision
grimoire route report [--json] Réussite au premier essai (pass^1) par (type, classe, modèle), escalade par couple, accord entre le routeur et le dispatch en mode shadow seulement (une issue session, defer ou refuse suivie d'un appel compte comme un désaccord) ; « non mesuré » sous 5 observations
grimoire route eval --set <jeu> [--json] Seuil d'activation D16 hors ligne ; sortie 0 (tenu), 1 (non tenu), 3 (non mesuré)

Politique : _grimoire/standard/routing-policy.yaml, sinon le défaut livré par le kit. Toutes les règles qui correspondent s'appliquent et le palier retenu est le maximum de leurs min_tier : le résultat ne dépend pas de l'ordre des règles. route: session est absorbant, V2 n'a jamais de route autonome, aucune règle qui correspond donne session, et le palier ne descend jamais sous le plancher de la classe (V0 cheap, V1 mid). Les conditions admises sont class, type, risk_any, exclusive_files_gt, needs_local : une règle qui nomme un quota ou un budget invalide la politique. type et risk_any se comparent en minuscules, sans espaces autour (comme les étiquettes de la tâche) : risk_any: [Security] vaut [security], une étiquette vide est refusée. Une politique malformée, sans version ou de version inconnue n'est jamais remplacée par le défaut : aucune route autonome (on_invalid: refuse) : la décision tracée est refuse et task dispatch ne lance aucune cascade (refus routing_policy_invalid, sortie 2), en shadow comme en active. Seul un routeur en panne (exception) laisse le dispatch suivre l'ancien chemin, avec une décision refuse et son erreur tracées.

version: 1
mode: shadow            # défaut ; `active` fait gouverner la décision
rules:
  - {id: r-risk, when: {risk_any: [security, migration]}, min_tier: strong}
  - {id: r-v1, when: {class: V1}, min_tier: mid}

Tentatives : max_attempts (défaut 3) borne le nombre d'appels de la cascade en mode active (appels en échec compris, tous paliers confondus) ; en shadow rien n'est appliqué, la valeur n'est que tracée dans les entrées de task.routed.

Mode : shadow (défaut) émet task.routed avant chaque cascade et laisse le dispatch suivre l'ancien chemin ; active fait gouverner la décision (palier de départ sauf --start-tier explicite, ordre des fournisseurs, modèle dans le palier). Dans le palier, le départage est : réussite au premier essai (au moins 5 observations, fenêtre de 50), puis, à réussite égale seulement, prix catalogue croissant (un prix inconnu passe après), puis ordre déclaré. Les modèles suspendus ou refroidis sont listés dans excluded[] avec leur raison. Sans candidat, la décision est defer : jamais de descente de palier. Revenir à shadow se fait en un seul champ.

En active, la décision n'est pas contournée : une issue session (règle route: session, V2, aucune règle qui correspond) ou defer ne lance aucune cascade (refus routed_to_session ou routed_defer, sortie 2, aucun task.dispatched). Les fournisseurs appelés sont ceux que la décision admet : une règle providers: {currency: local} vaut pour tous les paliers de la cascade, un fournisseur d'une autre monnaie n'est jamais appelé, et au palier retenu seuls les fournisseurs du classement le sont. En shadow, ces issues ne restent qu'une trace.

Attribution : chaque tentative (task.dispatched) compte pour le couple (type, classe, modèle) de cette tentative ; un 429, un timeout ou une panne d'appel sont non attribués et ne comptent jamais comme un succès.

Évaluation : le jeu est un fichier version: 1 / tasks: de tâches V0/V1 closes, chacune avec ses résultats enregistrés par modèle (results: {<modèle>: {passed, cost_usd}}). Le routeur est comparé à la base « fixe » (V0 vers cheap, V1 vers mid) : pass^1 du routeur >= base - 1 tâche et coût connu <= celui de la base. Un coût inconnu, un résultat manquant ou moins de 20 tâches rendent « non mesuré » : on n'active pas.

Besoins d'exécution : un flow déclare, le projet résout

Un node de flow ne référence pas pytest ni npm test en dur : son acceptance peut déclarer un besoin ({"run_need": "test-runner"}) plutôt qu'une commande (issue #205). grimoire flow run/resume résolvent ce besoin à la commande réelle du projet au chargement du blueprint — en deux temps, jamais un troisième : une déclaration explicite (needs.commands dans project-context.yaml) l'emporte toujours sur la détection par marqueur de projet (pyproject.toml, package.json, Cargo.toml, go.mod). Un besoin qui ne se résout ni par l'un ni par l'autre refuse le chargement du blueprint en le nommant, avant que le premier node soit présenté à l'hôte — jamais une installation qui échouerait au troisième node.

Commande Description
grimoire needs resolve [--project-root .] [--json] Le verdict de résolution de chaque besoin du catalogue pour ce projet, et sa source (declared, detected, unresolved)

Rétrocompatible : un blueprint à commandes en dur ({"run": "pytest -q"}) reste valide sans aucun changement. grimoire flow run affiche un avertissement (jamais un refus) quand une commande en dur correspond mot pour mot à un besoin résolu pour ce projet — une invitation à migrer vers run_need, pas une obligation.

Web

Le groupe grimoire web est le chemin par lequel un agent atteint le web. Il existe parce que le chemin nu ne suffit pas : web-browser.py rend son flux tel quel, et un agent qui colle ce flux dans son contexte ne distingue plus ce qu'il a lu de ce qu'on lui a demandé (OWASP LLM01).

Commande Description
grimoire web fetch <url> [--selector CSS] [--timeout N] [--json] Récupérer une page et la rendre enveloppée « donnée externe, pas instruction »

La sortie est encadrée par deux marqueurs portant un identifiant tiré au hasard à chaque appel, que la page ne peut pas connaître ; une source qui tente de recopier le marqueur le voit neutralisé et signalé. En --json, le résultat porte origin: external : il ne peut pas relayer une approbation.

Le navigateur tourne en sous-processus — le script est en zone gelée et n'est jamais importé. Voir Contenu externe : donnée, pas instruction.

Standard agentique gouverné

Le groupe grimoire standard pilote le standard agentique (profils, patterns gouvernés, preuves). Référence des patterns : Contrôles gouvernés.

Commande Description
grimoire standard profiles Lister les profils (starter → production)
grimoire standard needs Lister les besoins projet (groupés par tier)
grimoire standard plan --needs <id> Prévisualiser le plan (profil + patterns + extras) sans rien écrire
grimoire standard init [.] --needs <id> Générer les artefacts standard du projet
grimoire standard verify Vérifier les artefacts (fail-closed)
grimoire standard audit Rapport de conformité + gaps restants
grimoire standard score Calculer et persister un score de conformité
grimoire standard gate check [--strict] [--no-run] Gate CI : échoue si une preuve obligatoire manque ; chaque manque nomme son chemin et un remède copiable. --strict exécute lui-même gate run-tests si la tâche doit une preuve d'exécution et qu'aucun run vert et frais n'existe ; --no-run restaure l'ancien comportement
grimoire standard gate run-tests Exécuter la commande de test connue et enregistrer le verdict (test-run.json)
grimoire standard task scaffold [--task-id X] [--dry-run] Créer, s'ils manquent seulement, les artefacts par tâche que les gates exigent (enveloppe, pack de preuve, registre d'affirmations, dossier d'acceptance, context bundle, decision trace), pré-remplis depuis le Mission Ledger ; idempotent ; le hook SessionStart le fait déjà pour la tâche active
grimoire standard fix [--apply] Planifier / appliquer des correctifs sûrs
grimoire standard doctor Vérifier la disponibilité des extras technologiques
grimoire standard pattern Lister / inspecter les patterns
grimoire standard detect-providers Détecter les providers LLM disponibles
grimoire standard traceability [projet] Matrice exigences / contrôles / preuves de la norme ; avec un projet, le verdict de verify par artefact
grimoire standard upstream Le standard amont a-t-il avancé depuis la révision épinglée (sortie 0/2/3)

Sous-groupes (chacun avec --help) : board, memory, context, decision, rules, hooks, gate, events, pattern, knowledge, task.


Tâches agentiques

Le task board gouverné est une projection du Mission Ledger, pas une source (voir ADR-005). Éditer _grimoire/standard/task-board.yaml à la main ne change rien au ledger, et le prochain export l'écrase.

Commande Description
grimoire task board export [.] Régénérer le board depuis le Mission Ledger
grimoire task board export . --dry-run Afficher la projection sans écrire
grimoire task board export . --mission <id> N'exporter qu'une mission
grimoire task board export . -o <chemin> Écrire ailleurs que dans le board du standard
grimoire task add "<titre>" -a "<critère>" [--owner <qui>] [--ready] Ouvrir une tâche (un critère d'acceptation au moins) ; --ready la rend réclamable tout de suite, gate proposed_to_ready compris
grimoire task list [--status <état>] [--mission <id>] Lister les tâches et leur colonne de board
grimoire task show <id> Détailler une tâche et ce que chaque prochain pas exigera
grimoire task claim <id> [--actor <qui>] [--host <où>] Réclamer une tâche prête (ready → claimed)
grimoire task move <id> --to <état> Déplacer une tâche, si la machine à états et le gate le permettent
grimoire task block <id> --reason "<motif>" Bloquer en disant pourquoi
grimoire task close <id> Fermer une tâche vérifiée (verdict accepté exigé)
grimoire task prioritize <id> --to low\|medium\|high\|critical [--reason "<motif>"] Changer la priorité (issue #638) — l'historique reste au ledger, le board se retrie
grimoire task comment <id> "<texte>" [--kind comment\|directive] Poser un commentaire ou une consigne ; la session qui tient la tâche la lit au prochain UserPromptSubmit
grimoire task cancel <id> --reason "<motif>" [--force] Annuler avec sa raison (obligatoire) ; tenue par une autre session, elle exige --force
grimoire task ack <id> <dir-…> Accuser réception d'une consigne de l'orchestrateur
grimoire task link <id> --depends-on <id> Déclarer une dépendance
grimoire task context <id> Produire le context bundle d'une tâche réelle
grimoire task trace <id> [--causes] Timeline unifiée d'une tâche : transitions, outils refusés, gates rouges, checkpoints, abort, preuves, incidents
grimoire task trace-export <dest> [--format otel\|langfuse] [--mission-id <id>] Exporte le TraceLedger en JSONL, conventions sémantiques OTel GenAI ou contrat REST Langfuse
grimoire task recall <id> Ce que la mémoire du projet sait de cette tâche et de ses voisines — borné en tokens
grimoire task dispatch <id> --check "<commande>" [--check ...] [--dry-run] [--max-tier cheap\|mid\|strong] [--start-tier cheap\|mid\|strong] [--provider <id>] [--timeout <s>] Déléguer la tâche en cascade par palier de fournisseur

Sans ledger, la commande d'export refuse et sort en erreur plutôt que d'écrire un board vide — écraser le travail déclaré par du néant serait pire que ne rien faire.

Chaque transition d'état (claim, move, block, close, cancel) franchit deux portes avant de toucher le ledger : la machine à états, puis le gate de preuve de _grimoire/standard/evidence-gates.yaml. Un refus nomme la preuve manquante et le remède ; rien n'est écrit. Après une écriture acceptée, le board du standard est reprojeté depuis le ledger si le projet est enrôlé (_grimoire/standard/ présent) — plus besoin de relancer task board export pour qu'un claim se voie.

Les mêmes gestes sont exposés aux agents par le serveur MCP (task_add, task_list_ready, task_show, task_claim, task_update, task_context) : même service (TaskService.add pour l'ouverture), même gate, même refus. Voir Intégration MCP.

Vérifiabilité d'une tâche

grimoire task show <id> et la projection du board (verifiability) portent une classe dérivée — jamais déclarée — depuis le texte des critères d'acceptation et des preuves attendues : V0 si tous nomment un verdict qu'un programme rend seul (test, lint, schéma, gate, code de sortie, build/CI, fichier attendu), V1 si au moins un critère nomme une revue ou une validation par une personne ou un agent sans qu'aucun autre ne reste ambigu, V2 sinon — y compris une tâche sans aucun critère. Un critère formulé de façon vague (« le code est propre ») ne peut jamais produire un V0 : un seul critère ambigu suffit à faire monter la classe, jamais à la faire descendre. task show affiche, critère par critère, le motif reconnu — c'est ce qui rend lisible pourquoi une tâche n'est pas au niveau qu'on lui prêtait.

Plafonds MAST par instance de workflow

Chaque instance créée par le RuntimeKernel (create_instance) porte deux plafonds indépendants, surchargeables à la création (max_tool_calls=50, max_budget=100 par défaut) : le nombre d'appels d'outils que mediate_tool médiera — la seule unité de « tour » que le kernel observe — et un budget d'unités de coût consommées par ces mêmes appels (1 unité par appel par défaut ; un appelant qui connaît un coût réel, en tokens ou en devise, peut passer cost= à chaque appel). Le kernel ne voit aujourd'hui passer ni tokens ni coût ailleurs, d'où ce choix par défaut. Au premier appel qui dépasserait l'un des deux plafonds, l'instance passe dans l'état terminal refused : un checkpoint est écrit, un événement workflow.refused est journalisé, et l'appel — comme tout appel suivant sur cette instance — rend False sans jamais lever d'exception ni laisser l'instance continuer en silence. Voir src/grimoire/runtime/kernel.py et schemas.py (WorkflowStatus.REFUSED, RunEventType.WORKFLOW_REFUSED).

Pourquoi une tâche s'est arrêtée

grimoire task trace <id> lit les journaux qui portent chacun le task_id — le Mission Ledger (transitions, incidents), le TraceLedger des hooks (outils autorisés ou refusés par la policy, clôtures refusées, gates de transition rouges, dispatch d'agent ou non-choix), le RuntimeKernel (run events, checkpoints, abort/refus et leur raison), l'EvidenceService (packs, verdicts) et, s'il existe, l'export OTel du TraceLedger (grimoire task trace-export --format otel, #322) — et les trie dans le temps. Cette dernière source lit un fichier déjà écrit par trace-export (emplacement conventionnel : <traces>/otel-export.jsonl) ; elle ne relance jamais l'export elle-même. Les entrées qui expliquent un arrêt sont marquées et reprises dans une section « Cause(s) d'arrêt » ; --causes n'affiche qu'elles ; --output json rend la timeline complète avec ses sources. Une source absente est nommée comme telle ; rien n'est créé, rien n'est inventé. bootstrap se trace aussi — c'est là que les hooks écrivent tant qu'aucune tâche n'est réclamée.

Le cockpit et l'atelier affichent la même timeline dans l'espace Exécuter de la vue de travail (onglet Timeline, drill-down depuis une carte du board), et l'espace Observer y renvoie depuis un span OTel qui porte un grimoire.task_id — voir la page du cockpit, section « Le board (espace Exécuter) ».

GAO-livrer-la-ti-001 — Livrer la timeline  (running)
    21:14:39  ledger   ready → claimed par claude (claim claude@claude-code)
  ✗ 21:14:40  hooks    Bash refusé par la policy (args 3f2a9c1e0b7d4e11)
  ✗ 21:14:41  gate     gate « in_progress_to_review » refuse la transition — manque : evidence_pack, decision_trace
  ✗ 21:14:42  runtime  workflow WFI-recipe-livraison-001 abandonné — raison : suite pytest rouge

Cause(s) d'arrêt : 3

Dispatch par cascade

grimoire task dispatch <id> délègue une tâche à un fournisseur LLM du registre (llm-provider-registry.yaml), en cascadant par palier de coût (cheap → mid → strong) selon la classe de vérifiabilité de la tâche : une tâche V2 est refusée avant tout appel (aucun verdict mécanique ne peut la juger), une V0 cascade depuis cheap, une V1 cascade depuis mid et, au vert, passe en needs_verification au lieu d'être considérée close — le check mécanique n'y est qu'un indice, la classe exige encore un regard humain. Au moins un --check <commande> est obligatoire (code de sortie 0 = vert, toutes doivent l'être) ; sans lui, la classe dit que le verdict est mécanique, encore faut-il dire lequel.

Un échec d'appel (429, timeout, code de sortie non nul) passe au fournisseur suivant du même palier et pose un refroidissement (grimoire providers status) ; un --check rouge passe au palier suivant. Chaque tentative laisse un événement task.dispatched au Mission Ledger (palier, fournisseur, modèle, durée, verdict, coût si la sortie est un JSON portant total_cost_usd, type de tâche, classe de vérifiabilité, palier de départ et sa raison). --dry-run montre la classe, la chaîne de paliers prévue et le prompt sans rien appeler ; --max-tier borne la cascade ; --provider la restreint à un seul fournisseur.

Code de sortie : 0 si la chaîne finit au vert, 1 si elle s'épuise sans verdict vert, 2 sur un refus (V2, aucun --check, aucun fournisseur invocable). Ce lot ne worktree pas automatiquement : travaillez sur une branche propre avant de dispatcher — le fournisseur délégué écrit dans le dépôt courant.

Palier de départ ajusté par l'historique

Le palier de départ de la cascade n'est plus fixe : sauf --start-tier explicite, il vient de l'historique des dispatchs passés pour le couple (type de tâche, classe de vérifiabilité) — voir grimoire providers history (issue #312). Par défaut, cheap pour V0 et mid pour V1 (le plancher que la classe impose, jamais franchi vers le bas) ; ajusté vers mid, puis strong, quand un couple escalade trop souvent depuis son palier habituel, et re-sondé vers le bas quand il cesse d'escalader et que le palier inférieur n'a pas été retenté depuis un moment. Le rapport (start_tier, start_tier_reason) et l'événement task.dispatched disent tous deux quel palier a été retenu et pourquoi ; --start-tier cheap|mid|strong l'impose sans consulter l'historique.

Le pilote : combien dépenser par node (issue #209)

Une fonction de décision — jamais une couche — appelée avant chaque node dispatché par flow run --executor dispatch : le graphe dit quoi, le pilote dit combien. Une politique de projet optionnelle, _grimoire/standard/pilot.yaml, la paramètre ; absente, le comportement est exactement celui décrit ci-dessus (palier de départ ajusté par l'historique, aucun plafond).

start_tier:
  V0: mid          # ne peut jamais descendre sous le plancher de la classe
max_escalations: 1  # 0 = aucune escalade permise, absent = pas de plafond posé ici
max_cost_usd_per_node: 0.50
on_unknown_cost: stop  # défaut ; ou continue_flagged

max_cost_usd_per_node s'applique dans missions.dispatch.run_dispatch lui-même (max_cost_usd) : entre deux paliers, jamais au milieu d'une tentative ni après un vert déjà acquis — seule l'escalade vers un palier plus cher est abandonnée. Le rapport porte alors cost_capped (un message nommé) plutôt qu'une chaîne simplement épuisée ; côté flow status, le node apparaît avec le verdict cost_capped. Un pilot.yaml malformé refuse nommément le chargement plutôt que de retomber en silence sur « aucun plafond » — contrairement à orchestration-policy.yaml, un plafond de coût est un mécanisme de sécurité.

Un fournisseur qui ne rend pas son coût (aucun JSON portant total_cost_usd, le cas de la plupart des fournisseurs headless) laisse ce coût inconnu : il n'est jamais compté pour zéro. on_unknown_cost: stop (défaut, fail-closed) arrête l'escalade dès qu'un palier a répondu sans coût alors qu'un plafond est posé — le rapport porte cost_capped avec la raison cost_unknown (cost_cap_reason). continue_flagged laisse escalader ; le coût reste alors signalé lower_bound (>= 0.4200 USD (1 non pricés)) ou unknown dans le rapport, la trace dispatch.outcome, grimoire dispatch stats, flow status, flow list et le contrôle dispatch.cost_slo (tous rendent le même format, avec le décompte des appels sans prix). Dans un flow, cost_unknown ne sert qu'à l'escalade, à l'enchaînement des nodes d'un sous-flow et aux passes optionnelles de budget (non lancées sous stop, skipped_reason: cost_unknown) : un coût inconnu ne jette jamais un node déjà vert ni les éléments frères d'un fanout, verify-panel, loop-until-dry, judge ou replay-diff (seul un montant connu qui atteint le plafond, cost_reached, les arrête). Ces nodes continuent donc sous stop malgré un coût inconnu, mais ne passent pas pour « sous le plafond » : le node porte cost_cap_unevaluated: true (plafond posé, politique stop, appels sans prix — le plafond n'a pas pu être jugé), à lire avec cost_status. Le node porte cost_cap_reason (cost_reached | cost_unknown). La politique assume_tier_ceiling (estimer au plafond du palier) n'existe pas encore.

Classe de relisibilité

Un dispatch qui finit au vert classe aussi le diff qu'il a produit (git diff --name-only dans le projet) : review_required s'il touche une surface sensible, review_optional sinon. Surfaces par défaut, génériques : exports publics (*/__init__.py), surfaces d'entrée (*/cli/*, */mcp/*, */api/*), schémas (*schema*), standard du projet (_grimoire/standard/*, framework/agentic-standard/*), vocabulaire de décision (*/verifiability.py), politiques, sécurité et hooks (*/policies/*, */security/*, */hooks/*). Un diff confiné à tests/ ou docs/ reste toujours review_optional. La liste se surcharge projet par projet dans _grimoire/standard/orchestration-policy.yaml (clé review_surfaces, une liste de globs). Un projet qui n'est pas un dépôt git ne permet pas de calculer le diff : la classe reste review_optional, avec une note qui le dit plutôt qu'un silence trompeur. Le rapport (review, review_files) et l'événement task.dispatched portent tous deux le résultat ; task show affiche celui du dernier dispatch.

Incertitudes déclarées

Le prompt envoyé à l'ouvrier délégué se termine par une consigne : rendre un bloc délimité ```grimoire-uncertainties contenant une liste JSON d'objets {"where": ..., "what": ..., "why": ...} — le canal d'escalade le moins cher qui existe, lu ici mécaniquement plutôt qu'en prose. Le dispatch l'extrait de la sortie de l'ouvrier (le texte brut, ou le champ result si la sortie est un JSON qui l'enveloppe) et stocke le résultat sous uncertainties dans le rapport et dans l'événement task.dispatched. Un bloc absent est une liste vide, silencieusement — la plupart des ouvriers n'y répondront pas encore ; un bloc présent mais illisible (JSON invalide, pas une liste) est aussi une liste vide, mais avec un avertissement dans uncertainty_warnings ; un objet du bloc sans les trois clés est ignoré avec son propre avertissement, les autres objets du même bloc restent gardés. Rien de tout cela ne change le verdict ni le code de sortie du dispatch. task show affiche les incertitudes du dernier dispatch.

Ce que le claim rappelle

grimoire task recall <id> (#141) assemble ce qu'une tâche et ses voisines ont déjà traversé : son propre historique (tentatives précédentes bloquées ou échouées), ses tâches voisines — liées par task link, de la même mission, ou au titre proche — avec la cause de leur arrêt même si elles ont depuis été rouvertes, et ce que la mémoire du projet a consolidé sur des sujets voisins quand un backend mémoire est configuré (project-context.yaml). Sans lui, le rappel reste utile depuis le seul Mission Ledger. Le texte rendu est borné en tokens : c'est un rappel, pas un rapport.

[Grimoire — rappel de tâche] GAO-migrer-le-se-002 :
Tâches voisines :
  - GAO-migrer-le-se-001 (même mission, failed)
      cause : connexion refusée par la base cible : pool épuisé

Le même rappel est injecté par le hook SessionStart, entre la persona d'entrée et la directive du standard, seulement pour une tâche réclamée (task.claim posé — une tâche proposed ou ready ne rappelle rien) ; et par l'outil MCP task_recall, qui résout la tâche active de la même manière que task_context quand aucun identifiant n'est donné. À la clôture ou au blocage d'une tâche, TaskService consolide ce qui a été appris dans la mémoire du projet (decisions à la clôture, failures au blocage) — jamais sur un mouvement ordinaire.

Quelle tâche la session porte

Les hooks (SessionStart, UserPromptSubmit, Stop) et grimoire standard activation-context résolvent la tâche courante dans cet ordre :

  1. GRIMOIRE_TASK_ID — un opérateur dit de quelle tâche la session parle ;
  2. le claim actif du Mission Ledger : l'unique tâche claimed ou running, restreinte aux claims de GRIMOIRE_ACTOR quand cette variable est posée ;
  3. l'unique carte in_progress du board (projet sans ledger) ;
  4. bootstrap.

Deux claims simultanés (ou deux cartes in_progress) sont ambigus : le niveau est sauté plutôt que deviné, et GRIMOIRE_TASK_ID tranche. task_context sans argument, côté MCP, rend la tâche résolue et la règle qui l'a choisie.

Neuf états côté ledger se projettent sur les huit colonnes du standard. Les fusions sont décidées et testées : claimed et running deviennent in_progress, needs_verification devient review, failed devient blocked (avec un motif), closed devient accepted, cancelled devient archived.


Mémoire

Le groupe grimoire memory pilote le sous-système mémoire. Concepts, backends et projections : Système de mémoire.

Commande Description
grimoire memory status Santé du backend, nombre d'entrées, configuration
grimoire memory up Mettre en place la stack mémoire complète, plan par plan
grimoire memory remember <texte> Écriture typée idempotente — même texte et même agent n'écrivent qu'une fois
grimoire memory recall <requête> Rechercher parmi les mémoires typées
grimoire memory search <requête> Recherche par mot-clé ou similarité sémantique — fusionne vectoriel et BM25 (RRF) dès que le projet possède les deux ; --no-hybrid force le backend seul
grimoire memory list Lister les mémoires stockées, paginées
grimoire memory delete <id> Supprimer une entrée
grimoire memory gc Consolider et compacter
grimoire memory export / import Exporter vers JSON, réimporter
grimoire memory reindex-lexical Reconstruire l'index lexical compagnon
grimoire memory gate Gate de parité Memory OS entre Weaviate et Neo4j
grimoire memory graph / vector Synchroniser et vérifier les projections
grimoire memory bundle Construire, installer et vérifier les bundles de modèles d'embedding
grimoire memory shared Mémoire transverse : ce qui reste vrai d'un projet à l'autre
grimoire memory facts / diary Graphe de faits temporels, journaux d'agents
grimoire memory migrate Planifier et exporter les migrations Memory OS
grimoire memory taxonomy Taxonomie aile / salle / pièce

Hooks git

Commande Description
grimoire hooks list Lister les hooks disponibles et leur état d'installation
grimoire hooks status Résumer l'état d'installation — sortie 1 si incomplet
grimoire hooks install Installer les hooks git Grimoire dans le dépôt

Blueprints et flows

Un blueprint décrit un flow agentique comme un graphe de nodes typés. Ces commandes le manipulent sans passer par l'atelier web. Détail du format et de l'éditeur : Mode local et blueprints.

Commande Description
grimoire blueprint new <id> Scaffolder un .blueprint.json valide depuis un modèle embarqué
grimoire blueprint validate <fichier> Valider : JSON Schema, puis contrôles structurels de compilation
grimoire blueprint compile <fichier> Compiler en mission pack, avec les mêmes règles fail-closed que l'atelier
grimoire blueprint evals <fichier> --record <relevé> Rejouer les évals déclarées contre un relevé d'exécution

Le rejeu ne fabrique aucun verdict : un cas absent du relevé est rapporté comme non exécuté, jamais comme échoué.

validate et compile ont deux couches de contrôle, dont la première demande le paquet jsonschema. Quand il manque, la couche ne s'exécute pas et les deux commandes refusent : un contrôle qui n'a pas eu lieu ne peut pas conclure à un succès. --allow-skipped-schema accepte explicitement le contrôle partiel.

grimoire flow — le moteur conduit, l'hôte exécute un node

blueprint compile aplatit un blueprint en un unique prompt markdown : le modèle improvise l'ordre. grimoire flow inverse cela (#204) : le RuntimeKernel conduit un blueprint node par node, chaque node reçoit un contrat borné (entrées, frontière d'outils, critères d'acceptation, contrat de sortie), et l'hôte — jamais le kit — exécute le node. compile reste un repli valide pour les hôtes sans exécuteur de node ; flow ajoute une seconde sortie, il ne retire rien.

Commande Description
grimoire flow run <fichier> Démarrer un run et présenter le contrat du premier node ; sans argument, liste les runs
grimoire flow status <run-id> État du run : node courant, nodes faits, dernier refus, contrat courant
grimoire flow resume <run-id> --result <fichier> Vérifier la sortie du node courant contre son contrat ; avance ou suspend
grimoire flow abort <run-id> [--reason] Abandonner un run — terminal, jamais repris
grimoire flow extract <run-id> [--out <fichier>] Extraire un blueprint brouillon de la séquence réellement exécutée par ce run
grimoire flow list [--require-measure <blueprint-id>] Le registre local des flows : runs connus par blueprint, avec leur mesure de dispatch

Un checkpoint par node : un run interrompu reprend exactement au node courant, jamais du début. Une sortie non conforme au contrat de sortie du node suspend le run en nommant le node et la pin fautifs, avec un code de sortie non nul — jamais un échec muet.

flow extract — un flow s'extrait d'un run, il ne se dessine pas (#210)

Créer un flow devient éditer quelque chose qui a déjà fonctionné plutôt que partir d'un canevas vide. grimoire flow extract <run-id> joint les métadonnées du run (ordre topologique, blueprint source) au Mission Ledger (commande réellement exécutée par node, via --executor dispatch) pour produire un blueprint brouillon dans le même format .blueprint.json — texte d'abord, lisible et diffable, que le Studio peut ensuite éditer.

Par node, trois choses observées, jamais devinées : l'acceptance déclarée d'un node complété par la cascade est remplacée par la commande réellement exécutée ({"run": "..."}), réinférée en {"run_need": "..."} quand elle correspond caractère pour caractère à un besoin résolu pour ce projet (issue #205) ; un node jamais dispatché (classe V2, ou exécuté par un hôte interactif sans passer par la cascade) garde son acceptance d'origine verbatim ; un node jamais atteint (run incomplet ou abandonné) est marqué not_reached, sans qu'aucune commande n'y soit inventée. Chaque node du brouillon porte un objet "extraction" (status, et note sur un refus) qui dit lequel de ces trois cas s'est produit.

Le brouillon extrait est rejouable : flow run/resume le chargent comme n'importe quel blueprint, et reproduisent la même séquence de nodes que le run source sur le même projet.

kind: "composite" — un flow est un node (lot 3, issue #206)

Le schéma réservait déjà kind: "composite" pour un sous-flow (ref = use-case:<id> ou un chemin .blueprint.json), mais seul le compilateur Studio le validait — le moteur de flows ne l'exécutait pas. Depuis cette issue, un node composite expose des pins comme n'importe quel node, et son exécution (sous --executor dispatch) lance la ref comme un run à part entière : son propre run_id, ses propres checkpoints, son propre Mission Ledger — lié au parent par FlowRunMeta.parent_run_id/parent_node_id.

ref reconnaît trois formes, jamais une quatrième inventée :

  • un chemin se terminant par .blueprint.json, résolu relativement au blueprint qui le référence puis à la racine du projet ;
  • un id de flow nu, résolu contre le registre local (registry/blueprints/<id>.blueprint.json) ;
  • use-case:<id> — réservé à l'expansion Studio/catalogue : le moteur de flows refuse cette forme au chargement, il ne l'exécute pas.

Trois refus, tous au chargement du blueprint parent, jamais quand le node composite serait présenté à un exécuteur :

  • référence introuvable (fichier absent, id absent du registre) ;
  • cycle de composition — un blueprint qui se référence lui-même, directement ou via un intermédiaire ;
  • profondeur de composition supérieure à 3 (un flow racine qui référence un sous-flow qui en référence un troisième est la limite).

Le coût du sous-flow est remonté au node composite : flow status et le rapport de --executor dispatch montrent son cost_usd comme la somme des coûts de tous les nodes de l'enfant. Le plafond du pilote (issue #209, max_cost_usd_per_node) s'applique à ce total, vérifié entre chaque node de l'enfant — jamais après un node déjà vert : un dépassement abandonne le run enfant (flow status <child-run-id> le montre aborted) et ferme le node composite en cost_capped, comme un node simple dont la cascade aurait renoncé au palier suivant.

Sous l'exécuteur interactive (par défaut), un node composite n'est pas auto-lancé — son contrat affiche composite:<ref> comme frontière d'outils, et l'hôte lance lui-même grimoire flow run <ref> avant de soumettre un résultat conforme aux pins déclarées, comme pour tout autre node interactif.

flow extract (#210) ne l'aplatit jamais : le node composite reste kind: "composite" avec sa ref d'origine dans le brouillon, et son extraction porte le child_run_id du sous-flow qu'il a lancé quand il y en a un — le sous-flow s'extrait séparément, sur son propre run_id.

grimoire.flows.registry.describe_flow (utilisé par flow list, ci-dessous) lit, en plus, version/kitMin/kitMax au niveau du blueprint (tous optionnels — version retombe sur 0.0.0) et l'union des run_need déclarés par le flow et par tous ses sous-flows composite.

Les sept genres de node (lot 4, issue #207)

composite (ci-dessus) est le cas dégénéré : un sous-flow, une tentative, aucune agrégation. Sept genres de plus généralisent le même mécanisme — lancer un ou plusieurs sous-flows enfants — avec chacun sa propre politique d'agrégation. Aucun n'est exprimable dans un document de consignes statique ; tous deviennent directs dès que le moteur tient l'état. Chacun n'existe que sous --executor dispatch (grimoire.flows.genres, fonctions _execute_<genre> — module compagnon de grimoire.flows.dispatch_executor, extrait de lui pour rester sous le seuil du cliquet de lignes) ; sous interactive, le contrat affiche le genre et sa ref comme frontière d'outils, l'hôte orchestre lui-même.

Paramétrage refusé nommément au chargement du blueprint (grimoire.flows.blueprint_loader._validate_genre_config) — jamais un TypeError/KeyError anonyme à l'exécution :

Genre ref config.<genre> requis
fanout sous-flow modèle — (voir ci-dessous)
verify-panel sous-flow vérificateur k (entier ≥ 2), angles (liste de k chaînes)
loop-until-dry sous-flow maxRounds (entier ≥ 1)
judge sous-flow candidat n (entier ≥ 2), angles (liste de n chaînes)
checkpoint ignorée (chaîne vide par convention) —
budget ignorée — voir config.budget.passes maxCostUsd (nombre > 0), passes (liste non vide de refs)
replay-diff sous-flow —

fanout — un node produit N éléments, N sous-flows instanciés, les résultats sont recollés. Deux temps : le node est d'abord dispatché normalement (comme un node ordinaire), sa sortie doit porter, en plus de ses pins déclarées, une clé fanout_items (liste non vide) ; le moteur instancie alors un sous-flow (ref) par élément. N est borné par pilot.max_fanout_n (_grimoire/standard/pilot.yaml) — absent, le fan-out est refusé : jamais une politique manquante ne vaut un plafond infini implicite. Vert seulement si les N enfants finissent tous verts ; recoller un résultat partiel comme s'il était le tout serait l'invention que l'issue refuse.

verify-panel — k vérificateurs indépendants (config.verifyPanel.k), chacun sous un angle distinct (.angles, instruit de chercher à réfuter, jamais de confirmer par défaut), majorité requise. Coût = k tentatives, toujours — jamais une cascade qui s'arrête au premier consensus apparent : un plafond de coût qui empêche de compléter les k tentatives referme le node en cost_capped, jamais sur un vote partiel (« jamais un vert sur 1/k »).

loop-until-dry — relance jusqu'à config.loopUntilDry.maxRounds tours sans nouveauté. Chaque tour doit porter une clé novelty_key (chaîne) dans sa sortie ; la déduplication porte contre tout le vu depuis le premier tour (un ensemble cumulatif), jamais seulement contre le dernier tour retenu. maxRounds est une borne dure, distincte d'un séchage réel (loop_until_dry_stop_reason : "dry" / "max_rounds" / "cost_capped").

judge — N tentatives sous angles imposés (config.judge.n/.angles), puis le node lui-même est dispatché une seconde fois comme juge (V1 — « un humain choisit »), avec le résumé des N tentatives dans son contexte de tâche ; sa sortie doit porter judge_winner (index 0..N-1). La trace des N tentatives survit dans leurs propres runs (Mission Ledger de chaque enfant), jamais seulement dans un champ éphémère du node.

checkpoint — approuver, refuser, amender. Toujours une décision d'hôte forcée, jamais auto-décidée par la cascade (même sous --executor dispatch, ce genre pend systématiquement, comme un node V2). La reprise (flow resume --result, forme interactive, quel que soit l'exécuteur qui a conduit le reste du run) doit porter checkpoint_decision (approve/reject/amend) ; reject bloque le run en nommant le motif (checkpoint_reason) dans l'événement de refus du kernel — « le motif dans le graphe de décision » — une reprise ultérieure rouvre exactement ce même node. amend (W2-10) demande une révision : le node reste ouvert, la décision et son motif sont inscrits dans le journal du run (relu par flow status) et comptés. accept_as_is n'est accepté qu'après config.checkpoint.max_amendments amendements (entier >= 1, 3 par défaut) ; il exige checkpoint_reason (le risque nommé), inscrit accepted_risk, et pose task.risk_accepted sur la tâche du ledger liée au run (--task-id) si elle existe ; le ledger le rejoue dans la tâche (accepted_risks) et classify la remonte au moins en V1 pour toute surface (task show, MCP task_show/task_claim, dispatch_advice, transition needs_verification de task dispatch). Limite : le compteur est celui du journal du run, amend non attesté compris.

budget — plafond de coût déclaré (config.budget.maxCostUsd), abandon des passes optionnelles avant dépassement. passes est une liste de refs de sous-flows ; la première est obligatoire (son échec fait échouer le node) ; chacune des suivantes n'est lancée que si le coût cumulé reste sous le plafond — sinon abandonnée, jamais tentée, sans faire échouer le node. Distinct de pilot.max_cost_usd_per_node : ce plafond-ci est déclaré par le blueprint, propre à ce node.

replay-diff — rejoue le même flow (ref) sur la même entrée (deux runs enfants, sans variation d'un à l'autre) et compare les traces. replay_diverged (booléen, dans la sortie) dit si les deux traces (statut + nodes complétés) divergent — une divergence est un signal, jamais un défaut : le verdict reste vert tant que les deux relectures finissent, qu'elles divergent ou non.

Coût et pilote, pour les sept genres : pilot.max_cost_usd_per_node s'applique au total de chaque genre, jamais à une seule tentative — vérifié avant chaque nouveau sous-flow lancé, jamais après un enfant déjà vert (même garantie que pour composite). Extraction : flow extract ne les aplatit jamais — kind, ref et config.<genre> survivent verbatim dans le brouillon, exactement comme composite. Rust : aucun changement — les sept genres sont de l'orchestration Python (E/S, lancement de runs enfants), hors périmètre des fonctions pures déjà portées par grimoire-flows-core ; la grille de transitions et les contrats de node n'ont pas changé.

--executor dispatch — la cascade par classe de vérifiabilité (#311)

run et resume acceptent --executor dispatch (défaut : interactive, inchangé). Au lieu d'attendre un --result de l'hôte, chaque node est confié à grimoire.flows.dispatch_executor : une tâche de mission est créée (ou retrouvée) au ledger, liée au run et au node, avec pour critères d'acceptation ceux du node et pour preuve attendue son contrat de sortie ; elle est dispatchée en cascade (run_dispatch, #323) — l'ouvrier écrit sa sortie dans un fichier JSON que le kit vérifie contre les pins du node, avec la même fonction que flow resume, et exécute l'acceptance structurée du node quand le blueprint en déclare une (voir « Acceptance structurée d'un node », ci-dessous, issue #428) : une enveloppe conforme ne suffit plus seule à fermer un node V0 dont l'acceptance déclare une commande.

La chaîne suit la classe de vérifiabilité du node (#309) :

  • V0 : cheap → mid → strong.
  • V1 : démarre à mid ; un vert marque le node à relire (needs_verification côté ledger), jamais une fermeture.
  • V2 : refusé avant tout appel — le node revient à l'hôte, exactement comme flow run/flow resume interactifs : le contrat est présenté, flow resume --result reprend la main.

run --executor dispatch enchaîne les nodes tant que la cascade reste verte, checkpointe après chacun, et s'arrête au premier node rouge (chaîne épuisée), acceptance inexécutable, ou V2, avec un rapport par node (fournisseur, tentatives, verdict, coût, escalades, statut d'acceptance) plutôt qu'un contrat. resume --executor dispatch (sans --result) reprend de la même façon le node que le run avait laissé ouvert — utile après un crash comme après une suspension V2 corrigée autrement. flow status affiche, pour tout node dispatché, fournisseur, tentatives, verdict, relecture requise, incertitudes déclarées et statut d'acceptance (exécutée/inexécutable/jugée) — lus depuis l'événement task.dispatched du Mission Ledger, valables même dans un process qui n'a pas fait le dispatch. --max-tier et --timeout bornent la cascade comme sur grimoire task dispatch.

Acceptance structurée d'un node (issue #428)

Un node V0 est « vérifiable mécaniquement » : par défaut, le vocabulaire de son acceptance textuel (« la suite de tests passe », …) sert uniquement à dériver sa classe de vérifiabilité (#309) — le gate de la cascade ne vérifie que la conformité de l'enveloppe JSON au contrat de sortie du node, jamais le texte lui-même. Sur un flow réel rejoué le 2026-09-11 (épic #307, lot 3), cela a laissé fermer vert un node dont la vraie suite pytest ne pouvait pas même être collectée (dépendance absente) : l'enveloppe était conforme, rien d'autre n'avait tourné.

node.acceptance accepte désormais, en plus d'une chaîne libre (rétrocompatible, comportement inchangé), une entrée structurée que le gate exécute réellement après la réponse de l'ouvrier — dans le projet, en sous-processus, délai borné :

{"run": "pytest -q tests/test_x.py", "expect_exit": 0, "cwd": ".", "timeout_s": 120, "expect_stdout_contains": "passed"}

Seul run est requis ; expect_exit (0 par défaut), cwd (. par défaut), timeout_s (120 par défaut) et expect_stdout_contains (aucun par défaut) sont optionnels. Deux formes d'evidence mécanique existent aussi, pour éviter d'écrire une commande à la main :

  • {"path_exists": "dist/rapport.json"} — un fichier doit exister.
  • {"test": "tests/test_x.py::test_y"} — un test nommé doit passer (traduit en une invocation pytest du seul identifiant déclaré).

acceptance peut mélanger texte libre et entrées structurées dans la même liste. Une forme structurée invalide (clé inconnue, plusieurs clés sur la même entrée, type incorrect) est un refus nommé au chargement du blueprint (GrimoireRuntimeError), jamais un gate qui échouerait ouvert plus tard — et le kit n'infère jamais de commande depuis la prose : sans entrée structurée, un node V0 garde le comportement historique (enveloppe seule), documenté ci-dessous comme limite connue.

Le verdict d'un node dont l'acceptance est exécutée suit trois issues, jamais une quatrième :

  • exécutée, verte — toutes les commandes déclarées ont rendu le code de sortie attendu (et la sous-chaîne attendue, si expect_stdout_contains est posé). Le node ferme normalement.
  • exécutée, rouge — au moins une commande a rendu un code de sortie inattendu, sans qu'aucun signal d'inexécutable (ci-dessous) n'ait été détecté. Suit la cascade normale : réessai au fournisseur suivant du même palier, puis escalade au palier suivant, comme un check d'enveloppe rouge.
  • acceptance inexécutable — refus nommé, distinct d'un échec, jamais un succès : la commande n'a pas pu rendre de verdict exploitable (binaire introuvable — code de sortie 127 ; pytest qui rend 5 « no tests collected » ou 4 « usage error » ; une erreur d'import détectée dans la sortie, quel que soit le code de sortie). La cascade s'arrête net sur ce node — changer de fournisseur ou de palier ne répare pas un environnement cassé — et flow status nomme le node en faute.

La classe V0 exige une acceptance structurée

Un node dont le texte seul suffirait à le classer V0 (#309 — « la suite de tests passe », par exemple) mais qui ne déclare aucune entrée structurée est rétrogradé en V1 : la cascade démarre à mid (pas cheap), et un vert ne ferme jamais le node — il le marque à relire (needs_verification), exactement comme un vrai V1 déclaré. Sans cette règle, le texte mécanique seul aurait rouvert le fossé même que l'issue #428 corrige : le gate n'aurait toujours que le check d'enveloppe à faire tourner pour ce node, et fermerait vert sur la seule foi de l'ouvrier — la rétrogradation, pas seulement le libellé du rapport, est ce qui l'empêche.

Cette dérivation est appliquée une seule fois, au chargement du blueprint, et transmise à la fois au démarrage de la cascade (run_dispatch) et au rapport (DispatchExecutor) — flow status et flow run s'accordent donc sur la même classe pour le même node, jamais recalculée deux fois de façon divergente. Un avertissement nommé accompagne la rétrogradation, à la fois dans flow status/le rapport de dispatch et dans les logs :

nœud n classé V0 sans acceptance exécutable : traité comme V1

Le kit n'infère jamais de commande depuis la prose pour éviter cet avertissement : la seule sortie est de déclarer une entrée structurée (run/path_exists/test) sur le node.

Un node dont l'acceptance est V1 déclarée (vocabulaire de revue, « revue humaine avant fusion ») n'est pas concerné par cette règle — il n'a jamais prétendu être V0 — et garde le comportement actuel du kit, documenté ici sans être étendu : un vert V1 ferme la cascade en marquant le node à relire, sans qu'aucun juge automatisé n'intervienne. Faire arbitrer une classe V1 par un palier supérieur plutôt que par une revue humaine est hors périmètre de l'issue #428 (voir son texte : « ce que ce ticket refuse »), à traiter par un ticket séparé s'il devient nécessaire.

Dans les deux cas (V1 déclaré, ou V0 rétrogradé), flow status rapporte le statut d'acceptance « jugée » : le mode conservateur qui ne prétend jamais à une exécution qui n'a pas eu lieu.

La trace du node (visible dans flow status --output json et le rapport de flow run --executor dispatch) porte, pour chaque commande exécutée, le code de sortie et la sortie tronquée à 2 Ko (stdout puis stderr) — de quoi lire un message d'erreur pytest sans relancer la commande à la main.


Cadrage produit

Cinq phases posées sous _grimoire/cadrage/ : brief, brainstorm, compréhension, exigences, cahier des charges. Le need --needs project-discovery (grimoire up/grimoire standard init) scaffolde ce dossier par appel de code direct (cmd_up.py::_step_cadrage), pas par une suggestion textuelle. Détail complet, sévérités et intégration au gate : docs/cadrage.md.

Commande Description
grimoire cadrage init Poser les cinq phases du cadrage
grimoire cadrage status Progression, phase par phase
grimoire cadrage check Gate de complétude : exigences et cahier des charges doivent être renseignés

Le même gate est aussi visible dans grimoire standard verify/gate/score/ audit : error sur les phases exigences/cahier-des-charges quand le need project-discovery a été choisi, warning/info sinon (avis, jamais bloquant).


Cockpit multi-projets

Cockpit local de gouvernance, servi sur 127.0.0.1 uniquement. Le registre vit dans ~/.grimoire/cockpit/registry.json ; grimoire init y inscrit le projet et l'annonce, et GRIMOIRE_NO_COCKPIT désactive cette inscription.

Le cockpit ne scanne jamais le disque : list lit le registre tel quel, jamais le système de fichiers. Un projet qui porte les marqueurs Grimoire mais n'a jamais été enregistré n'apparaît donc pas dans list — ce n'est pas un défaut de détection, grimoire cockpit list signale « ce dossier ressemble à un projet Grimoire mais n'est pas enregistré » et donne la commande grimoire cockpit add <chemin> à lancer.

serve et start font l'exception (#351) : lancés depuis un dossier qui porte un marqueur Grimoire, ils l'enregistrent automatiquement s'il ne l'était pas encore et l'ouvrent sélectionné d'emblée — sans cesser d'être multi-projets, la bascule vers un autre projet reste dans l'UI. C'est l'intention exprimée en lançant la commande depuis ce dossier qui justifie l'ajout automatique, pas une décision prise à la place de l'utilisateur : le registre reste modifiable (remove, prune). Un registre vide, ou un lancement hors de tout projet Grimoire, nomme grimoire cockpit scan <racine>.

Commande Description
grimoire cockpit add <chemin> Enregistrer un projet local
grimoire cockpit list Lister les projets gouvernés
grimoire cockpit remove <slug> Retirer un projet du registre
grimoire cockpit prune Retirer les projets dont le chemin a disparu
grimoire cockpit scan <racine> Découvrir les projets sous une racine et les enrôler
grimoire cockpit refresh Régénérer la couche de données sans servir
grimoire cockpit serve Servir le cockpit (bloquant)
grimoire cockpit start / stop / status Lancer en arrière-plan, arrêter, interroger
grimoire cockpit open Ouvrir le cockpit en cours d'exécution dans le navigateur

serve, start et open ouvrent workspace/index.html — la même coque que grimoire serve, avec le niveau Flotte et le sélecteur de projet en plus (?project=<slug>). portfolio.html (et les autres pages historiques partagées avec l'atelier) reste servie mais redirige vers l'espace correspondant ; ?legacy=1 sur l'ancienne URL l'ouvre sans redirection. Voir l'ADR de la vue de travail.


Workflows

Un workflow a une nature. Les commandes d'hygiène (command) doublent un diagnostic CLI ; les orchestrations (orchestration) coordonnent plusieurs agents sur plusieurs tours et déclarent parfois l'équipe avec laquelle elles tournent. Les deux familles vivent dans des répertoires différents — les premières sous .github/prompts/, les secondes sous le tier kit — et le catalogue indexe les deux.

Commande Description
grimoire workflows list Lister les workflows — nature, agents, provenance
grimoire workflows list -k orchestration Ne garder que les workflows multi-agents
grimoire workflows list --all Inclure ceux qu'une commande CLI remplace
grimoire workflows teams Lister les équipes : membres, spécialité, chaîne de handoff
grimoire workflows search <terme> Chercher par slug, description, et optionnellement contenu
grimoire workflows show <slug> Afficher un workflow, l'équipe qu'il déclare, et son contenu
grimoire workflows install <slug> Installer un workflow du framework — la destination suit sa nature
grimoire workflows sync Synchroniser les prompts du framework vers le projet
grimoire workflows diff Différences entre framework et projet
grimoire workflows doctor Auditer les prompts du projet contre les défauts du framework
grimoire workflows prune Retirer les prompts propres au projet absents du framework

Workflows remplacés par une commande

Quatre des sept prompts livrés redisaient une commande du SDK :

Workflow Commande qui le remplace
/grimoire-status grimoire status
/grimoire-health-check grimoire doctor
/grimoire-self-heal grimoire doctor --fix
/grimoire-pre-push grimoire check

Ils occupaient la moitié du catalogue. Ils restent livrés et installables — un projet qui les a ne les perd pas — mais ne sont plus déployés dans les projets neufs ni listés par défaut : --all les montre, avec la commande à utiliser.

Les trois autres restent de plein droit : /grimoire-changelog, /grimoire-dream et /grimoire-session-bootstrap lisent l'historique et la mémoire pour en tirer une synthèse, ce qu'aucune commande ne fait.

Se déclarer pour entrer au catalogue

Un workflow d'orchestration entre au catalogue en le disant, dans son frontmatter — pas en étant deviné depuis son emplacement, parce que sous workflows/ vivent aussi des gabarits de rapport rendus à chaque run :

---
kind: orchestration
description: "Ce que fait ce workflow"
agents: [sm, architect, dev, qa]
team: team-build
triggers:
  - la situation qui appelle ce workflow
---

agents, team et patterns sont facultatifs ; description ne l'est pas en pratique, c'est ce que le catalogue affiche. Un fichier sans frontmatter reste sur disque et n'est pas listé.

patterns cite les identifiants du catalogue de patterns (ORC-01, KNO-02…) que le workflow instancie, et memory les couches du Memory OS qu'il lit ou écrit. Aucun workflow livré ne déclare de couche mémoire : leurs fichiers ne le disent pas, et l'inventer contredirait la règle du dépôt — ce qui décrit un artefact doit en être dérivé. Le champ existe pour les workflows que vous écrivez.

Un prompt qui redit une commande du SDK le déclare avec deprecated_by:, suivi de la commande.


Utilitaires

Commande Description
grimoire context-pack Écrire un context-pack durable (contrat catalogue) pour le dépôt
grimoire update Mettre à jour grimoire-kit — alias de grimoire self update
grimoire debugger status État de la réalité et du débogage des agents
grimoire debugger claims Affirmations enregistrées par les agents
grimoire debugger plan Plan de débogage courant
grimoire debugger generate Générer les artefacts de débogage
grimoire debugger serve Servir la vue de débogage

L'alias court grimoire dbg existe pour debugger.


Sous-commandes

grimoire config show

Affiche la configuration du projet (lecture seule).

grimoire config show [KEY]
  • Sans argument : affiche le YAML complet
  • Avec clé dot-notation : grimoire config show project.name
  • Avec --output json : sortie JSON

grimoire config get

Récupère une valeur de configuration par clé dot-notation.

grimoire config get project.name
grimoire config get user.skill_level
Option Description
--output, -o Format de sortie : text ou json

grimoire config path

Affiche le chemin résolu vers project-context.yaml.

grimoire config path

grimoire config set

Modifie une valeur de configuration par dot-notation.

grimoire config set KEY VALUE [--dry-run, -n]
Option Description
--dry-run, -n Affiche la modification sans l'appliquer
--output, -o Format de sortie : text ou json

Exemples :

grimoire config set project.name "mon-projet"
grimoire config set memory.backend qdrant-local --dry-run
grimoire -o json config set project.description "My app"

Note : les valeurs de type liste ne peuvent pas être définies via config set. Utilisez grimoire config edit pour modifier directement le fichier YAML.

grimoire config list

Liste toutes les clés de configuration avec leurs valeurs actuelles.

grimoire config list
Option Description
--output, -o Format de sortie : text (table Rich) ou json

grimoire config edit

Ouvre project-context.yaml dans l'éditeur système.

grimoire config edit

Utilise $VISUAL, puis $EDITOR, puis vi par défaut.

grimoire config validate

Valide le fichier project-context.yaml contre le schéma Grimoire.

grimoire config validate
grimoire -o json config validate
Option Description
--output, -o Format de sortie : text ou json ({valid, warnings})

Code de sortie 1 si la configuration est invalide.

grimoire self version

Affiche la version installée et vérifie les mises à jour sur PyPI.

grimoire self version
Option Description
--output, -o Format de sortie : text ou json

grimoire self diagnose

Exécute un auto-diagnostic de l'installation grimoire-kit.

grimoire self diagnose

Vérifie : dépendances requises/optionnelles, version Python, entry point CLI.

Option Description
--output, -o Format de sortie : text ou json

grimoire registry list

Liste les agents disponibles dans les archétypes installés.

grimoire registry list

Recherche un agent par mot-clé.

grimoire registry search QUERY

grimoire registry dispatches

Compte les choix d'agent (#366) et les non-choix (#389) observés, lus dans le TraceLedger du projet — pas la carte statique des agents déclarés.

grimoire registry dispatches
grimoire -o json registry dispatches

Deux tableaux : les agents réellement choisis comme persona d'entrée (combien de fois, la dernière fois), et les spécialités cherchées sans spécialiste trouvé (même forme). Voir Persona d'entrée → Non-choix.

grimoire agent-miss

Journalise un non-choix : le concierge a cherché un spécialiste et n'en a trouvé aucun, ou s'est rabattu sur un généraliste.

grimoire agent-miss --category tests
grimoire agent-miss --category infra --specialty terraform \
  --fallback backend-engineer --reason "aucun agent terraform déclaré"
Option Description
--category Catégorie de la demande telle que comprise (obligatoire, jamais son contenu)
--specialty Spécialité cherchée, si elle est nommable
--fallback Agent de repli retenu, s'il y en a un
--reason Pourquoi aucun spécialiste ne convenait

Appelée par la persona concierge (archetypes/meta/agents/concierge.md), pas par du code du kit : cette résolution se fait dans son raisonnement. Écriture best-effort — un journal indisponible ou illisible ne fait jamais échouer la commande. Détail : Persona d'entrée → Non-choix.

grimoire proposals

Le déclencheur d'artefact (issue #395) : à la répétition d'une même spécialité manquante (jamais au premier non-choix), propose un agent — ou un skill à attacher à un porteur existant — mais ne crée jamais rien sans acceptation explicite.

grimoire proposals list
grimoire proposals accept terraform-specialist
grimoire proposals reject terraform-specialist
grimoire -o json proposals list
Commande Description
grimoire proposals list Propositions en attente, rafraîchies depuis grimoire registry dispatches
grimoire proposals accept <slug> Écrit l'artefact réel dans _grimoire/overrides/ (même chemin que l'outil d'ajout d'agent)
grimoire proposals reject <slug> Marque la proposition refusée — reproposée seulement si son compte double depuis ce refus

Seuil configurable via proposals.threshold dans project-context.yaml (défaut 2, jamais 1). Aucune option --auto : accepter reste toujours un geste explicite. Même moteur que le cockpit (espace Piloter, section Agents), qui montre et actionne les mêmes propositions.

Choix du porteur (issue #402) — la persona d'entrée du projet (le concierge, ou l'agent que agents.entry désigne dans project-context.yaml) route les demandes vers un spécialiste ; elle n'en exécute aucune elle-même, donc elle n'est jamais retenue comme porteuse d'un skill, même quand c'est elle que le ledger enregistre comme agent de repli (grimoire agent-miss --fallback ...). La colonne « Porteur » de grimoire proposals list (et le champ target_agent en JSON) montre l'agent réellement retenu, distinct au besoin du fallback_agent brut ; la colonne « Raison » (carrier_reason) explique le choix :

carrier_reason Sens
repli observé Le repli enregistré n'est pas la persona d'entrée — il est utilisé tel quel
porteur par catégorie : <agent> Le repli était vide ou était la persona d'entrée ; exactement un agent déclaré couvre la catégorie observée (use_when, ou faisceau execute pour une catégorie d'exécution)
persona d'entrée exclue, aucun porteur : agent Le repli était vide ou était la persona d'entrée, et zéro ou plusieurs agents couvrent la catégorie — la proposition devient un agent plutôt qu'un skill ambigu

grimoire plugins list

Liste les plugins installés (tools et backends).

grimoire plugins list
Option Description
--output, -o Format de sortie : text ou json

grimoire completion install

Installe l'auto-complétion pour le shell.

grimoire completion install --shell bash|zsh|fish

grimoire completion export

Exporte le script de complétion vers stdout (pour piping/redirection).

grimoire completion export --shell bash > ~/.local/share/bash-completion/grimoire
grimoire completion export --shell zsh > _grimoire

Utile pour la configuration dotfiles et les environnements CI.


Gestion de projet

grimoire add

Ajoute un agent au projet.

grimoire add AGENT_ID [PATH] [--dry-run, -n]
Option Description
--dry-run, -n Affiche le plan sans modifier la configuration

grimoire remove

Retire un agent du projet.

grimoire remove AGENT_ID [PATH] [--dry-run, -n]
Option Description
--dry-run, -n Affiche le plan sans modifier la configuration

Confirmation

La commande remove demande une confirmation interactive. Utilisez --yes/-y pour la bypasser (CI/scripting), ou -o json (confirmation implicite).

Migre la structure du projet vers la dernière version.

grimoire upgrade [PATH] [--dry-run, -n] [-o json]

grimoire merge

Fusionne la configuration de deux projets.

grimoire merge SOURCE TARGET [--dry-run, -n] [--force] [--undo]

Confirmation

merge --undo demande une confirmation interactive. Utilisez --yes/-y pour la bypasser.

grimoire history

Affiche l'historique des opérations CLI récentes (audit trail).

grimoire history [-n LIMIT] [-f FILTER] [-o json]
Option Description Défaut
--limit, -n Nombre d'entrées à afficher 20
--filter, -f Filtrer par nom de commande (ex: add, init) —
--output, -o Format de sortie : text ou json text

Les opérations sont enregistrées automatiquement dans _grimoire/_memory/.grimoire-audit.jsonl lors de l'exécution de init, add, remove, config set, upgrade, et merge.

grimoire setup

Synchronise l'identité du projet — utilisateur, langues, niveau — entre project-context.yaml, la source de vérité, et les fichiers qui la reflètent (.github/copilot-instructions.md).

grimoire setup [PATH] --check                       # audit seul, sortie 1 si un miroir diverge
grimoire setup [PATH] --sync                        # réécrire les miroirs depuis project-context.yaml
grimoire setup [PATH] --user Guilhem --skill-level expert --lang Français --doc-lang Français

Une option écrit d'abord la section user: de project-context.yaml — créée si le projet est antérieur à son introduction — puis les miroirs ; la vérification finale relit le fichier et compare les miroirs à lui. Un « All config files are in sync » n'est donc annoncé que s'il est vrai.

grimoire repair

Auto-réparation des problèmes courants détectés par grimoire doctor.

grimoire repair [PATH] [--dry-run] [-o json]
Option Description Défaut
--dry-run, -n Prévisualise sans modifier False
--output, -o Format de sortie : text ou json text

Actions de réparation : - Création des répertoires manquants (_grimoire/, _grimoire-output/, _grimoire/_memory/) - Nettoyage des entrées d'audit de plus de 90 jours


Flags globaux

Flag Description
--version, -V Affiche la version et quitte
--verbose, -v Augmente la verbosité (-v = INFO, -vv = DEBUG)
--quiet, -q Supprime les sorties hors erreurs
--no-color Désactive la coloration (utile en CI)
--log-format Format des logs : text ou json
--output, -o Format de sortie : text ou json
--time Affiche le temps d'exécution en ms
--profile Affiche le breakdown timing par phase (arbre Rich)
--yes, -y Saute les confirmations interactives
--help Affiche l'aide

Sortie JSON pour le scripting

La plupart des commandes supportent --output json (ou -o json) pour une sortie machine-readable.

Commande JSON Exemple
status ✓ grimoire -o json status . \| jq .project
init ✓ grimoire -o json init myproject
doctor ✓ grimoire -o json doctor . \| jq .failed
validate ✓ grimoire -o json validate . \| jq .valid
check ✓ grimoire -o json check . \| jq .all_ok
lint ✓ grimoire lint . --format json \| jq .count
diff ✓ grimoire -o json diff .
env ✓ grimoire -o json env
version ✓ grimoire -o json version
config show ✓ grimoire -o json config show .
config get ✓ grimoire -o json config get project.name
config set ✓ grimoire -o json config set project.name "new"
config list ✓ grimoire -o json config list
config validate ✓ grimoire -o json config validate
add ✓ grimoire -o json add my-agent .
remove ✓ grimoire -o json remove my-agent .
self version ✓ grimoire -o json self version
self diagnose ✓ grimoire -o json self diagnose
registry list ✓ grimoire -o json registry list
registry search ✓ grimoire -o json registry search web
plugins list ✓ grimoire -o json plugins list
up ✓ grimoire -o json up .
upgrade ✓ grimoire -o json upgrade .
schema ✓ grimoire schema (toujours JSON)
history ✓ grimoire -o json history -n 50
repair ✓ grimoire -o json repair .

Variables d'environnement

Variable Description
GRIMOIRE_DEBUG 1 pour activer le traceback complet sur erreur
GRIMOIRE_LOG_LEVEL Niveau de log (DEBUG, INFO, WARNING, ERROR)
GRIMOIRE_LOG_FORMAT Format de log (text, json)
GRIMOIRE_OUTPUT Format de sortie par défaut (json pour l'activer sans -o json)
GRIMOIRE_QUIET 1 ou true pour activer le mode silencieux sans --quiet
NO_COLOR Toute valeur non vide désactive la couleur (no-color.org)
GRIMOIRE_OFFLINE 1 ou true pour forcer le mode hors-ligne (pas de vérification réseau)

Organisation de l'aide

Les commandes sont regroupées par catégorie dans grimoire --help :

Panneau Commandes
Project init, doctor, status, up
Agents add, remove, agent-miss, registry
Validation validate, lint, check, schema
Configuration config, diff
Utilities upgrade, merge, setup, repair, completion, plugins
Info version, env, self, history

Codes d'erreur

Les erreurs Grimoire incluent un code stable et une suggestion de récupération :

Code Signification Action suggérée
GR001 Erreur de configuration YAML grimoire validate
GR002 Projet non initialisé grimoire init <path>
GR003 Agent introuvable grimoire registry search <name>
GR004 Erreur d'exécution d'un outil grimoire doctor
GR005 Conflit de merge non résolu Résolution manuelle puis retry
GR010 Erreur réseau Vérifier la connexion
GR050 Erreur de validation schéma grimoire validate

grimoire ext

Gestion des extensions (bundles d'artefacts gouvernés). Voir Extensions & marketplace.

Commande Rôle
grimoire ext add <dossier> Installer depuis un dossier local
grimoire ext add <id> --registry <clone> [--version X.Y.Z] Installer depuis le registry, checksum vérifié
grimoire ext list Extensions installées et leurs patterns
grimoire ext verify <id> Vérification post-installation
grimoire ext remove <id> Désinstallation (hooks retirés du registre de sécurité)
grimoire ext publish <source> --registry <clone> Publier une extension ou un .blueprint.json
grimoire ext add-blueprint <id> --registry <clone> Installer un blueprint publié

grimoire serve (alias déprécié)

grimoire serve est un alias de grimoire cockpit serve (#351) : les deux commandes ouvraient la même UI, l'une en mono-projet, l'autre en multi-projets — cockpit serve fait maintenant les deux, en s'ouvrant directement sur le projet courant quand on le lance depuis un projet Grimoire. serve reste utilisable pour ne pas casser les scripts existants ; il affiche un avertissement et délègue à cockpit serve. --project-root est ignoré : lancer la commande depuis le projet visé suffit.

Pour une UI custom ou une racine de kit explicite (--ui-dir, --kit-root), utiliser la forme longue : python -m grimoire.tools.forge_server.

La vue de travail, page par défaut

--open ouvre workspace/index.html — la coque unique décrite par web/DESIGN-SPEC-workspace-2026-09.md et son ADR. Les pages historiques (atelier.html, kanban.html, observability.html, memory.html, blueprints.html, patterns.html, extensions.html, labs.html, documentation.html) restent servies mais redirigent désormais vers l'espace de la coque qui les remplace ; ajouter ?legacy=1 à l'URL sert encore l'ancienne page, sans redirection.

Source : IntelliSense déterministe (issue 280)

L'éditeur de l'espace Source colorie le frontmatter, les blocs <agent>/ <activation>/<step>, les placeholders ({project-root}, {{…}}) et les identifiants d'agents, de patterns et de workflows, sans dépendance ni bundler (surcouche par recouvrement sur la <textarea>, voir ADR-006 D2). Un correcteur signale un chemin du kit qui ne se résout pas (même logique que grimoire doctor), un agent routé mais absent du manifeste, une clé de frontmatter inconnue, un terme du glossaire cité mais non défini, ou un pattern/workflow inconnu du catalogue — recalculé à l'enregistrement et au repos de saisie, et repris dans l'onglet Problèmes du dock. La complétion (Ctrl+Espace, ou déclenchée par {, @, /) propose agents, workflows, patterns, chemins du kit et clés de schéma ; le survol d'un identifiant lié à une entrée du glossaire ouvre la même bulle épinglable que le reste de la vue de travail. Tout vient de GET /api/workspace/language (src/grimoire/tools/workspace_language.py), servi en lecture seule sur les deux hôtes — voir le tableau des routes dans web/workspace/README.md.

Source : suggestions par modèle local (issue 280, voie 2)

Derrière cette IntelliSense déterministe, jamais à sa place : un petit modèle local (Ollama) peut proposer du texte — compléter une clause d'emploi (use_when/dont_use_when), rédiger le corps d'un agent ou d'une étape de workflow, expliquer un diagnostic — mais ne fait jamais autorité sur les identifiants, les chemins ou les diagnostics, qui restent ceux de workspace_language.py. Deux conditions cumulatives, sinon l'interface ne montre rien et ne tente rien :

  1. le doctor voit Ollama sur le poste (même sonde que grimoire providers audit — GET /api/tags, sans dépenser de quota) ;
  2. project-context.yaml déclare source.assist.model: "<modèle>" — vide par défaut. Le modèle se choisit parmi ceux réellement présents (ollama list) ; qwen3-coder:30b, ou le plus petit modèle codeur trouvé, est un défaut raisonnable.

GET /api/workspace/assist (sans coût, jamais d'appel au modèle) dit si le bouton Suggérer de l'éditeur doit apparaître ; POST /api/workspace/assist (chemin, texte, position, intention) l'appelle réellement, avec un délai borné à 10 s. La réponse porte la suggestion brute du modèle et la liste de ce qu'elle cite sans figurer dans le paquet de langage (agent, workflow, pattern ou chemin) — jamais corrigée à la place de l'utilisateur, seulement marquée « inconnu ». Le panneau d'aperçu (Ctrl+Maj+Espace, ou le bouton Suggérer) affiche cette suggestion à côté de l'éditeur ; Insérer la place au curseur par le même chemin que la frappe clavier (colorisation et diagnostics se recalculent dessus), Ignorer referme le panneau sans rien écrire. Aucun envoi automatique à la frappe, aucun fournisseur distant, aucune clé, aucune donnée hors de la machine — le module src/grimoire/tools/source_assist.py ne contacte jamais qu'Ollama en local. Si l'URL Ollama résolue (OLLAMA_HOST) ne pointe pas vers une adresse de bouclage, l'appel est refusé (nommé) sauf déclaration explicite de source.assist.allow_lan: true.

Un modèle qui n'est pas encore chargé en mémoire (GET /api/ps) n'est pas une panne : GET /api/workspace/assist le déclenche lui-même en tâche de fond (un préchauffage sans génération) et répond « chargement du modèle, réessayez dans quelques secondes » — le bouton Suggérer reste visible mais désactivé, et l'éditeur re-sonde le statut toutes les 3 s jusqu'à ce qu'il devienne prêt. Le délai de 10 s ci-dessus ne s'applique qu'à un modèle déjà résident (issue #450).

Projets de la machine

Le bouton de projet, en haut de la barre latérale, ouvre le sélecteur. Trois entrées, parce qu'il y a trois situations :

Entrée Ce qu'elle fait
Liste Les projets déjà connus de la machine (registre partagé avec grimoire cockpit). Un clic re-route le serveur sur le projet choisi.
Parcourir Navigation dossier par dossier depuis $HOME, ou chemin absolu collé. Les projets sont signalés au passage.
Scanner Parcours borné d'une racine (profondeur 4 par défaut). Le scan propose : rien n'est enrôlé sans sélection explicite.

Le projet servi est enrôlé au registre à l'ouverture, s'il porte un marqueur (.git, project-context.yaml, _grimoire/). Ouvrir un projet n'écrit rien dans son arbre : registre et couche de données vivent sous ~/.grimoire/. Purger les entrées mortes : grimoire cockpit prune.

Données affichées : celles du projet, ou rien

Observatoire, Mémoire et Kanban lisent une couche générée sur le projet servi (gen-site-data.py, régénérée en arrière-plan au démarrage et à chaque changement de projet). Tant qu'elle n'existe pas, ces pages sont vides et le disent.

Le site embarqué dans la wheel contient aussi l'instantané de la vitrine publique — des projets de démonstration et les chiffres du dépôt du kit. Il n'est jamais servi en local : afficher 141 entrées mémoire et des traces d'agents vieilles de deux minutes pour un projet qui n'a rien lancé est pire qu'une page vide. Seules les références du kit (catalogue de patterns, marketplace, anatomie) restent servies telles quelles.

L'état de la couche est visible sur le tableau de bord, chip données ; un clic la régénère (POST /api/data/refresh).

grimoire features

Canaux de features : stable (contrat SemVer), beta (opt-in par projet, journalisées, promues sur métriques d'usage), experimental (surface R&D). État persisté dans _grimoire/features.json. La page Labs de l'atelier (grimoire serve) expose les mêmes bascules.

Sous-commande Rôle
list Lister les features à canal et leur état pour le projet
enable <id> · disable <id> Basculer une feature beta (certaines portent une action réelle, ex. stigmergy-hooks installe/retire les hooks)

grimoire stigmergy (beta)

Coordination indirecte par phéromones (canal beta — voir R&D expérimental). Tableau local _grimoire-output/pheromone-board.json.

Sous-commande Rôle
emit --type --location --text --agent [--tags] [--intensity] Déposer un signal typé (NEED, ALERT, OPPORTUNITY, PROGRESS, COMPLETE, BLOCK)
sense [--type] [--location] [--json] Détecter les signaux actifs (au-dessus du seuil)
amplify --id --agent · resolve --id --agent Renforcer / résoudre un signal
trails Patterns émergents (hot-zone, convergence, bottleneck, relay)
evaporate [--dry-run] · stats Purge des signaux morts / statistiques
install-hooks · uninstall-hooks Câbler / retirer l'émission + captation automatiques

Chaque sous-commande accepte --project-root (défaut : dossier courant). L'intensité décroît par demi-vie (72 h), calculée à la lecture — aucun démon.

Boucle vivante (hooks)

grimoire stigmergy install-hooks rend le système autonome, en copiant trois hooks non bloquants dans .github/hooks/ du projet :

  • SessionStart — injecte les signaux actifs dans le contexte de l'agent.
  • PostToolUse — une édition dépose (ou renforce, anti-bruit) un signal PROGRESS sur la zone touchée.
  • Stop — marque COMPLETE la zone la plus active et purge les signaux morts.

Ces hooks sont safe par construction : ils n'émettent que du contexte ou rien, jamais de décision de blocage. S'il existe, ils sont journalisés en mode shadow dans _grimoire-runtime/_config/hook-safety-registry.json.