Files
IdeA/.ideai/tickets/81/carnet.md
Blomios 98fb05447d chore(ideai): état runtime — tickets, mémoire, tâches de fond
État d'exécution accumulé (tickets créés/mis à jour hors #43, notes de
mémoire, tâche de fond) capturé au moment du commit de la feature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 07:37:19 +02:00

11 KiB

issueRef, version, updatedBy, updatedAt
issueRef version updatedBy updatedAt
#81 5
kind agent_id
agent a6ced819-b893-4213-b003-9e9dc79b9641
1784565918809

Cadrage — ticket #81

Objectif

Permettre aux agents IdeA d'administrer les templates d'agents via MCP, sans surface humaine nouvelle : créer, éditer et supprimer des templates globaux IdeA depuis des tools idea_*.

UX n'est pas concerné pour ce ticket : il n'y a pas d'écran, de workflow humain ni de libellés UI à concevoir. La seule surface est le catalogue MCP exposé aux agents.

État réel du système templates

Surfaces inspectées :

  • Domaine : crates/domain/src/template.rs
  • Port : TemplateStore dans crates/domain/src/ports.rs
  • Use cases : crates/application/src/template/usecases.rs
  • Store : crates/infrastructure/src/store/template.rs
  • Commands Tauri : crates/app-tauri/src/commands.rs
  • DTO : crates/backend/src/dto.rs / crates/app-tauri/src/dto.rs
  • Frontend existant : frontend/src/features/templates/*, frontend/src/adapters/template.ts
  • MCP + permissions #82 : crates/infrastructure/src/orchestrator/mcp/tools.rs, server.rs, backend/src/openai_tools.rs, app-tauri/src/openai_tools.rs

Templates existants :

AgentTemplate {
  id: TemplateId,
  name: String,
  content_md: MarkdownDoc,
  version: TemplateVersion,
  default_profile_id: ProfileId,
}

Invariants existants :

  • name non vide ;
  • version démarre à 1 ;
  • version est bumpée par AgentTemplate::with_updated_content, donc par changement de contenu Markdown ;
  • default_profile_id sert aux futurs agents créés depuis le template.

Stockage existant : global app-data, pas projet :

<app_data_dir>/templates/
├── index.json
└── md/<template-id>.md

index.json porte les métadonnées (id, name, version, contentHash, defaultProfileId) ; le Markdown vit dans md/<id>.md. Le store est déjà derrière TemplateStore, donc Tauri-agnostique côté infra.

Synchronisation template → agents

Les agents créés depuis un template copient le content_md dans leur propre contexte .md projet et gardent dans le manifeste :

  • template_id
  • synchronized
  • synced_template_version

UpdateTemplate actuel met à jour le template global, bump la version et publie DomainEvent::TemplateUpdated. Il ne modifie pas directement les agents existants.

DetectAgentDrift compare template.version > synced_template_version pour les agents synchronized == true et publie AgentDriftDetected.

SyncAgentWithTemplate est l'opération explicite qui remplace le .md de l'agent synchronisé par le contenu courant du template et met à jour synced_template_version.

Conclusion : si un agent édite un template via MCP, les agents synchronisés qui l'utilisent ne sont pas impactés immédiatement. Ils deviennent en drift jusqu'à appel explicite de sync. Au lancement suivant, ils relisent leur .md agent existant, pas automatiquement le template global. Ce comportement doit rester tel quel pour #81, sauf arbitrage produit séparé.

Tools MCP à ajouter

Ajouter une surface templates explicite ; idea_skill_read, idea_context_read et les tools existants ne couvrent pas les templates. Les templates ne sont ni des skills ni des contextes agent.

Proposition de catalogue :

Lecture, autorisée par défaut (#82)

  • idea_template_list

    • Rôle : lister les templates globaux disponibles.
    • Payload conseillé : templates complets ou résumés. Pour l'ergonomie agent, retour complet acceptable au premier lot (id, name, contentMd, version, defaultProfileId) car ListTemplates renvoie déjà les entités complètes.
  • idea_template_read

    • Rôle : lire un template par id.
    • Input : { "templateId": "..." }
    • Retour : même DTO qu'un template Tauri.
    • Nécessite un thin use case ReadTemplate ou un provider qui appelle TemplateStore::get via un use case applicatif dédié.

Écriture/action, refusée par défaut (#82)

  • idea_template_create

    • Input : { name, content, defaultProfileId }
    • Réutilise CreateTemplate.
    • Retour : template créé.
  • idea_template_update

    • Input minimal aligné existant : { templateId, content }.
    • Réutilise UpdateTemplate actuel, qui met à jour le contenu et bump la version.
    • Extension recommandée si on veut couvrir pleinement "éditer" : accepter aussi name? et defaultProfileId?, avec bump de version seulement si content change. Cela nécessite d'étendre le domaine/use case car aujourd'hui l'UI elle-même ne persiste pas le changement de nom/profil en mode edit.
    • Option de sûreté à arbitrer : ajouter expectedVersion pour éviter les écrasements concurrents entre agents. Le store/use case Tauri actuel n'a pas d'optimistic concurrency sur templates, donc ce serait une extension de contrat, pas une simple exposition MCP.
  • idea_template_delete

    • Input : { templateId }
    • Réutilise DeleteTemplate.
    • Effet existant : supprime de l'index global ; le fichier Markdown orphelin peut rester sur disque car le port FS n'a pas de delete. Les agents créés depuis ce template gardent leur .md; drift detection ignore le template absent.

Intégration obligatoire avec #82

#82 a introduit la classification canonique dans crates/infrastructure/src/orchestrator/mcp/tools.rs :

  • READ_ONLY_TOOLS
  • WRITE_ACTION_TOOLS
  • tool_access
  • test garde-fou catalogue_tools_have_explicit_read_or_write_access

Tout tool ajouté au catalogue doit être classé immédiatement, sinon le test doit échouer.

Classification #81 attendue :

READ_ONLY_TOOLS += [
  "idea_template_list",
  "idea_template_read",
]

WRITE_ACTION_TOOLS += [
  "idea_template_create",
  "idea_template_update",
  "idea_template_delete",
]

Comportement policy attendu :

  • agent sans override #82 : peut lire/lister les templates, ne peut pas créer/éditer/supprimer ;
  • agent avec override incluant un ou plusieurs tools idea_template_* d'écriture : peut seulement appeler ceux explicitement autorisés ;
  • le refus doit arriver avant effet applicatif, sur le serveur MCP stdio et sur l'invoker OpenAI-compatible.

Ce comportement est cohérent avec la demande #82 : par défaut seuls les tools de lecture sont autorisés. Pas d'arbitrage produit nécessaire sauf si l'utilisateur veut que certains agents aient une permission template-write préconfigurée par défaut.

Point d'implémentation recommandé

Ne pas ajouter ces opérations au OrchestratorCommand sauf nécessité. Les templates sont une famille CRUD applicative, comme les tickets, pas un protocole d'orchestration inter-agent. Le pattern le plus local est donc de créer un provider MCP dédié, parallèle à TicketToolProvider :

  • crates/infrastructure/src/orchestrator/mcp/templates.rs

    • TemplateToolProvider
    • TemplateToolError
    • is_template_tool(name)
    • catalogue() des tools templates
  • crates/infrastructure/src/orchestrator/mcp/tools.rs

    • étendre catalogue() avec templates::catalogue() ;
    • ajouter is_template_tool ;
    • ajouter les 5 tools dans les classifications #82 ;
    • si besoin, faire retourner tool_returns_reply pour les read/create/update/list/delete selon convention (delete peut retourner un ACK JSON).
  • crates/infrastructure/src/orchestrator/mcp/server.rs

    • ajouter template_tools: Option<Arc<dyn TemplateToolProvider>> ;
    • dans tools_call, après enforcement #82 et avant map_tool_call, router is_template_tool vers le provider, comme les tickets ;
    • garder l'enforcement durable/éphémère avant provider.
  • Composition root backend/app-tauri

    • créer LateBoundTemplateToolProvider si besoin pour casser les cycles comme LateBoundTicketToolProvider ;
    • binder un AppTemplateToolProvider construit avec create_template, list_templates, update_template, delete_template et le nouveau read_template si ajouté ;
    • injecter ce provider dans McpServer::new(...).with_template_tools(...) ;
    • injecter aussi dans AppOpenAiToolInvoker pour parité OpenAI-compatible.

Alternative possible : ajouter des variants OrchestratorCommand::Template* et mapper les tools via map_tool_call. Je ne la recommande pas en premier choix : cela gonfle l'orchestrateur avec un CRUD global qui n'est pas une coordination agent-agent, alors que le précédent ticket système a déjà accepté le pattern provider pour les tickets.

Lots proposés

Lot B1 — Catalogue MCP + classification #82 + provider squelette

  • Ajouter templates.rs côté MCP infra.
  • Ajouter les 5 tool defs.
  • Classer immédiatement idea_template_list/read en lecture et create/update/delete en écriture/action.
  • Tests : garde-fou catalogue/classification vert ; tools/list expose les templates selon policy #82.

Lot B2 — Use cases/DTO/provider templates

  • Ajouter ReadTemplate use case fin si on garde idea_template_read.
  • Implémenter AppTemplateToolProvider avec les use cases existants.
  • Mapper erreurs : notFound, invalid, store, internal.
  • Tests provider : create/list/read/update/delete sur fakes, version bump sur update contenu.

Lot B3 — Enforcement policy + OpenAI-compatible parity

  • Vérifier MCP stdio : un agent default read-only peut idea_template_list/read, mais idea_template_create/update/delete est refusé avant provider.
  • Vérifier override #82 : autoriser seulement idea_template_update n'autorise pas create/delete.
  • Répliquer le dispatch provider dans AppOpenAiToolInvoker, avec même policy durable avant effet.

Lot B4 — Édition complète optionnelle

À faire seulement si le produit veut que "éditer" couvre autre chose que le contenu Markdown :

  • étendre UpdateTemplateInput avec name?, defaultProfileId?, content? ;
  • préserver l'invariant : bump version uniquement quand content_md change ;
  • décider si changement de defaultProfileId doit avoir un effet sur agents existants (recommandation : non, seulement futurs CreateAgentFromTemplate) ;
  • ajouter éventuellement expectedVersion pour update/delete, avec erreur de conflit.

Frontières

Frontend/UX : hors périmètre. Aucune surface humaine nouvelle.

Domaine templates : réutiliser AgentTemplate, TemplateVersion, TemplateStore. Extension domaine seulement si B4 est retenu.

Projet .ideai/agents.json : hors périmètre pour CRUD templates. Les agents créés depuis template et leur sync existante restent inchangés.

Synchronisation automatique : hors périmètre. #81 ne doit pas auto-écraser les .md des agents synchronisés après update template ; laisser DetectAgentDrift/SyncAgentWithTemplate piloter cela.

Permissions #82 : dans le périmètre obligatoire. Aucun tool template ne doit entrer dans le catalogue sans classification explicite et sans enforcement identique MCP stdio/OpenAI-compatible.

Critères d'acceptation

  • Les agents voient les tools template dans le catalogue MCP selon leur policy #82.
  • Les tools lecture template sont accessibles à un agent sans override.
  • Les tools create/update/delete sont refusés à un agent sans override, avant mutation.
  • Une policy agent qui autorise un write template permet uniquement ce write.
  • idea_template_update bump la version quand le contenu change et publie TemplateUpdated via le use case existant.
  • Les agents synchronisés au template passent en drift, mais ne sont pas modifiés tant qu'un sync explicite n'est pas demandé.
  • Les chemins MCP stdio et OpenAI-compatible ont la même sémantique et les mêmes refus.