French family-benefit models (CNAF corpus) as executable rules with sources; independent demo
io.arxo/cnaf (io-arxo-cnaf) — Model Context Protocol (MCP) Server
The MCP server “io.arxo/cnaf” provides French family-benefit models (CNAF corpus) as executable rules with sources. It is described as an independent demo, exposing the models in a way that can be consumed by developers and tooling via MCP.
🛠️ Key Features
French family-benefit models from the CNAF corpus
Executable rules
Associated sources
Independent demo
🚀 Use Cases
Converting CNAF family-benefit model information into executable rule logic
Using referenced sources alongside rule execution in developer workflows
⚡ Developer Benefits
Structured rule execution based on the CNAF corpus
Source-linked rules to support traceability
⚠️ Limitations
Labeled as an “independent demo,” with no additional operational details provided.
Topics
computable-lawfrancelawlaw-as-coderules-as-code
Captured live from the server via tools/list.
law_search
Une RECHERCHE sémantique sur le droit formalisé : une question ou une notion dans vos propres mots → des candidats avec adresses — prédicats avec signatures, règles, fragments d'articles. C'est la couche de DÉCOUVERTE, non de la réponse : le résultat dit QUOI demander ensuite (law_ask par signature, law_rules, law_sources) et n'établit ni un fait ni une norme. Le classement est un embedder lexical déterministe, et la similarité de texte n'est pas l'applicabilité d'une norme. Si vous connaissez le nom exact, allez directement à law_packages/law_ask ; un résultat vide ne signifie PAS que la norme n'existe pas.
Parameters4
kinds
array
optional
restreindre les types de candidat
limit
integer
optional
combien de candidats (8, 25 au plus)
package
string
optional
chercher uniquement dans cet acte
query
string
required
une question ou une notion dans vos propres mots
Raw schema
{
"type": "object",
"properties": {
"kinds": {
"description": "restreindre les types de candidat",
"items": {
"enum": [
"package",
"predicate",
"rule",
"norm",
"constraint",
"fragment"
]
},
"type": "array"
},
"limit": {
"description": "combien de candidats (8, 25 au plus)",
"type": "integer"
},
"package": {
"description": "chercher uniquement dans cet acte",
"type": "string"
},
"query": {
"description": "une question ou une notion dans vos propres mots",
"type": "string"
}
},
"required": [
"query"
],
"additionalProperties": false
}
law_passport
Passeport d'une publication exacte : objet, interface, frontières, contrôles et performance. La section reports conserve l'historique des mesures, y compris les échecs. Les enregistrements sont paginés par JSON Pointer ; next poursuit la réponse.
Une matrice lisible par machine des producteurs Lens réellement installés, des contrôles replay/projection, des profils, des limites et des tests de contrat qui les confirment. declared_only désigne un schéma sans témoin exécutable.
Exécuter un producteur enregistré et obtenir producerControl/0.2 pour une préparation ultérieure vérifiable d'une Lens. Le producteur n'est choisi que dans le registre livré.
À la demande explicite de l'utilisateur, répéter entre 1 et 12 appels law_ask ou law_process_run antérieurs, comparer strictement leurs replayControl, et préparer un document figé non public pour 24 heures. Le client ne fournit jamais la réponse machine : le serveur ne l'obtient qu'en exécutant à nouveau. Un écart dans une entrée, dans le droit, dans une ressource, dans le code du serveur, dans la bibliothèque du moteur ou dans le résultat rejette le document entier.
Parameters6
assistant
object
optional
calculations
array
optional
documentVersion
enum
optional
Version du document immuable ; 0.1 est conservée pour la compatibilité transitoire, 0.2 inclut tous les résultats natifs et le lecteur commun.
language
enum
optional
producerRuns
array
optional
Exécutions de producteurs enregistrés avec control/0.2 ; mutuellement exclusives avec calculations.
Publier un document préparé. La répétition avec le même preparationId renvoie de façon idempotente la même URL et le même secret de révocation distinct.
Révoquer un document publié au moyen de son secret distinct. L'identifiant public à lui seul ne donne aucun contrôle ; la révocation ferme la page HTML, l'API et le téléchargement.
Le catalogue du droit formalisé : actes, prédicats avec signatures, frontières de couverture. C'est d'ici que viennent les NOMS des prédicats — ils ne doivent jamais être inventés. Mais ne commencez PAS par le catalogue pour trouver le bon acte : l'aperçu est vaste, et le titre d'un acte coïncide rarement avec les mots d'une question (« Newton's laws of motion » ne contient pas le mot « physics »). Une question dans vos propres mots va d'abord à law_search, qui renvoie des adresses ; le catalogue sert à la signature exacte de ce que vous avez trouvé. Sans arguments — l'aperçu : une ligne par acte (clé, titre, ordre juridique, compteurs de règles, faits, signatures, normes, constantes) ; un acte entier — package="kz-gpk" ; une recherche sur les signatures, étiquettes et constantes de tous les actes — query="substring". Les trois modes sont PAGINÉS : limit et offset, le reste nommé dans le texte (`showing a–b of N; k more`) et dans structuredContent (total, truncated, next — un appel de continuation tout prêt). L'unité d'une page est nommée par pageUnit : l'aperçu et query paginent les ACTES (20 et 20 par défaut), package=… pagine les SIGNATURES d'un acte (20 par défaut, 300 au plus) — les grands codes en portent des milliers. package=… avec catalog=… pagine une liste séparée de l'acte : "questions" — le CATALOGUE DES QUESTIONS : quelles demandes sont prévues (une question en mots, une forme, un prédicat ou des normes) et à quoi l'acte NE répond PAS, avec le type de motif ; une fiche est un modèle de demande, non une réponse, et tous les actes n'en ont pas ; "norms" — les NORMES de l'acte, "constants" — les CONSTANTES (noms des déclarations). "task-guides" — les PARCOURS DE TÂCHE : l'ordre d'application d'un canon à un document — quoi recueillir, quelles cartes interroger et comment lire les réponses ; un parcours ne répond à rien. catalog="task-guides" est admis aussi sans package — tous les parcours du profil ; guide=… — le détail d'un parcours ; le parcours lui-même — MCP Prompts sous le même nom. Le détail d'un acte imprime un aperçu de ces listes et nomme le compte et l'appel tout prêt du mode.
Parameters6
catalog
string
optional
avec package : paginer le catalogue des questions, les normes, les constantes ou les parcours de tâche de l'acte au lieu de ses signatures ; "task-guides" aussi sans package : tous les parcours de tâche du profil
guide
string
optional
avec catalog="task-guides" : le détail d'un parcours — un nom <paquet>/<id> (comme dans prompts/list) ou un id avec package
limit
integer
optional
combien par page : actes (aperçu 20, query 20), signatures d'un acte (20, 300 au plus) ou éléments d'une liste catalog (questions 20, normes 20, constantes 100, parcours de tâche 20)
offset
integer
optional
à partir de quel élément de la page (0) ; l'unité est le pageUnit de la réponse
package
string
optional
les signatures complètes de cet acte
query
string
optional
un filtre de sous-chaîne sur signatures, étiquettes et constantes (sans distinction de casse)
Raw schema
{
"type": "object",
"properties": {
"catalog": {
"description": "avec package : paginer le catalogue des questions, les normes, les constantes ou les parcours de tâche de l'acte au lieu de ses signatures ; \"task-guides\" aussi sans package : tous les parcours de tâche du profil",
"enum": [
"questions",
"norms",
"constants",
"task-guides"
],
"type": "string"
},
"guide": {
"description": "avec catalog=\"task-guides\" : le détail d'un parcours — un nom <paquet>/<id> (comme dans prompts/list) ou un id avec package",
"type": "string"
},
"limit": {
"description": "combien par page : actes (aperçu 20, query 20), signatures d'un acte (20, 300 au plus) ou éléments d'une liste catalog (questions 20, normes 20, constantes 100, parcours de tâche 20)",
"maximum": 500,
"minimum": 1,
"type": "integer"
},
"offset": {
"description": "à partir de quel élément de la page (0) ; l'unité est le pageUnit de la réponse",
"minimum": 0,
"type": "integer"
},
"package": {
"description": "les signatures complètes de cet acte",
"type": "string"
},
"query": {
"description": "un filtre de sous-chaîne sur signatures, étiquettes et constantes (sans distinction de casse)",
"type": "string"
}
},
"additionalProperties": false
}
law_ask
Poser une question au droit formalisé. Quand la réponse est « non établi », elle porte whyNot — le rapport why_not du moteur : les règles candidates et l'état de chaque conjonct (satisfait / non satisfait / indéterminé) ; les faits manquants y sont visibles et n'ont pas à être inventés. AVANT LE PREMIER appel, obtenez les noms de prédicats par law_search (une question dans vos propres mots → adresses) ou law_packages (les signatures d'un acte connu) — un nom inventé sera rejeté. Si l'outil a renvoyé une erreur ou « non établi », C'EST LA RÉPONSE : transmettez-la à l'utilisateur et ne la substituez pas par des connaissances générales sur le droit d'un autre pays. Mais « je n'ai trouvé aucun acte convenable » N'EST PAS une réponse tant que law_search n'a pas été interrogé : le silence du catalogue est une propriété de la recherche par titre, non une conclusion sur le corpus. kind='truth' — si un fait est établi ; kind='collect' — énumérer les enregistrements ; kind='deadline' — calculer un délai sur le calendrier officiel ; kind='positions' — quelles OBLIGATIONS sont nées des faits et quels sont leurs statuts ; kind='why_not' — le rapport why_not sur le même but, quel que soit le statut de la réponse. La réponse porte les règles appliquées, les avertissements et la provenance avec empreintes ; truth/collect portent aussi un bloc signature pour la présentation. Le serveur n'invente pas : là où une norme n'est pas formalisée, la réponse est « non établi » ou une erreur.
Parameters22
after
string
optional
deadline : la date de l'événement
afterTime
string
optional
deadline : l'heure de dépôt
args
array
optional
les arguments du prédicat dans l'ordre de sa signature ; avec kind='collect', exactement l'un d'eux est la variable de sélection ?name (par exemple ['urn:x:water', 'urn:x:mix', '?value']), les autres sont des valeurs. Les valeurs suivent le type du paramètre : une entité — 'urn:…' ou un nom court ; Date — 'YYYY-MM-DD' ; Money — '<nombre> <devise>' ('43250 KZT') ; Quantity — '<nombre> <unité>' avec l'unité exactement telle que le paquet l'écrit ; une constante du paquet — son nom
calc
any
optional
kind='calc' : un arbre {op,left,right}, op ∈ add|sub|mul|div|le|lt|ge|gt|eq|ne (les synonymes divide/multiply/plus/minus et les signes sont acceptés) ; les feuilles sont 5 | '3932 KZT' | '2 mrp' | {lookup: 'mrp', args: [2026]} — une valeur légale du corpus ; les agrégats sont {aggregate: 'sum', element: '?v', over: [{predicate, args with '?variables'}]} sur les faits donnés dans facts
context
object
optional
Contexte temporel explicite : timezone est un nom IANA ; decisionTime et knowledgeTime sont des instants complets avec UTC ou un décalage, conservés sans substitution. legalTime est aussi requis avec context ; le profil peut exiger tous ces champs
cutoff
string
optional
deadline : l'heure de clôture des opérations
days
integer
optional
deadline : la durée de la période
deadlinePolicy
string | object
optional
la politique de décompte des délais exprimés en jours : le StableId d'une deadline policy déclarée dans le monde de la question (p. ex. 'urn:kz:corpus:clir:administrative-code#AC_WORKING_DAY_TERMS'), ou son nom court lorsqu'une seule déclaration le porte. Un objet en ligne {start_count: 'same_day'|'next_day', include_end: true|false, roll: 'no_roll'|'next_working_day'|'previous_working_day'[, month_end: 'last_day_of_month']} n'est accepté que par un monde 0.1 ; un monde 0.2 le refuse, et le refus nomme les politiques déclarées. Sans politique, une norme portant un délai répond MISSING_POLICY — la politique est fixée par le droit de la procédure et le serveur n'en suppose jamais une. L'instantané du calendrier officiel pour les jours ouvrables est fourni par le serveur lui-même dès qu'un acte les compte.
evidence
array
optional
documents de l'affaire, section 74, nœuds evidence_item. Un document est référencé depuis provenance.evidence de plusieurs faits. payload.confidence est une donnée pour l'EvidencePolicy ; le moteur n'évalue pas le nombre
evidencePolicy
string
optional
StableId d'un nœud evidence_policy, section 78.2. Sans lui, les appels précédents gardent leur comportement. Le seuil de confidence est une règle de cette politique, pas un argument de l'appel
facts
array
optional
faits de l'affaire : [{predicate, args, provenance, negated?, package?, judgment?}]. provenance est obligatoire et doit être un objet ; {} est accepté. Ses champs sont facultatifs : {origin?, evidence?: StableId, span?: {page?, quote?, offset?}, extractor?: {name, version?, confidence?}, observedAt?, recordedAt?}. origin vaut case_input par défaut. evidence et observedAt ne sont pas obligatoires ; l'extracteur est abaissé en was_generated_by et le document en was_derived_from. confidence est une chaîne décimale ; le seuil est lu par l'EvidencePolicy du paquet, pas par l'hôte. package résout un nom court ambigu ; args suit la même notation que les args de la question
focused
boolean
optional
kind='truth' : poser la question en focused_truth — la même réponse que le truth complet, mais la preuve et les avertissements ne couvrent que le cône de la question ; la réponse porte evaluationKind et les empreintes de la coupe (focus) ; dans focus, le cône est réduit à coneHash et au nombre de prédicats, le manifeste complet du cône vient dans evaluation.focusManifest avec proof=true. Une coupe n'est pas un document d'audit : law_prepare_answer ne l'accepte pas pour publication
kind
enum
optional
le type de question (truth par défaut)
legalTime
string
optional
la date du droit (YYYY-MM-DD)
package
string
optional
restreindre la question à un paquet de droit
predicate
string
optional
ce qui est demandé, p. ex. 'duty_amount'
proof
boolean
optional
renvoyer dans la réponse le champ evaluation avec le graphe de preuve — une entrée toute prête pour law_explain (kind truth|collect ; par défaut un résumé sans le graphe)
responseMode
enum
optional
full (défaut) — la réponse complète. compact est accepté par compatibilité : ce serveur ne construit pas de réponse courte et renvoie la même réponse complète dans les deux modes ; il n'y a ni référence fullAnswer ni instantané enregistré de la réponse.
selectedInterpretations
array
optional
lectures nommées ; pour un groupe exactly_one, choisir exactement un StableId parmi law_packages/law_rules
supportEdges
array
optional
appuis, section 75, nœuds support_edge : from est l'id du document, to est le littéral du fait, relation est supports ou refutes. L'admission est décidée par l'EvidencePolicy du paquet, pas par l'hôte
unit
enum
optional
version
string
optional
la version exacte du paquet figée par le client (open('name@version')) ; si elle diffère de la composition du profil, l'hôte refuse au lieu de répondre avec une autre version
Raw schema
{
"type": "object",
"properties": {
"after": {
"description": "deadline : la date de l'événement",
"type": "string"
},
"afterTime": {
"description": "deadline : l'heure de dépôt",
"type": "string"
},
"args": {
"description": "les arguments du prédicat dans l'ordre de sa signature ; avec kind='collect', exactement l'un d'eux est la variable de sélection ?name (par exemple ['urn:x:water', 'urn:x:mix', '?value']), les autres sont des valeurs. Les valeurs suivent le type du paramètre : une entité — 'urn:…' ou un nom court ; Date — 'YYYY-MM-DD' ; Money — '<nombre> <devise>' ('43250 KZT') ; Quantity — '<nombre> <unité>' avec l'unité exactement telle que le paquet l'écrit ; une constante du paquet — son nom",
"type": "array"
},
"calc": {
"description": "kind='calc' : un arbre {op,left,right}, op ∈ add|sub|mul|div|le|lt|ge|gt|eq|ne (les synonymes divide/multiply/plus/minus et les signes sont acceptés) ; les feuilles sont 5 | '3932 KZT' | '2 mrp' | {lookup: 'mrp', args: [2026]} — une valeur légale du corpus ; les agrégats sont {aggregate: 'sum', element: '?v', over: [{predicate, args with '?variables'}]} sur les faits donnés dans facts"
},
"context": {
"additionalProperties": false,
"description": "Contexte temporel explicite : timezone est un nom IANA ; decisionTime et knowledgeTime sont des instants complets avec UTC ou un décalage, conservés sans substitution. legalTime est aussi requis avec context ; le profil peut exiger tous ces champs",
"properties": {
"decisionTime": {
"type": "string"
},
"knowledgeTime": {
"type": "string"
},
"timezone": {
"type": "string"
}
},
"required": [
"timezone",
"decisionTime",
"knowledgeTime"
],
"type": "object"
},
"cutoff": {
"description": "deadline : l'heure de clôture des opérations",
"type": "string"
},
"days": {
"description": "deadline : la durée de la période",
"type": "integer"
},
"deadlinePolicy": {
"description": "la politique de décompte des délais exprimés en jours : le StableId d'une deadline policy déclarée dans le monde de la question (p. ex. 'urn:kz:corpus:clir:administrative-code#AC_WORKING_DAY_TERMS'), ou son nom court lorsqu'une seule déclaration le porte. Un objet en ligne {start_count: 'same_day'|'next_day', include_end: true|false, roll: 'no_roll'|'next_working_day'|'previous_working_day'[, month_end: 'last_day_of_month']} n'est accepté que par un monde 0.1 ; un monde 0.2 le refuse, et le refus nomme les politiques déclarées. Sans politique, une norme portant un délai répond MISSING_POLICY — la politique est fixée par le droit de la procédure et le serveur n'en suppose jamais une. L'instantané du calendrier officiel pour les jours ouvrables est fourni par le serveur lui-même dès qu'un acte les compte.",
"type": [
"string",
"object"
]
},
"evidence": {
"description": "documents de l'affaire, section 74, nœuds evidence_item. Un document est référencé depuis provenance.evidence de plusieurs faits. payload.confidence est une donnée pour l'EvidencePolicy ; le moteur n'évalue pas le nombre",
"type": "array"
},
"evidencePolicy": {
"description": "StableId d'un nœud evidence_policy, section 78.2. Sans lui, les appels précédents gardent leur comportement. Le seuil de confidence est une règle de cette politique, pas un argument de l'appel",
"type": "string"
},
"facts": {
"description": "faits de l'affaire : [{predicate, args, provenance, negated?, package?, judgment?}]. provenance est obligatoire et doit être un objet ; {} est accepté. Ses champs sont facultatifs : {origin?, evidence?: StableId, span?: {page?, quote?, offset?}, extractor?: {name, version?, confidence?}, observedAt?, recordedAt?}. origin vaut case_input par défaut. evidence et observedAt ne sont pas obligatoires ; l'extracteur est abaissé en was_generated_by et le document en was_derived_from. confidence est une chaîne décimale ; le seuil est lu par l'EvidencePolicy du paquet, pas par l'hôte. package résout un nom court ambigu ; args suit la même notation que les args de la question",
"items": {
"properties": {
"args": {
"type": "array"
},
"predicate": {
"type": "string"
},
"provenance": {
"type": "object"
}
},
"required": [
"predicate",
"args",
"provenance"
],
"type": "object"
},
"type": "array"
},
"focused": {
"description": "kind='truth' : poser la question en focused_truth — la même réponse que le truth complet, mais la preuve et les avertissements ne couvrent que le cône de la question ; la réponse porte evaluationKind et les empreintes de la coupe (focus) ; dans focus, le cône est réduit à coneHash et au nombre de prédicats, le manifeste complet du cône vient dans evaluation.focusManifest avec proof=true. Une coupe n'est pas un document d'audit : law_prepare_answer ne l'accepte pas pour publication",
"type": "boolean"
},
"kind": {
"description": "le type de question (truth par défaut)",
"enum": [
"truth",
"collect",
"deadline",
"calc",
"positions",
"why_not"
]
},
"legalTime": {
"description": "la date du droit (YYYY-MM-DD)",
"type": "string"
},
"package": {
"description": "restreindre la question à un paquet de droit",
"type": "string"
},
"predicate": {
"description": "ce qui est demandé, p. ex. 'duty_amount'",
"type": "string"
},
"proof": {
"description": "renvoyer dans la réponse le champ evaluation avec le graphe de preuve — une entrée toute prête pour law_explain (kind truth|collect ; par défaut un résumé sans le graphe)",
"type": "boolean"
},
"responseMode": {
"description": "full (défaut) — la réponse complète. compact est accepté par compatibilité : ce serveur ne construit pas de réponse courte et renvoie la même réponse complète dans les deux modes ; il n'y a ni référence fullAnswer ni instantané enregistré de la réponse.",
"enum": [
"full",
"compact"
]
},
"selectedInterpretations": {
"description": "lectures nommées ; pour un groupe exactly_one, choisir exactement un StableId parmi law_packages/law_rules",
"items": {
"type": "string"
},
"type": "array"
},
"supportEdges": {
"description": "appuis, section 75, nœuds support_edge : from est l'id du document, to est le littéral du fait, relation est supports ou refutes. L'admission est décidée par l'EvidencePolicy du paquet, pas par l'hôte",
"type": "array"
},
"unit": {
"enum": [
"calendar_day",
"business_day"
]
},
"version": {
"description": "la version exacte du paquet figée par le client (open('name@version')) ; si elle diffère de la composition du profil, l'hôte refuse au lieu de répondre avec une autre version",
"type": "string"
}
},
"additionalProperties": false
}
law_screen
Construire une condition nécessaire — un surensemble — pour la présélection de lignes d'une source externe. Ce n'est PAS une réponse juridique et PAS du SQL : le résultat est un arbre typé et un manifeste des extensions jusqu'à TRUE. Chaque ligne qui passe doit ensuite être calculée en entier par le moteur, avec un graphe de preuve, sur le même instantané des données. Le binding est passé comme objet épinglable ; sourceSchemaContentHash est l'empreinte réelle du schéma source et est comparée bruyamment avec l'épingle. Les faits d'affaire qui portent une provenance (origin, document, citation, extractor) sont fournis à law_ask, pas ici. Le nombre confidence est lu par l'EvidencePolicy du paquet, pas par cet outil et pas par le moteur.
Parameters5
binding
object
required
un artefact law.screen.binding/0.1
goal
string
required
un StableId ou un nom court unique de l'objectif
legalTime
string
optional
la date du droit YYYY-MM-DD ; sans elle, toutes les fenêtres de toutes les règles sont prises en compte
package
string
required
la clé de paquet depuis law_packages
sourceSchemaContentHash
string
required
le sha256 réel du schéma source
Raw schema
{
"type": "object",
"properties": {
"binding": {
"description": "un artefact law.screen.binding/0.1",
"type": "object"
},
"goal": {
"description": "un StableId ou un nom court unique de l'objectif",
"type": "string"
},
"legalTime": {
"description": "la date du droit YYYY-MM-DD ; sans elle, toutes les fenêtres de toutes les règles sont prises en compte",
"type": "string"
},
"package": {
"description": "la clé de paquet depuis law_packages",
"type": "string"
},
"sourceSchemaContentHash": {
"description": "le sha256 réel du schéma source",
"type": "string"
}
},
"required": [
"package",
"goal",
"binding",
"sourceSchemaContentHash"
],
"additionalProperties": false
}
law_rules
Les règles du droit formalisé mises en mots : comment exactement un prédicat est dérivé (prémisses, articles sources). Appelez ceci AVANT de fournir des faits à law_ask — les règles disent quels faits sont nécessaires au lieu de les laisser à inventer. Pour les grands actes, package=… renvoie une table des matières ; le texte complet vient de predicate=…. La liste par paquet est paginée : limit (20 par défaut, 500 au plus) et offset ; le reste est nommé dans le texte (`showing a–b of N; k more`) et dans structuredContent (total, truncated, next — un appel de continuation tout prêt).
Parameters8
contract
boolean
optional
Return a machine input contract over the same import/dependency world as law_ask. No case evaluation.
inputLimit
integer
optional
Machine contract: leaf declarations per page (50).
inputOffset
integer
optional
Machine contract: offset of leaf declarations.
lang
enum
optional
la langue dans laquelle les règles sont mises
limit
integer
optional
package : combien de règles par page (20 ; le budget peut le baisser)
offset
integer
optional
package : à partir de quelle règle (0)
package
string
optional
toutes les règles de l'acte
predicate
string
optional
les règles qui dérivent ce prédicat
Raw schema
{
"type": "object",
"properties": {
"contract": {
"description": "Return a machine input contract over the same import/dependency world as law_ask. No case evaluation.",
"type": "boolean"
},
"inputLimit": {
"description": "Machine contract: leaf declarations per page (50).",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"inputOffset": {
"description": "Machine contract: offset of leaf declarations.",
"minimum": 0,
"type": "integer"
},
"lang": {
"description": "la langue dans laquelle les règles sont mises",
"enum": [
"ru",
"kk",
"en",
"ky",
"uz",
"ar",
"la",
"zh",
"de",
"fr",
"tr",
"es",
"fa",
"ja"
]
},
"limit": {
"description": "package : combien de règles par page (20 ; le budget peut le baisser)",
"maximum": 500,
"minimum": 1,
"type": "integer"
},
"offset": {
"description": "package : à partir de quelle règle (0)",
"minimum": 0,
"type": "integer"
},
"package": {
"description": "toutes les règles de l'acte",
"type": "string"
},
"predicate": {
"description": "les règles qui dérivent ce prédicat",
"type": "string"
}
},
"additionalProperties": false
}
law_explain
Déplier la preuve d'une réponse law_ask en une chaîne « règle ← prémisses → conclusion ». L'entrée compacte : question (les arguments law_ask d'origine, truth/collect), resultHash et codeHash issus de la provenance de la réponse. Le serveur répète le calcul et compare les empreintes ; si quelque chose a changé, il refuse explicitement. Autrement, passer l'évaluation de law_ask(proof=true). answerResource=fullAnswer.uri explique un instantané compact stocké sans recalcul et sans que le client charge des pages ; par défaut seulement la chaîne proofRef. nodeId sélectionne un nœud et toutes ses prémisses (jusqu'à 24 Ko, sinon un refus explicite). proofHash se rapporte au graphe entier ; scope marque la partie sélectionnée.
Parameters6
answerResource
string
optional
le fullAnswer.uri d'une réponse stockée prise avec proof=true
Inspecteur d'évaluation sur un document d'évaluation ENREGISTRÉ : summary — la fiche d'origine, la vérification de resultHash et de l'instantané, les listes de résultats, de positions et d'issues ; slice — la clôture des nœuds de preuve pour une question, une règle, une position ou un nœud avec leurs adresses, les deux côtés de BOTH, les défaites, les valeurs, les noms résolus d'après l'instantané ; diff — ce qui a changé entre deux documents aux niveaux du contexte, du résultat et de la justification ; locate — la déclaration par StableId. Rien n'est évalué ni recalculé : la source est evaluation de law_ask(proof=true) ou un answerResource. Une donnée absente est un état de limite (limits), jamais une négation.
L'opération ask : exécuter une affaire enregistrée d'un paquet-affaire sur ses dépendances épinglées et renvoyer la réponse : par défaut une projection du document d'évaluation sans graphe de preuve, avec responseMode full ou proof: true le document canonique avec une preuve et un manifeste. La question est du JSON selon query.schema.json (query), une chaîne evaluate (evaluate + queryId), un queryId enregistré sans query, ou card + args. Un refus de préparation est une erreur avec un code LDC-*, jamais une réponse vide.
Parameters9
args
object
optional
les paramètres de la carte : nom → expression textuelle du langage
card
string
optional
l'id d'une carte d'un catalogue installé
case
string
optional
le nom de la déclaration d'affaire dans [[cases]] ; facultatif s'il n'y a qu'une affaire
evaluate
string
optional
la chaîne `evaluate <expression>;` ; exige queryId
package
string
required
le chemin du paquet-affaire (le répertoire qui contient law.toml) depuis la racine du dépôt
proof
boolean
optional
true — le document complet avec le graphe de preuve (comme responseMode full) ; false — la projection. La même forme que dans law_ask.
query
object
optional
la question en JSON selon query.schema.json ; queryId est un URN dans l'espace de noms du paquet, ou un nom court donné dans queryId
queryId
string
optional
sans query/evaluate — le choix d'un queries/*.json enregistré par nom court ou URN complet ; avec evaluate — l'id de la question exécutée
responseMode
enum
optional
compact — une projection pour un agent : results, positions, conflicts, le manifeste, les issues au-dessus de info et tous les hachages sont conservés, proofGraph est remplacé par son hachage, ses racines et le nombre de nœuds (champ proof), le nombre d'issues info retirées est issuesOmitted. full — le document d'évaluation canonique complet, celui qu'écrit `law ask` ; proof: true demande la même chose. Le resultHash de la projection est celui du document complet ; une preuve ou une publication exige full.
Raw schema
{
"type": "object",
"properties": {
"args": {
"additionalProperties": {
"type": "string"
},
"description": "les paramètres de la carte : nom → expression textuelle du langage",
"type": "object"
},
"card": {
"description": "l'id d'une carte d'un catalogue installé",
"type": "string"
},
"case": {
"description": "le nom de la déclaration d'affaire dans [[cases]] ; facultatif s'il n'y a qu'une affaire",
"type": "string"
},
"evaluate": {
"description": "la chaîne `evaluate <expression>;` ; exige queryId",
"type": "string"
},
"package": {
"description": "le chemin du paquet-affaire (le répertoire qui contient law.toml) depuis la racine du dépôt",
"type": "string"
},
"proof": {
"description": "true — le document complet avec le graphe de preuve (comme responseMode full) ; false — la projection. La même forme que dans law_ask.",
"type": "boolean"
},
"query": {
"description": "la question en JSON selon query.schema.json ; queryId est un URN dans l'espace de noms du paquet, ou un nom court donné dans queryId",
"type": "object"
},
"queryId": {
"description": "sans query/evaluate — le choix d'un queries/*.json enregistré par nom court ou URN complet ; avec evaluate — l'id de la question exécutée",
"type": "string"
},
"responseMode": {
"description": "compact — une projection pour un agent : results, positions, conflicts, le manifeste, les issues au-dessus de info et tous les hachages sont conservés, proofGraph est remplacé par son hachage, ses racines et le nombre de nœuds (champ proof), le nombre d'issues info retirées est issuesOmitted. full — le document d'évaluation canonique complet, celui qu'écrit `law ask` ; proof: true demande la même chose. Le resultHash de la projection est celui du document complet ; une preuve ou une publication exige full.",
"enum": [
"full",
"compact"
]
}
},
"required": [
"package"
],
"additionalProperties": false
}
law_sources
Sources : par défaut de courts extraits (view=summary), 5 textes par page, avec l'adresse du texte complet dans fragments[].full. package ou fragment est requis (un StableId issu de law_search/law_rules). view=full renvoie des parties exactes du texte : textRange fixe une plage de caractères Unicode, fragments[].next est la continuation avec un contentHash. L'empreinte se rapporte à la source ENTIÈRE, non à l'extrait ni à la partie. textOffset/textLimit exigent fragment ; une continuation exige contentHash. Les listes sont paginées avec offset/limit ; le budget de réponse peut réduire une page.
Parameters10
contentHash
string
optional
l'empreinte du texte complet reprise de la partie précédente
fragment
string
optional
le StableId d'un fragment
language
string
optional
la langue de la variante, telle qu'indiquée sur la fiche source
limit
integer
optional
combien de textes : summary 5, full 1 (le budget peut le baisser)
offset
integer
optional
à partir de quel fragment (0)
package
string
optional
la clé de paquet — tous les fragments de cet acte
status
string
optional
le statut de la variante, tel qu'indiqué sur la fiche source
textLimit
integer
optional
le nombre maximal de caractères Unicode dans une partie du texte (aussi ≤8000 octets d'UTF-8)
textOffset
integer
optional
view
enum
optional
Raw schema
{
"type": "object",
"properties": {
"contentHash": {
"description": "l'empreinte du texte complet reprise de la partie précédente",
"type": "string"
},
"fragment": {
"description": "le StableId d'un fragment",
"type": "string"
},
"language": {
"description": "la langue de la variante, telle qu'indiquée sur la fiche source",
"type": "string"
},
"limit": {
"description": "combien de textes : summary 5, full 1 (le budget peut le baisser)",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"offset": {
"description": "à partir de quel fragment (0)",
"minimum": 0,
"type": "integer"
},
"package": {
"description": "la clé de paquet — tous les fragments de cet acte",
"type": "string"
},
"status": {
"description": "le statut de la variante, tel qu'indiqué sur la fiche source",
"type": "string"
},
"textLimit": {
"description": "le nombre maximal de caractères Unicode dans une partie du texte (aussi ≤8000 octets d'UTF-8)",
"maximum": 4096,
"minimum": 1,
"type": "integer"
},
"textOffset": {
"minimum": 0,
"type": "integer"
},
"view": {
"default": "summary",
"enum": [
"summary",
"full"
]
}
},
"additionalProperties": false
}
law_query
Une requête LawQL déterministe sur le CLIR d'une formalisation : une question sur le modèle de l'acte lui-même, pas sur une affaire. Relations (14) : anchors, edges, fields, imports, interpretations, labels, links, literals, nodes, norms, positions, rules, variables, windows. Listes des champs : `law query --schema`. Fonctions (9) : anchor/1, labels/1..2, short/1, contains/2, overlaps/2, starts_with/2, ends_with/2, position/2, derivation/2. exists/not exists sur une variable liée ; égalité et appartenance seulement, sans arithmétique ni comparaisons d'ordre. Périmètre : corpus par package.name (par exemple kz.corpus.labour_code, pas un nom de fichier) ou un glob ; sans corpus, toute la tranche du profil ; un périmètre hors profil est vide (CORPUS_EMPTY). Exemples : `from r in rules where r.head_predicate == "urn:…#eligible" select r.id as producer, r.strength as strength, anchor(r.id) as anchors` — qui produit ; `from l in literals where l.predicate == "urn:…#eligible" select l.node as reader, l.context as context` — qui lit ; `query eligible over "pkg" { for x: Person; where applicant(x); select eligible(x); }` — inférence par le noyau. C'est une orchestration au-dessus du CLIR et du noyau ; aucune sémantique juridique nouvelle n'est implémentée ici. Au lieu du texte, une question du catalogue avec arguments : anchors-of, imports-of, links-of, producers, readers, type-step (composition : `law query --list`) (les paramètres predicate/node/type sont des URN, pkg un package.name ou un glob). La réponse structurelle est une queryPage : resultHash du queryResult complet, snapshot (hachage de la liste des paquets du périmètre), rowCount, rows selon rowLimit (20, au plus 5000) et rowOffset, next avec le snapshot pour continuer ; full: true renvoie le queryResult complet quand le périmètre est un seul paquet. Chaque ligne porte sa provenance (nœuds CLIR) ; une réponse vide porte l'entonnoir explain (emptyAt nomme la clause) ; les erreurs portent des codes LDC-Qxxxx avec des indices ; un produit de sources trop large est refusé avant exécution (QUERY_TOO_BROAD), une continuation sur un autre instantané — SNAPSHOT_CHANGED.
Parameters11
arguments
object
optional
les paramètres de la question : un objet « nom → chaîne » (predicate, node, type — des URN ; pkg — un package.name ou un glob)
case
object
optional
l'affaire pour query-over ; elle remplace la clause case
corpus
string
optional
le périmètre de l'instantané : un package.name (par exemple kz.corpus.labour_code) ou un glob sur package.name ; sans corpus, toute la tranche du profil
engine
enum
optional
il y a un moteur — le noyau ; l'implémentation de référence est appelée par sa propre commande
full
boolean
optional
renvoyer le queryResult complet au lieu d'une page ; seulement quand le périmètre est un seul paquet
limit
integer
optional
un plafond explicite des matérialisations eval() (il ne borne PAS les lignes — voir rowLimit)
query
string
optional
inline LawQL
question
string
optional
le nom d'une question du catalogue de questions nommées (producers, readers, anchors-of, imports-of, links-of, type-step) ou d'un lint ; à la place de query
rowLimit
integer
optional
combien de lignes dans structuredContent (20 ; le budget peut le baisser)
rowOffset
integer
optional
à partir de quelle ligne (0) ; la continuation vient de next avec snapshot ; requêtes structurelles seulement
snapshot
string
optional
le hachage d'instantané de next.snapshot de la page précédente : une continuation sur un autre instantané est refusée (SNAPSHOT_CHANGED)
Raw schema
{
"type": "object",
"properties": {
"arguments": {
"description": "les paramètres de la question : un objet « nom → chaîne » (predicate, node, type — des URN ; pkg — un package.name ou un glob)",
"type": "object"
},
"case": {
"description": "l'affaire pour query-over ; elle remplace la clause case",
"type": "object"
},
"corpus": {
"description": "le périmètre de l'instantané : un package.name (par exemple kz.corpus.labour_code) ou un glob sur package.name ; sans corpus, toute la tranche du profil",
"type": "string"
},
"engine": {
"default": "lawc",
"description": "il y a un moteur — le noyau ; l'implémentation de référence est appelée par sa propre commande",
"enum": [
"lawc"
]
},
"full": {
"description": "renvoyer le queryResult complet au lieu d'une page ; seulement quand le périmètre est un seul paquet",
"type": "boolean"
},
"limit": {
"description": "un plafond explicite des matérialisations eval() (il ne borne PAS les lignes — voir rowLimit)",
"minimum": 1,
"type": "integer"
},
"query": {
"description": "inline LawQL",
"type": "string"
},
"question": {
"description": "le nom d'une question du catalogue de questions nommées (producers, readers, anchors-of, imports-of, links-of, type-step) ou d'un lint ; à la place de query",
"type": "string"
},
"rowLimit": {
"description": "combien de lignes dans structuredContent (20 ; le budget peut le baisser)",
"maximum": 5000,
"minimum": 1,
"type": "integer"
},
"rowOffset": {
"description": "à partir de quelle ligne (0) ; la continuation vient de next avec snapshot ; requêtes structurelles seulement",
"minimum": 0,
"type": "integer"
},
"snapshot": {
"description": "le hachage d'instantané de next.snapshot de la page précédente : une continuation sur un autre instantané est refusée (SNAPSHOT_CHANGED)",
"type": "string"
}
},
"required": [],
"additionalProperties": false
}
First of all, a demonstration. This repository shows what modelling legislation with Arxo can do:
French family-benefit law written as executable canons, with the source of every answer. It is an
independent model built from published French law for teaching and demonstration. It does not claim
legal accuracy or completeness, it is not an implementation by or for the Cnaf or any French
authority, and its answers are not legal advice. For a real file, rely on the official texts and the
competent bodies.
Choose your starting point
I want to…
Start here
Explore saved cases and their sources in a browser
French Benefits Lab, captured on 12 October 2026. Open the demo and choose
“Explore a saved family case” to inspect its inputs, answer and French sources.
The lab presents its own recorded evidence release; its coverage and version
are separate from this repository's export.
The input is the technical APL case below, with PpPlancherFinal selected.
The answer includes the engine's canonical document, proof and hashes.
This is a formula amount, not a final payable benefit. The package contains
all 21 models; loading a subpath parses only the selected world.
You need Git, Node.js 20+ and npm. This example uses the released
law 0.2.2 command-line tool, which executes the models. The package
already includes its pinned dependency; no Python, source restoration or
registry installation is needed for this scenario.
sh
npm install -g @arxo/cli@0.2.2
law --version
git clone https://github.com/arxohq/arxo-cnaf.git
cd arxo-cnaf/packages/fr.apl
law test . --file tests/finish-lecture-pp.lawtest --json
This runs seven scenarios about the personal contribution in housing aid
(article D. 823-17). Success means the command exits with code 0 and the
JSON report records no failed scenarios. These are checks against the
model's declared expectations, not certification of legal accuracy.
The successful report includes these fields:
The model records two readings of the personal contribution in article
D. 823-17. The choice enters at SensMinimumPp, an interpretation group
that requires exactly one of PpPlancherFinal or PpLitteral.
The scenario fixes a single
person with no dependants, zone II in metropolitan France, legal date
15 June 2024, supplied resources of €4,000 and zero rent.
It also supplies ordinary housing, sole tenancy, zero solidarity rent
reduction and no AAH/AEEH beneficiary. Zero rent deliberately isolates the
reading difference; this is a technical probe, not a realistic aid claim.
The pinned parameters used in this probe are P0 = €37.91, Tp = 0.0283,
R0 = €5,186, L = €0 and C = €58.08.
Selected reading
Personal contribution Pp
Formula amount Af
PpPlancherFinal — keep a final floor at P0
€37.91
€20.17
PpLitteral — apply the formula without that final floor
€4.3462
€53.7338
No reading selected
INTERPRETATION_REQUIRED
INTERPRETATION_REQUIRED
Both readings feed the same participation_personnelle relation. The same
AideFormule rule then uses Af = L + C − Pp. These are exact formula
amounts in the probe; neither is presented as the final payable benefit.
The model leaves the choice explicit rather than selecting a reading for you.
The rules behind the amount
This is the native unfold response for aide_formule, rendered as a tree
from the published fr.apl@0.1.0 world. Each rule exposes its premises,
strength and source anchors. The two contribution producers are both
visible: ParticipationPersonnelle and ParticipationPersonnelleLitterale.
No case, legal date or reading is selected. This shows the model's available
rules, not which rules applied to a particular answer. The depth-limit
markers come from the engine. Repeated article locators are grouped visually;
the JSON retains every dated source anchor.
The same view for droit_ouvert shows a defeasible opening rule alongside
its exception rules (defeater). Expanding surface_insuffisante exposes
its own producers and an exception to that condition. fact, derived,
judgment and test are distinct kinds of premise in the native response.
This is a map of declared rule structure across the published world, not
an eligibility finding for a person. No case, date or reading is selected.
Published text → executable rules → dated case facts → answer and evidence.
A canon is a package containing a legal model, its source references and
checks. A scenario supplies facts, dates and any selected interpretation,
then states the expected answer. A pinned source is a captured publication
identified by its provenance and a content hash, so the model's input can be
checked later.
The rules are data in .law files, executed by law. This repository carries
no separate implementation of the benefit formulas in application code.
Models have individual scope and date boundaries; read a package's source
and scenarios before applying its answers to a different case.
At a glance
This snapshot
Recorded value and evidence
Subject
French benefit models, including housing, family, disability, care and income support; each package has its own scope
The names below identify the subject of each model, not a claim of complete
coverage of that benefit. The version and scenario inventory
records the exported package versions and dependency counts.
Depth is recorded per model, against source revision
f2efcc6.
The unit is an article in a pinned publication edition: the same article
can occur in several editions. Identical document bytes are counted once per
package. Imports are excluded.
Executable / measured counts units with at least one deriving node.
The other levels are I — executable only under an explicit interpretation;
A — anchored without a deriving rule; S — source fragment only;
N — no model node. An executable unit can still be only partly expressed.
These counts describe the pinned excerpts, not the percentage of a benefit
or of French law that is completely formalized.
† Partial measurement: some own publications or declared documents are
outside the measured units; the report identifies them. Not measured
means no declared source-document division was available for this method,
not that the model has no executable rules. Rules / norms count own rule
nodes and norm templates separately. Scenarios are the recorded export
inventory; they were not rerun for this documentation update.
Addresses and hashes of source files that are not redistributed
The packages contain the public consumer kit; authoring reports and maintenance
scripts are excluded. See public package contents
for the preservation rules and the read-only guard.
Published with Law as Code in Practice: French Family Benefits
(Law as Code by Country · Volume 1), available at Arxo Books.
The canons were exported on 12 October 2026 from Arxo commit
7206473829, with 1,985 scenarios passing on law 0.2.1
(law.core/0.2.11). The book's reproduction kit was checked with released
law 0.2.2. These are recorded execution results for this export.
The packages workflow compiles each package,
runs its scenarios on both evaluators, replays saved evaluations and rebuilds
from the release using pinned law-package-tools 0.3.0. The
registry workflow checks schemas, addresses
and hashes. See the reproducibility guide for
requirements and commands.
Found an error?
You do not need to know the rule language to report a problem.
Open an issue with:
Where: the package, article or scenario, and the legal date.
What happened: fictional or anonymized input facts, the selected
reading, your law --version, and the returned answer or test report.
What you expected: the relevant published source, its date/version,
and the reasoning that leads to a different result.
Use fictional or anonymized examples; omit personal records and identifiers.
If you mean the browser lab, include its page link and recorded release.
A difference between readings may need an explicit alternative rather than
a change to a shared rule. A confirmed defect should be accompanied by a
scenario that reproduces it.
Cite this snapshot
Arxo (2026). French benefit rules on Arxo: executable, source-linked models.
Canon export of 12 October 2026, public source revision
f2efcc6788465484f145146a3ed5f76b13d41703.
bibtex
@software{arxo_french_benefits_2026,
author = {Arxo},
title = {French benefit rules on Arxo: executable, source-linked models},
year = {2026},
url = {https://github.com/arxohq/arxo-cnaf/tree/f2efcc6788465484f145146a3ed5f76b13d41703},
note = {Canon export: 12 October 2026; semantics: law.core/0.2.11}
}
For a particular result, also identify its package version, scenario or case,
legal date and selected reading, and retain the execution evidence and hashes.
The source revision above pins the exported canons; the lab is a separate release.
Rights and contact
Code and model: Apache-2.0. Captured publisher texts retain their
own reproduction terms, listed per package in NOTICE; the code
licence does not cover those texts. Some source files are
withheld from redistribution.