bots-garden/mini-mepublic Fork
⑂ v0.1.0
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

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

Download ZIP
🛟 Updated. 37a5a39 · on v0.1.0 · k33g · Sep 21, 2026
acp.md · 133 lines · 11.1 KBmarkdown
Blame HistoryOpen raw

Référence : surface Agent Client Protocol

Description neutre de ce que mm -acp expose en JSON-RPC 2.0 sur stdio, via github.com/coder/acp-go-sdk v0.13.5.

Transport

Aspect Valeur
Entrée stdin, un message JSON-RPC par ligne.
Sortie stdout, messages JSON-RPC uniquement.
Journaux stderr : bannière, avertissements, lignes [acp] …, logger du SDK.
Durée de vie Jusqu'à ce que le client ferme stdin ou que le contexte du processus soit annulé.

Réponse à initialize

Champ Valeur
protocolVersion 1
agentCapabilities loadSession: true quand sessions.enabled est activé, absente (false) sinon. Tout le reste absent (false) : pas de prompts image ou audio, pas de MCP HTTP.
agentInfo.name bob
agentInfo.title Bob (bash-first agent)
agentInfo.version 0.11.0
authMethods []

Méthodes

Méthode Comportement
initialize Journalise le nom du client et la version du protocole sur stderr ; renvoie les valeurs ci-dessus.
authenticate Renvoie une réponse vide.
session/new Crée une session avec un identifiant triable par date (20260916-101530-4f2a9c1e) et le cwd de la requête, un historique neuf contenant le prompt système et un ensemble « toujours autoriser » vide. Les mcpServers sont comptés dans le journal et ignorés. Une fois la réponse écrite, envoie une notification available_commands_update listant les commandes slash (voir plus bas). Avec sessions.enabled, écrit <cwd>/<sessions.dir>/<id>.json immédiatement et le réécrit après chaque tour, /new et /compact.
session/prompt Exécute une génération sur l'historique de la session, ou exécute une commande slash sans consulter le modèle. Les tours sont sérialisés à l'échelle du processus.
session/cancel Annule le tour en cours pour cette session.
session/load Avec sessions.enabled : lit <cwd>/<sessions.dir>/<sessionId>.json, remplace son prompt système par l'actuel, enregistre la session (ensemble « toujours autoriser » vide), envoie le rejeu (ci-dessous) puis un available_commands_update, et répond {}. Identifiant inconnu ou fichier illisible : invalid params portant le sessionId et l'erreur. Sans sessions.enabled : method not found.
session/set_mode, session/set_config_option, session/list, session/resume, session/close, logout method not found.

Les skills comme commandes

ACP n'a aucune notion de skill. Un prompt porte du text, une image, de l'audio, une resource ou un resource_link — ce dernier étant ce qu'envoie le sélecteur @ d'un éditeur — et rien pour « exécute cette procédure ».

AvailableCommand est le bon créneau, et les exemples du protocole le disent : sa documentation propose create_plan et research_codebase, qui sont des procédures et non des commandes de session. Chaque skill du catalogue y est donc annoncé, et l'éditeur le liste dans son propre menu / :

/compact                                              Compress the history now, keeping the last turns
/new                                                  Clear the history and start a new session
/bg-jobs          [input: parameters, if …]           Start, wait on, inspect and stop a long-running background job…
/greetings        [input: parameters, if …]           Greet somebody with a festive message.
/vulcan-salute    [input: parameters, if …]           Send a vulcan salute to somebody.

C'est l'input.hint qui porte les paramètres : le protocole dit « tout le texte tapé après le nom de la commande est fourni en entrée », ce qui est exactement ce qu'attend un skill.

Aspect Comportement
Ce que fait /greetings Bob Pas intercepté. Réécrit en la notation $greetings Bob, et le tour se déroule normalement : c'est toujours le modèle qui fait l'appel read_skill, donc le détecteur de boucle, la demande de permission et le recap 📖 N skill(s) le voient tous, et mm ne charge jamais un skill dans le dos du modèle.
Une vraie commande gagne session/prompt tente l'interception d'abord, donc un skill nommé compact ou new ne peut jamais en masquer une. Un tel skill n'est pas annoncé non plus, et la bannière de démarrage le signale — sinon il serait silencieusement inatteignable depuis le menu.
Un /nom inconnu Laissé tel quel et passé au modèle, comme n'importe quel texte slash arbitraire avant.
Taper $greetings Bob à la main Marche aussi, dans l'éditeur comme dans le terminal : la notation est résolue dans session/prompt, que le menu l'ait écrite ou l'utilisateur.

À noter, l'invariant a changé avec ça : c'était « n'annoncer que ce que session/prompt intercepte », c'est maintenant « n'annoncer que ce que cette façade traite » — réécrire, c'est traiter.

Rejeu de session/load

Envoyé avant la réponse, une notification par élément de l'historique enregistré, dans l'ordre. Le prompt système n'est pas envoyé.

Élément enregistré Notification
Message utilisateur user_message_chunk avec son texte.
Résumé de compression (message de rôle utilisateur marqué par /compact) agent_message_chunk avec 🗜️ suivi du résumé.
Texte du modèle agent_message_chunk.
Appel d'outil avec sa réponse enregistrée tool_call avec toolCallId = la référence de l'appel, title et kind tels que l'outil en direct les donnerait (bash: <commande> execute, read_file: <chemin> read, write_file/edit_file edit, read_skill: <nom> read), status: completed, rawInput, rawOutput.output et un contenu text portant la sortie.
Appel d'outil sans réponse enregistrée tool_call avec status: failed et sans contenu.

Aucun outil ne s'exécute pendant un rejeu. Journalisé comme [acp] session <id> loaded from <dir>: N message(s) replayed.

session/prompt

Aspect Comportement
sessionId inconnu Erreur invalid params portant le sessionId.
Contenu du prompt Blocs text concaténés ; un resource_link devient \n[attached file: <chemin sans file://>] ; les autres types de blocs sont ignorés. Ensuite, chaque @chemin du texte qui désigne un fichier ou un répertoire existant sous le cwd de la session (ou un chemin absolu / ~) ajoute \n[attached file: <chemin absolu>] ou \n[attached directory: …], une fois par chemin, et est journalisé comme [acp] session <id>: attached <chemin>.
Commande slash Quand le texte aplati, débarrassé de ses espaces, est exactement /new ou /compact, aucune génération n'a lieu ; la commande répond par un agent_message_chunk et stopReason: end_turn.
/new L'historique de la session revient au seul prompt système, le dernier compte de tokens d'entrée du moteur est oublié, le fragment est 🆕 New session: N message(s) forgotten.. L'identifiant de session, le cwd et les autorisations « toujours autoriser » sont conservés. Avec sessions.enabled, la conversation écoulée est d'abord enregistrée sous un nouvel identifiant (journalisé previous conversation kept as <id> ; rien n'est enregistré si elle était vide) et le fichier de la session est réécrit avec l'historique neuf. Journalisé comme [acp] session <id>: new session, N message(s) forgotten.
/compact L'historique est compressé avec les réglages context, en mode forcé (le seuil est ignoré, keepLastTurns est respecté). Le fragment est 🗜️ compressed N messages → 1 summary + N kept (… tokens, …s), ou 🗜️ nothing to compact: N message(s), no turn older than the last K (historique inchangé), ou [compact: failed, history kept: <explication>] (historique inchangé). Le compte de tokens n'est oublié que si l'historique a changé. Attend la fin d'un tour en cours : les tours sont sérialisés. Journalisé comme [acp] session <id>: /compact — <ligne>.
Historique L'historique complet renvoyé par le moteur est conservé, même après un échec ou une annulation ; une question restée sans aucune réponse est retirée.
Succès stopReason: end_turn.
Annulé stopReason: cancelled.
Échec internal error avec error: <explication en une ligne>.
Ligne de journal [acp] turn done: N command(s) · N file op(s) · N skill(s) sur stderr.

Notifications session/update envoyées

Mise à jour Quand
available_commands_update Une fois par session, juste après l'écriture de la réponse à session/new (l'éditeur doit connaître l'id de session d'abord, sinon il ignore la notification). Liste ce que cette façade traite : les commandes slash que session/prompt intercepte, puis une commande par skill. Envoyée aussi à la fin d'un rejeu session/load.
agent_message_chunk (texte) Chaque fragment diffusé de la réponse du modèle, espaces préservés ; aussi la ligne de confirmation d'une commande slash.
tool_call statut pending Avant l'exécution d'un outil ; porte title, kind, rawInput, et locations avec le chemin absolu quand un fichier est concerné.
tool_call_update statut in_progress Permission accordée, outil en cours d'exécution.
tool_call_update statut completed ou failed Outil terminé ; content est un diff pour les changements de fichier, sinon un bloc text avec la sortie ; rawOutput.output porte toujours la sortie.

Commandes disponibles

name description input
new Clear the history and start a new session aucun
compact Compress the history now, keeping the last turns aucun
un par skill la description du skill { "hint": "parameters, if this skill needs any" }

Les clients affichent le nom précédé d'une barre oblique et le renvoient comme texte d'un session/prompt. Les deux commandes ci-dessus y sont interceptées ; la commande d'un skill est réécrite en la notation $skill et le tour se déroule — voir Les skills comme commandes.

Requêtes session/request_permission envoyées

Envoyées avant l'exécution de bash, read_file, write_file et edit_file ; jamais pour read_skill.

Identifiant d'option Genre Effet
allow allow_once Exécute l'outil.
allow_always allow_always Exécute l'outil et supprime le dialogue pour ce nom d'outil jusqu'à la fin de la session.
reject reject_once N'exécute pas ; le modèle reçoit [command rejected by the user].

Une erreur de transport ou un résultat cancelled compte comme un refus.

Genres d'outils

Genre mm ToolKind ACP Outils
execute execute bash (et tout genre inconnu)
read read read_skill, read_file
edit edit write_file, edit_file

Identifiants d'appel d'outil

call_1, call_2, … numérotés par processus et jamais remis à zéro.

  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
# Référence : surface Agent Client Protocol

> Description neutre de ce que `mm -acp` expose en JSON-RPC 2.0 sur stdio, via `github.com/coder/acp-go-sdk` v0.13.5.

## Transport

| Aspect | Valeur |
|--------|--------|
| Entrée | stdin, un message JSON-RPC par ligne. |
| Sortie | stdout, messages JSON-RPC uniquement. |
| Journaux | stderr : bannière, avertissements, lignes `[acp] …`, logger du SDK. |
| Durée de vie | Jusqu'à ce que le client ferme stdin ou que le contexte du processus soit annulé. |

## Réponse à `initialize`

| Champ | Valeur |
|-------|--------|
| `protocolVersion` | `1` |
| `agentCapabilities` | `loadSession: true` quand `sessions.enabled` est activé, absente (false) sinon. Tout le reste absent (false) : pas de prompts image ou audio, pas de MCP HTTP. |
| `agentInfo.name` | `bob` |
| `agentInfo.title` | `Bob (bash-first agent)` |
| `agentInfo.version` | `0.11.0` |
| `authMethods` | `[]` |

## Méthodes

| Méthode | Comportement |
|---------|--------------|
| `initialize` | Journalise le nom du client et la version du protocole sur stderr ; renvoie les valeurs ci-dessus. |
| `authenticate` | Renvoie une réponse vide. |
| `session/new` | Crée une session avec un identifiant triable par date (`20260916-101530-4f2a9c1e`) et le `cwd` de la requête, un historique neuf contenant le prompt système et un ensemble « toujours autoriser » vide. Les `mcpServers` sont comptés dans le journal et ignorés. Une fois la réponse écrite, envoie une notification `available_commands_update` listant les commandes slash (voir plus bas). Avec `sessions.enabled`, écrit `<cwd>/<sessions.dir>/<id>.json` immédiatement et le réécrit après chaque tour, `/new` et `/compact`. |
| `session/prompt` | Exécute une génération sur l'historique de la session, ou exécute une commande slash sans consulter le modèle. Les tours sont sérialisés à l'échelle du processus. |
| `session/cancel` | Annule le tour en cours pour cette session. |
| `session/load` | Avec `sessions.enabled` : lit `<cwd>/<sessions.dir>/<sessionId>.json`, remplace son prompt système par l'actuel, enregistre la session (ensemble « toujours autoriser » vide), envoie le rejeu (ci-dessous) puis un `available_commands_update`, et répond `{}`. Identifiant inconnu ou fichier illisible : `invalid params` portant le `sessionId` et l'erreur. Sans `sessions.enabled` : `method not found`. |
| `session/set_mode`, `session/set_config_option`, `session/list`, `session/resume`, `session/close`, `logout` | `method not found`. |

## Les skills comme commandes

ACP n'a aucune notion de skill. Un prompt porte du `text`, une `image`, de l'`audio`, une `resource` ou un `resource_link` — ce dernier étant ce qu'envoie le sélecteur `@` d'un éditeur — et rien pour « exécute cette procédure ».

`AvailableCommand` est le bon créneau, et les exemples du protocole le disent : sa documentation propose `create_plan` et `research_codebase`, qui sont des procédures et non des commandes de session. Chaque skill du catalogue y est donc annoncé, et l'éditeur le liste dans son propre menu `/` :

```
/compact                                              Compress the history now, keeping the last turns
/new                                                  Clear the history and start a new session
/bg-jobs          [input: parameters, if …]           Start, wait on, inspect and stop a long-running background job…
/greetings        [input: parameters, if …]           Greet somebody with a festive message.
/vulcan-salute    [input: parameters, if …]           Send a vulcan salute to somebody.
```

C'est l'`input.hint` qui porte les paramètres : le protocole dit « tout le texte tapé après le nom de la commande est fourni en entrée », ce qui est exactement ce qu'attend un skill.

| Aspect | Comportement |
|---|---|
| Ce que fait `/greetings Bob` | **Pas intercepté.** Réécrit en la notation `$greetings Bob`, et le tour se déroule normalement : c'est toujours le modèle qui fait l'appel `read_skill`, donc le détecteur de boucle, la demande de permission et le recap `📖 N skill(s)` le voient tous, et `mm` ne charge jamais un skill dans le dos du modèle. |
| Une vraie commande gagne | `session/prompt` tente l'interception d'abord, donc un skill nommé `compact` ou `new` ne peut jamais en masquer une. Un tel skill n'est **pas annoncé** non plus, et la bannière de démarrage le signale — sinon il serait silencieusement inatteignable depuis le menu. |
| Un `/nom` inconnu | Laissé tel quel et passé au modèle, comme n'importe quel texte slash arbitraire avant. |
| Taper `$greetings Bob` à la main | Marche aussi, dans l'éditeur comme dans le terminal : la notation est résolue dans `session/prompt`, que le menu l'ait écrite ou l'utilisateur. |

À noter, l'invariant a changé avec ça : c'était « n'annoncer que ce que `session/prompt` intercepte », c'est maintenant « n'annoncer que ce que cette façade **traite** » — réécrire, c'est traiter.

## Rejeu de `session/load`

Envoyé avant la réponse, une notification par élément de l'historique enregistré, dans l'ordre. Le prompt système n'est pas envoyé.

| Élément enregistré | Notification |
|--------------------|--------------|
| Message utilisateur | `user_message_chunk` avec son texte. |
| Résumé de compression (message de rôle utilisateur marqué par `/compact`) | `agent_message_chunk` avec `🗜️ ` suivi du résumé. |
| Texte du modèle | `agent_message_chunk`. |
| Appel d'outil avec sa réponse enregistrée | `tool_call` avec `toolCallId` = la référence de l'appel, `title` et `kind` tels que l'outil en direct les donnerait (`bash: <commande>` execute, `read_file: <chemin>` read, `write_file`/`edit_file` edit, `read_skill: <nom>` read), `status: completed`, `rawInput`, `rawOutput.output` et un contenu `text` portant la sortie. |
| Appel d'outil sans réponse enregistrée | `tool_call` avec `status: failed` et sans contenu. |

Aucun outil ne s'exécute pendant un rejeu. Journalisé comme `[acp] session <id> loaded from <dir>: N message(s) replayed`.

## `session/prompt`

| Aspect | Comportement |
|--------|--------------|
| `sessionId` inconnu | Erreur `invalid params` portant le `sessionId`. |
| Contenu du prompt | Blocs `text` concaténés ; un `resource_link` devient `\n[attached file: <chemin sans file://>]` ; les autres types de blocs sont ignorés. Ensuite, chaque `@chemin` du texte qui désigne un fichier ou un répertoire existant sous le `cwd` de la session (ou un chemin absolu / `~`) ajoute `\n[attached file: <chemin absolu>]` ou `\n[attached directory: …]`, une fois par chemin, et est journalisé comme `[acp] session <id>: attached <chemin>`. |
| Commande slash | Quand le texte aplati, débarrassé de ses espaces, est exactement `/new` ou `/compact`, aucune génération n'a lieu ; la commande répond par un `agent_message_chunk` et `stopReason: end_turn`. |
| `/new` | L'historique de la session revient au seul prompt système, le dernier compte de tokens d'entrée du moteur est oublié, le fragment est `🆕 New session: N message(s) forgotten.`. L'identifiant de session, le `cwd` et les autorisations « toujours autoriser » sont conservés. Avec `sessions.enabled`, la conversation écoulée est d'abord enregistrée sous un nouvel identifiant (journalisé `previous conversation kept as <id>` ; rien n'est enregistré si elle était vide) et le fichier de la session est réécrit avec l'historique neuf. Journalisé comme `[acp] session <id>: new session, N message(s) forgotten`. |
| `/compact` | L'historique est compressé avec les réglages `context`, en mode forcé (le seuil est ignoré, `keepLastTurns` est respecté). Le fragment est `🗜️ compressed N messages → 1 summary + N kept (… tokens, …s)`, ou `🗜️ nothing to compact: N message(s), no turn older than the last K` (historique inchangé), ou `[compact: failed, history kept: <explication>]` (historique inchangé). Le compte de tokens n'est oublié que si l'historique a changé. Attend la fin d'un tour en cours : les tours sont sérialisés. Journalisé comme `[acp] session <id>: /compact — <ligne>`. |
| Historique | L'historique complet renvoyé par le moteur est conservé, même après un échec ou une annulation ; une question restée sans aucune réponse est retirée. |
| Succès | `stopReason: end_turn`. |
| Annulé | `stopReason: cancelled`. |
| Échec | `internal error` avec `error: <explication en une ligne>`. |
| Ligne de journal | `[acp] turn done: N command(s) · N file op(s) · N skill(s)` sur stderr. |

## Notifications `session/update` envoyées

| Mise à jour | Quand |
|-------------|-------|
| `available_commands_update` | Une fois par session, juste après l'écriture de la réponse à `session/new` (l'éditeur doit connaître l'id de session d'abord, sinon il ignore la notification). Liste ce que cette façade **traite** : les commandes slash que `session/prompt` intercepte, puis une commande par **skill**. Envoyée aussi à la fin d'un rejeu `session/load`. |
| `agent_message_chunk` (texte) | Chaque fragment diffusé de la réponse du modèle, espaces préservés ; aussi la ligne de confirmation d'une commande slash. |
| `tool_call` statut `pending` | Avant l'exécution d'un outil ; porte `title`, `kind`, `rawInput`, et `locations` avec le chemin absolu quand un fichier est concerné. |
| `tool_call_update` statut `in_progress` | Permission accordée, outil en cours d'exécution. |
| `tool_call_update` statut `completed` ou `failed` | Outil terminé ; `content` est un `diff` pour les changements de fichier, sinon un bloc `text` avec la sortie ; `rawOutput.output` porte toujours la sortie. |

## Commandes disponibles

| `name` | `description` | `input` |
|--------|---------------|---------|
| `new` | `Clear the history and start a new session` | aucun |
| `compact` | `Compress the history now, keeping the last turns` | aucun |
| un par skill | la `description` du skill | `{ "hint": "parameters, if this skill needs any" }` |

Les clients affichent le nom précédé d'une barre oblique et le renvoient comme texte d'un `session/prompt`. Les deux commandes ci-dessus y sont interceptées ; la commande d'un skill est réécrite en la notation `$skill` et le tour se déroule — voir [Les skills comme commandes](#les-skills-comme-commandes).

## Requêtes `session/request_permission` envoyées

Envoyées avant l'exécution de `bash`, `read_file`, `write_file` et `edit_file` ; jamais pour `read_skill`.

| Identifiant d'option | Genre | Effet |
|----------------------|-------|-------|
| `allow` | `allow_once` | Exécute l'outil. |
| `allow_always` | `allow_always` | Exécute l'outil et supprime le dialogue pour ce nom d'outil jusqu'à la fin de la session. |
| `reject` | `reject_once` | N'exécute pas ; le modèle reçoit `[command rejected by the user]`. |

Une erreur de transport ou un résultat `cancelled` compte comme un refus.

## Genres d'outils

| Genre `mm` | `ToolKind` ACP | Outils |
|------------|----------------|--------|
| `execute` | `execute` | `bash` (et tout genre inconnu) |
| `read` | `read` | `read_skill`, `read_file` |
| `edit` | `edit` | `write_file`, `edit_file` |

## Identifiants d'appel d'outil

`call_1`, `call_2`, … numérotés par processus et jamais remis à zéro.