[{"data":1,"prerenderedAt":21},["ShallowReactive",2],{"doc:en:plugins\u002Fharnesses":3},{"title":4,"lede":5,"html":6,"headings":7},"A described ACP harness","An agent that speaks ACP (Agent Client Protocol) becomes a harness of Escouade through a declarative plugin: its manifest describes it, without a line of code, and the ACP plugin shipped with Escouade does the rest.","\u003Cp>That plugin (\u003Ccode class=\"key\">dev.escouade.acp\u003C\u002Fcode>) launches the agent, speaks to it and shows its conversation, its permissions, its diffs and the end of its turns, as for Claude Code. The agent shows in the “Harness” menu beside “New agent”.\u003C\u002Fp>\n\u003Ch2 id=\"the-manifest\">The manifest\u003C\u002Fh2>\n\u003Cp>The Goose plugin (\u003Ccode class=\"key\">plugins\u002Fgoose\u002F\u003C\u002Fcode> of Escouade’s repository), tried with Goose 1.57:\u003C\u002Fp>\n\u003Cp>\u003Ccode>plugins\u002Fgoose\u002Fescouade-plugin.json\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">{\n  &quot;$schema&quot;: &quot;https:\u002F\u002Fescouade.dev\u002Fschemas\u002Fplugin-1.json&quot;,\n  &quot;id&quot;: &quot;dev.escouade.goose&quot;,\n  &quot;name&quot;: &quot;Goose&quot;,\n  &quot;version&quot;: &quot;1.0.0&quot;,\n  &quot;description&quot;: {\n    &quot;fr&quot;: &quot;Goose, l&#39;agent open source de Block, comme harness : décrit par ACP, sans code.&quot;,\n    &quot;en&quot;: &quot;Goose, Block&#39;s open source agent, as a harness: described over ACP, no code.&quot;\n  },\n  &quot;author&quot;: { &quot;name&quot;: &quot;Escouade&quot;, &quot;url&quot;: &quot;https:\u002F\u002Fescouade.dev&quot; },\n  &quot;license&quot;: &quot;MIT&quot;,\n  &quot;repository&quot;: &quot;https:\u002F\u002Fgithub.com\u002Fguillaume-gagnaire\u002Fescouade\u002Ftree\u002Fmain\u002Fplugins\u002Fgoose&quot;,\n  &quot;escouade&quot;: { &quot;api&quot;: &quot;1&quot;, &quot;min&quot;: &quot;2.1.0&quot; },\n  &quot;contributes&quot;: {\n    &quot;harnesses&quot;: [\n      {\n        &quot;id&quot;: &quot;goose&quot;,\n        &quot;name&quot;: &quot;Goose&quot;,\n        &quot;speaker&quot;: &quot;Goose&quot;,\n        &quot;writer&quot;: &quot;Goose&quot;,\n        &quot;locate&quot;: { &quot;names&quot;: [&quot;goose&quot;] },\n        &quot;tested&quot;: { &quot;oldest&quot;: &quot;1.57.0&quot;, &quot;newest&quot;: &quot;1.57.0&quot; },\n        &quot;caps&quot;: {\n          &quot;modes&quot;: [\n            {\n              &quot;id&quot;: &quot;default&quot;,\n              &quot;meaning&quot;: {\n                &quot;fr&quot;: &quot;Goose demande avant chaque outil (son mode approve). Il écrit les fichiers lui-même, sans les faire passer par Escouade.&quot;,\n                &quot;en&quot;: &quot;Goose asks before each tool (its approve mode). It writes files by itself, without passing them through Escouade.&quot;\n              }\n            },\n            {\n              &quot;id&quot;: &quot;acceptEdits&quot;,\n              &quot;meaning&quot;: {\n                &quot;fr&quot;: &quot;Goose ne demande que pour ce qu&#39;il juge sensible (son mode smart_approve) ; Escouade accepte ses écritures dans le dossier de l&#39;agent.&quot;,\n                &quot;en&quot;: &quot;Goose asks only for what it deems sensitive (its smart_approve mode); Escouade accepts its writes in the agent&#39;s folder.&quot;\n              }\n            },\n            {\n              &quot;id&quot;: &quot;bypassPermissions&quot;,\n              &quot;meaning&quot;: {\n                &quot;fr&quot;: &quot;Goose ne demande rien (son mode auto) : commandes, fichiers, tout le disque. Pas de bac à sable.&quot;,\n                &quot;en&quot;: &quot;Goose asks nothing (its auto mode): commands, files, the whole disk. No sandbox.&quot;\n              }\n            }\n          ],\n          &quot;readOnly&quot;: true\n        },\n        &quot;accountVar&quot;: &quot;GOOSE_PATH_ROOT&quot;,\n        &quot;install&quot;: {\n          &quot;windows&quot;: &quot;Invoke-WebRequest -Uri https:\u002F\u002Fraw.githubusercontent.com\u002Faaif-goose\u002Fgoose\u002Fmain\u002Fdownload_cli.ps1 -OutFile download_cli.ps1; .\u002Fdownload_cli.ps1&quot;,\n          &quot;unix&quot;: &quot;curl -fsSL https:\u002F\u002Fgithub.com\u002Faaif-goose\u002Fgoose\u002Freleases\u002Fdownload\u002Fstable\u002Fdownload_cli.sh | CONFIGURE=false bash&quot;\n        },\n        &quot;updateCommand&quot;: &quot;goose update&quot;,\n        &quot;acp&quot;: {\n          &quot;args&quot;: [&quot;acp&quot;],\n          &quot;fs&quot;: false,\n          &quot;modes&quot;: { &quot;default&quot;: &quot;approve&quot;, &quot;acceptEdits&quot;: &quot;smart_approve&quot;, &quot;bypassPermissions&quot;: &quot;auto&quot; },\n          &quot;readOnlyMode&quot;: &quot;chat&quot;,\n          &quot;modelOption&quot;: &quot;model&quot;,\n          &quot;questionsInText&quot;: true,\n          &quot;tools&quot;: { &quot;shell&quot;: &quot;Bash&quot;, &quot;write&quot;: &quot;Write&quot;, &quot;edit&quot;: &quot;Edit&quot;, &quot;text_editor&quot;: &quot;Edit&quot;, &quot;read&quot;: &quot;Read&quot;, &quot;tree&quot;: &quot;Glob&quot; }\n        }\n      }\n    ]\n  }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Each entry of \u003Ccode>contributes.harnesses\u003C\u002Fcode> with an \u003Ccode class=\"key\">acp\u003C\u002Fcode> object is a described harness:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode class=\"key\">id\u003C\u002Fcode>, \u003Ccode class=\"key\">name\u003C\u002Fcode>, \u003Ccode class=\"key\">speaker\u003C\u002Fcode> (the name of its agents in the texts), \u003Ccode class=\"key\">writer\u003C\u002Fcode> (who drafts the texts);\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">locate.names\u003C\u002Fcode>: the names of its program, looked for on the PATH; a declarative plugin never gives a path;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">versionArgs\u003C\u002Fcode> (\u003Ccode class=\"key\">--version\u003C\u002Fcode> by default) and \u003Ccode class=\"key\">tested\u003C\u002Fcode>: the version read and the versions tried, as for Escouade’s harnesses;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">caps\u003C\u002Fcode>: its modes, each by its id or with its meaning (\u003Ccode class=\"key\">meaning\u003C\u002Fcode>, what the menu of modes says), and what it can do (\u003Ccode class=\"key\">images\u003C\u002Fcode>, \u003Ccode class=\"key\">pdf\u003C\u002Fcode>, \u003Ccode class=\"key\">readOnly\u003C\u002Fcode>…); what is not said, it does not do;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">models\u003C\u002Fcode>: the models of its menu (\u003Ccode class=\"key\">id\u003C\u002Fcode>, \u003Ccode class=\"key\">label\u003C\u002Fcode>);\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">accountVar\u003C\u002Fcode>: the variable that gives each account its configuration folder;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">install\u003C\u002Fcode> and \u003Ccode class=\"key\">updateCommand\u003C\u002Fcode>: its install command (Windows, Unix) and its update command.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"the-acp-object\">The \u003Ccode class=\"key\">acp\u003C\u002Fcode> object\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ccode class=\"key\">args\u003C\u002Fcode>: its arguments (\u003Ccode class=\"key\">[&quot;acp&quot;]\u003C\u002Fcode>); \u003Ccode class=\"key\">env\u003C\u002Fcode> and \u003Ccode class=\"key\">removeEnv\u003C\u002Fcode>: variables of its own (never a secret: a manifest is read by all), and those of the app it must not get;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">fs\u003C\u002Fcode>: it reads and writes files \u003Cstrong>through Escouade\u003C\u002Fstrong> (\u003Ccode class=\"key\">fs\u002Fread_text_file\u003C\u002Fcode>, \u003Ccode class=\"key\">fs\u002Fwrite_text_file\u003C\u002Fcode>), true by default. Set \u003Ccode class=\"key\">false\u003C\u002Fcode> for an agent that reads and writes them itself, as Goose and Cursor CLI do, even when Escouade offers it;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">modes\u003C\u002Fcode>: the ACP mode (\u003Ccode class=\"key\">session\u002Fset_mode\u003C\u002Fcode>) of each mode of Escouade; \u003Ccode class=\"key\">readOnlyMode\u003C\u002Fcode>: the one that changes nothing, for the discussions of the Docs tab;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">modelOption\u003C\u002Fcode>: the configuration option of the model (\u003Ccode>session\u002Fset_config_option\u003C\u002Fcode>), else \u003Ccode class=\"key\">session\u002Fset_model\u003C\u002Fcode>;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">questionsInText\u003C\u002Fcode>: the agent has no tool to ask a question; its first message tells it to end its turn on a block \u003Ccode class=\"key\">&lt;escouade_question&gt;\u003C\u002Fcode>, which Escouade shows as a question’s card;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">tools\u003C\u002Fcode>: Escouade’s name (Claude Code’s) of its tools of the kind \u003Ccode class=\"key\">other\u003C\u002Fcode> (\u003Ccode>{ &quot;shell&quot;: &quot;Bash&quot; }\u003C\u002Fcode>), read from \u003Ccode>_meta.&lt;agent&gt;.toolCall.toolName\u003C\u002Fcode> or from their title before “·”; \u003Ccode class=\"key\">subagentTools\u003C\u002Fcode>: those that start a subagent;\u003C\u002Fli>\n\u003Cli>\u003Ccode class=\"key\">extensions\u003C\u002Fcode>: \u003Ccode class=\"key\">cursor\u003C\u002Fcode> for the extensions \u003Ccode class=\"key\">cursor\u002F*\u003C\u002Fcode> of Cursor CLI.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"what-escouade-holds\">What Escouade holds\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>The launch.\u003C\u002Fstrong> Escouade finds the program, asks the ACP plugin how to launch it, checks the description and launches it itself. Escouade’s MCP server goes to the session (\u003Ccode class=\"key\">mcpServers\u003C\u002Fcode>), its token in a header, on the agent’s input: never among its arguments.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>The permissions.\u003C\u002Fstrong> Each permission asked is a card, with its diff for a write. “Accept edits” lets the writes in the agent’s folder through, “Bypass” all it asks.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Private projects.\u003C\u002Fstrong> Escouade refuses the files of another project the agent reads or writes through it. When the agent reads or writes a file by itself while a fence holds, the conversation says so: the fence does not hold for these. A harness declared \u003Ccode>&quot;fs&quot;: false\u003C\u002Fcode> does not start in a private project.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>What ACP does not tell\u003C\u002Fstrong> stays unknown: the quota, the cost, the accounts. A turn’s tokens are counted when the agent gives them.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A plugin uninstalled or turned off (or the ACP plugin itself): its agents stay, marked “Harness missing”, with their conversations. They come back with it. The id of a described harness is \u003Ccode>plugin:&lt;plugin&gt;:&lt;harness&gt;\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>For now, a described harness has no terminal view and drafts no texts.\u003C\u002Fp>\n\u003Cp>A harness that ACP does not describe is written in Rust: see \u003Ca href=\"\u002Fen\u002Fdocs\u002Fplugins\u002Frust\u002F#writing-a-harness\">writing a harness\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"trying-it\">Trying it\u003C\u002Fh2>\n\u003Cp>Install your plugin’s folder from the Plugins view (“In development”), then pick its harness in the “Harness” menu. Before the install, the window shows the program its agents will run (\u003Ccode>goose acp\u003C\u002Fcode>). Escouade’s bench of the harnesses plays the same client on a fake ACP agent described by a manifest (\u003Ccode>tests\u002Ffixtures\u002Fplugins\u002Ffake-acp\u002F\u003C\u002Fcode>).\u003C\u002Fp>\n",[8,12,15,18],{"id":9,"text":10,"depth":11},"the-manifest","The manifest",2,{"id":13,"text":14,"depth":11},"the-acp-object","The acp object",{"id":16,"text":17,"depth":11},"what-escouade-holds","What Escouade holds",{"id":19,"text":20,"depth":11},"trying-it","Trying it",1793889382328]