CoDesign
README.md
# CoDesign
CoDesign est un service MCP Apps local pour concevoir un produit dans Goose, depuis les preuves et le cadrage jusqu’au handoff et à la QA.
## Installation locale
### Prérequis
- [Bun](https://bun.sh/) 1.3 ou supérieur ;
- Goose Desktop ;
- actuellement, un accès `read:packages` aux packages privés `@servier-github/*`, utilisés par la fixture CRA 360.
Le dépôt contient un `.npmrc` sans secret qui route uniquement `@servier-github/*` vers GitHub Packages. Injectez le token pendant l’installation :
```bash
git clone https://github.com/bioinfornatics/co-design.git
cd co-design
NODE_AUTH_TOKEN="<token GitHub avec read:packages>" bun install --frozen-lockfile
bun run build
```
Le token doit avoir accès aux packages Servier et, si nécessaire, être autorisé par le SSO de l’organisation. Ne le commitez jamais.
### Ajouter CoDesign à Goose
Dans `~/.config/goose/config.yaml`, ajoutez l’extension ci-dessous en remplaçant les deux chemins absolus :
```yaml
extensions:
co-design:
name: CoDesign
description: Product Design MCP App workspace
enabled: true
type: stdio
cmd: /chemin/absolu/vers/bun
args:
- /chemin/absolu/vers/co-design/packages/server/dist/stdio.js
timeout: 300
envs: {}
```
Obtenez le chemin de Bun avec `command -v bun` et le chemin du dépôt avec `pwd`. Dans Goose Desktop, cette même configuration peut aussi être saisie depuis **Extensions → Add custom extension**, avec le type **Standard IO**. Redémarrez ensuite Goose ou désactivez/réactivez CoDesign depuis **Extensions**.
### Ouvrir CoDesign
- **Recommandé** : dans une conversation, demandez à Goose d’appeler `open-design-workspace`. L’interface s’affiche dans le chat et peut publier son contexte à Goose.
- **Fenêtre autonome** : activez l’extension **Apps**, ouvrez **Apps** dans la barre latérale, puis lancez **Product Design Workspace**. Cette fenêtre autonome n’échange pas de messages avec Goose.
Les données locales sont conservées par défaut dans `~/.local/state/co-design/durable-demo.json`.
### Garder CoDesign visible
Depuis l’en-tête de l’espace de travail, utilisez **Garder visible** pour demander le mode picture-in-picture (PiP), recommandé afin de conserver CoDesign à portée pendant le défilement de la conversation. **Agrandir** demande le plein écran pour les travaux de conception, et **Retour au fil** revient au rendu inline. Ces commandes ne sont affichées que si l’hôte annonce les modes correspondants : selon la version ou l’hôte MCP Apps, elles peuvent donc être absentes. L’hôte reste décisionnaire et CoDesign applique le mode réellement accordé.
Cette intégration suit les API MCP Apps [`Host context`](https://modelcontextprotocol.io/docs/extensions/apps#host-context) et [`requestDisplayMode`](https://modelcontextprotocol.io/docs/extensions/apps#display-modes). Aucun changement de mode n’est demandé automatiquement, et les aperçus locaux n’établissent aucune connexion MCP.
### Dépannage rapide
- `401` ou `403` pendant `bun install` : vérifiez `read:packages`, l’accès aux packages et le SSO du token.
- CoDesign absent de Goose : vérifiez les chemins absolus, puis désactivez/réactivez l’extension.
- L’interface ne s’ouvre pas inline : demandez explicitement à Goose d’appeler `open-design-workspace`.
### Vérifier l’installation
```bash
bun run check
```
Cette commande exécute les vérifications TypeScript, les tests et les builds.
## Stack
- Bun 1.3+
- Elysia 1.4 pour l’adaptateur HTTP optionnel
- MCP TypeScript SDK 1.30 + MCP Apps 1.7
- React 19 + Vite
- Zod 4
## Pipeline visuel
CoDesign peut maintenant gouverner les sorties de `product-design:ideate` :
```text
3 planches candidates
→ sélection d’un parcours (réversible)
→ approbation du jeu exact d’écrans
→ Build Source Set immuable
→ binding route/état
→ comparaison source/rendu
→ annotations d’implémentation
```
Les images sont servies comme ressources MCP content-addressed et les chemins du dépôt ne sont jamais exposés au client. La fixture inclut les trois variantes V1–V3, le parcours HYBRID approuvé et un rendu React lié à H-S6. Ce rendu est volontairement marqué `mismatch`; H-S1 à H-S5 restent non capturés. Voir [docs/visual-ideation-pipeline.md](docs/visual-ideation-pipeline.md) et [design-qa.md](design-qa.md).
## Current vertical slice — Living Product Brief and traceable journey decision
- Canonical evidence carries a source locator and explicit verification status/method; insights reference evidence and every V1/V2/V3 journey references insights.
- `select-design-target` is host-presented and selects for review; selection is explicitly **not approval**.
- `approve-journey` is host-presented and requires rationale, at least one criterion, and `expectedRevision` optimistic concurrency control.
- Approval locks the decision and durably snapshots an immutable, versioned projection containing journey, screens, rationale, criteria, traceability and annotations.
- `get-implementation-handoff` is model-visible and refuses access before explicit host-presented approval.
- Approval publishes a compact Goose model context pointing to the handoff tool. Brief acceptance, rejection, and freeze publish compact brief lifecycle context; ordinary journey browsing and annotations remain canonical workspace state without context noise.
- One durable local portfolio stores multiple isolated projects. New projects are generic blanks; the bundled CRA 360 project is explicitly marked as an example fixture.
## Architecture
```text
apps/workspace React MCP App (single HTML)
packages/server/src/domain Runtime-independent session contract
packages/server/src/application State transitions
packages/server/src/mcp MCP tools and resource
packages/server/src/entrypoints stdio and Elysia HTTP entrypoints
```
## Verification
```bash
bun run check
```
This runs TypeScript checks, Bun unit/integration tests, the real stdio subprocess test, the live Elysia Streamable HTTP test, the React single-file integrity test, and both builds. The acceptance plan and expected deliverables are in [docs/plan.md](docs/plan.md).
| Surface | Evidence |
|---|---|
| Domain invariants and defensive copies | `packages/server/test/session-service.test.ts` |
| MCP Apps tools, visibility, resource and mutations | `packages/server/test/mcp.test.ts` |
| Real Bun stdio process and clean shutdown | `packages/server/test/stdio.test.ts` |
| Elysia HTTP, CORS and cross-request state | `packages/server/test/http.test.ts` |
| App bridge behavior and model context | `apps/workspace/test/controller.test.ts` |
| Self-contained HTML | `apps/workspace/test/build-integrity.test.ts` |
## Security baseline
HTTP binds to `127.0.0.1` by default. CORS accepts only `http://127.0.0.1` and `http://localhost` by default; override it with a comma-separated `CORS_ALLOWED_ORIGINS`. This is a local demo in `local-untrusted-caller` mode: every client with server access can invoke every tool, and `_meta.ui.visibility` is presentation metadata rather than authorization. Server-enforced authentication and authorization are blocking requirements before any remote or production exposure. Resource metadata declares no external origins. Do not put secrets or customer data in model context or annotations.
## Known limits
- Session, Product Brief, proposals, metadata history, decision and approved handoff survive restart in one local JSON snapshot; this is not a multi-user database or append-only audit log. Proposal payloads are strict allowlisted effective diffs; invalid/no-op proposals fail atomically, and legacy empty proposals fail closed without file mutation.
- Immutability is enforced through defensive snapshots; no cryptographic signing exists.
- The HTTP adapter is stateless at the MCP transport layer but shares one process-local domain service; it is not yet multi-tenant.
- Goose Desktop rendering, `ui/update-model-context` et les transitions réelles `ui/request-display-mode` nécessitent toujours une recette sur l’hôte ; les tests automatisés couvrent le contrat App/bridge, pas la WebView de Goose. Goose 1.47 fournit le handler de mode et son support effectif reste annoncé dynamiquement via `availableDisplayModes`.
- `@modelcontextprotocol/ext-apps@1.7.5` currently peers with MCP SDK 1.x, so the exact SDK `1.30.0` pin is deliberate. Upgrade both only after rerunning the full conformance suite.
- The server statically embeds `apps/workspace/dist/index.html`; build the workspace before starting or bundling the server. A missing asset is a build/startup failure, not a runtime fallback.
## Durable local portfolio
Real stdio and HTTP entrypoints persist one local portfolio snapshot outside the bundle. The default is `~/.local/state/co-design/durable-demo.json`; override its directory with `CODDESIGN_DATA_DIR`. Durable persistence is explicitly supported on Linux and macOS; startup rejects other platforms. The file is schema-validated on startup, written with owner-only directory/file modes, an fsynced same-directory temporary, atomic rename, and directory fsync. Missing state bootstraps the canonical demo with the same durability protocol. Invalid/corrupt state aborts startup explicitly and is never overwritten.
Every accepted mutation is persisted, including directory fsync, before MCP success. If a failure occurs after rename, the repository atomically restores and fsyncs the prior snapshot (or removes and fsyncs a first snapshot). If restoration cannot be proven, the call fails with a typed uncertain error and the service rereads disk to reconcile memory; it never reports a rollback it cannot prove. The workspace History view shows project-scoped metadata history and offers **Reset active project**. It requires the contextual phrase `RESET ACTIVE PROJECT: <current title>` plus current portfolio and session revisions. Reset is one atomic portfolio write: blank projects are recreated with `createBlankSession` from retained title/objective/design-target metadata and never receive CRA/capacity/DNA data; only the fixture-marked CRA project is recreated with `createDemoSession`. Other projects are unchanged. `get-demo-status` is model-visible; `get-design-history` and `reset-active-project` are host-presented.
### Exact local demo
```bash
bun install
bun run check
export CODDESIGN_DATA_DIR="$(mktemp -d)"
bun run build
bun run dev:stdio
```
Connect Goose to that stdio command, open `open-design-workspace`, create/review a brief proposal, select and approve a journey, then call `get-implementation-handoff`. Stop and restart the same command with the same `CODDESIGN_DATA_DIR`; call `get-demo-status`, reopen the workspace, and retrieve the handoff again. Use History to inspect events or type the exact reset confirmation. Do not print or inspect the state file through stdout while stdio is active.
## Suivi Beads optionnel
La feuille de route native reste la source de vérité. La Phase 0 détecte Beads 1.1.2 en lecture seule et affiche un aperçu pur de projection. Aucun outil Beads d’activation, synchronisation, déconnexion ou écriture n’est exposé, quel que soit le transport ou l’environnement. Les phases d’écriture restent planifiées et bloquées par les exigences de sécurité décrites dans [docs/beads-tracking.md](docs/beads-tracking.md).
### Local ideation import (explicit opt-in)
Dynamic visual import is **disabled by default** and is never enabled by the HTTP transport. It is a local stdio-only capability and is not an authorization boundary: production authentication remains a blocker.
To enable it, create a dedicated directory containing only import manifests/assets and start stdio with both variables set. `CODDESIGN_DESIGN_ROOT` must be absolute and already exist; there is no current-directory fallback.
```bash
mkdir -p "$HOME/co-design-imports"
CODDESIGN_IDEATION_IMPORT=1 \
CODDESIGN_DESIGN_ROOT="$HOME/co-design-imports" \
CODDESIGN_DATA_DIR="$HOME/.local/state/co-design" \
bun run dev:stdio
```
`get-ideation-import-status` reports `IDEATION_IMPORT_READY`, `IDEATION_IMPORT_DISABLED`, or a configuration error without revealing the absolute root. Preview/import tools remain app-only and return stable public error codes. Inputs are opened with no-follow descriptor checks, bounded before allocation, hashed, and revalidated at import/resource read. PNG/JPEG/WebP validation is structural **header-level validation**, not full decoding; dimensions are capped at 4096 px per edge and 16 MP. Imported paths therefore remain mutable local inputs and are descriptor/integrity checked on every use; fixture assets remain static and unaffected.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues