Aller au contenu

Exécuter Claude Code avec Olivares (co-déploiement)

C’est la moitié Operate de l’histoire Anthropic-first : non seulement observer et gouverner Claude Code, mais le conduire. Le control plane lance un véritable processus claude, relie ses E/S dans un flux gouverné, ancre chaque transition de cycle de vie dans le ledger d’audit, et le démantèle — sur un workspace partagé, depuis l’API/la CLI (et, plus tard, le portail), sans SSH. Cette page co-déploie les deux moitiés sur un seul hôte Linux en quatre topologies, sécurisées par défaut.

Pour le chemin observation coopérative (télémétrie OTLP → access map), voir Connecter Claude Code ; pour le chemin gouvernance (hooks PreToolUse en tant que PEP), voir l’exemple govern-claude-code. Cette page traite du co-déploiement : faire fonctionner les deux runtimes ensemble.

  1. Opt-in. L’image de base Olivares est distroless et ne porte aucun claude. La couche Operate-Claude-Code est un artefact distinct — une image combinée (Dockerfile.agentops) ou un module complémentaire d’installation native. Si vous n’exécutez pas de Claude Code gouverné, vous ne la récupérez jamais, et sa surface supplémentaire ne touche jamais votre control plane.
  2. Source officielle, jamais redistribuée. Les conditions d’Anthropic n’autorisent pas la redistribution du binaire claude, donc nous l’installons depuis la source officielle d’Anthropic, signée GPG au build/premier lancement (les dépôts apt/dnf/apk signés), épinglée et avec l’auto-updater désactivé. Nous ne livrons aucun binaire tiers. Vous pouvez aussi apporter le vôtre (claude) et y pointer le moteur.
#OlivaresClaude CodeComment le moteur le conduitStatut
1DockerDockerMême conteneur (image combinée), enfant procRunnerRecommandé (même chemin gouverné que 2)
2NatifNatifMême hôte (systemd), enfant procRunnerRecommandé, testé en smoke de bout en bout
3DockerNatif (hôte)Inter-namespace — non gouvernable tel quelCo-localisez plutôt (voir ci-dessous)
4NatifDocker (par session)Conteneur par session via l’API DockerÀ venir (documenté)

Les deux topologies co-localisées (1, 2) sont le défaut sécurisé. La topologie 2 (native) est testée de bout en bout par scripts/smoke-agentops.sh ; la topologie 1 réutilise le même chemin procRunner gouverné (le build/run de l’image combinée n’est pas encore câblé dans un test automatisé). Les topologies 3 et 4 veulent le gouverneur et le gouverné dans des conteneurs différents ; relier le stdio à travers cette frontière nécessite un accès à l’API Docker (un privilège que le moteur ne prend délibérément pas par défaut). Leurs chemins honnêtes sont détaillés dans Topologies mixtes.


Topologie 1 — les deux dans Docker (recommandée)

Section intitulée « Topologie 1 — les deux dans Docker (recommandée) »

Un conteneur durci exécute le moteur et claude ; un volume workspace est le répertoire de travail partagé. Loopback uniquement, non-root, système de fichiers racine en lecture seule — posture identique au compose de base, plus le runtime conduit.

claude est installé au moment du build depuis le dépôt apt signé d’Anthropic, avec l’empreinte de la clé de signature épinglée (31DD DE24 DDFA B679 F42D 7BD2 BAA9 29FF 1A7E CACE) et l’auto-update désactivé. Épinglez la base du moteur par digest et vérifiez-la d’abord :

Fenêtre de terminal
# verify the engine image you build FROM (it is cosign-signed)
cosign verify docker.io/olivaresai/olivares:26.8.0 \
--certificate-identity-regexp '^https://github\.com/olivaresai/olivares/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
docker build -f Dockerfile.agentops \
--build-arg OLIVARES_IMAGE=docker.io/olivaresai/olivares@sha256:<digest> \
--build-arg CLAUDE_CHANNEL=stable \
-t olivares-agentops:26.8.0 .

Apportez plutôt votre propre claude avec --build-arg CLAUDE_INSTALL=byo (l’image est livrée sans claude ; montez le vôtre au runtime et définissez OLIVARES_SESSION_RUNTIME_CLAUDE_BIN).

Fenêtre de terminal
export OLIVARES_AGENTOPS_IMAGE=olivares-agentops:26.8.0
docker compose -f deploy/compose/docker-compose.yml \
-f deploy/compose/docker-compose.agentops.yml up -d

L’override ne change que ce dont Operate a besoin : l’image combinée, quatre volumes inscriptibles (données du moteur, workspace, home ~/.claude de claude, le jeton d’inférence à durée de vie courte), et l’environnement du session-runtime. Tout le reste — les ports liés à 127.0.0.1, uid 65532, racine read_only, cap_drop: ALL, no-new-privileges — est hérité de la base.


Le moteur et claude sur l’hôte ; systemd exécute le moteur, qui conduit claude. Le workspace réside dans /var/lib/olivares/workspaces.

Fenêtre de terminal
curl -fsSL https://raw.githubusercontent.com/olivaresai/olivares/main/scripts/install-agentops.sh | sh

Il détecte automatiquement la topologie native, installe le binaire du moteur vérifié (le install.sh gardé par cosign), installe claude depuis le dépôt apt/dnf/apk signé (avec vérification de l’empreinte de clé — ou OLIVARES_CLAUDE_INSTALL=byo pour ignorer), crée l’utilisateur de service olivares sans login et le répertoire workspace, et dépose l’override systemd durci + l’exemple d’environnement. Il ne démarre pas automatiquement un plan de gouvernance — en exécuter un est votre décision explicite.

  • packaging/systemd/olivares.service.d/agentops.conf — un drop-in qui donne au claude conduit un HOME inscriptible pour ~/.claude (gardé sous /var/lib/olivares, de sorte que ProtectHome=true protège toujours les véritables utilisateurs), s’assure que le répertoire workspace existe, et lève exactement une propriété de sandbox : MemoryDenyWriteExecute (le runtime claude compile en JIT et a besoin de mémoire W→X). Toutes les autres directives de durcissement de l’unité de base restent en vigueur.
  • /etc/olivares/agentops.env — la configuration du session-runtime (fichier de jeton, TTL, URL de base de gateway optionnelle, chemin BYO claude optionnel).

Ensuite, délibérément :

Fenêtre de terminal
sudo nano /etc/olivares/agentops.env # wire the short-lived inference token (refresher)
sudo systemctl enable --now olivares # loopback-only by default

Les mêmes étapes dans l’une ou l’autre topologie co-localisée. Authentifiez la CLI, enregistrez le workspace partagé, lancez :

Fenêtre de terminal
export OLIVARES_SERVER_URL=https://127.0.0.1:8443
export OLIVARES_TOKEN=<your-api-token>
export OLIVARES_TENANT=<your-tenant-id>
# 1) register the shared workspace (the session's working dir; jailed file API on top)
olivares agent workspace add /var/lib/olivares/workspaces/project-x --name project-x --mode rw
# 2) launch a governed session over the stream-json transport
olivares agent session create --transport stream-json \
--permission-mode acceptEdits --model opus \
--workspace <workspace-ref> --isolation native
# 3) attach to its live, bridged I/O (lossless replay from a cursor); send input; stop
olivares agent session attach <run-ref>
olivares agent session input <run-ref> --line '{"type":"user","message":{"role":"user","content":"…"}}'
olivares agent session stop <run-ref>

Chaque transition (created → launched → … → stopped) est ancrée dans le ledger d’audit signé (olivares agent session events <run-ref>) ; l’API de fichiers du workspace (olivares agent workspace files|get|put|…) est jailée et auditée. Le contrat de reproductibilité de tout cela est scripts/smoke-agentops.sh, qui fait monter le co-déploiement natif contre un faux claude hermétique et affirme que la session est gouvernable de bout en bout.


Celles-ci séparent le gouverneur et le gouverné de part et d’autre d’une frontière de conteneur. Soyez lucide sur ce que cela coûte.

Topologie 3 — Olivares dans Docker, Claude sur l’hôte

Section intitulée « Topologie 3 — Olivares dans Docker, Claude sur l’hôte »

Il n’y a aucun chemin gouverné propre : un moteur conteneurisé ne peut pas posséder le stdio d’un processus dans les namespaces de l’hôte, et le transport gouverné est le stdio. Atteindre un claude hôte exigerait de partager le namespace PID de l’hôte et les mounts dans le conteneur du moteur — une dé-isolation importante et délibérée qui anéantit l’intérêt de contenir le moteur. Co-localisez plutôt : exécutez les deux dans l’image combinée (c’est bien la topologie 1), ou exécutez les deux en natif (topologie 2). C’est une limite réelle, énoncée plutôt que masquée.

Topologie 4 — Olivares natif, Claude dans un conteneur par session

Section intitulée « Topologie 4 — Olivares natif, Claude dans un conteneur par session »

C’est le foyer naturel de l’isolation par conteneur frais par session : chaque session reçoit un tout nouveau conteneur claude durci (workspace bind-mounté, racine en lecture seule, non-root, cap-drop), créé et démantelé par le moteur via l’API Docker, avec stdio relié par Docker attach/hijack. Le seam du modèle de données le modélise déjà (--isolation container est une valeur valide, et la primitive de mount de l’exécuteur qu’il consommera est déjà livrée) — mais le runner qui le porte n’est pas encore câblé, donc le runner natif refuse cette valeur aujourd’hui (voir la note ci-dessus).

C’est un suivi documenté, non livré dans cette version. Piloter des conteneurs frères signifie donner au moteur l’accès à l’API Docker (idéalement via un proxy de socket au moindre privilège) — une surface de confiance que cette version évite délibérément au profit de l’image combinée sans socket. Choisir cette topologie, c’est choisir une isolation gouverneur/gouverné plus forte au prix de cet octroi d’API Docker ; elle arrivera derrière le seam isolation=container existant. D’ici là, le défaut sécurisé est la co-localisation.


  • Loopback par défaut. Les ports de l’hôte ne publient que sur 127.0.0.1. Dans un conteneur, le moteur écoute sur 0.0.0.0 à l’intérieur du conteneur, donc le mapping du port de l’hôte est la frontière d’exposition — ne le publiez jamais sur une adresse d’hôte non-loopback sans votre propre proxy d’auth qui termine le TLS. Le bind natif/systemd par défaut est loopback. Exposez délibérément.
  • Non-root, moindre privilège. uid/gid 65532, système de fichiers racine en lecture seule, cap_drop: ALL, no-new-privileges (Docker) / l’ensemble complet Protect*/Restrict* moins l’unique relâchement W^X documenté (systemd).
  • Environnement à données minimales, à allowlist. Le claude enfant n’hérite que d’une allowlist explicite (PATH, HOME, locale…) plus le jeton d’inférence en mémoire — aucune clé de signature OLIVARES_*, aucun ANTHROPIC_*/CLAUDE_CODE_* ambiant qui pourrait masquer le credential émis.
  • Chaîne d’approvisionnement vérifiée. Le moteur est signé par cosign (vérifiez-le / épinglez par digest) ; claude s’installe depuis les dépôts signés d’Anthropic avec l’empreinte de clé épinglée. L’installateur refuse d’exécuter un moteur non vérifié sauf si vous le désactivez explicitement.
  • Audit ancré. Chaque transition de cycle de vie et chaque mutation de workspace est scellée dans le ledger signé et hash-chaîné par PayloadHash — les octets des fichiers et le contenu des frames ne sont jamais persistés.