{"_id":"@efrembaraldo/gsd-pi-discussion-arena","_rev":"18-b0886456d671e1381d3538e014420174","name":"@efrembaraldo/gsd-pi-discussion-arena","dist-tags":{"latest":"0.9.2"},"versions":{"0.7.5":{"name":"@efrembaraldo/gsd-pi-discussion-arena","version":"0.7.5","keywords":["gsd-pi","pi-coding-agent","extension","multi-agent"],"author":{"name":"Efrem Baraldo"},"license":"MIT","_id":"@efrembaraldo/gsd-pi-discussion-arena@0.7.5","maintainers":[{"name":"efrembaraldo","email":"efrem.baraldo@gmail.com"}],"homepage":"https://github.com/efrembaraldo/gsd-pi-discussion-arena#readme","bugs":{"url":"https://github.com/efrembaraldo/gsd-pi-discussion-arena/issues"},"pi":{"extensions":["./index.ts"]},"gsd":{"extension":true},"dist":{"shasum":"04453bdb5ee3791fe572be9457093b089ccec7cd","tarball":"https://registry.npmjs.org/@efrembaraldo/gsd-pi-discussion-arena/-/gsd-pi-discussion-arena-0.7.5.tgz","fileCount":26,"integrity":"sha512-/jXF290/OkEhykhJXPKb+gAIS1qeu6p5aZ/TXQxtvPZzD0G+l0btSCuq+NkAXIyNSHQGnPUIUDCteShZOvYxdg==","signatures":[{"sig":"MEUCIQDEpLaOQugusGKtTWdlm7VwsR2sncW587GIJzAkXVgClAIgUlM1Natw0+WAnGQNZRMYydjaDY3athMfhtXgq2wRwUE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@efrembaraldo%2fgsd-pi-discussion-arena@0.7.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":204034},"type":"module","gitHead":"db4d2fa3c96ab5febf598f2f282cc02b5c7e4689","scripts":{"test":"node --import ./tests/ts-esm-loader.mjs --test","typecheck":"tsc --noEmit --pretty false","setup-types":"node scripts/setup-types.mjs","pretypecheck":"node scripts/setup-types.mjs","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:02fc2791-65aa-4219-ba2e-50717ffe17b5"}},"repository":{"url":"git+https://github.com/efrembaraldo/gsd-pi-discussion-arena.git","type":"git"},"_npmVersion":"12.0.2","description":"Agent Discussion Arena per gsd-pi: consiglio di agenti con ruoli configurabili, coordinato dal ciclo auto di gsd-pi","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"typebox":"^1.3.10","typescript":"^5.9.0","@types/node":"^20.0.0"},"peerDependencies":{"typebox":"*","@gsd/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@gsd/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/gsd-pi-discussion-arena_0.7.5_1786657303942_0.6992285614347011","host":"s3://npm-registry-packages-npm-production"}},"0.7.6":{"name":"@efrembaraldo/gsd-pi-discussion-arena","version":"0.7.6","keywords":["gsd-pi","pi-coding-agent","extension","multi-agent"],"author":{"name":"Efrem Baraldo"},"license":"MIT","_id":"@efrembaraldo/gsd-pi-discussion-arena@0.7.6","maintainers":[{"name":"efrembaraldo","email":"efrem.baraldo@gmail.com"}],"homepage":"https://github.com/efrembaraldo/gsd-pi-discussion-arena#readme","bugs":{"url":"https://github.com/efrembaraldo/gsd-pi-discussion-arena/issues"},"pi":{"extensions":["./index.ts"]},"gsd":{"extension":true},"dist":{"shasum":"8dd16415e7751d6db88d7533dea2c1998ea00993","tarball":"https://registry.npmjs.org/@efrembaraldo/gsd-pi-discussion-arena/-/gsd-pi-discussion-arena-0.7.6.tgz","fileCount":32,"integrity":"sha512-M4RztPT41HOu9c4j/xIT8VvOPnO5O8JpGolMQ2A7IRnG139SAoLiPVO+oMU//f5UhqhbXpYqmVmmTfCc0LRdGw==","signatures":[{"sig":"MEQCIB7Pf5wo4N16/NcGGDLC+DM3JEnPddoruCmK9iJeW80BAiACsVRdmxkc+Ia2IPWwnMjCy0nO7qPWmQDRQMJzBOtvPg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@efrembaraldo%2fgsd-pi-discussion-arena@0.7.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":284888},"type":"module","gitHead":"d95e7836f2f11525aa86f433a865af1a3258b8b2","scripts":{"test":"node --import ./tests/ts-esm-loader.mjs --test","typecheck":"tsc --noEmit --pretty false","setup-types":"node scripts/setup-types.mjs","pretypecheck":"node scripts/setup-types.mjs","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:02fc2791-65aa-4219-ba2e-50717ffe17b5"}},"repository":{"url":"git+https://github.com/efrembaraldo/gsd-pi-discussion-arena.git","type":"git"},"_npmVersion":"12.0.2","description":"Agent Discussion Arena per gsd-pi: consiglio di agenti con ruoli configurabili, coordinato dal ciclo auto di gsd-pi","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"typebox":"^1.3.10","typescript":"^5.9.0","@types/node":"^20.0.0"},"peerDependencies":{"typebox":"*","@gsd/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@gsd/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/gsd-pi-discussion-arena_0.7.6_1786798011838_0.9534330279802059","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@efrembaraldo/gsd-pi-discussion-arena","version":"0.8.0","keywords":["gsd-pi","pi-coding-agent","extension","multi-agent"],"author":{"name":"Efrem Baraldo"},"license":"MIT","_id":"@efrembaraldo/gsd-pi-discussion-arena@0.8.0","maintainers":[{"name":"efrembaraldo","email":"efrem.baraldo@gmail.com"}],"homepage":"https://github.com/efrembaraldo/gsd-pi-discussion-arena#readme","bugs":{"url":"https://github.com/efrembaraldo/gsd-pi-discussion-arena/issues"},"pi":{"extensions":["./index.ts"]},"gsd":{"extension":true},"dist":{"shasum":"7fa9a0c75acf0b615f2e699cc571c387821ce9af","tarball":"https://registry.npmjs.org/@efrembaraldo/gsd-pi-discussion-arena/-/gsd-pi-discussion-arena-0.8.0.tgz","fileCount":42,"integrity":"sha512-G9z4GsArZ+p/ZBImlfIs6bwo0UgJd/J1EcppiaQ6pD7krslKcf/9bC1UmG48/vArzryW640m128egH7AYuxN+w==","signatures":[{"sig":"MEUCIGqltgR9atYJUuADGTMIA7MF690jMP25fROaYwPdCwl5AiEAlEkY13l4UNphmP4yrZ+/9Qeafo7S8YDvinFOpiw7g98=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@efrembaraldo%2fgsd-pi-discussion-arena@0.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":415181},"type":"module","gitHead":"316613f08c9caa8d8b4fd68ce6d803ee079965a8","scripts":{"test":"node --import ./tests/ts-esm-loader.mjs --test","e2e-real":"node --import ./tests/ts-esm-loader.mjs scripts/e2e-real.mjs","typecheck":"tsc --noEmit --pretty false","pree2e-real":"node scripts/setup-types.mjs","setup-types":"node scripts/setup-types.mjs","pretypecheck":"node scripts/setup-types.mjs","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:02fc2791-65aa-4219-ba2e-50717ffe17b5"}},"repository":{"url":"git+https://github.com/efrembaraldo/gsd-pi-discussion-arena.git","type":"git"},"_npmVersion":"12.0.2","description":"Agent Discussion Arena per gsd-pi: consiglio di agenti con ruoli configurabili, coordinato dal ciclo auto di gsd-pi","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"typebox":"^1.3.10","typescript":"^5.9.0","@types/node":"^20.0.0"},"peerDependencies":{"typebox":"*","@gsd/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@gsd/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/gsd-pi-discussion-arena_0.8.0_1787633441322_0.950859907172761","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@efrembaraldo/gsd-pi-discussion-arena","version":"0.9.0","keywords":["gsd-pi","pi-coding-agent","extension","multi-agent"],"author":{"name":"Efrem Baraldo"},"license":"MIT","_id":"@efrembaraldo/gsd-pi-discussion-arena@0.9.0","maintainers":[{"name":"efrembaraldo","email":"efrem.baraldo@gmail.com"}],"homepage":"https://github.com/efrembaraldo/gsd-pi-discussion-arena#readme","bugs":{"url":"https://github.com/efrembaraldo/gsd-pi-discussion-arena/issues"},"pi":{"extensions":["./index.ts"]},"gsd":{"extension":true},"dist":{"shasum":"a22905359f10dcd426447d339aa53e081311b7d2","tarball":"https://registry.npmjs.org/@efrembaraldo/gsd-pi-discussion-arena/-/gsd-pi-discussion-arena-0.9.0.tgz","fileCount":45,"integrity":"sha512-gmXzgjLLEUO5FqMTVRigoPONd/11VLpxQTkIsklcL0OuIBKFpsNqjobIFmn/mE/qjr7X5NOpivprPlGJYf4Q7A==","signatures":[{"sig":"MEYCIQC5Psjp8x3tnIND3GHJaXvvjfZY2Gv8pwAWeM6vxlF1BAIhAISFDQrxbepGxJkWUR6cU5pmQJi51Ih+ZQQ8fr7UhnXT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@efrembaraldo%2fgsd-pi-discussion-arena@0.9.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":467177},"type":"module","gitHead":"f2b67c6d659d6844409e99413eeca679fa4a1a5f","scripts":{"test":"node --import ./tests/ts-esm-loader.mjs --test","e2e-real":"node --import ./tests/ts-esm-loader.mjs scripts/e2e-real.mjs","typecheck":"tsc --noEmit --pretty false","pree2e-real":"node scripts/setup-types.mjs","setup-types":"node scripts/setup-types.mjs","pretypecheck":"node scripts/setup-types.mjs","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:02fc2791-65aa-4219-ba2e-50717ffe17b5"}},"repository":{"url":"git+https://github.com/efrembaraldo/gsd-pi-discussion-arena.git","type":"git"},"_npmVersion":"12.0.2","description":"Agent Discussion Arena per gsd-pi: consiglio di agenti con ruoli configurabili, coordinato dal ciclo auto di gsd-pi","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"typebox":"^1.3.10","typescript":"^5.9.0","@types/node":"^20.0.0"},"peerDependencies":{"typebox":"*","@gsd/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@gsd/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/gsd-pi-discussion-arena_0.9.0_1788125664162_0.27292159056855647","host":"s3://npm-registry-packages-npm-production"}},"0.9.1":{"name":"@efrembaraldo/gsd-pi-discussion-arena","version":"0.9.1","keywords":["gsd-pi","pi-coding-agent","extension","multi-agent"],"author":{"name":"Efrem Baraldo"},"license":"MIT","_id":"@efrembaraldo/gsd-pi-discussion-arena@0.9.1","maintainers":[{"name":"efrembaraldo","email":"efrem.baraldo@gmail.com"}],"homepage":"https://github.com/efrembaraldo/gsd-pi-discussion-arena#readme","bugs":{"url":"https://github.com/efrembaraldo/gsd-pi-discussion-arena/issues"},"pi":{"extensions":["./index.ts"]},"gsd":{"extension":true},"dist":{"shasum":"f9a889e6f41ef2754fcaf1f69536720e2d4095f1","tarball":"https://registry.npmjs.org/@efrembaraldo/gsd-pi-discussion-arena/-/gsd-pi-discussion-arena-0.9.1.tgz","fileCount":47,"integrity":"sha512-14GY9uowFMN3L/3Jg5tWheJ4hDB4fZrwAQ1ooQF1qjpb+rxW1BPzIjDayZhBWvlaWeqcxQ8OStMiP5p1a5Iq9A==","signatures":[{"sig":"MEQCIC4p7SoxHZTOim8ffGzHTXvvd8lys+1TcHpzanXA7EthAiByY5SrlYnyzc9HUDTNyE75pFui+zvy4fdojRgg9nqOFA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@efrembaraldo%2fgsd-pi-discussion-arena@0.9.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":482769},"type":"module","gitHead":"a7e7f9ef389810976323e6c7ef9eb61c736a2c6c","scripts":{"test":"node --import ./tests/ts-esm-loader.mjs --test","e2e-real":"node --import ./tests/ts-esm-loader.mjs scripts/e2e-real.mjs","typecheck":"tsc --noEmit --pretty false","postinstall":"node scripts/copy-template.mjs","pree2e-real":"node scripts/setup-types.mjs","setup-types":"node scripts/setup-types.mjs","pretypecheck":"node scripts/setup-types.mjs","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:02fc2791-65aa-4219-ba2e-50717ffe17b5"}},"repository":{"url":"git+https://github.com/efrembaraldo/gsd-pi-discussion-arena.git","type":"git"},"_npmVersion":"12.0.2","description":"Agent Discussion Arena per gsd-pi: consiglio di agenti con ruoli configurabili, coordinato dal ciclo auto di gsd-pi","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"typebox":"^1.3.10","typescript":"^5.9.0","@types/node":"^20.0.0"},"peerDependencies":{"typebox":"*","@gsd/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@gsd/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/gsd-pi-discussion-arena_0.9.1_1788222003313_0.1453680501304193","host":"s3://npm-registry-packages-npm-production"}},"0.9.2":{"name":"@efrembaraldo/gsd-pi-discussion-arena","version":"0.9.2","description":"Agent Discussion Arena per gsd-pi: consiglio di agenti con ruoli configurabili, coordinato dal ciclo auto di gsd-pi","type":"module","license":"MIT","author":{"name":"Efrem Baraldo"},"repository":{"type":"git","url":"git+https://github.com/efrembaraldo/gsd-pi-discussion-arena.git"},"keywords":["gsd-pi","pi-coding-agent","extension","multi-agent"],"gsd":{"extension":true},"pi":{"extensions":["./index.ts"]},"peerDependencies":{"@gsd/pi-coding-agent":"*","typebox":"*"},"peerDependenciesMeta":{"@gsd/pi-coding-agent":{"optional":true},"typebox":{"optional":true}},"devDependencies":{"@types/node":"^20.0.0","typebox":"^1.3.10","typescript":"^5.9.0"},"scripts":{"setup-types":"node scripts/setup-types.mjs","pretypecheck":"node scripts/setup-types.mjs","typecheck":"tsc --noEmit --pretty false","test":"node --import ./tests/ts-esm-loader.mjs --test --test-skip-pattern=\"E2E real-path\"","e2e-real":"node --import ./tests/ts-esm-loader.mjs scripts/e2e-real.mjs","pree2e-real":"node scripts/setup-types.mjs","prepublishOnly":"npm run typecheck && npm test","postinstall":"node scripts/copy-template.mjs","test:e2e-hermes":"node --import ./tests/ts-esm-loader.mjs --test tests/e2e-real-hermes.test.ts"},"publishConfig":{"access":"public","provenance":true},"gitHead":"78e9620a7088b70fb7ac431f4f5f30290f43f198","_id":"@efrembaraldo/gsd-pi-discussion-arena@0.9.2","bugs":{"url":"https://github.com/efrembaraldo/gsd-pi-discussion-arena/issues"},"homepage":"https://github.com/efrembaraldo/gsd-pi-discussion-arena#readme","_nodeVersion":"24.19.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-9mCuBItfYHGqcHPHLBq076q1bu8vEk+YikAOVb+nJpN3nzmo4njHcjNiuoc/+he3utPYRUi9WPajZB8wGEw53w==","shasum":"0eeaaf261b3284d20af8517bda084db5887ac58e","tarball":"https://registry.npmjs.org/@efrembaraldo/gsd-pi-discussion-arena/-/gsd-pi-discussion-arena-0.9.2.tgz","fileCount":47,"unpackedSize":565078,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@efrembaraldo%2fgsd-pi-discussion-arena@0.9.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC7WbH1MGRItPKXXQjw3Q7ODirkOnqHSqrHBca75lif+QIhAM4gSLO8S6H3w7ZcA+lyQ0cD6FJvmvkVIFh/CWTJxaEg"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:02fc2791-65aa-4219-ba2e-50717ffe17b5"}},"directories":{},"maintainers":[{"name":"efrembaraldo","email":"efrem.baraldo@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gsd-pi-discussion-arena_0.9.2_1788433049504_0.28299831097365513"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-05T22:59:15.488Z","modified":"2026-09-03T10:57:29.981Z","0.1.0":"2026-08-05T22:59:15.806Z","0.1.2":"2026-08-06T08:57:50.640Z","0.2.0":"2026-08-06T09:44:57.107Z","0.7.0":"2026-08-11T00:00:59.390Z","0.7.1":"2026-08-11T00:36:11.013Z","0.7.2":"2026-08-12T09:41:59.682Z","0.7.5":"2026-08-13T21:41:44.117Z","0.7.6":"2026-08-15T12:46:51.977Z","0.8.0":"2026-08-25T04:50:41.470Z","0.9.0":"2026-08-30T21:34:24.347Z","0.9.1":"2026-09-01T00:20:03.458Z","0.9.2":"2026-09-03T10:57:29.642Z"},"bugs":{"url":"https://github.com/efrembaraldo/gsd-pi-discussion-arena/issues"},"author":{"name":"Efrem Baraldo"},"license":"MIT","homepage":"https://github.com/efrembaraldo/gsd-pi-discussion-arena#readme","keywords":["gsd-pi","pi-coding-agent","extension","multi-agent"],"repository":{"type":"git","url":"git+https://github.com/efrembaraldo/gsd-pi-discussion-arena.git"},"description":"Agent Discussion Arena per gsd-pi: consiglio di agenti con ruoli configurabili, coordinato dal ciclo auto di gsd-pi","maintainers":[{"name":"efrembaraldo","email":"efrem.baraldo@gmail.com"}],"readme":"# Agent Discussion Arena for gsd-pi\n\n**Languages:** [English](README.md) · [Italiano](README.it.md)\n\n[![CI](https://github.com/efrembaraldo/gsd-pi-discussion-arena/actions/workflows/ci.yml/badge.svg)](https://github.com/efrembaraldo/gsd-pi-discussion-arena/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/@efrembaraldo/gsd-pi-discussion-arena)](https://www.npmjs.com/package/@efrembaraldo/gsd-pi-discussion-arena)\n\nExtension that adds a `discussion_arena` tool and a `/discussion-arena` command\nto gsd-pi. It makes N participants (roles/skills you define in Markdown)\ndiscuss a topic for K rounds, and returns the transcript to the agent that\ninvoked the tool — so **gsd-pi stays the coordinator**: the discussion arena is\nonly a tool that the agent active in the current unit may decide to use,\nexactly like it would use bash or web-search.\n\n## Documentation\n\n| Section | Audience | Covers |\n| --- | --- | --- |\n| [User Guide](docs/user-guide/index.md) | People who install and use the extension | Installation, configuration, usage, persistent sessions, troubleshooting |\n| [Contributor Guide](docs/contributor-guide/index.md) | People who extend the extension | Adding roles, writing loadable examples, repository and documentation conventions |\n| [Architecture Reference](docs/architecture/index.md) | People who modify internals | Tool registration, subprocess model, trigger resolution, auto-mode hooks, runtime limits |\n\n## How it works\n\n1. `discussion_arena` is a tool registered via `api.registerTool()` — the\n   same mechanism as any custom gsd-pi tool.\n2. Each participant runs as an isolated `gsd --mode json -p --no-session`\n   subprocess, with its own system prompt and (optionally) its own model and\n   restricted tool set.\n3. Rounds are sequential on purpose: in round N each participant sees the\n   turns already given by the others in the same round (real dialogue). For a\n   simultaneous debate where nobody sees the others until the end of the\n   round, see the comment in `index.ts` (`runDiscussionArena`) on how to\n   invert the order with `Promise.all`.\n4. The resulting transcript returns as the tool result to the calling agent,\n   which decides what to do with it (synthesize, decide, write code\n   accordingly) — the phase/progression logic stays entirely in the gsd-pi\n   auto orchestrator (`resolveDispatch`, `orchestrator.ts`), which has no\n   awareness of the discussion arena.\n\n## Engines: `gsd` (default) and `hermes -z` (opt-in)\n\nEach participant runs as an isolated subprocess. The discussion arena supports two\nengines, declared per-participant in the `.md` frontmatter:\n\n- **`gsd` (default)** — the original `gsd --mode json -p --no-session`\n  subprocess described in \"How it works\" above. This is what every bundled\n  participant (`analyst`, `architect`, `dev`, `qa`) uses and is the\n  unchanged behavior from M001–M014.\n- **`hermes -z` (opt-in)** — added in milestone M015 (`Hermes come motore\n  di un partecipante nella Discussion Arena`). A participant opts in by\n  setting `engine: hermes` in its frontmatter, plus optional `provider`,\n  `hermes_toolsets`, `hermes_skills`, and `soft_deadline_ms`. The discussion arena\n  spawns `hermes -z <prompt> --usage-file <path>` reusing the existing\n  timer/abort/kill layer (D039), and degrades to `gsd` — emitting a one-shot\n  warning on stderr plus a `<!-- engine: gsd (degradato...) -->` marker in the\n  transcript — when the `hermes` binary is not in `PATH`.\n\nThe bundled `participants/researcher.md` is a working example of an\n`engine: hermes` participant. See\n[`docs/architecture/participant-subprocesses.md`](docs/architecture/participant-subprocesses.md)\nfor the full engine contract (D126, D127) and the soft-deadline / recovery\nblock semantics (R042, R043).\n\n## Installation (from npm, after publishing — see dedicated section)\n\n```bash\n# Top-level CLI command (verified in packages/pi-coding-agent/src/core/package-commands.ts —\n# appName resolves to \"gsd\" for this binary)\ngsd install npm:@efrembaraldo/gsd-pi-discussion-arena\n\n# Alternatively, inside an interactive session:\n# /gsd extensions install @efrembaraldo/gsd-pi-discussion-arena\n```\n\nThen restart gsd-pi (or `/reload` in an interactive session).\n\n## Manual installation (without npm, for local testing)\n\n```bash\nmkdir -p ~/.gsd/agent/extensions/gsd-pi-discussion-arena\ncp -r index.ts participants.ts run-participant.ts package.json extension-manifest.json ~/.gsd/agent/extensions/gsd-pi-discussion-arena/\n\nmkdir -p ~/.gsd/agent/discussion-arena/participants\ncp participants/*.md ~/.gsd/agent/discussion-arena/participants/\n```\n\nFor a **project** scope (different participants per repo), create instead:\n\n```bash\nmkdir -p .gsd/discussion-arena/participants\ncp participants/*.md .gsd/discussion-arena/participants/\n```\n\nProject participants take precedence over user ones with the same `name`\n(the same project > user precedence rule gsd-pi uses for skills).\n\n## Verifying the installation\n\n```bash\ngsd extensions info gsd-pi-discussion-arena   # confirms the manifest was read\ngsd -p \"list the available tools\" --mode json | grep discussion_arena\n```\n\nQuick manual test, outside auto mode:\n\n```bash\ngsd\n> /discussion-arena Should we migrate hel-arxai from MongoDB 7.x to a hybrid model with Postgres for the relational data?\n```\n\n## Bootstrap\n\nThe `/discussion-arena-init` slash command scaffolds the project-level\ncoordination tree for the discussion arena. It is safe to run at any time,\neven after the extension is already installed and used.\n\n### Slash command: /discussion-arena-init\n\n```\n/discussion-arena-init\n```\n\nTakes no arguments. On first run it creates the following structure under\nthe current working directory:\n\n```\n.gsd/discussion-arena/\n├── participants/           # project-level participants (override of bundled/user)\n│   └── .gitkeep\n├── participants-overrides/ # per-role overrides for project participants\n│   └── .gitkeep\n└── transcripts/            # saved sessions of the discussion arena\n    └── .gitkeep\n```\n\nOn subsequent runs the command is **idempotent**: existing directories are\nleft untouched, and `.gitkeep` files are only written when a subdirectory is\nfreshly created. You can drop your own `analyst.md`, `architect.md`, etc.\ninto `participants/` and the command will never overwrite or disturb them\n— the init flow is non-destructive by design.\n\nThe command is **failure-safe**: it never throws. Filesystem errors\n(`EACCES`, `ENOSPC`, and similar) are collected into the result's `errors[]`\nand surfaced through the session notification, so the worst-case outcome is\na visible \"what failed\" message rather than a crashed pipeline.\n\n## Streaming mode\n\nThe `stream` parameter controls the live streaming mode of the discussion arena tool.\nDefault: `\"off\"` (current behavior).\n\n- `\"off\"` — No live streaming. The `onProgress` callback receives the\n  cumulative `partialTranscript` as usual.\n- `\"events\"` — Populates `details.streamingEvents: StreamingEvent[]` at\n  every discussion event. Each `StreamingEvent` carries `ts` (ISO 8601),\n  `type`, `participantId`, `round`, `costUsd`, `durationMs`,\n  `cumulativeCost`, `text`. Useful for UIs that want real-time per-participant\n  rendering.\n- `\"transcript\"` — Minimal stub (M018): accepts the parameter, emits a\n  warning to stderr, and falls back to `\"off\"`. Full implementation is\n  planned for a future slice.\n\nExample:\n\n```typescript\nawait discussionArena({\n  topic: \"Architectural trade-offs for module X\",\n  participants: [\"analyst\", \"architect\"],\n  rounds: 3,\n  stream: \"events\",\n});\n```\n\nNote: sessions with many participants and rounds can produce thousands of\nevents. The consumer is responsible for throttling and rendering.\n\n## Branching di sessioni\n\nThe `discussion_arena` tool accepts an optional `branch` parameter that\ncreates a new child session derived from an existing ancestor session,\nleaving the ancestor fully untouched. This is a capability-additive\nfeature (R058): it short-circuits the normal run flow and reuses the\nexisting `continuation?` mechanism of `runDiscussionArena`, so the round\nloop itself is unchanged. The validator lives in `branch.ts` as a pure\nhelper (`validateBranchRequest`) and is invoked before any subprocess is\nspawned, so the failure paths are fail-fast.\n\nThe `branch` parameter is a JSON-like object with four fields:\n\n- `fromSessionId` — string, the logical ID of the ancestor session\n  (defaults to `fromTopicSlug` when omitted).\n- `fromTopicSlug` — string, the topic-slug of the ancestor session used\n  for the transcript path lookup.\n- `afterRound` — integer with 1 ≤ value ≤ MAX_ROUNDS, the 1-based last\n  round (inclusive) to inherit from the ancestor's transcript.\n- `newTopic` — string, the topic of the new child session. It must not\n  already exist (no overwrite).\n\nBehavior on the happy path:\n\n- Creates a new transcript file named `<cwdHash>-<newTopic>.md` inside\n  `<cwd>/.gsd/discussion-arena/transcripts/`, with three new frontmatter\n  fields populated: `parentSessionId`, `parentTopicSlug`, and\n  `branchedFromRound`. These three fields are optional in the parser,\n  so legacy files written without them keep loading unchanged\n  (R064 anti-regressione).\n- Prefixes the ancestor transcript (rounds 1 through `afterRound`,\n  inclusive) as the starting context, so the child session continues\n  from that point with the same participants and the same accumulated\n  cost and duration.\n- The ancestor session file is left fully untouched: same content, same\n  mtime. No part of the ancestor is mutated.\n\nThree blocking error scenarios (validated up-front, before any subprocess\nis spawned — D058):\n\n1. `afterRound` is greater than the round count of the ancestor session —\n   the request is rejected and the existing files are not modified.\n2. The ancestor session cannot be found by `fromTopicSlug` — the request\n   is rejected with a canonical \"parent session not found\" error.\n3. `newTopic` collides with an existing transcript file — the request is\n   rejected. The existing file is never overwritten, even if the caller\n   asks for it explicitly.\n\nExample (the example takes the first two rounds of an ancestor\ndiscussion titled \"AI value in ERP\" and forks them as the starting\ncontext of a new child discussion titled \"AI value in ERP - optimization\nbranch\"; the ancestor file keeps its original content and mtime, the\nchild file is a brand-new session with the parent fields populated):\n\n```typescript\nawait discussionArena({\n  topic: \"AI value in ERP - optimization branch\",\n  participants: [\"analyst\", \"architect\"],\n  rounds: 2,\n  branch: {\n    fromSessionId: \"AI value in ERP\",\n    fromTopicSlug: \"AI value in ERP\",\n    afterRound: 2,\n    newTopic: \"AI value in ERP - optimization branch\",\n  },\n});\n```\n\nThis feature is purely additive: callers that do not pass `branch`\ncontinue to use the regular run flow unchanged. See\n`docs/architecture/invocation-flow.md` for the full source-anchored\ncontract of the factory short-circuit.\n\n## Decision schema\n\nThe `discussion_arena` tool accepts two optional parameters,\n`decisionSchema` and `persistDecision`, that together enable structured\nper-turn decision capture alongside the free-form transcript. This is\na capability-additive feature (R064): the existing flow is untouched\nwhen the parameters are omitted, so callers that never pass them keep\nworking with zero behavioral diff.\n\n`decisionSchema` is a JSON-like object describing the schema that every\nparticipant turn is expected to emit. It carries three fields:\n\n- `type` — string literal, currently the only supported value is\n  `\"approve-reject\"`. Additional types (e.g. `\"ranked\"`, `\"graded\"`)\n  will be added in future slices by extending the type's union; the\n  literal-only constraint keeps forward compatibility tight.\n- `description` — optional human-readable description, propagated to\n  participants as contextual hint (best-effort, depends on participant\n  cooperation).\n- `fields` — optional map of arbitrary key/value pairs, reserved for\n  future validation rules (enums, min/max, …). Currently a no-op\n  sink; accepted so future schema extensions can land without\n  breaking existing callers.\n\n`persistDecision` is an optional boolean. When `true`, the tool intends\nto persist the synthesized final decision via an MCP write (R066).\nThe MCP writer is not yet implemented in M018/S05 — passing `true`\nemits a canonical `[discussion-arena] warning` on stderr and sets\n`details.persistDecisionWritten = false`. A dedicated slice is\nrequired to enable the actual write path.\n\n### Output format\n\nEvery participant turn (including the Scribe synthesis turn) may embed\nzero or more fenced decision blocks in the transcript. The delimiter\nfor per-turn decisions is triple backticks followed by `decision`:\n\n````text\n```decision\n{ \"choice\": \"approve\", \"confidence\": 0.9 }\n```\n````\n\nThe Scribe synthesis turn may additionally emit a single\n`final-decision` block to canonically record the synthesized arbitration\nresult:\n\n````text\n```final-decision\n{ \"consensus_level\": 0.85, \"final_choice\": \"approve\" }\n```\n````\n\nThese blocks are orthogonal to the existing `extractResearchDecisions`\nmarkdown-section parser: the two systems coexist on the same transcript\nwithout interfering with each other.\n\nWhen `decisionSchema` is set, the factory enriches the response's\n`details` with three additional fields:\n\n- `details.decisions` — array of `{participantId, round, parsed,\n  parseError}` objects, one per per-turn block found in the transcript,\n  in document order. `parsed` is the JSON.parse'd payload (or `null`\n  if malformed); `parseError` is the parser's error message (or `null`\n  on success). The raw text of the block is intentionally omitted\n  from this envelope to keep it minimal — the full transcript is\n  still returned in the response content for callers that need it.\n- `details.finalDecision` — `{rawText, parsed, parseError}` from the\n  Scribe's `final-decision` block, or `undefined` if no Scribe turn\n  was produced (or the Scribe emitted no final-decision block). When\n  present, `rawText` is included because the Scribe's synthesis is\n  authoritative arbitration content.\n- `details.persistDecisionWritten` — boolean, only present when\n  `persistDecision: true`. Always `false` in M018/S05 (MCP writer\n  not implemented; see warning above).\n\n### Five tolerant error scenarios\n\nThe factory does not reject malformed input; instead, it populates the\nenvelope so callers can introspect failures:\n\n1. **JSON malformed** — a `decision` or `final-decision` block whose\n   payload is not valid JSON (e.g. truncated, wrong quotes, comments\n   inside). Result: the corresponding `details.decisions[i].parsed` is\n   `null` and `parseError` carries the parser message.\n2. **No decision block found** — the transcript contains no `decision`\n   blocks at all. Result: `details.decisions` is an empty array; no\n   error is raised.\n3. **No Scribe synthesis** — the transcript has no Scribe turn (no\n   role equals `\"Scribe\"`). Result: `details.finalDecision` is\n   `undefined` (the field is omitted from the envelope, not set to\n   `null`).\n4. **Scribe without final-decision block** — the Scribe emits a turn\n   but no `final-decision` fenced block. Result: `details.finalDecision`\n   is `undefined` (same as no Scribe).\n5. **Scribe with malformed final-decision block** — the Scribe emits a\n   `final-decision` block with invalid JSON. Result:\n   `details.finalDecision.parsed` is `null` and `parseError` is\n   non-null. The field IS present (not `undefined`) because the caller\n   wants to know the block exists but is broken.\n\n### Behavior outside the happy paths\n\n- **Replay short-circuit** — when `replay` is set, the response is\n  served from the saved transcript without invoking\n  `runDiscussionArena`. No decision schema enrichment is applied;\n  `details.replay` carries the replay metadata unchanged.\n- **Branch path** — when `branch` is set, the child session's\n  transcript is enriched identically to the main run path. The same\n  five error scenarios apply on the branch transcript.\n- **Error catch** — when `runDiscussionArena` throws, the catch\n  handler returns `details.pendingResearchWritten: false` directly,\n  without invoking the decision schema enrichment.\n\n### Backward compatibility (R064)\n\nCallers that do not pass `decisionSchema` see exactly the same\nresponse shape as before M018/S05. The three new `details` fields are\npopulated only when `decisionSchema !== undefined`. This is verified\nby an anti-regression test in `tests/decision-schema.test.ts`.\n\n### End-to-end example\n\n```typescript\nconst result = await discussionArena({\n  topic: \"Refactor auth provider\",\n  participants: [\"engineer\", \"reviewer\"],\n  rounds: 2,\n  decisionSchema: {\n    type: \"approve-reject\",\n    description: \"Approve or reject the proposed refactor\",\n  },\n});\n\n// result.details.decisions:\n// [\n//   { participantId: \"engineer\", round: 1, parsed: { choice: \"approve\", confidence: 0.9 }, parseError: null },\n//   { participantId: \"reviewer\", round: 1, parsed: { choice: \"approve\", confidence: 0.8 }, parseError: null },\n//   { participantId: \"engineer\", round: 2, parsed: null, parseError: \"Unexpected token } in JSON at position 42\" },\n// ]\n\n// result.details.finalDecision:\n// { rawText: \"{ \\\"consensus_level\\\": 0.85, \\\"final_choice\\\": \\\"approve\\\" }\",\n//   parsed: { consensus_level: 0.85, final_choice: \"approve\" },\n//   parseError: null }\n```\n\nSee `docs/architecture/invocation-flow.md` for the source-anchored\ncontract of the enrichment wiring in the factory.\n\n## Viewer\n\nThe command `discussion-arena-view <id>` renders the discussion arena event log\nof a completed run into a single self-contained HTML file that you can open\noffline in any browser.\n\n- `<id>` is the `details.discussionArenaId` value returned by the\n  discussion arena tool. The event log exists only for runs started with\n  `eventLog: true`;\n  for an id without an event log the command fails with\n  `event log not found or empty: <id>`.\n- The file is written to `<cwd>/.gsd/discussion-arena/views/<id>.html`. On\n  success the command notifies the written path together with a ready-to-open\n  `file://` URL; on failure it notifies\n  `[discussion-arena-view] error: <message>` (the other canonical failure is\n  `invalid replay id format: <id>` for a malformed id).\n- Open the produced file in any browser via the printed `file://` URL.\n\nGuarantees of the generated file:\n\n- Standalone document: `doctype` / `html` / `head` (inline `<style>`) / `body`\n  / `main` with one `article` per round.\n- Embedded CSS with `prefers-color-scheme` support (dark mode included);\n  zero external assets: no `<link>`, no `script src=`, no CDN reference.\n- Every participant text is HTML-escaped (`&`, `<`, `>`, quotes), so\n  participant output can never inject markup or scripts (no XSS).\n- Idempotent: re-running the command for the same id rewrites the file\n  byte-identically (rendering is deterministic and clock-free).\n- When the decision schema is active, each round with a well-formed decision\n  block shows a decision box with the pretty-printed parsed JSON; a malformed\n  block shows a visible parse error instead.\n\n## Status\n\nThe command `discussion-arena-status` (no arguments) reports a read-only\nsnapshot of the discussion arena data for the current working directory,\ndelivered through a session notification prefixed\n`[discussion-arena-status]` — never on stdout.\n\nWhat it shows:\n\n- **Sessions, turns, aggregated cost** — number of transcript sessions (at\n  most the latest 20 by modification time), the total `### Round` turns\n  counted in them, and the summed USD cost from the per-session event logs.\n- **Engine distribution** — sessions classified from the\n  `<!-- engine: ... -->` markers in the transcript (`gsd`, `hermes`,\n  or `unknown`).\n- **Outcomes** — `complete` / `partial` / `unknown` counts from the session\n  event logs.\n- **Health probe** — the last persisted outcome from `health.json` plus a\n  failure counter, always visible even when it is `0` (it is `1` when the\n  last known outcome is anything other than `success`).\n- **Structured metrics** — the `metrics.json` counters when present;\n  an explicit `non disponibili (<path>)` line when the file is missing\n  or malformed.\n- **Paths** — the transcripts/events/health/metrics locations, always\n  shown even when the files do not exist yet.\n\nGuarantees:\n\n- Purely read-only: no subprocesses, no writes of any kind.\n- No parent-directory traversal: it reads only under\n  `<cwd>/.gsd/discussion-arena/`.\n- At most the 20 most recently modified sessions are counted; when there\n  are more, the report says so explicitly (older sessions are not counted).\n- Corrupted or unreadable files are counted as `unreadable` in the report\n  and are never fatal — the command never throws on hostile input.\n- Output goes through the session notify channel only, never stdout.\n\n## Customizing roles and skills\n\nAfter installation the discussion arena works out of the box with the 4\nbundled example participants (`analyst`, `architect`, `dev`, `qa`). To add or\noverride roles, create a `.md` file in one of these directories (precedence:\nproject > user > bundled):\n\n- `.gsd/discussion-arena/participants/` — project level (walk-up to the git root)\n- `~/.gsd/agent/discussion-arena/participants/` — user level\n- `participants/` next to the installed module — the bundled examples (conceptual read-only)\n\n## Configuring the model\n\nEach participant `.md` can specify `model:` in the frontmatter — it is the\nmodel used to spawn `gsd` as a subprocess for that participant:\n\n```markdown\n---\nname: analyst\nrole: Business Analyst\ndescription: Clarifies requirements\nmodel: claude-sonnet-5            # ← model for this participant\ntools: read, grep\n---\n```\n\nIf `model:` is omitted, the `gsd` subprocess uses the active model of the\nparent session (i.e. the one set with `/model` or `gsd --model`).\n\nTo force a model **for an entire session** without editing files, use the\n`--model <id>` command flag:\n\n```\n/discussion-arena \"topic\" 2 --model claude-sonnet-5\n```\n\nThe override applies to all rounds of the session; on the next invocation\nwithout `--model`, participants fall back to their `.md`.\n\n## Persistent sessions and continuation\n\nEvery command invocation saves the cumulative transcript to\n`<cwd>/.gsd/discussion-arena/transcripts/<cwd-hash>-<topic-slug>.md` (YAML frontmatter + markdown body). Project-relative: the transcript is visible in the repo working tree (tip: add `.gsd/` to your project `.gitignore` if you don't want to commit transcripts).\n\nTo add rounds to an existing session without starting over, use `--continue`:\n\n```\n/discussion-arena \"AI value in ERP\" 2           # rounds 1-2, saves the session\n/... read, decide ...\n/discussion-arena \"AI value in ERP\" 1 --continue # round 3 (continuous numbering)\n/discussion-arena \"AI value in ERP\" 2 --continue # rounds 4-5, then you see the MAX_ROUNDS message\n```\n\nWithout `--continue`, every invocation starts from scratch. `--new` forces a\nnew session even if a file already exists.\n\nEach `.md` file follows this frontmatter:\n\n```markdown\n---\nname: unique-identifier       # used to invoke it from participants: [...]\nrole: Label shown in the transcript\ndescription: One line, also used in the tool promptSnippet\ntools: read, grep, find, ls        # optional — subset of allowed tools\nmodel: claude-sonnet-5             # optional — model override for this role\n---\n\nFile body = the role's system prompt. Behavioral instructions,\nnot domain knowledge to repeat every round.\n```\n\nI included 4 example participants (`analyst`, `architect`, `dev`, `qa`),\ntranslated from the equivalent BMAD-METHOD roles (`bmad-agent-analyst`,\n`bmad-agent-architect`, `bmad-agent-dev`, plus a QA synthesized from the\n`bmad-qa-generate-e2e-tests`/`bmad-code-review` skills since BMAD has no\nsingle dedicated QA agent file in the current v6). Add more by copying the\nschema — e.g. a `ux-designer.md` from the content of\n`bmad-agent-ux-designer/SKILL.md`.\n\n## Auto-mode: three activation tiers (Tier 1-2-3)\n\nInside the gsd-pi auto loop the discussion arena behavior has **two states**:\n\n- **Available** — in every phase (`researching`, `planning`, `executing`,\n  `verifying`, `closeout`) the `discussion_arena` tool is registered and\n  visible to the agent, which can invoke it on its own when it considers it\n  useful, as the tool's `promptGuidelines` urge it to do (decisions that\n  benefit from multiple perspectives, not executive work).\n- **Forced** — only in the `planning` phase and only if one of the Tier 1/2\n  triggers below is active, the extension forces the agent to use the\n  discussion arena before deciding the plan: it adds the tool to the toolset\n  and injects a specific instruction into the prompt.\n\nThe decision between the two states is a pure function (`trigger-resolver.ts`)\nwith deterministic order — it never throws, there is always a result:\n\n1. **Tier 1 — environment variable.** `GSD_DISCUSSION_ARENA_AUTO=1` →\n   the discussion arena is mandatory (source `env`). The simplest and most\n   global way to force it: set the variable in the terminal before starting\n   `gsd auto`.\n2. **Tier 2 — coordination file (`activation:`).** If in the `activation:`\n   section of `<cwd>/.gsd/discussion-arena/discussion-arena-coordination.md`\n   the current milestone has `milestones.<MID>.enabled: true`, or `enabled:\n   true` at global level, the discussion arena is mandatory (source\n   `preferences`). The legacy `discussion_arena:` section in\n   `<cwd>/.gsd/PREFERENCES.md` is still honored for backwards compatibility\n   but emits a one-shot deprecation warning; see\n   [Migration path](#migration-path-discussion_arena--activation).\n3. **Tier 3 — availability-only fallback.** If neither Tier 1 nor Tier 2\n   enable it, the default is `availability-only`: the discussion arena stays\n   **available but not forced** (no `adjust_tool_set` adds it, no instruction\n   in the prompt). It is the default M001 behavior, deterministic and safe.\n\nTier 1 and Tier 2 are the only paths that make the invocation **mandatory**.\n`always-on` as a fallback would be too aggressive: the user could not disable\nthe discussion arena for a low-risk milestone without an explicit opt-out.\n\n### Migration path: `discussion_arena:` → `activation:`\n\nThe `discussion_arena:` section in `<cwd>/.gsd/PREFERENCES.md` is\n**deprecated** but still read. New setups — and the interactive wizard —\nconfigure the discussion arena in the coordination file\n`<cwd>/.gsd/discussion-arena/discussion-arena-coordination.md` under the\n`activation:` section. The two share the same keys and the same 2/4/6-space\nindentation contract (D025), so migration is a straight copy.\n\nA project that still defines the legacy section shows a one-shot warning on\nstderr:\n\n```\n[discussion-arena] DEPRECATION: discussion_arena: section in PREFERENCES.md is deprecated — move to .gsd/discussion-arena/discussion-arena-coordination.md under activation:.\n```\n\nTo migrate, remove `discussion_arena:` from `PREFERENCES.md` and add\n`activation:` to the coordination file:\n\n```yaml\nactivation:\n  enabled: true\n  mode: per-milestone\n  milestones:\n    M001:\n      enabled: true\n```\n\n### The (legacy) `discussion_arena:` schema in PREFERENCES.md (D025)\n\nInside the frontmatter of `<cwd>/.gsd/PREFERENCES.md` (minimal YAML parser,\nzero dependencies — D004), the section uses this schema:\n\n```yaml\ndiscussion_arena:\n  enabled: false            # bool — default false; true = always-on\n  mode: availability-only   # per-milestone | always-on | availability-only\n  milestones:\n    M003:\n      enabled: true         # force only for that milestone\n```\n\nThe parser distinguishes 4 states: missing file, missing section, valid\nconfig, malformed config — on malformed config it emits a warning (never a\n`throw`) and applies the deterministic fallback.\n\n### Interactive wizard (TUI) at milestone_start\n\nAt the `milestone_start` event, if the session has a TUI (`hasUI === true`),\nthe extension proposes a 3-choice picker (`ui.select`) and persists the\nchoice **atomically** (read-modify-write) in the `activation:` section of the\ncoordination file\n`<cwd>/.gsd/discussion-arena/discussion-arena-coordination.md`:\n\n- `per-milestone` → writes `activation.milestones.<MID>.enabled: true`\n- `always-on` → writes `activation.enabled: true`\n- `availability-only` → writes `activation.enabled: false` (default)\n\nIf `hasUI === false` (CI/print/no-TUI mode), the wizard is a **strict no-op**:\nit only writes a diagnostic to `stderr` and returns, never blocking the\npipeline.\n\n### Phase hooks (S06)\n\nThe current phase is tracked by the `unit_start` event (D024). The obligation\nto use the discussion arena fires only when both conditions are true: the\ncurrent phase is `planning` **and** `resolveTrigger().decision === \"forced\"`. In that\ncase:\n\n- `adjust_tool_set` adds `discussion_arena` to `toolNames` (removes nothing);\n- `before_agent_start` adds an idempotent instruction to the prompt\n  (identified by an HTML marker, never duplicated) that pushes to use the\n  discussion arena before deciding the plan.\n\nIn every other phase (`executing`, `verifying`, `closeout`), or in decision\n`availability-only`, the tool stays registered but **never forced**.\n\n## Known limitations\n\n- `MAX_PARTICIPANTS = 8`, `MAX_ROUNDS = 5` — hardcoded in\n  `index.ts`, raise them if you need wider discussions.\n- For very long transcripts (e.g. after many `--continue` sessions), the\n  prompt passed to the model is truncated to ~100KB discarding the oldest\n  rounds (prompt only — the full transcript on disk is preserved, see the\n  \"Persistent sessions\" section).\n- Every turn of every participant is a full `gsd` process: cost and latency\n  scale linearly with participants × rounds. With 4 participants and 2 rounds\n  that is 8 model invocations for a single tool call.\n- It has not been compiled against the real gsd-pi tree (that would require\n  `pnpm install` of the whole monorepo): the `ExtensionAPI`,\n  `ToolDefinition`, `AgentToolResult` signatures were verified by reading\n  `packages/pi-coding-agent/src/core/extensions/extension-upstream-types.ts`\n  and `packages/pi-agent-core/src/types.ts` in the cloned repo, but a real\n  `tsc --noEmit` before the first production use is recommended.\n\n### Integration gaps with gsd-pi (Vision v2 §2)\n\nBeyond the internal limits above, the extension has **not** yet achieved the\n\"deterministic forced integration\" described in Vision v2 §2. That analysis\n(seven gaps, G1–G7) lives in an internal planning document kept in the local\nworking tree as an honest, in-flight artifact — untracked in git and not part\nof the shipped docs graph. Each gap below lists its current state\n(`workaround` = a local mitigation exists, `open` = no mitigation yet):\n\n- **G1** — `unit_start` is never emitted by `gsd-pi` (no `before_agent_start`\n  call-site), so every auto-mode hook is a no-op and Tier 1/2/3 \"forced\" does\n  not run. *State: open* (degraded probe workaround is theoretical only).\n- **G2** — The `\"planning\"` unit-type does not exist in `gsd-pi`, so even if\n  G1 were fixed `currentUnitType` would not match; hooks stay silently\n  inactive. *State: open*.\n- **G3** — The bundled model `minimax/minimax-m3` (verified in\n  `participants/architect.md:6`, `participants/analyst.md:6`,\n  `participants/dev.md:6`, `participants/qa.md:6`, and in all\n  `examples/participants/*.example.md`; provider-id format per D092)\n  must be resolvable in the caller's registry or participant subprocesses\n  fail out-of-the-box and the quickstart does not work. *State:\n  workaround* — point the model at a valid provider/project-level\n  `model_default` in the coordination file.\n- **G4** — `writePendingResearch` is never invoked from `index.ts` and no\n  `scribe` participant is bundled, so the S04 pipeline\n  (research-decision → REQUIREMENTS.md) is dead. *State: open*.\n- **G5** — `adjust_tool_set` short-circuits on the first handler\n  (`runner.ts:1183`), a race between the core listener and the extension\n  listener; the tool injection is not applied unless the load order is the\n  expected one. *State: workaround* — this is a load-order concern handled\n  by the upstream framework; the extension manifest intentionally does not\n  declare a `priority` field (D083 removed it because the loader did not\n  honor it), so we rely on the documented core-first extension ordering.\n- **G6** — The test suite is entirely stub-based (redirect of\n  `@gsd/pi-coding-agent` to `tests/fixtures/`): CI passes by simulating\n  events that `gsd-pi` does not emit. *State: open*.\n- **G7** — `extension-manifest.json` declares neither capabilities nor\n  runtime dependencies, so the registry cannot guess what the extension\n  expects out-of-the-box. *State: open*.\n\nThe seven runtime risks (R1–R7) these gaps imply are tracked in\n[`docs/architecture/runtime-fallbacks.md`](docs/architecture/runtime-fallbacks.md) /\n[`runtime-fallbacks.it.md`](docs/architecture/runtime-fallbacks.it.md). As\nof this writing, R1, R2, R3, R5, and R6 are populated with their local\nmitigations (zero-PR umbrella strategy, `src/phase-mapping.ts` matrix,\nTier F/A/D/G runtime classifier, the S02 scribe bundled as\n`participants/scribe.md`, and the S01 cross-process lock); R4 and\nR7 remain explicit \"not yet implemented\" placeholders (honest\nskeletons, not closure claims).\n\n## License\n\nMIT License\n\nCopyright (c) 2026 Efrem Baraldo\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","readmeFilename":"README.md"}