Manuel N0

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.

01 · Ce que N0 est

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 :

Configuration client
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.

02 · Installation

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.

Linux / macOS
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.

03 · Configuration

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) :

Shell
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
VariableRôleDéfaut / note
CLOISON_VAULT_PATHActive le mode N0 — coffre redb chiffré AES-256-GCMabsent → mode edge (hébergé)
CLOISON_LISTEN_ADDRAdresse d'écoute du daemondé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_PASSPHRASEClé du coffre (HKDF)requise, jamais persistée en clair ; keychain OS possible (CLOISON_VAULT_KEYCHAIN_SERVICE)
CLOISON_EXPECTED_ACCESS_TOKENJeton mn_ localcomparé à temps constant ; 401 fail-closed sinon
CLOISON_SESSION_SALT_FILESel de session persistant (0600)défaut <vault_path>.salt — les conversations survivent aux redémarrages
CLOISON_NER_MODEL_ONNX + CLOISON_NER_TOKENIZERNER 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_THRESHOLDSeuil de score du NERdéfaut 0.70 (meilleur F1 mesuré ; plus haut = moins de faux positifs, plus bas = plus de rappel)
CLOISON_RESTORE_BARE_INNARDSRestauration des intérieurs de jetons nus — certains modèles retirent les délimiteurs ⟦…⟧ et recopient le corps du jeton seuldéfaut 1 (restauré ssi jeton émis pour la requête : registre + MAC, jamais de faux positif) ; 0 = désactivé
CLOISON_GEO_WHITELISTLes noms de pays ne sont jamais masqués (whitelist français + anglais embarquée)défaut 1 ; 0 = tout toponyme masqué
CLOISON_DISABLE_DETECTORSClasses de détecteurs désactivées (virgules) — les valeurs de ces types partent alors en clairvide ; person,location,ville_sn,… ; nom inconnu = refus de démarrer
CLOISON_UPSTREAM_TIMEOUT_MSTimeout amont — les modèles « thinking » peuvent tenir plusieurs minutes par requêtedéfaut 300000 (5 min) ; un 502/503 ou un corps tronqué déclenche un réessai identique (non-stream)
CLOISON_AUDIT_MODEMode observe-only (détecte et compte, ne masque rien)1/true/yes/on → observe-only ; 0/false/absent → masquage actif (défaut)
CLOISON_REALISTIC_FAKEFaux 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_EXPANSIONAlias intra-session (formes dérivées des mentions canoniques)1 par défaut — jamais les pronoms
CLOISON_QUASI_ID_GAUGEJauge 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.

04 · Les modes

ModeCe que reçoit le fournisseurQuand l'utiliser
Masquage actif (défaut)des jetons ⟦…⟧ uniquement — le clair ne part jamaistoute utilisation réelle
Observe-only (CLOISON_AUDIT_MODE=1)le texte en clair (rien n'est transformé) + reçus signés locauxmesurer/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.

05 · Agents & modèles « thinking »

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).

06 · Limites honnêtes

Limites honnêtes
Poste compromis. N0 ne protège pas contre un malware ou un vol de la machine : le coffre et la clé y vivent. La sécurité de N0 est celle de votre poste.
Texte libre sans NER léger. Sans CLOISON_NER_MODEL_ONNX, les noms hors gazetteers nom_sn/ville_sn en texte libre restent un risque de clair. Le NER embarqué (PERSON/LOC, seuil 0.70) comble ce fossé — installez-le.
PII hallucinée. Le modèle peut inventer une PII sans jeton correspondant — non résoluble par le proxy. Les sentinelles forgées ne sont en revanche jamais restaurées (registre d'émission + MAC) : elles ressortent en marqueur neutre [REDACTED], jamais en clair.
/v1/embeddings bloqué. Un embedding de PII reste dérivé de PII : la route est absente (404). Piste documentée, non livrée.
Restauration bornée à la requête. Seuls les jetons émis pour la requête en cours sont restaurés (registre + MAC) : un jeton d'une requête antérieure n'est jamais restauré. Après rotation du sel (.salt supprimé), les anciens jetons deviennent [REDACTED].

07 · Vérifier que ça marche

Shell
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.

08 · Coffre : sauvegarde & restauration

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.

Shell
# 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.