bots-garden/sidekickspublic Fork
⑂ v1.2.0
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/sidekicks.git
git clone ssh://git@rickub.com/bots-garden/sidekicks.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
📦️ Create a release. 0a53b99 · on v1.2.0 · k33g · 2d ago
configuration.md · 250 lines · 16.6 KBmarkdown
Blame HistoryOpen raw

Référence : le fichier de configuration

Un fichier YAML décrit les agents avec lesquels Sidekicks peut converser, les channels créés au démarrage et les préférences. Les conversations, les messages et les sessions ACP n'y figurent pas (voir Architecture).

L'application le lit avec le package Go internal/config (milestone M1) : validation, valeurs par défaut, chemins, fichier par défaut, rechargement à chaque enregistrement.

Emplacement

Le fichier est cherché dans cet ordre ; la première source applicable l'emporte :

# Source Exemple
1 option de ligne de commande --config <chemin> sidekicks --config ~/agents/equipe.yaml
2 variable d'environnement SIDEKICKS_CONFIG SIDEKICKS_CONFIG=~/agents/equipe.yaml
3 le dernier fichier ouvert depuis l'application (Settings → Open… ou Recent…), conservé dans <dossier de config utilisateur>/sidekicks/preferences.json —
4 l'emplacement par défaut : <dossier de config utilisateur>/sidekicks/config.yaml macOS : ~/Library/Application Support/sidekicks/config.yaml, Linux : ~/.config/sidekicks/config.yaml

<dossier de config utilisateur> est celui de os.UserConfigDir() en Go. Si le fichier par défaut n'existe pas, Sidekicks le crée avec des commentaires qui expliquent chaque clé (issue #9).

Chemins

  • Un chemin relatif est résolu par rapport au dossier du fichier de configuration, jamais par rapport au dossier courant. Un dossier qui contient une configuration et ses agents peut donc être déplacé ou versionné avec git d'un seul tenant.
  • ~ en début de chemin désigne le dossier personnel de l'utilisateur.
  • command : un nom seul (mm, docker) est cherché dans le PATH ; tout ce qui contient / est un chemin, résolu comme ci-dessus.
  • args est transmis tel quel, sans réécriture : le processus de l'agent démarre dans son workspace, donc les arguments relatifs au workspace fonctionnent.

Clés

Racine

Clé Type Obligatoire Défaut Signification
version entier oui — Version du format ; seule 1 existe. Un format ultérieur l'incrémente, pour que Sidekicks puisse migrer ou refuser explicitement un ancien fichier.
ui objet non Préférences d'interface.
limits objet non Limites de ressources.
agents liste d'agents oui Les agents disponibles avec @nom. Peut être vide.
channels liste de channels non [] Channels créés au démarrage s'ils n'existent pas encore.

Les clés inconnues sont des erreurs, à tous les niveaux : une faute de frappe comme comand: doit être signalée, pas ignorée en silence.

ui

Clé Valeurs Défaut Signification
theme system, light, dark system Thème de couleurs ; system suit le système d'exploitation.
language en, fr en Langue de l'interface : ses libellés et les messages d'erreur de la configuration.

limits

Clé Type Défaut Signification
maxRunningAgents entier ≥ 1 2 Agents actifs en même temps. Chaque agent local garde un modèle en mémoire ; la valeur par défaut convient à un portable de 32 Go avec de petits modèles.
stopIdleAgentsAfter durée Go (30s, 10m, 1h30m), ou 0 (nombre ou texte) 10m Arrête un agent inutilisé depuis ce délai pour libérer sa mémoire. 0 ne l'arrête jamais.

Un agent

Clé Type Obligatoire Défaut Signification
name identifiant oui Minuscules, chiffres, -, _ ; commence par une lettre ; 32 caractères au plus. Sert dans @nom et /nom:commande. Unique.
title texte non name Nom affiché dans l'interface.
icon texte (un emoji ou une lettre) non Affiché à côté de l'agent. Un emoji est affiché tel quel ; sinon sa première lettre est affichée dans un rond coloré (la couleur dépend de name). Sans icon, le rond contient la première lettre de title.
description texte non Une phrase affichée dans la liste @.
command texte oui Programme qui sert ACP sur stdio.
args liste de textes non [] Ses arguments.
env dictionnaire texte → texte non Variables d'environnement supplémentaires.
afterStop liste de textes, au moins un non Commande lancée à chaque fin du processus de l'agent — arrêt, crash, arrêt pour faire de la place, ou fermeture de Sidekicks : le programme (un nom seul est cherché dans le PATH, un chemin est relatif à ce fichier), puis ses arguments. Elle tourne dans workspace avec env, 30 s au plus ; sa sortie va dans le journal de l'agent ; Sidekicks l'attend avant de se fermer. Un programme introuvable est un avertissement. Exemple : [../scripts/agents.sh, unload, alice] pour décharger le modèle.
workspace chemin non le dossier de la configuration Le dossier de l'agent : le processus y démarre et c'est le cwd de ses sessions ACP. mm y lit AGENTS.md et skills/.
protect liste de textes non Fichiers du dossier de l'agent que l'interface (onglet Files) ne peut ni modifier ni supprimer : chemins relatifs au dossier, ou motifs où * et ? remplacent des caractères d'un nom et ** un nombre quelconque de dossiers ([AGENTS.md, "skills/**"]). Un dossier qui contient un fichier protégé ne peut pas être supprimé. Toujours protégés, s'ils sont dans son dossier : AGENTS.md, skills/**, le fichier de configuration de l'agent (l'argument qui suit --config, -config ou serve acp dans args), et les fichiers à partir desquels runtime.lifecycle construit le conteneur ou la sandbox — le fichier Compose (après -f/--file, ou compose.yaml… sans lui), le Dockerfile du dossier des commandes pour un conteneur, le fichier d'environnement sbx (sbxenv.yaml ou celui nommé). Seule la configuration lève une protection ; l'agent lui-même, le terminal ou le Finder n'y sont pas soumis.
runtime objet non {type: local} Où tourne l'agent (voir ci-dessous).

runtime

Le runtime indique à Sidekicks comment atteindre les fichiers et le terminal de l'agent (panel Agents, issue #28). Il ne change pas la façon de démarrer l'agent : c'est le rôle de command et args.

type Clés supplémentaires Signification
local aucune L'agent tourne sur cet ordinateur ; workspace est un dossier local.
container container (obligatoire), workspacePath, lifecycle L'agent tourne dans un conteneur Docker ; fichiers et terminal passent par docker exec. Un conteneur arrêté est démarré avant l'agent.
sbx sandbox (obligatoire), workspacePath, lifecycle L'agent tourne dans une sandbox Docker (sbx) ; fichiers et terminal passent par sbx exec.

workspacePath est un chemin absolu dans le conteneur ou la sandbox ; par défaut, celui de workspace (le même chemin, comme avec un dossier monté). Comportement de chaque runtime : workspaces.

runtime.lifecycle (conteneur et sbx)

Commandes facultatives qui gèrent le conteneur ou la sandbox de l'agent (issues #47 et #48). Chaque commande est une liste : le programme (un nom seul est cherché dans le PATH, un chemin est relatif à ce fichier), puis ses arguments.

Clé Type Par défaut Signification
folder texte workspace Dossier où les commandes sont lancées. Relatif à ce fichier ; ~ est le dossier personnel.
create liste de textes, au moins un Crée le conteneur ou la sandbox. Avant de démarrer l'agent, Sidekicks vérifie qu'il existe (docker container inspect, sbx ls -q) ; sinon, il lance cette commande, puis vérifie à nouveau.
stop liste de textes, au moins un L'arrête. Proposé par ■ Arrêter le conteneur / ■ Arrêter la sandbox dans le panel Agents ; l'agent est arrêté d'abord.
remove liste de textes, au moins un Le supprime. Proposé par 🗑 Supprimer le conteneur / 🗑 Supprimer la sandbox dans le panel Agents, après confirmation ; l'agent est arrêté d'abord.

Une sandbox arrêtée n'a besoin de rien : sbx exec la démarre. Un conteneur arrêté est démarré par docker start, même sans lifecycle. Les commandes ne reçoivent aucune entrée (une commande qui pose une question échoue), tournent avec l'env de l'agent, et ce qu'elles affichent va dans le journal de l'agent, préfixé par sandbox: . Un create qui échoue met l'agent en état error avec la raison.

runtime:
  type: sbx
  sandbox: milo-sbx            # le name: du sbxenv.yaml
  lifecycle:
    folder: /Users/moi/agents/milo   # là où est sbxenv.yaml
    create: [sbx, env, create, --force]
    stop: [sbx, stop, milo-sbx]
    remove: [sbx, env, rm, --force]

Avec un fichier d'environnement qui ne s'appelle pas sbxenv.yaml, nommez-le : [sbx, env, create, dev.yaml, --force], [sbx, env, rm, dev.yaml, --force]. Sans fichier d'environnement, utilisez les commandes simples, par exemple remove: [sbx, rm, milo-sbx, --force].

Un conteneur d'un service Docker Compose (ce qu'écrit l'assistant quand un compose.yaml est déposé) :

runtime:
  type: container
  container: team-scout-1      # container_name, ou <projet>-<service>-1
  lifecycle:
    folder: /Users/moi/agents/team   # là où est compose.yaml
    create: [docker, compose, -f, compose.yaml, up, -d, --wait, scout]
    stop: [docker, compose, -f, compose.yaml, stop, scout]
    remove: [docker, compose, -f, compose.yaml, rm, --stop, --force, scout]

up --wait rend la main une fois le service démarré (en bonne santé, s'il a un healthcheck) ; rm --stop --force scout supprime seulement le conteneur de ce service, pas les autres services comme le ferait down. Sans Compose : create: [docker, run, -d, --name, scout-box, -v, "/Users/moi/agents/scout:/Users/moi/agents/scout", mon-image].

Un channel

Clé Type Obligatoire Signification
name texte, 1 à 64 caractères oui Affiché #nom. Unique. Accents et espaces autorisés.
description texte non Affichée au survol du nom du channel, et dans un channel vide.
agents liste de noms d'agents non Membres du channel. Un agent de la liste qui n'est pas encore membre est ajouté au démarrage et au rechargement du fichier ; le retirer de la liste ne retire rien. Sans doublon.

Un channel déclaré ici est créé au démarrage, ou au rechargement du fichier, si aucun channel ne porte encore ce nom (sans tenir compte de la casse) ; il vit ensuite dans l'application comme n'importe quel channel, et peut y être renommé ou supprimé. Le retirer du fichier ne le supprime pas (supprimer un historique doit être une action explicite de l'utilisateur). Chaque fichier de configuration a ses propres channels et son propre historique (où il est gardé).

Ce qu'écrit l'assistant « Ajouter un agent »

L'assistant ajoute une entrée à la fin de agents ; le reste du fichier, commentaires compris, est gardé. Rien n'est écrit si le résultat ne serait pas valide.

Champ de l'assistant Écrit comme
Nom utilisé avec @, Nom affiché, Icône, Ce qu'il fait name, title, icon, description (champs vides omis)
Dossier de l'agent workspace, tel que saisi (~ et chemins relatifs résolus comme tout workspace)
Sur cet ordinateur command: <programme>, args: [<arguments>]
Dans un conteneur Docker command: docker, args: [exec, -i, <conteneur>, <programme>, <arguments>], runtime: {type: container, container: <conteneur>}
Dans une sandbox sbx command: sbx, args: [exec, -i, <sandbox>, <programme>, <arguments>], runtime: {type: sbx, sandbox: <sandbox>}
Dossier où les commandes sont lancées, Commande qui crée / arrête / supprime la sandbox (sbx uniquement) runtime.lifecycle: {folder, create, stop, remove}, chaque commande découpée comme les arguments ; omis si aucune commande n'est donnée

Les arguments sont découpés comme le ferait un shell dans les cas simples : les espaces séparent, les guillemets simples ou doubles regroupent. Le programme est découpé de la même façon, sauf si c'est un chemin (il commence par / ou ~) : docker agent donne command: docker et agent comme premier argument.

Quand le fichier de configuration de l'agent est indiqué (déposé ou choisi, où que tourne l'agent : une sandbox sbx partage les dossiers de l'hôte au même chemin, et un conteneur doit monter le dossier du fichier au même chemin), le dossier de l'agent est celui du fichier, et les arguments utilisent le chemin absolu du fichier :

Programme Arguments
mm --acp --config <fichier>
docker-agent serve acp <fichier>
docker agent serve acp <fichier> (écrit command: docker, args: [agent, serve, acp, <fichier>])
tout autre inchangés : tapés par l'utilisateur

Règles vérifiées par le chargeur, pas par le schéma

JSON Schema ne sait pas les exprimer ; le chargeur de configuration (issue #9) les vérifie et les signale comme les erreurs de schéma :

  1. les noms d'agents sont uniques ;
  2. les noms de channels sont uniques ;
  3. chaque nom de la liste agents d'un channel est le nom d'un agent ;
  4. command existe (dans le PATH, ou comme fichier) — signalé comme avertissement, car un agent peut être installé plus tard.

Messages d'erreur

Chaque erreur indique la ligne et la clé, dans la langue de l'interface, et dit comment corriger. Exemples avec l'interface en français (language: fr) :

Problème Message
name: Alice Smith ligne 12 — agents[0].name : « Alice Smith » n'est pas un nom valide : minuscules, chiffres, « - » ou « _ », sans espace, en commençant par une lettre (ex. « alice »)
comand: mm ligne 14 — agents[0].comand : clé inconnue « comand » ; vouliez-vous dire « command » ?
command absente ligne 3 — agents[0] : il manque la clé « command »

Exemple complet

version: 1

ui:
  theme: system
  language: fr

limits:
  maxRunningAgents: 2
  stopIdleAgentsAfter: 10m

agents:
  - name: alice
    title: Alice (assistante)
    icon: "👩"
    description: Questions simples, sans outils
    command: mm
    args: ["-acp", "-config", "agent.yaml"]
    workspace: ./agents/alice

  - name: garfield
    title: Garfield (traducteur)
    icon: "🐮"
    command: mm
    args: ["-acp", "-config", "agent.yaml"]
    workspace: ./agents/garfield

  - name: translator-sbx
    title: Traducteur (sandbox)
    command: sbx
    args: ["exec", "-i", "mm-translator", "mm", "-acp"]
    workspace: ./agents/translator/workspace
    runtime:
      type: sbx
      sandbox: mm-translator

channels:
  - name: général
    agents: [alice]
  - name: traductions
    agents: [garfield]

sbx exec -i <sandbox> <programme> lance l'agent dans la sandbox ; sbx monte le dossier de l'hôte au même chemin, donc workspace est aussi le dossier vu à l'intérieur. Cet exemple est aussi un cas de test (schema/testdata/valid/spec-example.yaml).

Package Go schema

git.rickub.com/bots-garden/sidekicks/schema embarque le JSON Schema et valide des documents avec lui.

Identifiant Signature Description
ConfigSchemaURL const string Le $id du schéma : https://git.rickub.com/bots-garden/sidekicks/schema/config.schema.json.
ConfigSchema func() []byte Une copie du document JSON Schema.
ValidateConfig func(document []byte) error nil si le document YAML respecte le schéma ; une erreur de syntaxe YAML s'il ne peut pas être lu ; sinon une *jsonschema.ValidationError qui liste toutes les violations.
if err := schema.ValidateConfig(content); err != nil {
    fmt.Println("configuration invalide :", err)
}

Une violation telle que la renvoie ValidateConfig :

jsonschema validation failed with 'https://git.rickub.com/bots-garden/sidekicks/schema/config.schema.json#'
- at '/agents/0': additional properties 'comand' not allowed
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# Référence : le fichier de configuration

- **Version du format** : 1
- **Issue** : [#4 — Spécifier le format du fichier de configuration YAML](../../../.tickets/issues/0004-specifier-le-format-du-fichier-de-configuration.yaml)
- **Schéma** : [schema/config.schema.json](../../../schema/config.schema.json) (JSON Schema 2020-12), vérifié par `go test ./schema`
- **Exemple** : [examples/test-agents.yaml](../../../examples/test-agents.yaml)

Un fichier YAML décrit les agents avec lesquels Sidekicks peut converser, les channels créés au démarrage et les préférences. Les conversations, les messages et les sessions ACP n'y figurent pas (voir [Architecture](../explanation/architecture.md)).

L'application le lit avec le package Go `internal/config` (milestone M1) : validation, valeurs par défaut, chemins, fichier par défaut, rechargement à chaque enregistrement.

## Emplacement

Le fichier est cherché dans cet ordre ; la première source applicable l'emporte :

| # | Source | Exemple |
| --- | --- | --- |
| 1 | option de ligne de commande `--config <chemin>` | `sidekicks --config ~/agents/equipe.yaml` |
| 2 | variable d'environnement `SIDEKICKS_CONFIG` | `SIDEKICKS_CONFIG=~/agents/equipe.yaml` |
| 3 | le dernier fichier ouvert depuis l'application (Settings → **Open…** ou **Recent…**), conservé dans `<dossier de config utilisateur>/sidekicks/preferences.json` | — |
| 4 | l'emplacement par défaut : `<dossier de config utilisateur>/sidekicks/config.yaml` | macOS : `~/Library/Application Support/sidekicks/config.yaml`, Linux : `~/.config/sidekicks/config.yaml` |

`<dossier de config utilisateur>` est celui de `os.UserConfigDir()` en Go. Si le fichier par défaut n'existe pas, Sidekicks le crée avec des commentaires qui expliquent chaque clé (issue #9).

## Chemins

- Un chemin relatif est résolu **par rapport au dossier du fichier de configuration**, jamais par rapport au dossier courant. Un dossier qui contient une configuration et ses agents peut donc être déplacé ou versionné avec git d'un seul tenant.
- `~` en début de chemin désigne le dossier personnel de l'utilisateur.
- `command` : un nom seul (`mm`, `docker`) est cherché dans le `PATH` ; tout ce qui contient `/` est un chemin, résolu comme ci-dessus.
- `args` est transmis tel quel, sans réécriture : le processus de l'agent démarre dans son `workspace`, donc les arguments relatifs au workspace fonctionnent.

## Clés

### Racine

| Clé | Type | Obligatoire | Défaut | Signification |
| --- | --- | --- | --- | --- |
| `version` | entier | oui | — | Version du format ; seule `1` existe. Un format ultérieur l'incrémente, pour que Sidekicks puisse migrer ou refuser explicitement un ancien fichier. |
| `ui` | objet | non | | Préférences d'interface. |
| `limits` | objet | non | | Limites de ressources. |
| `agents` | liste d'agents | oui | | Les agents disponibles avec `@nom`. Peut être vide. |
| `channels` | liste de channels | non | `[]` | Channels créés au démarrage s'ils n'existent pas encore. |

Les clés inconnues sont des **erreurs**, à tous les niveaux : une faute de frappe comme `comand:` doit être signalée, pas ignorée en silence.

### `ui`

| Clé | Valeurs | Défaut | Signification |
| --- | --- | --- | --- |
| `theme` | `system`, `light`, `dark` | `system` | Thème de couleurs ; `system` suit le système d'exploitation. |
| `language` | `en`, `fr` | `en` | Langue de l'interface : ses libellés et les messages d'erreur de la configuration. |

### `limits`

| Clé | Type | Défaut | Signification |
| --- | --- | --- | --- |
| `maxRunningAgents` | entier ≥ 1 | `2` | Agents actifs en même temps. Chaque agent local garde un modèle en mémoire ; la valeur par défaut convient à un portable de 32 Go avec de petits modèles. |
| `stopIdleAgentsAfter` | durée Go (`30s`, `10m`, `1h30m`), ou `0` (nombre ou texte) | `10m` | Arrête un agent inutilisé depuis ce délai pour libérer sa mémoire. `0` ne l'arrête jamais. |

### Un agent

| Clé | Type | Obligatoire | Défaut | Signification |
| --- | --- | --- | --- | --- |
| `name` | identifiant | oui | | Minuscules, chiffres, `-`, `_` ; commence par une lettre ; 32 caractères au plus. Sert dans `@nom` et `/nom:commande`. **Unique.** |
| `title` | texte | non | `name` | Nom affiché dans l'interface. |
| `icon` | texte (un emoji ou une lettre) | non | | Affiché à côté de l'agent. Un emoji est affiché tel quel ; sinon sa première lettre est affichée dans un rond coloré (la couleur dépend de `name`). Sans `icon`, le rond contient la première lettre de `title`. |
| `description` | texte | non | | Une phrase affichée dans la liste `@`. |
| `command` | texte | oui | | Programme qui sert ACP sur stdio. |
| `args` | liste de textes | non | `[]` | Ses arguments. |
| `env` | dictionnaire texte → texte | non | | Variables d'environnement supplémentaires. |
| `afterStop` | liste de textes, au moins un | non | | Commande lancée à chaque fin du processus de l'agent — arrêt, crash, arrêt pour faire de la place, ou fermeture de Sidekicks : le programme (un nom seul est cherché dans le PATH, un chemin est relatif à ce fichier), puis ses arguments. Elle tourne dans `workspace` avec `env`, 30 s au plus ; sa sortie va dans le journal de l'agent ; Sidekicks l'attend avant de se fermer. Un programme introuvable est un avertissement. Exemple : `[../scripts/agents.sh, unload, alice]` pour décharger le modèle. |
| `workspace` | chemin | non | le dossier de la configuration | Le dossier de l'agent : le processus y démarre et c'est le `cwd` de ses sessions ACP. mm y lit `AGENTS.md` et `skills/`. |
| `protect` | liste de textes | non | | Fichiers du dossier de l'agent que l'interface (onglet Files) ne peut ni modifier ni supprimer : chemins relatifs au dossier, ou motifs où `*` et `?` remplacent des caractères d'un nom et `**` un nombre quelconque de dossiers (`[AGENTS.md, "skills/**"]`). Un dossier qui contient un fichier protégé ne peut pas être supprimé. Toujours protégés, s'ils sont dans son dossier : `AGENTS.md`, `skills/**`, le fichier de configuration de l'agent (l'argument qui suit `--config`, `-config` ou `serve acp` dans `args`), et les fichiers à partir desquels `runtime.lifecycle` construit le conteneur ou la sandbox — le fichier Compose (après `-f`/`--file`, ou `compose.yaml`… sans lui), le `Dockerfile` du dossier des commandes pour un conteneur, le fichier d'environnement sbx (`sbxenv.yaml` ou celui nommé). Seule la configuration lève une protection ; l'agent lui-même, le terminal ou le Finder n'y sont pas soumis. |
| `runtime` | objet | non | `{type: local}` | Où tourne l'agent (voir ci-dessous). |

### `runtime`

Le runtime indique à Sidekicks comment atteindre les **fichiers et le terminal** de l'agent (panel Agents, issue #28). Il ne change pas la façon de démarrer l'agent : c'est le rôle de `command` et `args`.

| `type` | Clés supplémentaires | Signification |
| --- | --- | --- |
| `local` | aucune | L'agent tourne sur cet ordinateur ; `workspace` est un dossier local. |
| `container` | `container` (obligatoire), `workspacePath`, `lifecycle` | L'agent tourne dans un conteneur Docker ; fichiers et terminal passent par `docker exec`. Un conteneur arrêté est démarré avant l'agent. |
| `sbx` | `sandbox` (obligatoire), `workspacePath`, `lifecycle` | L'agent tourne dans une sandbox Docker (`sbx`) ; fichiers et terminal passent par `sbx exec`. |

`workspacePath` est un chemin absolu dans le conteneur ou la sandbox ; par défaut, celui de `workspace` (le même chemin, comme avec un dossier monté). Comportement de chaque runtime : [workspaces](agents-et-evenements.md#workspaces-milestone-m4).

### `runtime.lifecycle` (conteneur et sbx)

Commandes facultatives qui gèrent le conteneur ou la sandbox de l'agent (issues #47 et #48). Chaque commande est une liste : le programme (un nom seul est cherché dans le PATH, un chemin est relatif à ce fichier), puis ses arguments.

| Clé | Type | Par défaut | Signification |
| --- | --- | --- | --- |
| `folder` | texte | `workspace` | Dossier où les commandes sont lancées. Relatif à ce fichier ; `~` est le dossier personnel. |
| `create` | liste de textes, au moins un | | Crée le conteneur ou la sandbox. Avant de démarrer l'agent, Sidekicks vérifie qu'il existe (`docker container inspect`, `sbx ls -q`) ; sinon, il lance cette commande, puis vérifie à nouveau. |
| `stop` | liste de textes, au moins un | | L'arrête. Proposé par **■ Arrêter le conteneur** / **■ Arrêter la sandbox** dans le panel Agents ; l'agent est arrêté d'abord. |
| `remove` | liste de textes, au moins un | | Le supprime. Proposé par **🗑 Supprimer le conteneur** / **🗑 Supprimer la sandbox** dans le panel Agents, après confirmation ; l'agent est arrêté d'abord. |

Une sandbox arrêtée n'a besoin de rien : `sbx exec` la démarre. Un conteneur arrêté est démarré par `docker start`, même sans `lifecycle`. Les commandes ne reçoivent aucune entrée (une commande qui pose une question échoue), tournent avec l'`env` de l'agent, et ce qu'elles affichent va dans le journal de l'agent, préfixé par `sandbox: `. Un `create` qui échoue met l'agent en état `error` avec la raison.

```yaml
runtime:
  type: sbx
  sandbox: milo-sbx            # le name: du sbxenv.yaml
  lifecycle:
    folder: /Users/moi/agents/milo   # là où est sbxenv.yaml
    create: [sbx, env, create, --force]
    stop: [sbx, stop, milo-sbx]
    remove: [sbx, env, rm, --force]
```

Avec un fichier d'environnement qui ne s'appelle pas `sbxenv.yaml`, nommez-le : `[sbx, env, create, dev.yaml, --force]`, `[sbx, env, rm, dev.yaml, --force]`. Sans fichier d'environnement, utilisez les commandes simples, par exemple `remove: [sbx, rm, milo-sbx, --force]`.

Un conteneur d'un service Docker Compose (ce qu'écrit l'assistant quand un `compose.yaml` est déposé) :

```yaml
runtime:
  type: container
  container: team-scout-1      # container_name, ou <projet>-<service>-1
  lifecycle:
    folder: /Users/moi/agents/team   # là où est compose.yaml
    create: [docker, compose, -f, compose.yaml, up, -d, --wait, scout]
    stop: [docker, compose, -f, compose.yaml, stop, scout]
    remove: [docker, compose, -f, compose.yaml, rm, --stop, --force, scout]
```

`up --wait` rend la main une fois le service démarré (en bonne santé, s'il a un healthcheck) ; `rm --stop --force scout` supprime seulement le conteneur de ce service, pas les autres services comme le ferait `down`. Sans Compose : `create: [docker, run, -d, --name, scout-box, -v, "/Users/moi/agents/scout:/Users/moi/agents/scout", mon-image]`.

### Un channel

| Clé | Type | Obligatoire | Signification |
| --- | --- | --- | --- |
| `name` | texte, 1 à 64 caractères | oui | Affiché `#nom`. **Unique.** Accents et espaces autorisés. |
| `description` | texte | non | Affichée au survol du nom du channel, et dans un channel vide. |
| `agents` | liste de noms d'agents | non | Membres du channel. Un agent de la liste qui n'est pas encore membre est ajouté au démarrage et au rechargement du fichier ; le retirer de la liste ne retire rien. Sans doublon. |

Un channel déclaré ici est créé au démarrage, ou au rechargement du fichier, **si aucun channel ne porte encore ce nom** (sans tenir compte de la casse) ; il vit ensuite dans l'application comme n'importe quel channel, et peut y être renommé ou supprimé. Le retirer du fichier ne le supprime pas (supprimer un historique doit être une action explicite de l'utilisateur). Chaque fichier de configuration a ses propres channels et son propre historique ([où il est gardé](agents-et-evenements.md#historique)).

## Ce qu'écrit l'assistant « Ajouter un agent »

L'assistant ajoute une entrée à la fin de `agents` ; le reste du fichier, commentaires compris, est gardé. Rien n'est écrit si le résultat ne serait pas valide.

| Champ de l'assistant | Écrit comme |
| --- | --- |
| Nom utilisé avec @, Nom affiché, Icône, Ce qu'il fait | `name`, `title`, `icon`, `description` (champs vides omis) |
| Dossier de l'agent | `workspace`, tel que saisi (`~` et chemins relatifs résolus comme tout `workspace`) |
| Sur cet ordinateur | `command: <programme>`, `args: [<arguments>]` |
| Dans un conteneur Docker | `command: docker`, `args: [exec, -i, <conteneur>, <programme>, <arguments>]`, `runtime: {type: container, container: <conteneur>}` |
| Dans une sandbox sbx | `command: sbx`, `args: [exec, -i, <sandbox>, <programme>, <arguments>]`, `runtime: {type: sbx, sandbox: <sandbox>}` |
| Dossier où les commandes sont lancées, Commande qui crée / arrête / supprime la sandbox (sbx uniquement) | `runtime.lifecycle: {folder, create, stop, remove}`, chaque commande découpée comme les arguments ; omis si aucune commande n'est donnée |

Les arguments sont découpés comme le ferait un shell dans les cas simples : les espaces séparent, les guillemets simples ou doubles regroupent. Le programme est découpé de la même façon, sauf si c'est un chemin (il commence par `/` ou `~`) : **docker agent** donne `command: docker` et `agent` comme premier argument.

Quand le fichier de configuration de l'agent est indiqué (déposé ou choisi, où que tourne l'agent : une sandbox sbx partage les dossiers de l'hôte au même chemin, et un conteneur doit monter le dossier du fichier au même chemin), le dossier de l'agent est celui du fichier, et les arguments utilisent le chemin absolu du fichier :

| Programme | Arguments |
| --- | --- |
| `mm` | `--acp --config <fichier>` |
| `docker-agent` | `serve acp <fichier>` |
| `docker agent` | `serve acp <fichier>` (écrit `command: docker`, `args: [agent, serve, acp, <fichier>]`) |
| tout autre | inchangés : tapés par l'utilisateur |

## Règles vérifiées par le chargeur, pas par le schéma

JSON Schema ne sait pas les exprimer ; le chargeur de configuration (issue #9) les vérifie et les signale comme les erreurs de schéma :

1. les noms d'agents sont uniques ;
2. les noms de channels sont uniques ;
3. chaque nom de la liste `agents` d'un channel est le nom d'un agent ;
4. `command` existe (dans le `PATH`, ou comme fichier) — signalé comme avertissement, car un agent peut être installé plus tard.

## Messages d'erreur

Chaque erreur indique la ligne et la clé, dans la langue de l'interface, et dit comment corriger. Exemples avec l'interface en français (`language: fr`) :

| Problème | Message |
| --- | --- |
| `name: Alice Smith` | ligne 12 — agents[0].name : « Alice Smith » n'est pas un nom valide : minuscules, chiffres, « - » ou « _ », sans espace, en commençant par une lettre (ex. « alice ») |
| `comand: mm` | ligne 14 — agents[0].comand : clé inconnue « comand » ; vouliez-vous dire « command » ? |
| `command` absente | ligne 3 — agents[0] : il manque la clé « command » |

## Exemple complet

```yaml
version: 1

ui:
  theme: system
  language: fr

limits:
  maxRunningAgents: 2
  stopIdleAgentsAfter: 10m

agents:
  - name: alice
    title: Alice (assistante)
    icon: "👩"
    description: Questions simples, sans outils
    command: mm
    args: ["-acp", "-config", "agent.yaml"]
    workspace: ./agents/alice

  - name: garfield
    title: Garfield (traducteur)
    icon: "🐮"
    command: mm
    args: ["-acp", "-config", "agent.yaml"]
    workspace: ./agents/garfield

  - name: translator-sbx
    title: Traducteur (sandbox)
    command: sbx
    args: ["exec", "-i", "mm-translator", "mm", "-acp"]
    workspace: ./agents/translator/workspace
    runtime:
      type: sbx
      sandbox: mm-translator

channels:
  - name: général
    agents: [alice]
  - name: traductions
    agents: [garfield]
```

`sbx exec -i <sandbox> <programme>` lance l'agent dans la sandbox ; sbx monte le dossier de l'hôte au même chemin, donc `workspace` est aussi le dossier vu à l'intérieur. Cet exemple est aussi un cas de test (`schema/testdata/valid/spec-example.yaml`).

## Package Go `schema`

`git.rickub.com/bots-garden/sidekicks/schema` embarque le JSON Schema et valide des documents avec lui.

| Identifiant | Signature | Description |
| --- | --- | --- |
| `ConfigSchemaURL` | `const string` | Le `$id` du schéma : `https://git.rickub.com/bots-garden/sidekicks/schema/config.schema.json`. |
| `ConfigSchema` | `func() []byte` | Une copie du document JSON Schema. |
| `ValidateConfig` | `func(document []byte) error` | `nil` si le document YAML respecte le schéma ; une erreur de syntaxe YAML s'il ne peut pas être lu ; sinon une `*jsonschema.ValidationError` qui liste toutes les violations. |

```go
if err := schema.ValidateConfig(content); err != nil {
    fmt.Println("configuration invalide :", err)
}
```

Une violation telle que la renvoie `ValidateConfig` :

```text
jsonschema validation failed with 'https://git.rickub.com/bots-garden/sidekicks/schema/config.schema.json#'
- at '/agents/0': additional properties 'comand' not allowed
```