--- issueRef: "#99" version: 4 updatedBy: {"kind":"user"} updatedAt: 1785271085627 --- # Carnet #99 — Cadrage (prêt pour le cycle) > Cadrage établi par Main après investigation code + **vérification empirique des binaires > installés** (`codex-cli 0.145.0`, `Claude Code 2.1.220`). Les faits CLI ci-dessous sont > **capitalisés et vérifiés** ; ils conditionnent toute l'architecture. Architect doit valider > les ports/VO et les questions ouvertes (§6) avant l'implémentation. --- ## 1. État des lieux vérifié — comparaison des 3 moteurs | Moteur | Modèle contrôlé par IdeA ? | Mécanisme | Source | |---|---|---|---| | **OpenCode** | ✅ Oui | `model` écrit à la racine du `opencode.json` isolé (`OPENCODE_CONFIG`), lu par la session structured | `lifecycle.rs:2686-2689`, `2786-2788` | | **Codex** | ❌ Non | aucun `--model`, `codex_config_toml` n'écrit pas `model` → défaut du binaire | `codex.rs:215-239`, `lifecycle.rs:2941-2955` | | **Claude** | ❌ Non | aucun `--model`, `claude_settings_seed` n'écrit pas `model` → défaut du binaire | `claude.rs:273-284`, `infrastructure/permission/claude.rs:59` | PTY et headless sont **deux processus OS séparés** pour un même agent (`allow_structured_alongside_pty: true`, `lifecycle.rs:1512-1517`) ; ils partagent le même `CODEX_HOME`/cwd mais **aucun état modèle** n'est synchronisé entre eux côté IdeA. Le `/model` de la TUI ne sort jamais du process TUI (pass-through brut, `terminal/usecases.rs:140`). ## 2. Faits CLI vérifiés (capitalisation) — la clé qui débloque tout ### Codex 0.145.0 — `model` est une clé config.toml **documentée** - L'exemple littéral du `--help` est `-c model="o3"`. `config.toml` est chargé depuis `$CODEX_HOME/config.toml`. - **Honorée par `codex` (TUI) ET `codex exec` (headless)** — même mécanisme de base (`--ignore-user-config` confirme qu'il est chargé par défaut). - Bonus : `codex exec` accepte aussi `-m, --model ` (seconde porte d'injection). - **→ Écrire `model = "..."` dans le `$CODEX_HOME/config.toml` isolé fixe le défaut pour les DEUX canaux.** ### Claude 2.1.220 — `model` est gérable via settings + flag - `--model ` fonctionne en interactif **et** `-p/--print` (headless). - `--settings ` + la hiérarchie `./.claude/settings.local.json` (project-local) supportent une clé `model`. - **→ Écrire `"model": "..."` dans le `.claude/settings.local.json` du run dir fixe le défaut pour les DEUX canaux** (cwd = run dir, lu par PTY et headless). ### Conclusion d'architecture Les trois moteurs convergent vers **le même pattern** : écrire le modèle du profil dans le **fichier de config isolé du run dir**. Le fichier partagé = point de vérité unique pour headless + TUI au lancement. L'exigence produit « modèle par défaut = modèle headless = modèle exposé TUI au lancement » est satisfaite **par construction**, sans sync à coder. ## 3. Points d'intégration IdeA précis (avec chemins) | Moteur | Renderer à modifier | Fichier produit | Ownership | Isolation | |---|---|---|---|---| | **Codex** | `codex_config_toml` (`application/agent/lifecycle.rs:2941-2955`) | `$CODEX_HOME/config.toml` | `MergeToml` (préservé aux régénérations) | `CODEX_HOME={runDir}/.codex` déjà isolé (`lifecycle.rs:2361`) | | **Claude** | `claude_settings_seed` (`infrastructure/src/permission/claude.rs:59`) | `{runDir}/.claude/settings.local.json` | `Replace` (régénéré du profil à chaque lancement) | cwd=run dir ; pas d'iso home mais **project-local override user** → le modèle IdeA gagne | Champ existant à consommer ou déprécier : **`AgentProfile.model: Option`** (`domain/src/profile.rs:1008`) — actuellement code mort. Référence OpenCode à répliquer : `OpenCodeProviderConfig { provider_id, model, api_key_ref }` (`domain/src/profile.rs:372-391`) + `SaveOpenCodeProviderProfile` (`application/agent/usecases.rs`). ## 4. Architecture proposée — découpage en lots - **A. Domaine** — Nouveaux VO miroir d'`OpenCodeProviderConfig` : `CodexProviderConfig { provider, model, api_key_ref }` et `ClaudeProviderConfig { provider, model, api_key_ref }`. Rendre les backends mutuellement exclusifs par moteur (cf. `opencode_backend_is_consistent`, `domain/src/profile.rs:363-364,1224`). **Décision Architect** : nouveau VO vs réutiliser `AgentProfile.model` (voir §6). - **B. Renderers de config** — `codex_config_toml` écrit `model` (+ `model_provider` si requis par la sémantique codex) ; `claude_settings_seed` écrit la clé `model`. - **C. Use cases / persistance** — `SaveCodexProviderProfile` / `SaveClaudeProviderProfile` miroirs de `SaveOpenCodeProviderProfile`, même SecretRef pour la clé scellée. - **D. UI / wizard** — duplication de profils Codex/Claude comme OpenCode (catalogue providers, sélection modèle, clé scellée). Réutiliser `provider_catalogue` + picker existants. - **E. QA** — assert headless + TUI utilisent le modèle du profil (voir §5). ## 5. Invariants (à respecter, à tester) - **Source de vérité unique** : le modèle vient du profil AI, écrit dans le fichier de config isolé du run dir, lu par headless **et** TUI au lancement. - **Isolation préservée** : Codex via `CODEX_HOME` (rien ne change) ; Claude via project-local override (rien ne change). Pas d'accès au home global pour le modèle. - **`/model` en cours de session TUI ne corrompt pas le headless** (acceptable : ne concerne que le process PTY en cours ; le prochain lancement réapplique le défaut du profil). - **Non-régression OpenCode** : rendu `opencode.json` byte-identique (rien ne touche ce chemin). - **Non-régression permissions** : `codex_config_toml` et `claude_settings_seed` continuent d'écrire `mcp`/`sandbox`/`trust`/`approval` comme aujourd'hui (le `model` s'ajoute). ## 6. Questions ouvertes pour Architect (à trancher avant DevBackend) 1. **VO** : créer `CodexProviderConfig`/`ClaudeProviderConfig` (homogène à OpenCode) **ou** consommer le champ existant `AgentProfile.model` (code mort) ? Recommandation Main : nouveaux VO pour rester isomorphe à OpenCode (provider + clé scellée), déprécier `AgentProfile.model`. 2. **Codex `model_provider`** : la config codex distingue `model` et `model_provider`. Faut-il exposer les deux au profil, ou `model` seul suffit (provider implicite) ? 3. **Claude** : clé `model` dans `settings.local.json` suffit, ou faut-il gérer aussi la clé API Anthropic du profil (SecretRef) pour que le modèle soit réellement joignable ? 4. **Catalogue providers** : quels providers exposer pour Codex (lié OpenAI) et Claude (Anthropic) ? Réutiliser `provider_catalogue.rs` ou catalogue dédié par moteur ? 5. **Sémantique TUI** : confirmer qu'aucune CLI n'écrase `config.toml`/`settings` au démarrage (risque équivalent au « gate refresh » du ticket #98 côté OpenCode). ## 7. Périmètre QA — 2 couches (cf. méthodologie #98) - **Couche 1 (unitaire pure)** : le rendu `codex_config_toml` contient la clé `model` attendue ; `claude_settings_seed` contient `"model"` attendue ; non-régression byte-identique du reste (mcp/sandbox/trust/approval) ; exclusion mutuelle des backends. - **Couche 2 (intégration gated)** : spawn réel `codex exec` et `claude -p` sur un profil avec modèle X → assert le modèle actif est X (pas le défaut binaire). Vérifier côté TUI aussi (modèle exposé au lancement). **Gate §6.5** à lever. ## 8. Hors périmètre (exclu de ce ticket) - Override **runtime** du modèle à l'appel (`idea_ask_agent` porterait un modèle) — autre lot. - Providers distants SSH/WSL (ne concerne que le spawn local). - Détail de la `provider_catalogue` au-delà de la réutilisation (fast-follow). --- ## Contexte de mise à jour - Cadrage Main après vérification empirique CLI (codex 0.145.0, claude 2.1.220). - Lié à #98 (relatesTo) — même famille « modèle au spawn ». - Prochaine étape cycle : **Architect** (valide ports/VO + tranche §6) → **Git** (branche) → **DevBackend** (lots A-C) + **DevFrontend** (lot D) → **QA** (2 couches) → **Git** (commit).