agent-health
Reads production/traces/agent-metrics.jsonl and displays a per-agent performance summary table for the current or a specified session. Highlights agents with…
Provides Angular best practices for components, modules, services, and reactive patterns. Use when working with Angular TypeScript files, component templates, NgModules, RxJS observables, or when the user mentions Angular, ng, or Angular CLI.
$ npx -y skills add tranhieutt/software_development_department --skill angular-best-practices --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/angular-best-practicesContext preview
The summary Claude sees to decide when to auto-load this skill.
Provides Angular best practices for components, modules, services, and reactive patterns. Use when working with Angular TypeScript files, component templates, NgModules, RxJS observables, or when the user mentions Angular, ng, or Angular CLI.
name: angular-best-practices type: reference description: "Provides Angular best practices for components, modules, services, and reactive patterns. Use when working with Angular TypeScript files, component templates, NgModules, RxJS observables, or when the user mentions Angular, ng, or Angular CLI." paths: ["**/*.component.ts", "**/*.service.ts", "**/*.module.ts", "**/angular.json"] effort: 3 allowed-tools: Read, Glob, Grep, Write, Edit, Bash user-invocable: true when_to_use: "When building Angular applications or working with RxJS streams"
@Component({
selector: "app-product-list",
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@for (product of products(); track product.id) {
<app-product-card [product]="product" />
}
@if (loading()) { <app-spinner /> }
`,
})
export class ProductListComponent {
products = input.required<Product[]>();
loading = input(false);
// Computed signal
total = computed(() => this.products().length);
}@Injectable({ providedIn: "root" })
export class CartService {
private _items = signal<CartItem[]>([]);
items = this._items.asReadonly();
total = computed(() => this._items().reduce((sum, i) => sum + i.price * i.qty, 0));
addItem(item: CartItem) {
this._items.update(items =>
items.some(i => i.id === item.id)
? items.map(i => i.id === item.id ? { ...i, qty: i.qty + 1 } : i)
: [...items, { ...item, qty: 1 }]
);
}
}// auth interceptor
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = inject(AuthService).token();
if (!token) return next(req);
return next(req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })).pipe(
catchError(err => {
if (err.status === 401) inject(Router).navigate(["/login"]);
return throwError(() => err);
})
);
};
// Register in app.config.ts
provideHttpClient(withInterceptors([authInterceptor]))// switchMap: cancels previous — good for search, bad for saves search$.pipe( debounceTime(300), distinctUntilChanged(), switchMap(term => this.api.search(term)) // cancels in-flight request on new input ) // exhaustMap: ignores new while processing — good for login button loginClick$.pipe( exhaustMap(() => this.auth.login(credentials)) // prevents double-submit ) // mergeMap: parallel — good for independent operations ids$.pipe(mergeMap(id => this.api.fetch(id), 3)) // 3 concurrent max // combineLatest vs withLatestFrom: // combineLatest: emits when ANY source emits // withLatestFrom: emits only when primary source emits, takes latest from secondary primary$.pipe(withLatestFrom(secondary$)) // common for "take latest filter value on button click"
// Angular 16+ (preferred)
@Component({...})
export class MyComponent {
private destroyRef = inject(DestroyRef);
ngOnInit() {
this.data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(...);
}
}
// Before Angular 16
export class MyComponent implements OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() { this.data$.pipe(takeUntil(this.destroy$)).subscribe(...); }
ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); }
}// app.routes.ts
export const routes: Routes = [
{
path: "admin",
loadChildren: () => import("./admin/admin.routes").then(m => m.ADMIN_ROUTES),
canMatch: [adminGuard],
},
];
// Standalone component (Angular 15+)
@Component({
standalone: true,
imports: [CommonModule, RouterModule, ReactiveFormsModule],
template: `...`,
})
export class ProfileComponent {}| Pitfall | Fix | |---|---| | Memory leak from unsubscribed Observable | Use `takeUntilDestroyed()` or `async` pipe | | `ExpressionChangedAfterChecked` error | Defer with `afterNextRender()` or move to signals | | Heavy computation in template | Move to `computed()` signal or `pipe(map(...))` | | `*ngIf` with `async` pipe fetches twice | Use `as` syntax: `*ngIf="data$ \| async as data"` | | Zone.js performance in loops | Use `ChangeDetectionStrategy.OnPush` + signals |
Repo: tranhieutt/software_development_department
Reads production/traces/agent-metrics.jsonl and displays a per-agent performance summary table for the current or a specified session. Highlights agents with…
Provides the vendored agent-style v0.3.5 prose rule pack as a portable Claude skill. Use when installing, syncing, applying, or auditing SDD Agent-Style…
Records unexpected API behaviors, undocumented caveats, version bugs, or non-obvious workarounds into .claude/memory/annotations.md. Use immediately when an…
Defines REST and GraphQL API contracts including endpoints, request/response schemas, auth flows, and versioning strategy. Use when designing a new API,…
Manages the ADR (Architecture Decision Record) registry. Use when recording tech-stack choices, design patterns, or infrastructure decisions with context,…
Provides AWS serverless architecture patterns for Lambda, API Gateway, DynamoDB, SQS, and SAM/CDK. Use when working with AWS serverless files (serverless.yml,…