Le daemon N0 : le moteur de pseudonymisation sur votre poste. L'opérateur ne lit rien — le clair ne quitte jamais votre machine, le fournisseur ne reçoit que des jetons ⟦…⟧, et la réponse vous revient restaurée. Ce manuel documente la configuration, les modes et les limites honnêtes du daemon.
N0 est un daemon local (binaire cloison-proxy en mode N0) qui expose un endpoint compatible OpenAI sur http://localhost:8787. Votre interface IA (Open WebUI, LibreChat, opencode, agents…) s'y branche avec deux champs :
Base URL : http://localhost:8787/v1
Clé : mn_<jeton_local>.<clé_amont>
Toute PII détectée est remplacée par une sentinelle ⟦…⟧ avant d'atteindre le fournisseur LLM, puis restaurée dans la réponse. La table jeton ↔ valeur (le coffre) vit chez vous, chiffrée sur disque : le fournisseur et l'opérateur ne voient jamais le clair.
L'authentification est 100 % locale : le jeton mn_ est comparé à temps constant, aucun appel au plan de contrôle n'est nécessaire pour masquer. Sans le jeton exact, le daemon répond 401 (fail-closed) et rien n'appelle le fournisseur.
Le daemon est distribué en release GitHub (binaire par OS + NER léger embarqué + lib onnxruntime, checksums SHA-256 vérifiés). Aucune toolchain, aucun téléchargement de modèle à la demande.
bash <(curl -fsSL https://raw.githubusercontent.com/coucagog/cloison-proxy/main/install-n0.sh) \
--version v0.3.3.2
Épingler la version est la règle (--version) : le tag latest a connu des incohérences de bundle NER sur Linux. Le script crée ~/.cloison, génère la clé locataire (affichée une seule fois) et affiche la configuration à placer dans votre profil. Le détail complet (Windows, options, mise à jour, rollback) est sur la page Installer N0.
Le mode N0 s'active en posant CLOISON_VAULT_PATH — toute la configuration passe par des variables d'environnement (il n'y a pas de fichier de politique en N0) :
export CLOISON_LISTEN_ADDR=127.0.0.1:8787 # local uniquement
export CLOISON_UPSTREAM_BASE_URL=https://api.deepseek.com/v1 # votre fournisseur
export CLOISON_VAULT_PATH=~/.cloison/vault.redb # coffre persistant (active N0)
export CLOISON_VAULT_PASSPHRASE='votre-passphrase' # clé du coffre, jamais persistée
export CLOISON_EXPECTED_ACCESS_TOKEN=mon_jeton_local # jeton mn_ (sans le préfixe)
export CLOISON_TENANT_KEY_HEX=$(openssl rand -hex 32) # clé locataire
cloison-proxy
| Variable | Rôle | Défaut / note |
|---|---|---|
| CLOISON_VAULT_PATH | Active le mode N0 — coffre redb chiffré AES-256-GCM | absent → mode edge (hébergé) |
| CLOISON_LISTEN_ADDR | Adresse d'écoute du daemon | défaut 127.0.0.1:8787 en N0 (local uniquement) ; 0.0.0.0:8787 en edge conteneurisé — poser 0.0.0.0 explicite si vous exposez volontairement le daemon |
| CLOISON_VAULT_PASSPHRASE | Clé du coffre (HKDF) | requise, jamais persistée en clair ; keychain OS possible (CLOISON_VAULT_KEYCHAIN_SERVICE) |
| CLOISON_EXPECTED_ACCESS_TOKEN | Jeton mn_ local | comparé à temps constant ; 401 fail-closed sinon |
| CLOISON_SESSION_SALT_FILE | Sel de session persistant (0600) | défaut <vault_path>.salt — les conversations survivent aux redémarrages |
| CLOISON_NER_MODEL_ONNX + CLOISON_NER_TOKENIZER | NER léger embarqué (PERSON/LOC in-core, jamais de sidecar Python) | posés ensemble → détection en texte libre ; absents → gazetteers + alias seuls |
| CLOISON_NER_THRESHOLD | Seuil de score du NER | défaut 0.70 (meilleur F1 mesuré ; plus haut = moins de faux positifs, plus bas = plus de rappel) |
| CLOISON_RESTORE_BARE_INNARDS | Restauration des intérieurs de jetons nus — certains modèles retirent les délimiteurs ⟦…⟧ et recopient le corps du jeton seul | défaut 1 (restauré ssi jeton émis pour la requête : registre + MAC, jamais de faux positif) ; 0 = désactivé |
| CLOISON_GEO_WHITELIST | Les noms de pays ne sont jamais masqués (whitelist français + anglais embarquée) | défaut 1 ; 0 = tout toponyme masqué |
| CLOISON_DISABLE_DETECTORS | Classes de détecteurs désactivées (virgules) — les valeurs de ces types partent alors en clair | vide ; person,location,ville_sn,… ; nom inconnu = refus de démarrer |
| CLOISON_UPSTREAM_TIMEOUT_MS | Timeout amont — les modèles « thinking » peuvent tenir plusieurs minutes par requête | défaut 300000 (5 min) ; un 502/503 ou un corps tronqué déclenche un réessai identique (non-stream) |
| CLOISON_AUDIT_MODE | Mode observe-only (détecte et compte, ne masque rien) | 1/true/yes/on → observe-only ; 0/false/absent → masquage actif (défaut) |
| CLOISON_REALISTIC_FAKE | Faux réaliste déterministe et irréversible (au lieu des sentinelles) | opt-in par tenant, 4 conditions mesurées — voir manuel d'utilisation |
| CLOISON_ALIAS_EXPANSION | Alias intra-session (formes dérivées des mentions canoniques) | 1 par défaut — jamais les pronoms |
| CLOISON_QUASI_ID_GAUGE | Jauge quasi-id (densité âge+acte+date+lieu) | 0 par défaut (opt-in) — signal, jamais de résolution |
Fail-loud au boot : passphrase absente, mauvaise passphrase ou coffre corrompu → le daemon refuse de démarrer. Jamais de recréation silencieuse du coffre, jamais de masquage dégradé sans le dire.
| Mode | Ce que reçoit le fournisseur | Quand l'utiliser |
|---|---|---|
| Masquage actif (défaut) | des jetons ⟦…⟧ uniquement — le clair ne part jamais | toute utilisation réelle |
| Observe-only (CLOISON_AUDIT_MODE=1) | le texte en clair (rien n'est transformé) + reçus signés locaux | mesurer/auditer un flux réel, inventorier les faux positifs — jamais sur un flux à protéger |
| Faux réaliste (CLOISON_REALISTIC_FAKE=1) | des valeurs plausibles irréversibles (jamais restaurées) | opt-in par tenant, quand le modèle « dépouille » les sentinelles — après mesure, jamais par défaut |
Dans tous les modes, les faibles cardinalités sont généralisées, jamais tokenisées (la fréquence trahirait le jeton) : date → YYYY-MM, IP → [IP], carte bancaire → •••••••••1234, ville → [VILLE_SN].
Sémantique du rapport d'audit (GET /v1/audit/report, observe-only) : total_requests = requêtes de la période ; redacted = projection k-anonyme des compteurs (les cellules sous k sont masquées, jamais exposées) ; le détail par type (masked_by_type) n'est pas exposé publiquement (il reste dans les reçus locaux signés) ; publishable = vrai uniquement si assez de requêtes et toutes les cellules non nulles ≥ k. Pour un inventaire fin des faux positifs lors d'un audit initial, passez par des sondes locales.
CLOISON est compatible avec tout client OpenAI-compatible (opencode, Codex, LibreChat, Open WebUI, SDK maison…) et tout fournisseur (DeepSeek, GLM, OpenRouter…). Deux comportements à connaître avec les modèles « thinking » :
reasoning_content est géré de bout en bout. À l'aller, le raisonnement rejoué entre les tours est transmis uniquement sous forme de jetons ⟦…⟧ ; au retour, les sentinelles sont restaurées dans le raisonnement (réponses normales et flux). Certains clients ne rejouent pas ce champ entre les tours : le fournisseur renvoie alors un 400 — indépendamment de CLOISON. Utilisez un client qui rejoue le champ (ou signalez-le à l'éditeur du SDK) : dès qu'il est présent, CLOISON le transporte.
Les modèles « thinking » peuvent tenir plusieurs minutes par requête : le timeout amont par défaut est de 5 minutes, et un échec 502/503 ou un corps tronqué déclenche un réessai identique. Certains modèles retirent les délimiteurs ⟦…⟧ et recopient l'intérieur du jeton : CLOISON restaure ces intérieurs nus (registre de la requête + MAC — jamais de faux positif).
curl -s http://localhost:8787/v1/chat/completions \
-H "Authorization: Bearer mn_<jeton>.<clé_amont>" \
-H "Content-Type: application/json" \
-d '{"model":"x","messages":[{"role":"user","content":
"Contact: Aminata Diop, user@example.com, tel +221 77 123 45 67"}]}'
# → la réponse contient « Aminata Diop, user@example.com, +221 77 123 45 67 »
# (restaurés) et aucune sentinelle ⟦…⟧ résiduelle.
Le coffre ne contient aucune valeur en clair (chiffré AES-256-GCM) : grep Aminata ~/.cloison/vault.redb ne trouve rien.
Trois éléments font la restaur-abilité de vos conversations : le coffre vault.redb, le sel .salt (0600, à côté du coffre) et la passphrase (dans votre tête ou le keychain OS). Sauvegardez les trois ensemble — l'un sans les autres ne restaure rien.
# Sauvegarde (daemon arrêté) — jamais dans un cloud sans chiffrement :
cp ~/.cloison/vault.redb ~/backups/ # coffre chiffré
cp ~/.cloison/.salt ~/backups/ # sel de session (0600)
# la passphrase : keychain OS ou gestionnaire de mots de passe
# Restauration (nouvelle machine / après incident) :
# 1. reposer vault.redb + .salt dans ~/.cloison
# 2. redémarrer avec la même passphrase (CLOISON_VAULT_PASSPHRASE)
# 3. rejouer la sonde du §06 — les anciens jetons redeviennent restaur-ables.
Exercice recommandé (une fois) : sauvegardez, supprimez le coffre, restaurez, re-sondez. Si la restauration échoue à froid, mieux vaut le découvrir en exercice qu'en incident.