Files
agent-manager/ARCHITECTURE.md
T

20 KiB
Raw Blame History

🏗️ 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.2 · 🦀 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) :

  1. config.yaml embarqué (catalogue par défaut, ~72 agents)
  2. ~/.config/agent-manager/config.yaml
  3. ./agent-manager.yaml (configuration locale par projet)
  4. --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.rs vérifie chaque dépendance via <outil> --version
  • toolchain.rs détecte l'OS et le gestionnaire de paquets :
    • Windows : scoop → winget
    • Linux : apt / dnf / pacman / apk
    • macOS : brew
  • Si auto_install_deps: true, am propose 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_install
  • on_start
  • on_stop
  • on_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 / k ou 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/*.rs sous #[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.2_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.rs enregistre le commit et la branche git pour am version
  • scripts/build-release.ps1 construit les releases multiplateformes
  • scripts/render-manifests.ps1 gé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ées
  • AGENT_MANAGER_STATE : remplace le répertoire d'état

🔐 Sécurité

  • Mode --dry-run universel pour simuler sans modifier
  • Checksums sha256 pour 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 crate
  • src/cli.rs:24 : options globales
  • src/cli.rs:61 : énumération des commandes
  • src/app.rs:16 : struct App
  • src/config.rs:25 : struct Config
  • src/config.rs:148 : struct AgentDef
  • src/config.rs:241 : enum InstallType
  • src/state.rs:12 : struct StateFile
  • src/events.rs:57 : struct Event
  • README.md : documentation utilisateur complète

Document généré pour agent-manager v0.4.2 🚀