Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,30 @@ Config MCP de référence :

---

## EPIC 7 — Absorption d'agent-vm dans le bundle (vendoring)

### T7.1 🔴 Vendoriser agent-vm dans vendor/vm/ ✅ implémenté
**But :** arrêter de cloner agent-vm depuis GitHub à chaque install. Copier les scripts au commit 6f20194 dans `vendor/vm/` du repo albert-code. Plus de clone, plus de dépendance réseau pour le moteur d'isolation.
**DoD :** `vendor/vm/` contient `agent-vm.sh`, `agent-vm.setup.sh`, `runtime.example.sh`, `LICENSE` (MIT, attribution Sylvain Zimmer), `VERSION`. Le repo albert-code est auto-suffisant. `bin/albert-code` + `install.sh` : `AGENT_VM_DIR` pointe vers `$SELF_DIR/vendor/vm`, plus de `AGENT_VM_REPO`.

### T7.2 🔴 Supprimer le shim et le nom « agent-vm » du PATH utilisateur ✅ implémenté
**But :** agent-vm n'est plus une commande utilisateur. Albert Code l'appelle en interne via `_vm()` helper après l'avoir sourcé. Plus de shim `agent-vm` sur le PATH, plus de sourçage dans `~/.zshrc`.
**DoD :** `install_agent_vm()` ne clone plus, ne pose plus de shim, ne modifie plus le rc. Vérifie seulement la présence de `vendor/vm/agent-vm.sh`. Nettoyage non-destructif : si un ancien shim ou sourçage traîne, propose de les retirer.

### T7.3 🔴 VM de base OpenCode-only (--preinstall) ✅ implémenté
**But :** `agent-vm setup` installait tous les harnais (Claude, Codex, Vibe, OpenCode). Albert Code n'a besoin que d'OpenCode. Passage de `--preinstall=node,gh,chromium,opencode`.
**DoD :** `check_base_vm()` et `phase_run()` appellent `_vm setup --preinstall=node,gh,chromium,opencode`. Migration : si une VM de base multi-harnais existe, l'utilisateur peut la garder ou la refaire.

### T7.4 🔴 chrome-devtools au niveau MCP, pas global VM ✅ implémenté
**But :** agent-vm écrivait chrome-devtools dans le `opencode.json` global de la VM. Ce MCP doit être géré au niveau projet (opt-in au setup, avec flags headless).
**DoD :** `vendor/vm/agent-vm.setup.sh` patché : le bloc OpenCode chrome-devtools est désactivé par défaut (`INSTALL_OPENCODE_MCP=0`). `config/opencode.template.json` et `scaffold_opencode_json` ajoutent `--headless=true --isolated=true` à la commande chrome-devtools.

### T7.5 🟠 UI sans « agent-vm » pour l'utilisateur ✅ implémenté
**But :** l'utilisateur ne voit plus « agent-vm » dans les messages, juste des références à « la VM isolée » / « le moteur de VM d'Albert Code ».
**DoD :** tous les messages utilisateur dans `lib/phases.sh`, `lib/ui.sh`, `install.sh`, `README.md` sont reformulés. Le nom « agent-vm » reste dans les commentaires de code, la LICENSE et `vendor/vm/`.

---

## EPIC 6 — Interface 3 verbes & simplification profils `<- AC-R014, AC-R015, AC-R016, AC-R017`

### T6.1 🔴 Commande `albert-code` à 3 verbes `<- AC-R014`
Expand Down
2 changes: 2 additions & 0 deletions FEEDBACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

---

| AC-R035 | ⚙️ | 🟠 | Absorption d'agent-vm dans le bundle : le code est vendored sous `vendor/vm/`, plus de clone GitHub, plus de shim `agent-vm` sur le PATH. Installation OpenCode-only (`--preinstall=node,gh,chromium,opencode`). chrome-devtools MCP géré au niveau projet (pas global VM). | Chantier technique 2026-07-07 | ✅ traité | `BACKLOG.md` EPIC 7 · `TESTS.md` S39 |

## Registre

| ID | Type | Sév | Retour | Source | Statut | Renvoi |
Expand Down
31 changes: 15 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@

⚠️ PROJET EXPÉRIMENTAL ⚠️

**Stack d'agentic coding souveraine pour l'État, en une commande : OpenCode + agent-vm + Albert API + skills de l'État + MCP.**
**Stack d'agentic coding souveraine pour l'État, en une commande : OpenCode + VM isolée + Albert API + skills de l'État + MCP.**

Albert Code assemble des briques existantes pour coder avec une IA souveraine, isolée, avec les standards de l'administration embarqués :

- **[Albert API](https://albert.api.etalab.gouv.fr)** : modèles souverains de l'État (hébergement SecNumCloud), provider OpenAI-compatible.
- **[agent-vm](https://github.com/sylvinus/agent-vm)** : sandbox Lima jetable. L'agent tourne en autonomie sans accès à l'hôte.
- **[agent-vm](https://github.com/sylvinus/agent-vm)** (vendored) : sandbox Lima jetable. L'agent tourne en autonomie sans accès à l'hôte.
- **[OpenCode](https://opencode.ai)** : le harness (assistant de code en terminal).
- **[Skills de l'État](https://github.com/etalab-ia/skills)** : DSFR, accessibilité (RGAA), sécurité, data.gouv (à la carte, choisis au setup).
- **MCP** : data.gouv, context7, playwright, chrome-devtools (à la carte, choisis au setup).
Expand All @@ -40,15 +40,15 @@ cd ~/albert-code
./install.sh
```

> Le chemin d'installation ne doit **pas contenir d'espace** (contrainte agent-vm/Lima, qui monte le répertoire de travail dans la VM).
> Le chemin d'installation ne doit **pas contenir d'espace** (contrainte du moteur de VM/Lima, qui monte le répertoire de travail dans la VM).

Après installation, tu disposes de la commande `albert-code` à 3 verbes :

| Verbe | Action |
|---|---|
| `albert-code install` | **1ʳᵉ fois** : bootstrap le poste (Lima, agent-vm, clés, skills). |
| `albert-code install` | **1ʳᵉ fois** : bootstrap le poste (Lima, VM isolée, clés, skills). |
| `albert-code setup` | **Par projet** : configure un projet (AGENTS.md + opencode.json + choix skills/MCP). |
| `albert-code run` | **Lancement** : crée la VM de base si absente, puis ouvre la bulle agent-vm. |
| `albert-code run` | **Lancement** : crée la VM de base si absente, puis ouvre la VM isolée. |

`install.sh` est **idempotent** et **non-destructif** : il amorce le poste (Phase A) et pose le shim `albert-code`. Ensuite, c'est `albert-code setup` puis `albert-code run`.

Expand All @@ -71,23 +71,23 @@ Les commandes exactes (avec tes valeurs) s'affichent à la fin de `albert-code s

### Ressources de la VM

Les défauts d'agent-vm (1 CPU / 3 GiB / 10 GiB) sont trop justes pour un agent de code. Albert Code applique par défaut `4 CPU / 8 GiB / 32 GiB`, surchargeables par variable d'environnement :
Les défauts du moteur de VM (1 CPU / 3 GiB / 10 GiB) sont trop justes pour un agent de code. Albert Code applique par défaut `4 CPU / 8 GiB / 32 GiB`, surchargeables par variable d'environnement :

```bash
AC_VM_CPUS=8 AC_VM_MEMORY=16 AC_VM_DISK=64 ./install.sh
```

| Variable | Défaut | Rôle |
|---|---|---|
| `AC_VM_CPUS` | `4` | CPU alloués (s'applique au lancement `agent-vm opencode`). |
| `AC_VM_CPUS` | `4` | CPU alloués (s'applique au lancement de la VM). |
| `AC_VM_MEMORY` | `8` (GiB) | RAM allouée (s'applique au lancement). |
| `AC_VM_DISK` | `32` (GiB) | Disque, fixé au 1er `agent-vm setup`, ne peut ensuite que grandir. |
| `AC_VM_DISK` | `32` (GiB) | Disque, fixé au 1er lancement, ne peut ensuite que grandir. |

**Garde-fou hôte** (lecture seule, macOS + Linux) : `install.sh` détecte les ressources de ta machine (`sysctl`/`nproc`) et ne propose jamais plus de ~la moitié du CPU/RAM hôte, même si `AC_VM_*` demande plus — pour ne pas sur-allouer sur un petit poste. Le disque n'est jamais rogné (sparse : alloué à l'usage, pas d'un coup) ; un avertissement s'affiche si l'espace libre est insuffisant.

### Push & PR depuis la VM

Par défaut, l'agent peut **committer** dans la VM mais **ni pusher ni ouvrir de PR** : agent-vm isole la bulle de tes credentials hôte (aucun SSH, aucun token). Pour l'autoriser, fournis un **token GitHub dédié**.
Par défaut, l'agent peut **committer** dans la VM mais **ni pusher ni ouvrir de PR** : la VM isole la bulle de tes credentials hôte (aucun SSH, aucun token). Pour l'autoriser, fournis un **token GitHub dédié**.

1. **Crée un PAT fine-grained** sur [github.com/settings/personal-access-tokens](https://github.com/settings/personal-access-tokens) :
- *Repository access* → seulement les dépôts que l'agent doit toucher (pas « All repositories »).
Expand All @@ -105,13 +105,13 @@ Par défaut, l'agent peut **committer** dans la VM mais **ni pusher ni ouvrir de
# --- /albert-code ---
```
Utilise ton **email noreply GitHub** ([settings/emails](https://github.com/settings/emails)) pour ne pas exposer ton email perso dans l'historique git.
3. **Relance la bulle** (`agent-vm opencode`). Le runtime du bundle branche alors automatiquement le credential helper (`gh auth setup-git`) et pose l'identité git. `git push` et `gh pr create` marchent depuis la VM.
3. **Relance la bulle** (`albert-code run`). Le runtime du bundle branche alors automatiquement le credential helper (`gh auth setup-git`) et pose l'identité git. `git push` et `gh pr create` marchent depuis la VM.

> Le token vit dans une bulle exposée au prompt-injection : garde-le **fine-grained, scopé, révocable**, et **relis chaque PR avant merge**. Un contenu malveillant pourrait pousser l'agent à en abuser dans la limite de sa portée — d'où les permissions minimales.

## Sécurité

- **Isolation noyau (Lima)** : l'agent n'a aucun accès à tes clés SSH, credentials, cookies ou sessions de l'hôte. La VM est jetable (`agent-vm rm`).
- **Isolation noyau (Lima)** : l'agent n'a aucun accès à tes clés SSH, credentials, cookies ou sessions de l'hôte. La VM est jetable.
- **Secrets** : les clés (`ALBERT_API_KEY`, `CONTEXT7_API_KEY`) ne sont jamais versionnées ni loggées ; elles sont persistées dans le `~/.zshenv` de la VM en `chmod 600`.
- **Risque résiduel (prompt-injection)** : un contenu malveillant (page web, issue, fichier) pourrait pousser l'agent à exfiltrer une clé par le réseau. Bonnes pratiques : clé Albert **dédiée et révocable** (pas ta clé maître), revue humaine de chaque PR avant merge, pas de données sensibles confiées à l'agent.

Expand All @@ -129,16 +129,15 @@ Par défaut, l'agent peut **committer** dans la VM mais **ni pusher ni ouvrir de
Pour changer le modèle par défaut d'un projet, édite `model` dans son `opencode.json`.
- **Config** : `opencode.json` de **portée projet** (jamais le global de l'utilisateur, qui peut avoir d'autres providers).
- **Skills** : `etalab-ia/skills` cloné dans un cache (`~/.config/opencode/.albert-skills-cache`) et symliqué dans le dossier scanné par OpenCode. Au `setup`, chaque skill est proposée en Y/N avec son objectif. La sélection est écrite dans `.albert-code/skills.txt` à la racine du projet. Au boot de la VM, `sync_skills` ne symlinke que les skills sélectionnées puis réconcilie (retire les symlinks des skills non sélectionnées, sans jamais toucher les skills perso). Sans manifeste `.albert-code/skills.txt`, toutes les skills sont installées (rétrocompat). Mise à jour à chaque démarrage de VM.
- **MCP** : les 4 connecteurs sont désormais **tous opt-in**. Au `setup`, chaque MCP est proposé en Y/N avec son objectif : `data-gouv` (accès aux données publiques), `context7` (doc à jour des librairies, clé API requise via https://context7.com/plans), `playwright` (navigateur headless), `chrome-devtools` (debug navigateur). Seuls les MCP acceptés sont écrits dans `opencode.json` du projet (`enabled:false` par défaut). Note : le MCP `chrome-devtools` peut aussi apparaître dans OpenCode même si non coché — il est préinstallé par agent-vm (outil d'isolation en amont) et n'est pas sous le contrôle d'Albert Code.
- **MCP** : les 4 connecteurs sont désormais **tous opt-in**. Au `setup`, chaque MCP est proposé en Y/N avec son objectif : `data-gouv` (accès aux données publiques), `context7` (doc à jour des librairies, clé API requise via https://context7.com/plans), `playwright` (navigateur headless), `chrome-devtools` (debug navigateur). Seuls les MCP acceptés sont écrits dans `opencode.json` du projet (`enabled:false` par défaut). Note : le MCP `chrome-devtools` peut aussi apparaître dans OpenCode même si non coché — il est préinstallé par le moteur d'isolation en amont et n'est pas sous le contrôle d'Albert Code.
- **Conventions** : `AGENTS.md` depuis `templates/AGENTS.default.md` (sécurité, plan mode, task management, code quality, git, accessibilité). Si le projet a déjà son `AGENTS.md`, il est conservé.

Docs : [OpenCode](https://opencode.ai/docs/fr) · [Albert API](https://doc.incubateur.net/alliance/albert-api) · [agent-vm](https://github.com/sylvinus/agent-vm) · [Skills État](https://github.com/etalab-ia/skills)

## Dépannage

- **`agent-vm: command not found` juste après l'install** → le shim est posé sur le PATH. Si vraiment absent, ouvre un nouveau terminal pour recharger le PATH.
- **`Base VM not found. Run 'agent-vm setup' first.`** → lance `agent-vm setup --disk 32` une seule fois (l'install le propose aussi automatiquement).
- **Je suis dans OpenCode mais pas connecté à Albert (pas de `/models`, `/mcp`, `/skills`)** → tu as lancé `agent-vm opencode` (ou `albert-code run`) dans un dossier **sans `opencode.json`** (ex. le dépôt albert-code lui-même, ou un projet jamais scaffoldé). Scaffolde d'abord : `cd <ton-projet> && albert-code setup`, puis relance `albert-code run`.
- **`Base VM not found`** → lance `albert-code run` une fois ; la VM de base se crée automatiquement.
- **Je suis dans OpenCode mais pas connecté à Albert (pas de `/models`, `/mcp`, `/skills`)** → tu as lancé `albert-code run` dans un dossier **sans `opencode.json`** (ex. le dépôt albert-code lui-même, ou un projet jamais scaffoldé). Scaffolde d'abord : `cd <ton-projet> && albert-code setup`, puis relance `albert-code run`.
- **Mon projet a déjà un `opencode.json`** → il est **conservé** (non-destructif). Vérifie qu'il contient le provider albert ; sinon Albert n'est pas câblé — ajoute à la main le bloc `provider.albert` + `model`/`small_model`.

## Désinstallation
Expand All @@ -153,7 +152,7 @@ Retire le bloc albert-code du runtime VM, le cache et les symlinks skills. Prés

Issues et PR bienvenues. Le dépôt suit ses propres conventions dans [`AGENTS.md`](AGENTS.md) ; le contexte et les décisions sont dans [`docs/PLAN.md`](docs/PLAN.md).

> **Développer Albert Code lui-même** : `cp config/opencode.template.json opencode.json` (déjà gitignoré) puis `agent-vm opencode` — `install.sh` ne scaffolde pas son propre dépôt.
> **Développer Albert Code lui-même** : `cp config/opencode.template.json opencode.json` (déjà gitignoré) puis lance `albert-code run` — `install.sh` ne scaffolde pas son propre dépôt.

---

Expand Down
15 changes: 15 additions & 0 deletions TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ et le bloc marqueur a disparu.
- Une description absente retourne chaîne vide (l'afficheur utilise « (aucune description) »).
**Validé le :** — (non exécuté).

## S39 — Absorption agent-vm : vendoring, OpenCode-only, chrome-devtools projet, pas de nom agent-vm dans l'UI ☐

**Préconditions :** dépôt albert-code sur branche `feat/absorb-agent-vm`.

**Étapes :**
1. Vérifier `vendor/vm/agent-vm.sh` + `vendor/vm/agent-vm.setup.sh` + `vendor/vm/VERSION` + `vendor/vm/LICENSE` présents.
2. `bash bin/albert-code install --dry-run` — vérifier qu'aucun message ne contient « agent-vm » (sauf commentaires de code).
3. `bash bin/albert-code setup --dry-run` — idem.
4. `bash bin/albert-code run --dry-run` — idem.
5. Vérifier que `config/opencode.template.json` contient `--headless=true --isolated=true` pour chrome-devtools.
6. Vérifier que `vendor/vm/agent-vm.setup.sh` contient `INSTALL_OPENCODE_MCP="${AGENT_VM_INSTALL_OPENCODE_MCP:-0}"`.
7. `bash tests/check_no_personal_paths.sh` — exit 0.

**Attendu :** aucun message utilisateur ne contient « agent-vm ». La VM de base se crée avec `--preinstall=node,gh,chromium,opencode`. chrome-devtools a les flags headless, n'est plus injecté globalement par agent-vm. Vérification chemin personnel OK.

---

## Critères d'acceptation v1 (Definition of Done globale)
Expand Down
9 changes: 4 additions & 5 deletions bin/albert-code
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ set -euo pipefail
SELF_DIR="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)"
LIB_DIR="$SELF_DIR/lib"

source "$LIB_DIR/ui.sh"
source "$LIB_DIR/phases.sh"

# --- Ressources VM (surchargeables) -------------------------------------------
AC_VM_CPUS="${AC_VM_CPUS:-4}"
AC_VM_MEMORY="${AC_VM_MEMORY:-8}"
AC_VM_DISK="${AC_VM_DISK:-32}"

AGENT_VM_DIR="${AGENT_VM_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/agent-vm}"
AGENT_VM_REPO="https://github.com/sylvinus/agent-vm.git"
AGENT_VM_DIR="${AGENT_VM_DIR:-$SELF_DIR/vendor/vm}"
RUNTIME_VM_FILE="$HOME/.agent-vm/runtime.sh"
ZSHENV="$HOME/.zshenv"

source "$LIB_DIR/ui.sh"
source "$LIB_DIR/phases.sh"

# --- Parsing des arguments -----------------------------------------------------
while [ $# -gt 0 ]; do
case "$1" in
Expand Down
2 changes: 1 addition & 1 deletion config/opencode.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
},
"chrome-devtools": {
"type": "local",
"command": ["npx", "-y", "chrome-devtools-mcp@latest"],
"command": ["npx", "-y", "chrome-devtools-mcp@latest", "--headless=true", "--isolated=true"],
"enabled": false
}
},
Expand Down
25 changes: 12 additions & 13 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#
# Après installation, utilise :
# albert-code setup → configurer un projet
# albert-code run → lancer la bulle agent-vm
# albert-code run → lancer la VM isolée
#
# Non-destructif : ne réinstalle rien déjà présent, n'écrase aucune config.
# Compatible bash 3.2 (macOS).
Expand All @@ -30,24 +30,23 @@ while [ $# -gt 0 ]; do
shift
done

# Source les phases (contient phase_a, phase_b, phase_run)
if [ -f "$LIB_DIR/phases.sh" ]; then
source "$LIB_DIR/phases.sh"
else
err "lib/phases.sh introuvable. Albert Code est-il complet ?"
exit 1
fi

# --- Ressources VM -----------------------------------------------------------
AC_VM_CPUS="${AC_VM_CPUS:-4}"
AC_VM_MEMORY="${AC_VM_MEMORY:-8}"
AC_VM_DISK="${AC_VM_DISK:-32}"

AGENT_VM_DIR="${AGENT_VM_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/agent-vm}"
AGENT_VM_REPO="https://github.com/sylvinus/agent-vm.git"
AGENT_VM_DIR="${AGENT_VM_DIR:-$SELF_DIR/vendor/vm}"
RUNTIME_VM_FILE="$HOME/.agent-vm/runtime.sh"
ZSHENV="$HOME/.zshenv"

# Source les phases (contient phase_a, phase_b, phase_run)
if [ -f "$LIB_DIR/phases.sh" ]; then
source "$LIB_DIR/phases.sh"
else
err "lib/phases.sh introuvable. Albert Code est-il complet ?"
exit 1
fi

# --- Détection ancien installeur (albert-code() dans shell rc) -----------------
_detect_old_albert_code_function() {
local rc_file="$1"
Expand Down Expand Up @@ -79,7 +78,7 @@ _remove_old_albert_code_function() {
}

# --- Exécution (shim + Phase A, rétrocompat) ----------------------------------
# Le shim doit être posé AVANT la VM de base (fragile). Si agent-vm setup
# Le shim doit être posé AVANT la VM de base (fragile). Si la création de VM
# échoue (429, réseau, etc.), la commande `albert-code` est quand même
# disponible pour un essai ultérieur. Cf. AC-R021.
banner
Expand All @@ -106,4 +105,4 @@ echo
title "C'est prêt. Bon code avec Albert."
echo
info "Utilise « albert-code setup » pour configurer un projet,"
info "ou « albert-code run » pour lancer la bulle."
info "ou « albert-code run » pour lancer la VM isolée."
Loading
Loading