- #65: update policies + per-agent version pinning - add settings.update_policy (stable/latest/skip) - add AgentDef.pin_version - honor both in update_cmd - add update_policy tests - #69: REPL color theme CLI command - add am theme [name] (show/switch) - persist selected theme to config - #72: doctor checks local model runtimes - verify ollama and llama-server on PATH - for ollama, also check server responds (ollama ls) Version 0.4.4
20 KiB
🏗️ Document d'architecture — agent-manager (am)
Ce document décrit la conception, le fonctionnement et les fonctionnalités de agent-manager (binaire
am), un CLI Rust multiplateforme pour gérer des agents IA de coding locaux.📦 Version :
0.4.4· 🦀 Rust 2021 · ✅ Windows · ✅ Linux · ✅ macOS
🎯 Vue d'ensemble
am est un gestionnaire d'agents IA de coding qui permet de :
- 📋 Découvrir et lister plus de 72 agents via un catalogue YAML embarqué
- 📦 Les installer avec 9 méthodes différentes (npm, pip, uv, cargo, go, bun, curl, binaire, git)
- 🚀 Les démarrer, arrêter, redémarrer en avant-plan ou en arrière-plan
- 🔍 Observer leur état, leurs logs, leurs statistiques d'utilisation
- 🛠️ Gérer dépendances, alias, groupes, profils, secrets, favoris et annotations
Le tout sans toucher au système : chaque agent est installé dans un répertoire utilisateur isolé.
🧩 Architecture globale
flowchart TB
subgraph UI["🖥️ Interfaces utilisateur"]
CLI["Ligne de commande<br/>clap v4"]
REPL["Shell interactif<br/>rustyline"]
TUI["Dashboard TUI<br/>ratatui + crossterm"]
end
subgraph CORE["⚙️ Noyau applicatif"]
APP["App<br/>contexte partagé"]
CLI_DEF["cli.rs<br/>définition des commandes"]
CMD["commands/<br/>dispatch"]
end
subgraph DATA["💾 Données persistantes"]
CONFIG["Configuration YAML<br/>embarquée + utilisateur"]
CATALOG["Catalog<br/>index agents/alias/groupes"]
STATE["StateStore<br/>state.json"]
EVENTS["Journal JSONL<br/>events-YYYYMM.jsonl"]
CACHE["Probe cache<br/>probe-cache.json"]
end
subgraph EXEC["🔧 Exécution"]
RUNNER["Runner trait<br/>système / mock"]
INSTALLERS["installers/<br/>9 méthodes"]
DEPS["deps.rs<br/>vérification dépendances"]
PROCESS["process.rs<br/>PID / signaux"]
end
subgraph OBS["👁️ Observation"]
PROBE["probe.rs<br/>détection agents externes"]
DASH["dashboard.rs<br/>agrégation"]
STATS["stats.rs<br/>statistiques"]
SESSIONS["sessions.rs<br/>registre sessions"]
end
CLI --> APP
REPL --> APP
TUI --> APP
APP --> CLI_DEF
APP --> CONFIG
APP --> CATALOG
APP --> STATE
APP --> EVENTS
APP --> CACHE
CMD --> RUNNER
CMD --> INSTALLERS
CMD --> DEPS
CMD --> PROCESS
CMD --> PROBE
CMD --> DASH
CMD --> STATS
CMD --> SESSIONS
🚀 Flux d'exécution d'une commande
sequenceDiagram
autonumber
participant User
participant main as main.rs
participant lib as lib.rs
participant help as help.rs
participant cli as cli.rs
participant app as app.rs
participant cfg as config.rs
participant state as state.rs
participant cmd as commands/mod.rs
participant impl as commands/xxx_cmd.rs
User->>main: am install jcode
main->>lib: main_entry()
lib->>lib: spawn thread 8 Mo
lib->>help: intercept(-h/--help) ?
help-->>lib: None
lib->>cli: Cli::parse()
cli-->>lib: Cli { command: Install {...} }
lib->>app: App::from_cli(cli)
app->>cfg: load() config embarquée + user
cfg-->>app: Config
app->>state: StateStore::new()
state-->>app: state.json chargé
app-->>lib: App
lib->>cmd: commands::execute(&app)
cmd->>impl: install_cmd::run(...)
impl->>impl: vérifier dépendances, installer
impl->>state: persister
impl->>app: emit(event install)
impl-->>cmd: Ok(0)
cmd-->>lib: 0
lib-->>main: code sortie
📁 Structure du code source
src/
├── main.rs 🚪 Point d'entrée
├── lib.rs 🧭 main_entry(), doc du crate
├── cli.rs 📋 Définition clap de toutes les commandes
├── app.rs 🧰 Contexte App (config, state, paths, logger, theme)
├── config.rs ⚙️ Schéma YAML, chargement, fusion, validation
├── catalog.rs 🔍 Index agents + recherche fuzzy + suggestions
├── state.rs 💾 Base JSON des installations et annotations
├── events.rs 📝 Journal d'événements JSONL
├── runner.rs 🏃 Trait d'exécution système / mock
├── process.rs ⚙️ Lancement, arrêt, signaux des processus
├── deps.rs ✅ Vérification et auto-installation des dépendances
├── toolchain.rs 🖥️ Détection OS / gestionnaire de paquets
├── download.rs ⬇️ Téléchargement, checksums, extraction
├── probe.rs 🔎 Détection des agents externes sur le PATH
├── dashboard.rs 📊 Données agrégées du dashboard
├── ps.rs 🧮 Table des processus
├── context.rs 📂 Contexte du projet courant
├── repl.rs 💬 Shell interactif
├── shell.rs 🐚 Gestion des shells supportés
├── help.rs ❓ Aide Nushell-style
├── output.rs 🖨️ Logger et rendu
├── tables.rs 📋 Rendu tabulaire
├── theme.rs 🎨 Thèmes de couleur
├── history.rs ⏪ Historique des commandes
├── sessions.rs 📅 Registre des sessions
├── projects.rs 🗂️️ Agrégation par projet
├── hooks.rs 🪝 Hooks de cycle de vie
├── secrets.rs 🔒 Gestion des secrets (keyring OS)
├── version.rs 🏷️ Informations de version
├── commands/ 📦 35 modules, un par commande
└── installers/ 📦 9 installateurs spécialisés
⚙️ Configuration : catalogue YAML extensible
Hiérarchie de chargement
flowchart LR
EMB["📦 config.yaml<br/>embarqué dans le binaire"] --> MERGE["🔀 Fusion"]
USER["👤 ~/.config/agent-manager/config.yaml"] --> MERGE
LOCAL["📂 ./agent-manager.yaml"] --> MERGE
FLAG["⚡ --config <file>"] --> MERGE
MERGE --> EFFECTIVE["✅ Configuration effective"]
Priorité (la plus prioritaire en dernier) :
config.yamlembarqué (catalogue par défaut, ~72 agents)~/.config/agent-manager/config.yaml./agent-manager.yaml(configuration locale par projet)--config <fichier>
Schéma de configuration
version: "1.0"
settings:
install_dir: null # ~/.local/share/agent-manager/agents
log_dir: null # ~/.local/state/agent-manager/logs
default_shell: null # shell utilisateur par défaut
auto_install_deps: true # proposer d'installer les dépendances manquantes
confirm_before_run: true # confirmer avant les scripts d'installation
stop_timeout_secs: 5 # délai SIGTERM → SIGKILL
self_update_repo: Projets/agent-manager
self_update_base_url: https://git.dracodev.net/api/v1
theme: null
hooks:
on_install: []
on_start: []
on_stop: []
on_update: []
aliases:
cc: claude-code
gemini: gemini-cli
groups:
dev: [claude-code, aider, codex]
include:
- ./extra-agents.yaml
agents:
- name: claude-code
display_name: "Claude Code"
description: "..."
category: coding-agent
website: https://github.com/anthropics/claude-code
install:
type: npm
package: "@anthropic-ai/claude-code"
dependencies:
- { name: node, min_version: "18.0.0" }
run: claude
tags: [anthropic, assistant]
profiles:
dev:
agent: claude-code
env: { API_ENV: dev }
args: [--verbose]
projects:
mon-projet:
root: ~/projets/mon-projet
default_agent: claude-code
env: { KEY: value }
Définition d'un agent (AgentDef)
| Champ | Description |
|---|---|
name |
Identifiant unique (slug) |
display_name |
Nom lisible |
description |
Description longue |
category |
Catégorie (coding-agent, assistant, local-first...) |
website |
URL du projet |
install |
Spécification d'installation |
dependencies |
Outils requis (node, python, go...) avec version min |
run |
Commande de lancement |
args |
Arguments par défaut |
env |
Variables d'environnement par défaut |
tags |
Tags pour recherche/filtrage |
installable |
false pour les agents SaaS/Desktop |
platforms |
Restriction linux/macos/windows |
Méthodes d'installation supportées
| Type | Fichier | Principe |
|---|---|---|
npm |
installers/npm.rs |
npm install -g --prefix <root> |
bun |
installers/npm.rs |
bun install -g |
pip / uv |
installers/pipuv.rs |
virtualenv privé dans install_dir |
cargo |
installers/cargo.rs |
cargo install --root |
go |
installers/golang.rs |
go install avec GOBIN local |
curl |
installers/script.rs |
Télécharge et exécute un script |
binary |
installers/binary.rs |
Release GitHub/Gitea → extraction archive |
git |
installers/git.rs |
Clone + build + binary_path |
💾 Gestion des états
state.json — base d'installation locale
Format JSON version 3, atomique (écriture .tmp + rename).
{
"version": 3,
"installed": {
"jcode": {
"name": "jcode",
"version": "0.76.0",
"method": "binary",
"directory": ".../agents/jcode",
"binaries": ["jcode"],
"pid": null,
"installed_at": "...",
"updated_at": "..."
}
},
"annotations": {
"jcode": {
"favorite": true,
"note": "mon agent préféré",
"tags": ["perso"]
}
}
}
Journal d'événements JSONL
- Un fichier par mois :
events-YYYYMM.jsonl - Append-only, horodaté
- Types d'événements :
start,stop,run,install,update,uninstall,doctor,config,repl,shell,annotate - Les secrets ne sont jamais journalisés
- Source de vérité pour les statistiques, sessions, projets et timeline
Cache de sondes
probe-cache.json évite de re-scanner le PATH à chaque commande pour détecter les agents externes et leurs versions.
🛡️ Gestion des dépendances
flowchart LR
INSTALL["am install jcode"] --> CHECK["deps::check_dep"]
CHECK --> MISSING{Manquant ?}
MISSING -->|Oui| DETECT["toolchain::detect OS"]
DETECT --> COMMANDS["toolchain::install_commands"]
COMMANDS --> PROMPT["Proposer la commande"]
PROMPT --> AUTO["Exécuter si --yes"]
AUTO --> INSTALL2["installers::run_install"]
MISSING -->|Non| INSTALL2
deps.rsvérifie chaque dépendance via<outil> --versiontoolchain.rsdétecte l'OS et le gestionnaire de paquets :- Windows :
scoop→winget - Linux :
apt/dnf/pacman/apk - macOS :
brew
- Windows :
- Si
auto_install_deps: true,ampropose et peut exécuter la commande d'installation - Les dépendances de l'agent (modules npm/pip) restent isolées dans le répertoire
install_dir
⚡ Gestion des processus
flowchart TB
START["am start <agent>"] --> MODE{Mode ?}
MODE -->|Foreground| FG["Attache au terminal<br/>Ctrl-C pour quitter"]
MODE -->|Background| BG["spawn_background()"]
BG --> LOG["Redirection stdout/stderr<br/>vers log agent"]
LOG --> PID["Enregistrement PID<br/>dans state.json"]
PID --> EVENT["Émission événement start"]
STOP["am stop <agent>"] --> SIGTERM["SIGTERM"]
SIGTERM --> WAIT{"Processus terminé ?"}
WAIT -->|Non| SIGKILL["SIGKILL après timeout"]
WAIT -->|Oui| CLEAN["PID effacé"]
- Démarrage avant-plan (
-f) ou arrière-plan (-b,--background) - Variables d'environnement injectées via
--env KEY=VALUE - Secrets via
--env KEY=@secret(résolu depuis le trousseau OS) - Arrêt gracieux avec timeout configurable (défaut 5 s)
- Notifications desktop optionnelles (
--notify)
📋 Commandes détaillées
🔍 Découvrir
| Commande | Description |
|---|---|
am list |
Agents installés + détectés sur le PATH |
am list --all |
Tout le catalogue avec état |
am search <mot> |
Recherche fuzzy avec suggestions |
am info <agent> |
Fiche détaillée |
am status [agent] |
État, version, PID, logs |
📦 Cycle de vie
| Commande | Description |
|---|---|
am install <agent> |
Installe un agent et ses dépendances |
am install <agent> --method pip |
Choisit la méthode |
am uninstall <agent> [--purge] |
Désinstalle et nettoie |
am update <agent> / --all |
Met à jour |
am start [agent] |
Lance en avant-plan |
am start <agent> -b |
Lance en arrière-plan |
am stop <agent> |
Arrêt gracieux |
am restart <agent> |
Redémarrage |
am run <agent> [args...] |
Exécution directe sans gestion de PID |
👁️ Observer
| Commande | Description |
|---|---|
am logs <agent> |
Tail du log agent |
am log [agent] |
Journal des événements am |
am timeline |
Vue chronologique unifiée |
am sessions [agent] |
Registre des sessions |
am stats [agent] --period 7d |
Statistiques d'utilisation |
am top --period 30d |
Top 10 agents |
am report --last-week |
Rapport markdown |
am projects [nom] |
Agents par projet |
am dashboard |
Dashboard TUI temps réel |
am watch <agent> --restart |
Supervision et relance automatique |
🎯 Personnaliser
| Commande | Description |
|---|---|
am favorite <agent> |
Marquer comme favori |
am note <agent> <texte> |
Ajouter une note |
am tag <agent> <tag> |
Taguer |
am tags [agent] |
Lister les tags |
am profile list/show <name> |
Profils d'environnement |
am alias add <nom> <cible> |
Créer un alias |
am secret set <nom> --agent <a> --value <v> |
Secret dans le trousseau |
🛠️ Système
| Commande | Description |
|---|---|
am doctor [--fix] |
Diagnostic environnement |
am config show/path/edit/validate/set |
Gestion config |
am completion <shell> |
Script de complétion |
am man [commande] |
Page de manuel |
am open <agent> |
Ouvrir le répertoire d'installation |
am export/import |
Sauvegarde/restauration |
am self-update [--check] |
Mise à jour de am |
am self-uninstall |
Désinstallation complète |
am version |
Version et build |
am (sans commande) |
REPL interactif |
🌐 Options globales
Disponibles avant ou après la sous-commande.
| Option | Effet |
|---|---|
-c, --config <FILE> |
Fichier de configuration alternatif |
-v, --verbose |
Affiche chaque commande exécutée |
-q, --quiet |
Seules les erreurs sont affichées |
-y, --yes |
Oui à toutes les confirmations |
--dry-run |
Simulation sans modification |
--json |
Sortie JSON structurée |
--no-color |
Désactive les couleurs |
--theme <THEME> |
Thème de couleur |
🎨 Fonctionnalités avancées
Alias
aliases:
cc: claude-code
gemini: gemini-cli
am start cc démarre claude-code.
Groupes
groups:
dev: [claude-code, aider, codex]
am start group:dev démarre tous les agents du groupe en arrière-plan.
Profils d'environnement
profiles:
dev:
agent: claude-code
env: { API_ENV: dev }
args: [--verbose]
am start --profile dev lance claude-code avec les variables et arguments du profil.
Projets
projects:
mon-projet:
root: ~/projets/mon-projet
default_agent: claude-code
Dans le répertoire du projet, am start sans argument lance l'agent par défaut du projet.
Secrets
Les secrets sont stockés dans le trousseau du système d'exploitation (via keyring), jamais en clair dans la config.
am secret set OPENAI_API_KEY --agent claude-code --value sk-...
am start claude-code --env OPENAI_API_KEY=@secret
Hooks
Commandes exécutées automatiquement aux étapes clés du cycle de vie :
on_installon_starton_stopon_update
Définissables globalement dans settings.hooks ou par projet.
Shell interactif (REPL)
Lancé par am sans sous-commande :
- Complétion Tab personnalisée (commandes, agents, alias, groupes, flags, shells, thèmes)
- Historique des commandes
- Passerelle système : commandes inconnues exécutées dans le shell actif
- Commandes internes :
ls,dir,cd,ps,where,get,shell,theme,exit,/help - Bannière ASCII art
📊 Dashboard TUI
flowchart LR
DASH["am dashboard"] --> OVER["Overview"]
DASH --> ACT["Activité"]
DASH --> STATS["Statistiques"]
DASH --> SESS["Sessions"]
DASH --> PROJ["Projets"]
- Navigation :
Tab/←/→pour les onglets - Défilement :
j/kou flèches - Quitter :
q - Données agrégées depuis
state.json, le journal d'événements, les sessions et les projets
🧪 Tests
Organisation
- Tests unitaires : dans chaque module
src/*.rssous#[cfg(test)] - Tests d'intégration : dans
tests/
Fichiers de tests notables
| Fichier | Couverture |
|---|---|
annotations_test.rs |
Favoris, notes, tags |
config_test.rs |
Chargement/validation/fusion |
dashboard_test.rs |
Dashboard |
doctor_test.rs |
am doctor |
dry_run_test.rs |
Mode --dry-run |
events_test.rs |
Journal d'événements |
history_test.rs |
Historique |
process_test.rs |
Processus |
profiles_test.rs |
Profils |
projects_test.rs |
Projets |
sessions_test.rs |
Sessions |
stats_test.rs |
Statistiques |
Lancer les tests :
cargo test
📦 Packaging et distribution
dist/ Binaires précompilés
├── am-linux-x86_64
├── am-linux-aarch64
├── am-windows-x86_64.zip
├── am_0.4.3_amd64.deb
└── ...
packaging/ Scripts de packaging
├── deb/
├── rpm/
├── homebrew/
├── scoop/
└── winget/
completions/ Scripts de complétion
├── _am zsh
├── _am.ps1 PowerShell
├── am.bash bash
├── am.elv elvish
└── am.fish fish
man/ Pages de manuel générées
build.rsenregistre le commit et la branche git pouram versionscripts/build-release.ps1construit les releases multiplateformesscripts/render-manifests.ps1génère les manifests de packaging
🗂️️ Arborescence des données utilisateur
Windows
%LOCALAPPDATA%\agent-manager\
├── agents\ installations
├── logs\ logs agents
└── state\ state.json, events-*.jsonl, probe-cache.json
Linux
~/.local/share/agent-manager/ données
~/.local/state/agent-manager/ logs, state, events, cache
~/.config/agent-manager/ config.yaml
macOS
~/Library/Application Support/agent-manager/ données
~/.local/state/agent-manager/ logs, state, events, cache
~/.config/agent-manager/ config.yaml
Variables d'environnement de débogage/test :
AGENT_MANAGER_DATA: remplace le répertoire de donnéesAGENT_MANAGER_STATE: remplace le répertoire d'état
🔐 Sécurité
- Mode
--dry-rununiversel pour simuler sans modifier - Checksums
sha256pour les binaires téléchargés - Confirmation avant exécution des scripts d'installation
- Secrets dans le trousseau OS, jamais dans les logs ni le journal
- Installation isolée : aucune modification système
🔁 Résumé du flux de données
flowchart LR
CONFIG["📄 YAML config"] --> CATALOG["📚 Catalog"]
CATALOG --> INSTALL["📦 Installateurs"]
INSTALL --> STATE["💾 state.json"]
STATE --> PROCESS["⚙️ Processus"]
PROCESS --> EVENTS["📝 Journal JSONL"]
EVENTS --> STATS["📊 Stats / Dashboard"]
EVENTS --> SESSIONS["📅 Sessions"]
EVENTS --> PROJECTS["🗂️️ Projets"]
📚 Références
src/lib.rs:4: documentation d'architecture du cratesrc/cli.rs:24: options globalessrc/cli.rs:61: énumération des commandessrc/app.rs:16: structAppsrc/config.rs:25: structConfigsrc/config.rs:148: structAgentDefsrc/config.rs:241: enumInstallTypesrc/state.rs:12: structStateFilesrc/events.rs:57: structEventREADME.md: documentation utilisateur complète
Document généré pour agent-manager v0.4.3 🚀