
A secure* runtime for autonomous AI agents. Policy from plain-English constitutions. (*https://ironcurtain.dev)
Un runtime sécurisé* pour les agents IA autonomes, dont la politique de sécurité est dérivée d'une constitution lisible par l'homme.
*Quand quelqu'un écrit "sécurisé", vous devriez immédiatement être sceptique. Qu'entendons-nous par sécurisé ?
[!WARNING] Prototype de recherche. IronCurtain est un projet de recherche à un stade précoce explorant comment rendre les agents IA suffisamment sûrs pour être véritablement utiles. Les API, les formats de configuration et l'architecture peuvent changer. Les contributions et les retours sont les bienvenus.
L'agent est invité à cloner un dépôt et à pousser des modifications. git_clone et git_push sont tous deux escaladés par le moteur de politique, mais l'approbateur automatique les approuve automatiquement — l'entrée de confiance de l'utilisateur en mode commande (Ctrl-A) a fourni une intention claire, donc aucune approbation manuelle /approve n'était nécessaire.
Les agents IA autonomes peuvent gérer des fichiers, exécuter des commandes git, envoyer des messages et interagir avec des API en votre nom. Mais les frameworks d'agents actuels donnent à l'agent les mêmes privilèges que l'utilisateur, comme l'accès complet au système de fichiers, aux identifiants et au réseau. Les chercheurs en sécurité appellent cela l'autorité ambiante, et cela signifie qu'une seule injection de prompt ou une dérive multitour peut amener un agent à supprimer des fichiers, exfiltrer des données ou pousser du code malveillant.
La réponse courante est soit de restreindre les agents à un sandbox étroit (limitant leur utilité), soit de demander à l'utilisateur d'approuver chaque action (limitant leur autonomie). Aucune des deux n'est satisfaisante.
IronCurtain emprunte une voie différente : exprimez votre intention de sécurité en anglais simple, puis laissez le système décider de la mise en œuvre.
Vous écrivez une constitution qui est un court document décrivant ce que votre agent a le droit de faire ou non. IronCurtain compile cela en une politique de sécurité déterministe à l'aide d'un pipeline LLM, valide les règles compilées par rapport à des scénarios de test générés, puis applique la politique à l'exécution sur chaque appel d'outil. Le résultat est un agent qui peut travailler de manière autonome à l'intérieur des limites que vous définissez en langage naturel.
Les idées clés :
IronCurtain prend en charge deux modes de session avec des modèles de confiance différents :
Agent intégré (Mode Code) — Le propre agent LLM d'IronCurtain écrit des extraits TypeScript qui s'exécutent dans un sandbox V8. IronCurtain contrôle l'agent, le sandbox et le moteur de politique. Chaque appel d'outil sort du sandbox en tant que requête MCP structurée, passe par le moteur de politique (autoriser / refuser / escalader) et n'atteint le vrai serveur MCP qu'ensuite.
Mode Agent Docker — Un agent externe (Claude Code, Goose, etc.) s'exécute à l'intérieur d'un conteneur Docker sans accès réseau. IronCurtain médiatise les effets externes : les appels API LLM passent par un proxy MITM mettant fin au TLS (liste blanche d'hôtes, échange de clés fictives/réelles), les appels d'outils MCP passent par le même moteur de politique, et les installations de paquets (npm/PyPI) passent par un proxy de registre de validation.
Dans les deux modes, l'agent n'est pas digne de confiance. La sécurité ne dépend pas du respect des instructions par le modèle — elle est appliquée à la frontière.
Voir SANDBOXING.md pour l'architecture complète avec diagrammes, analyse de confiance couche par couche, et notes sur la plateforme macOS.
isolated-vm ; 24 et 26 installent des binaires préconstruits, Node 22 compile à partir de la source lors de l'installation et nécessite une chaîne d'outils C/C++). Les lignes impaires (23, 25) fonctionnent mais ne sont pas testées — ironcurtain doctor émet un avertissement.container fonctionne comme backend alternatif (VM par conteneur ; utilisé automatiquement lorsque ses services sont en cours d'exécution — voir containerRuntime dans ironcurtain config)En tant qu'outil CLI global (utilisateurs finaux) :```bash npm install -g @provos/ironcurtain
**À partir de la source (développement):**```bash
git clone https://github.com/provos/ironcurtain.git
cd ironcurtain
npm install
1. Définissez votre clé API :```bash export ANTHROPIC_API_KEY=sk-ant-...
Vous pouvez également placer les clés dans un fichier `.env` à la racine du projet (chargé automatiquement via `dotenv`), ou les ajouter dans `~/.ironcurtain/config.json` via `ironcurtain config`. Les variables d'environnement priment sur les valeurs du fichier de configuration. Pris en charge : `ANTHROPIC_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, `OPENAI_API_KEY`.
**2. Exécutez l'assistant de premier démarrage** (lancez-le explicitement avant d'utiliser le chemin mux recommandé ; il s'exécute également automatiquement lors du premier `ironcurtain start` non mux) :```bash
ironcurtain setup
Vous guide à travers la configuration du jeton GitHub, du fournisseur de recherche web, de la sélection du modèle et d'autres paramètres. Crée ~/.ironcurtain/config.json avec vos choix.
IronCurtain est livré avec une politique par défaut orientée vers l'expérience développeur — les opérations en lecture seule sont autorisées, les mutations (écritures, pushs, création de PR) nécessitent une approbation humaine. Vous pouvez commencer à l'utiliser immédiatement après la configuration.
La manière recommandée d'utiliser IronCurtain. Elle vous donne toute la puissance de l'interface TUI interactive de votre agent (Claude Code ou Goose) tandis qu'IronCurtain intervient comme médiateur pour chaque appel d'outil via son moteur de politique — le tout dans un seul terminal.```bash ironcurtain mux
**Fonctionnalités clés :**
- **TUI complet de l’agent** — L’agent s’exécute dans un PTY à l’intérieur d’un conteneur Docker sans accès réseau. Vous interagissez avec lui exactement comme s’il s’exécutait localement.
- **Gestion des escalades en ligne** — Lorsqu’un appel d’outil nécessite une approbation, un sélecteur d’escalade recouvre la zone d’affichage avec des actions à une touche (a/d/w pour approuver/refuser/mettre sur liste blanche). Utilisez `/approve+ N` pour mettre un domaine ou un chemin sur liste blanche pour le reste de la session.
- **Entrée utilisateur de confiance** — Le texte saisi en mode commande (Ctrl-A) est capturé côté hôte avant d’entrer dans le conteneur. Cela crée un signal d’intention vérifié que l’approbateur automatique peut utiliser — par exemple, taper « pousser mes modifications vers origin » approuvera automatiquement une escalade `git_push` ultérieure.
- **Gestion des onglets** — Lancez plusieurs sessions simultanées (`/new`), basculez entre elles (`/tab N`, Alt-1..9), fermez-les (`/close`). Plusieurs instances de mux peuvent s’exécuter en parallèle.
Voir [DEVELOPER_GUIDE.md](https://github.com/provos/ironcurtain/blob/HEAD/DEVELOPER_GUIDE.md) pour la présentation complète : modes de saisie, modèle de sécurité des entrées de confiance, flux de travail des escalades et référence du clavier.
### Sessions non-mux
Utilisez `ironcurtain start` pour des tâches ponctuelles rapides, des scripts ou lorsque vous voulez explicitement l’agent intégré local. Pour un travail normal et interactif avec l’agent Docker, utilisez `ironcurtain mux`.```bash
ironcurtain start "Summarize the files in ./src" # Single-shot mode
ironcurtain start -w ./my-project "Fix the tests" # Single-shot workspace mode
ironcurtain start --agent builtin # Local builtin REPL, no Docker
ironcurtain start --persona my-assistant "Check my email" # Use a persona
IronCurtain prend également en charge la reprise de session (--resume <session-id>), un mode PTY brut/hérité de débogage, un transport de messagerie Signal pour approbation mobile, et un mode démon pour les tâches cron planifiées. Le démon dispose d'une interface web optionnelle (--web-ui) pour la surveillance et la gestion des escalades via navigateur. Voir RUNNING_MODES.md pour les détails.
IronCurtain orchestre plusieurs agents IA à travers des workflows structurés. Le workflow de découverte de vulnérabilités inclus traque les bugs de sécurité mémoire et de logique dans le code natif via un pipeline de harnais à plusieurs niveaux (Niveau 1 fonction isolée → Niveau 2 multi-composant → Niveau 3 construction complète) avec un contrôle de couverture libFuzzer/AFL++, des états discover/triage basés sur des hypothèses, et une porte finale de révision de rapport humain. Le workflow conception-et-code exécute des cycles planification / conception / implémentation / révision, également avec des portes humaines. Chaque agent s'exécute dans son propre conteneur Docker avec des limites de politique spécifiques au rôle ; le moteur gère automatiquement les transitions d'état, le passage d'artefacts et le point de contrôle de reprise après crash. Open source, s'exécute entièrement sur votre machine, applique des politiques de sécurité par agent via le moteur de politiques basé sur une constitution, et fonctionne avec tout agent conteneurisé Docker — comparable en portée à Amazon Kiro et Google Jules pour les tâches de codage, mais avec une sécurité de premier ordre et un format de définition de workflow extensible.

L'interface web est l'interface prévue pour les exécutions de workflows. Démarrez le démon, ouvrez l'URL imprimée, et gérez les exécutions depuis la page Workflows — le graphe de machine d'état ci-dessus est en direct, la chronologie des messages des agents défile avec rendu markdown, les revues de porte incluent un navigateur d'espace de travail + artefacts, et les exécutions passées restent listées.```bash ironcurtain daemon --web-ui
L'accès CLI est disponible pour le scripting, l'automatisation et le débogage :```bash
ironcurtain workflow start vuln-discovery \
"Find memory-safety bugs in libical" --workspace ~/src/libical
ironcurtain workflow start design-and-code \
"Build a REST API with authentication"
Voir WORKFLOWS.md pour la documentation complète.
La politique par défaut fonctionne bien pour le développement général, mais vous pouvez l'adapter à votre flux de travail :
1. Personnalisez votre constitution (optionnel mais recommandé) :```bash ironcurtain customize-policy
Une conversation assistée par LLM qui génère une constitution adaptée à votre flux de travail, sauvegardée dans `~/.ironcurtain/constitution-user.md`. Vous pouvez également modifier ce fichier directement.
**2. Compilez la politique :**```bash
ironcurtain compile-policy
Traduit votre constitution en règles déterministes, génère des scénarios de test et les vérifie. Les artefacts compilés vont dans ~/.ironcurtain/generated/.
Les Personas sont des profils de politiques nommés — chacun regroupe une constitution, une politique compilée, un espace de travail persistant et une mémoire sémantique. Utilisez-les pour exécuter des agents avec différents rôles ou niveaux d'accès.```bash ironcurtain persona create my-assistant # Create a persona ironcurtain persona compile my-assistant # Compile its policy ironcurtain start --persona my-assistant "Check my calendar"
In mux mode, `/new my-assistant` crée un onglet en utilisant ce persona. Les personas peuvent également être assignés à des tâches cron. Voir [DAEMON.md](https://github.com/provos/ironcurtain/blob/HEAD/DAEMON.md) pour la configuration des tâches planifiées.
Les personas peuvent également être gérés depuis l'[interface web](https://github.com/provos/ironcurtain/blob/HEAD/DAEMON.md#persona-policy-management) — parcourir, créer, modifier les constitutions et compiler les politiques avec suivi en direct. Comme une politique est une frontière de sécurité, les contrôles de mutation de l'interface web sont en lecture seule sauf si le daemon est démarré avec `--allow-policy-mutation` (désactivé par défaut).
### Skills
Déposez des packages SKILL.md dans `~/.ironcurtain/skills/<name>/` pour rendre des directives spécifiques à un objectif (scripts d'aide, vérifications déterministes, connaissances du domaine) disponibles pour chaque session d'agent Docker. L'ensemble fusionné est placé dans un répertoire hôte par bundle et monté **en lecture seule** dans le conteneur au chemin que la découverte native de l'agent actif parcourt — Claude Code est pointé vers le répertoire de staging via `--add-dir`, Goose scanne `~/.config/goose/skills/<name>/SKILL.md`. L'agent les découvre automatiquement et décide quand les lire en fonction de la description de chaque skill dans le frontmatter. Le _format_ SKILL.md est le standard ouvert adopté par Claude Code, Goose et Codex ; seul le _chemin de découverte_ diffère selon l'agent. Les workflows peuvent inclure des skills par état dans le package de workflow — voir [WORKFLOWS.md](https://github.com/provos/ironcurtain/blob/HEAD/WORKFLOWS.md#skills).
## Policy: Constitution → Enforcement
Vous écrivez l'intention en anglais simple ; IronCurtain la compile en règles déterministes :```
constitution.md → [Annotate] → [Compile] → [Resolve Lists] → [Generate Scenarios] → [Verify & Repair]
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
tool-annotations compiled-policy dynamic-lists test-scenarios verified policy
.json .json .json .json (or build failure)
@list-name.dynamic-lists.json, modifiable par l'utilisateur. Ignoré lorsqu'aucune liste n'est présente.Tous les artefacts sont mis en cache par hachage de contenu — seules les entrées modifiées déclenchent une recompilation.
Une clause de constitution comme :```markdown
compile vers :```json
[
{ "tool": "git_status", "decision": "allow", "condition": { "directory": { "within": "$SANDBOX" } } },
{ "tool": "git_diff", "decision": "allow", "condition": { "directory": { "within": "$SANDBOX" } } },
{ "tool": "git_push", "decision": "escalate", "reason": "Remote-contacting git operations require human approval" }
]
Tout appel qui ne correspond pas à une règle explicite allow ou escalate est refusé par défaut.```bash
ironcurtain annotate-tools --server filesystem # Annotate one server (merge with existing)
ironcurtain annotate-tools --all # Re-annotate all servers
ironcurtain compile-policy # Compile constitution into rules and verify
ironcurtain refresh-lists # Re-resolve dynamic lists without full recompilation
ironcurtain refresh-lists --list major-news # Refresh a single list
Examinez le fichier généré `~/.ironcurtain/generated/compiled-policy.json` — ce sont les règles exactes appliquées lors de l'exécution.
## Configuration
IronCurtain stocke la configuration et les données de session dans `~/.ironcurtain/` :```
~/.ironcurtain/
├── config.json # User configuration
├── constitution.md # User-local base constitution (overrides package default)
├── constitution-user.md # Your policy customizations (generated by customize-policy)
├── generated/ # User-compiled policy artifacts (overrides package defaults)
├── personas/ # Persona directories (constitution, policy, workspace, memory)
├── skills/ # User-global SKILL.md packages, mounted into every Docker session
├── jobs/ # Cron job definitions, workspaces, and run records
├── sessions/
│ └── {sessionId}/
│ ├── sandbox/ # Per-session filesystem sandbox
│ ├── escalations/ # File-based IPC for human approval
│ ├── audit.jsonl # Per-session audit log
│ └── session.log # Diagnostics
└── workflow-runs/ # Shared-container workflow runs (see below)
Les exécutions de session unique (ironcurtain start, onglets mux, tâches cron) écrivent sous sessions/. Les exécutions de workflow en conteneur partagé écrivent sous workflow-runs/ à la place — voir la section suivante.
Une définition de workflow peut opter pour un conteneur Docker partagé en définissant settings.sharedContainer: true dans son YAML. Dans ce mode, chaque état d'agent s'exécute dans le même conteneur de longue durée et partage une instance de moteur de politique ; entre les états, l'orchestrateur échange à chaud la politique active afin que chaque persona voit ses propres règles. Tous les artefacts de l'exécution atterrissent dans une arborescence unique :```
~/.ironcurtain/workflow-runs//
├── audit.jsonl # Persona-tagged append-only audit
├── messages.jsonl # Orchestrator message log
├── workspace/ # Agent workspace (filesystem MCP root)
├── bundle/ # Shared container support (claude-state, orientation, sockets, escalations, system-prompt.txt)
├── states/
│ └── ./ # session.log + session-metadata.json per invocation
└── proxy-control.sock # Coordinator UDS for policy hot-swap
Aucune entrée par session n'est créée sous `~/.ironcurtain/sessions/` pour une exécution de workflow en conteneur partagé. Les commandes visibles par l'utilisateur (`ironcurtain workflow start|resume|inspect|list`) sont inchangées. Voir [WORKFLOWS.md](https://github.com/provos/ironcurtain/blob/HEAD/WORKFLOWS.md) pour la création de définitions de workflow et le cycle de vie complet.
Modifier la configuration de manière interactive :```bash
ironcurtain config
Zones clés de configuration : modèles et clés API, budgets de ressources (limites de jetons/étapes/temps/coût), escalades d'approbation automatique, fournisseur de recherche web, rédaction d'audit, et paramètres LLM du serveur mémoire. Voir CONFIG.md pour la référence complète.
Pour acheminer le trafic LLM via une passerelle comme LiteLLM ou OpenRouter (en mode Code et en mode Agent Docker), voir MODEL_ROUTING.md.
Acheminez les agents Docker via des profils de fournisseur de modèles (par exemple GLM-5.2 via OpenRouter, sans sidecar) avec ironcurtain config → Model Providers, puis sélectionnez un profil dans /new ou avec --provider-profile — voir MODEL_ROUTING.md#first-class-openrouter.
IronCurtain est livré avec six serveurs MCP préconfigurés. Tous les appels d'outils (sauf mémoire) sont régis par votre politique compilée.
Les opérations en lecture seule sont autorisées par la politique par défaut ; les mutations (écritures, push, création de PR) sont escaladées pour approbation humaine. Les outils utilisent la nomenclature server.tool (par exemple filesystem.read_file, memory.recall). Voir ADDING_MCP_SERVERS.md pour ajouter les vôtres.
En mode Agent Docker, le conteneur n'a pas d'accès réseau — tout le trafic passe par le proxy MITM d'IronCurtain. Par défaut, seuls les domaines des fournisseurs LLM sont accessibles. L'agent peut demander l'accès à des domaines supplémentaires à l'exécution via le serveur MCP virtuel proxy (add_proxy_domain). Chaque demande nécessite une approbation humaine via le flux d'escalade.
Les domaines approuvés obtiennent un tunnel de passage brut — les connexions HTTP, HTTPS et WebSocket sont transmises sans inspection du contenu ni injection de justificatifs. Cela donne à l'agent une plus grande utilité (appel d'API tierces, streaming de données depuis des services externes) mais signifie que le trafic vers ces domaines est non médiatisé. Voir SECURITY_CONCERNS.md section 2b-i pour le modèle de menace et DEVELOPER_GUIDE.md pour les détails d'utilisation.
IronCurtain est conçu autour d'un modèle de menace spécifique : le LLM devient malveillant. Cela peut se produire par injection d'invite (un email malveillant ou une page web détourne l'agent) ou par dérive multi-tours (l'agent s'écarte progressivement de l'intention de l'utilisateur au cours d'une longue session).
Ceci est un prototype de recherche. Les lacunes connues incluent :
compiled-policy.json compilé.Voir docs/SECURITY_CONCERNS.md pour une analyse détaillée des menaces.
npm test # Run all tests npm test -- test/policy-engine.test.ts # Run a single test file npm test -- -t "denies delete_file" # Run a single test by name npm run lint # Lint npm run build # TypeScript compilation + asset copy
Voir [TESTING.md](https://github.com/provos/ironcurtain/blob/HEAD/TESTING.md) pour le guide de test complet, y compris les drapeaux de test d'intégration et les conventions.
### Structure du projet```
src/
├── index.ts # Entry point
├── cli.ts # CLI command dispatcher
├── config/ # Configuration loading, constitution, MCP server definitions
├── session/ # Multi-turn session management, budgets, loop detection
├── sandbox/ # V8 isolated execution environment
├── trusted-process/ # Policy engine, MCP proxy, audit log, escalation handler
├── pipeline/ # Constitution → policy compilation pipeline
├── escalation/ # Escalation listener: session registry, TUI dashboard, state
├── mux/ # Terminal multiplexer: PTY bridge, renderer, trusted input
├── persona/ # Persona management (create, compile, resolve)
├── memory/ # Memory server integration (config, annotations, path resolution)
├── signal/ # Signal messaging transport (bot daemon, setup, formatting)
├── daemon/ # Unified daemon (Signal + cron scheduler, control socket)
├── cron/ # Cron job management (scheduler, job store, git sync, policy)
├── docker/ # Docker agent mode, PTY session, MITM proxy, registry proxy
├── workflow/ # Multi-agent workflow engine (orchestrator, state machine, gates)
├── web-ui/ # Web UI backend (JSON-RPC dispatch, event bus, workflow manager)
├── servers/ # Built-in MCP servers (fetch, web search providers)
└── types/ # Shared type definitions
packages/
└── memory-mcp-server/ # Standalone memory MCP server (publishable npm package)
| Serveur | Outils | Fonctionnalités clés |
|---|
| Filesystem | 14 | Lire, écrire, éditer, rechercher des fichiers ; arborescence de répertoires ; déplacer ; calcul de différences |
| Git | 28 | Workflow git complet: status, diff, log, commit, branch, push/pull/fetch, clone, stash, blame |
| Fetch | 2 | HTTP GET avec conversion HTML vers markdown ; recherche web (Brave, Tavily, SerpAPI) |
| GitHub | 41 | Issues, PRs, recherche de code, révisions via ghcr.io/github/github-mcp-server ; nécessite un token d'accès personnel GitHub |
| Google Workspace | 128 | Gmail, Calendar, Drive, Docs, Sheets — nécessite une configuration OAuth via ironcurtain auth |
| Memory | 5 | Mémoire sémantique persistante avec recherche hybride vectorielle+par mots-clés, résumé LLM, et compactage automatique. Activé pour les sessions persona et cron. |
| Problème | Conseils |
|---|
| Clé API manquante | Définissez la variable d'environnement (ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, ou OPENAI_API_KEY) ou ajoutez la clé correspondante à ~/.ironcurtain/config.json. |
| Sandbox indisponible | Le sandboxing au niveau OS nécessite bubblewrap et socat. Installez les deux, ou définissez "sandboxPolicy": "warn" dans la configuration de votre serveur MCP pour le développement. |
| Budget épuisé | Ajustez les limites dans ~/.ironcurtain/config.json sous resourceBudget. Mettez toute limite individuelle à null pour la désactiver. |
| Erreurs de version Node | Les versions Node.js supportées sont 22, 24 et 26 — les versions majeures paires testées par IronCurtain (isolated-vm). 24 et 26 installent des binaires préconstruits ; Node 22 compile isolated-vm depuis les sources et nécessite une chaîne d'outils C/C++. Les versions impaires (23, 25) ne sont pas testées — ironcurtain doctor les signale avec un avertissement plutôt qu'une erreur fatale. |
| La politique ne correspond pas à l'intention | Examinez compiled-policy.json pour voir les règles générées. Exécutez ironcurtain customize-policy pour affiner votre constitution, puis ironcurtain compile-policy pour recompiler. Un libellé spécifique produit de meilleures règles — un phrasé vague mène à une politique vague. |
| L'approbation automatique ne se déclenche pas | L'approbateur automatique n'approuve que lorsque le message de l'utilisateur autorise explicitement l'action (par exemple « push to origin » pour git_push). Les messages vagues escaladent toujours vers une revue humaine. Vérifiez que autoApprove.enabled est true dans config.json. |
| Terminal PTY/mux brouillé après la sortie | Exécutez reset dans ce terminal pour restaurer le mode normal. Ceci est nécessaire lorsque le processus est tué de manière non gracieuse et que le mode brut n'est pas restauré. |
| Mux/listener : « already running » | Un seul mux ou escalation-listener peut s'exécuter à la fois. Le verrou à ~/.ironcurtain/escalation-listener.lock est automatiquement effacé si le processus précédent est mort. S'il persiste, vérifiez le PID dans le fichier de verrou. |
| Le bot Signal ne répond pas | Vérifiez que le conteneur signal-cli est en cours d'exécution (`docker ps |