Decouvrez comment utiliser les Agent Skills pour enseigner a Claude Code les patterns modernes d'Angular (standalone, signals, inject). Tutoriel complet avec exemples pratiques, installation de la collection AnalogJS et bonnes pratiques pour creer vos propres skills.
Le problème : Claude génère du code Angular daté
Si vous utilisez Claude Code pour développer avec Angular, vous avez probablement rencontré ce problème récurrent : l'IA génère du code utilisant des patterns obsolètes comme les NgModules, les décorateurs @Input(), ou l'injection par constructeur, alors qu'Angular a introduit des approches modernes bien plus efficaces.
Ce décalage s'explique par la date de coupure des données d'entraînement : Claude ne connaît pas nativement les conventions les plus récentes d'Angular (standalone components, signals, fonction inject(), etc.).
Qu'est-ce que les Agent Skills ?
Les Agent Skills sont des fichiers d'instructions structurés qui enseignent à Claude des patterns de code spécifiques à votre projet. Pensez à eux comme des "fiches de recette" que vous donnez à un chef cuisinier : l'IA sait déjà coder, mais les Skills lui indiquent exactement comment vous voulez que ce soit fait.
Structure d'un Skill
Chaque Skill est composé de :
- SKILL.md : Fichier markdown avec un en-tête YAML définissant le nom et la description du Skill
- references/ : Dossier optionnel contenant des exemples détaillés de patterns
Exemple de structure :
.claude/
skills/
angular-component/
SKILL.md
references/
standalone-component.ts
signal-input.ts
Exemple de fichier SKILL.md
---
name: angular-component
description: Créer des composants Angular standalone avec signals et inject()
---
# Composant Angular moderne
Toujours utiliser les **standalone components** avec la nouvelle syntaxe.
## Pattern à suivre
<exemple>
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-user-profile',
standalone: true,
template: `
<div>
<h2>{{ name() }}</h2>
<button (click)="updateName()">Changer</button>
</div>
`
})
export class UserProfileComponent {
name = signal('John Doe');
updateName() {
this.name.set('Jane Doe');
}
}
</exemple>
## Anti-patterns à éviter
❌ Ne pas utiliser NgModules
❌ Ne pas utiliser @Input() avec décorateur (utiliser input())
❌ Ne pas injecter dans le constructeur (utiliser inject())
Comment les Skills s'intègrent dans Claude Code
Claude Code utilise trois couches de contexte qui fonctionnent ensemble :
1. CLAUDE.md - Fichier à la racine du projet définissant la stack technique et conventions générales
2. Skills - S'activent automatiquement selon la pertinence de la tâche
3. Built-in Skills - Gèrent la création de fichiers standards
Chargement progressif
Pour éviter de surcharger le contexte, Claude utilise un système de chargement progressif :
- Seuls les
nameetdescriptionde tous les Skills sont chargés initialement - Le contenu complet n'est chargé que lorsque le Skill devient pertinent pour la tâche en cours
La collection AnalogJS Angular Skills
Brandon Roberts, créateur d'AnalogJS, a publié une collection complète de Skills couvrant tous les aspects modernes d'Angular.
Contenu de la collection
- Composants : Standalone, signals, OnPush change detection
- Signals API : computed, effect, interop avec RxJS
- Injection de dépendances : fonction
inject(), providers modernes - Signal Forms : Formulaires réactifs avec signals
- HTTP Resources : Gestion des appels HTTP avec resources
- Routing : Routes standalone, guards fonctionnels
- Directives : Directives standalone modernes
- SSR : Server-Side Rendering avec Angular Universal
- Testing : TestBed moderne, Vitest pour Angular 21+
- CLI et outils : Commandes Angular CLI à jour
Installation
Pour installer la collection AnalogJS dans votre projet :
npx skills add analogjs/angular-skills
Cette commande télécharge automatiquement tous les Skills dans le dossier .claude/skills/ de votre projet.
Bonnes pratiques pour écrire vos propres Skills
1. Soyez concis
"Claude est déjà très intelligent. Ajoutez uniquement le contexte que Claude n'a pas déjà."
Ne répétez pas les bases de JavaScript, TypeScript ou Angular. Concentrez-vous sur vos conventions spécifiques.
2. Adaptez la spécificité au risque
Plus une opération est risquée ou critique, plus les instructions doivent être détaillées :
- Opérations critiques (migrations, modifications de base de données) → Instructions très précises
- Tâches créatives (design de composants) → Directives générales uniquement
3. Les anti-patterns comptent autant que les patterns
"Dire à Claude ce qu'il ne doit PAS faire est souvent plus précieux que de lui dire quoi faire."
Exemple :
## ❌ Anti-patterns à éviter
- Ne jamais utiliser NgModules dans les nouveaux composants
- Ne pas utiliser @Input() décorateur (privilégier input())
- Ne pas injecter via le constructeur (utiliser inject())
- Éviter BehaviorSubject pour l'état local (utiliser signals)
4. Privilégiez les exemples complets
Montrez des fichiers entiers plutôt que des fragments de code. Claude comprend mieux le contexte avec un exemple complet.
// ✅ BON : Exemple complet
import { Component, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-counter',
standalone: true,
imports: [CommonModule],
template: `
<div>
<p>Count: {{ count() }}</p>
<p>Double: {{ doubled() }}</p>
<button (click)="increment()">+</button>
</div>
`
})
export class CounterComponent {
count = signal(0);
doubled = computed(() => this.count() * 2);
increment() {
this.count.update(val => val + 1);
}
}
5. Divulgation progressive
Gardez le fichier SKILL.md principal sous 5 000 mots. Pour les détails complexes, créez des fichiers séparés dans references/.
.claude/skills/angular-state/
SKILL.md # Vue d'ensemble (2000 mots)
references/
signals.md # Détails sur signals
rxjs-interop.md # Interopérabilité RxJS
ngrx.md # Cas NgRx complexes
Implémentation pratique
Voici l'approche recommandée en trois étapes pour intégrer les Skills dans votre workflow Angular :
Étape 1 : Installer la collection AnalogJS
cd votre-projet-angular
npx skills add analogjs/angular-skills
Étape 2 : Créer un fichier CLAUDE.md
Créez un fichier CLAUDE.md à la racine de votre projet avec vos conventions globales :
# Projet Angular - Conventions
## Stack technique
- Angular 18+
- TypeScript 5.5+
- Standalone components uniquement
- Signals pour l'état réactif
- RxJS uniquement pour HTTP et événements asynchrones complexes
## Conventions de code
- Tous les composants doivent être standalone
- Utiliser input() et output() au lieu de @Input/@Output
- Injection via inject() plutôt que constructor
- OnPush change detection par défaut
- Pas de NgModules dans les nouveaux fichiers
## Structure des dossiers
src/
app/
features/ # Features modules
shared/ # Composants partagés
core/ # Services globaux
models/ # Interfaces et types
## Naming conventions
- Composants : user-profile.component.ts
- Services : user.service.ts
- Guards : auth.guard.ts
- Interfaces : user.interface.ts
Étape 3 : Créer un Skill personnalisé
Créez un Skill pour le pattern le plus répété dans votre équipe. Par exemple, un Skill pour votre pattern de service HTTP :
mkdir -p .claude/skills/http-service
touch .claude/skills/http-service/SKILL.md
Contenu du fichier :
---
name: http-service
description: Créer un service HTTP Angular avec gestion d'erreurs et retry
---
# Service HTTP Angular
Pattern standard pour tous les services HTTP du projet.
## Template de base
<exemple>
import { inject } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
export class UserService {
private readonly http = inject(HttpClient);
private readonly baseUrl = '/api/users';
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.baseUrl).pipe(
retry(2),
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
console.error('HTTP Error:', error);
return throwError(() => new Error('Request failed'));
}
}
</exemple>
## Règles
- Toujours utiliser inject() pour HttpClient
- Retry automatique sur erreurs réseau (max 2)
- Gestion centralisée des erreurs via handleError
- Types explicites pour les retours Observable
Exemples de Skills Angular
Skill : Composant standalone avec signals
---
name: angular-standalone-component
description: Créer un composant Angular standalone avec signals
---
# Composant Standalone Angular
## Pattern recommandé
<exemple>
import { Component, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-user-card',
standalone: true,
imports: [CommonModule],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="card">
<h3>{{ fullName() }}</h3>
<p>{{ email() }}</p>
<button (click)="toggleActive()">
{{ isActive() ? 'Désactiver' : 'Activer' }}
</button>
</div>
`
})
export class UserCardComponent {
firstName = signal('John');
lastName = signal('Doe');
email = signal('john@example.com');
isActive = signal(true);
fullName = computed(() =>
`${this.firstName()} ${this.lastName()}`
);
toggleActive() {
this.isActive.update(val => !val);
}
}
</exemple>
## Checklist
✅ standalone: true obligatoire
✅ OnPush change detection
✅ Signals pour l'état réactif
✅ computed() pour valeurs dérivées
✅ Imports explicites (CommonModule, etc.)
## Anti-patterns
❌ Pas de NgModules
❌ Pas de @Input/@Output décorators
❌ Pas de BehaviorSubject pour état local
Skill : Service avec inject()
---
name: angular-service-inject
description: Créer un service Angular avec inject() au lieu de constructor
---
# Service Angular avec inject()
## Pattern moderne
<exemple>
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class AuthService {
private readonly http = inject(HttpClient);
private readonly router = inject(Router);
isAuthenticated = signal(false);
login(credentials: LoginCredentials) {
return this.http.post('/api/login', credentials).pipe(
tap(() => this.isAuthenticated.set(true)),
tap(() => this.router.navigate(['/dashboard']))
);
}
logout() {
this.isAuthenticated.set(false);
this.router.navigate(['/login']);
}
}
</exemple>
## Règles
- providedIn: 'root' pour services singletons
- inject() au lieu de constructor injection
- Signals pour l'état du service
- Méthodes retournant Observable pour opérations async
## Anti-patterns
❌ Ne pas injecter via constructor
❌ Ne pas utiliser BehaviorSubject (préférer signals)
Skill : Formulaire réactif avec signals
---
name: angular-signal-forms
description: Créer un formulaire réactif Angular avec signals
---
# Formulaires Réactifs avec Signals
## Pattern recommandé
<exemple>
import { Component, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { inject } from '@angular/core';
@Component({
selector: 'app-user-form',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="name" placeholder="Nom">
<input formControlName="email" placeholder="Email">
<button [disabled]="!form.valid">Envoyer</button>
</form>
<p>{{ statusMessage() }}</p>
`
})
export class UserFormComponent {
private readonly fb = inject(FormBuilder);
statusMessage = signal('');
form = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
onSubmit() {
if (this.form.valid) {
this.statusMessage.set('Envoi en cours...');
// Traitement du formulaire
}
}
}
</exemple>
## Règles
- FormBuilder injecté avec inject()
- Validation déclarative avec Validators
- Signals pour les messages de statut
- Désactivation du bouton si formulaire invalide