# L12 — Skills **Binôme :** `dev-skills` / `test-skills` **Zones :** `domain/skill`, `application/skill`, `infrastructure/store`, `frontend/features/skills` **Dépendances amont :** L0, L1, L5, L6 (convention file généré à l'activation), L7 (store global réutilisé). ## Objectif Modéliser les **Skills** : workflows réutilisables (équivalent universel des slash-commands, sans dépendance à la syntaxe `/command` d'un modèle). Stockage global IDE + projet, assignation agent↔skills, **injection des skills assignés dans le convention file** généré à l'activation de l'agent. Cf. ARCHITECTURE §14.2. ## Périmètre (DEV) - **Domaine** : entité `Skill { id, name, content_md: MarkdownDoc, scope: SkillScope(Global|Project) }`. Invariants : `name` non vide, `content_md` non vide. Event `SkillAssigned`. - **Port `SkillStore`** : CRUD skills globaux (`/IdeA/skills/`) + skills projet (`.ideai/skills/.md`), résolution selon `scope` (compose `FileSystem`/store global comme L7). - **AgentManifest** : étendre pour porter la liste `skills: Vec` assignés à chaque agent (0..N). - **Use cases** (`application/skill`) : `CreateSkill`, `UpdateSkill`, `DeleteSkill`, `ListSkills(scope)`, `AssignSkillToAgent`, `UnassignSkillFromAgent`. - **Injection** : à l'activation (fil L6), composer le convention file en concaténant persona agent + chemin project root + **skills assignés** (lus via `SkillStore`). Pas de mécanisme CLI propriétaire. - **Front** : onglet/section Skills (liste globale + projet, CRUD, éditeur md), assignation skills↔agent dans `AgentsPanel`. ## Périmètre (TEST) - `Skill` rejette `name`/`content_md` vides. - `SkillStore` : CRUD round-trip en tmpdir pour les deux scopes ; un skill `Project` n'apparaît pas dans le scope `Global` et inversement. - `AssignSkillToAgent` / `UnassignSkillFromAgent` : mutent l'`AgentManifest`, émettent `SkillAssigned`, idempotents (pas de doublon). - **Injection** : le convention file généré contient bien le `content_md` des skills assignés et **rien** des skills non assignés ; ordre déterministe. - Front : CRUD skills + assignation via gateway mock (RTL) ; garde-fou « no direct invoke ». ## Definition of Done - `cargo test` (skill/store/app) + `vitest` verts ; cycle manuel : créer un skill, l'assigner à un agent, l'activer → le skill apparaît dans le convention file de `.ideai/run//`. - DoD commune (cf. README) respectée ; zéro régression. ## Avancement ### ✅ Domaine (vert) - **Entité `Skill`** (`domain/skill.rs`) : `id: SkillId`, `name`, `content_md: MarkdownDoc`, `scope: SkillScope(Global|Project)`. Constructeur validant (`name` + `content_md` non vides), `with_content` re-valide l'invariant. - **`SkillRef { skill_id, scope }`** : référence d'assignation portée par l'agent ; `From<&Skill>`. - **`SkillId`** ajouté (`ids.rs`), event **`SkillAssigned { agent_id, skill_id, assigned }`** (`events.rs`), DTO + arm de mapping côté `app-tauri` (`events.rs`). - **`Agent`** étendu : champ `skills: Vec` (serde `default`), méthodes `assign_skill` (idempotent), `unassign_skill`, `with_skills` (dédup). **`ManifestEntry`** : champ `skills` (serde `default` + `skip_serializing_if` → rétrocompat des manifests pré-L12) ; `from_agent`/`to_agent` préservent les skills. - **Tests** : 8 invariants (`entities.rs`) + 3 serde dont rétrocompat d'un manifest legacy sans clé `skills` (`serde_roundtrip.rs`). `cargo test -p domain` vert ; `cargo test --workspace` vert (0 régression) ; clippy clean. ### ⏳ Reste à faire - Port `SkillStore` (`domain/ports.rs`) + adapter `FsSkillStore` (`infrastructure/store`). - Use cases `application/skill` : CRUD + `AssignSkillToAgent`/`UnassignSkillFromAgent`. - Injection des skills assignés dans le convention file à l'activation (fil L6). - IPC `app-tauri` + front `features/skills`.