

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
12345## Context67This instruction file applies to Angular frontend code. The project uses Angular 15+ with standalone components as the default architecture (NgModule is only used for legacy modules). New code targets Angular 16+ and should leverage the Signals API (`signal()`, `computed()`, `effect()`) for reactive state management. Components use `OnPush` change detection throughout. The design system uses SCSS with BEM naming conventions.89---1011## Coding Standards1213- **Standalone components:** All new components, directives, and pipes must use `standalone: true` — no NgModule declarations unless integrating with a legacy module14- **Signals API:** Prefer `signal()`, `computed()`, and `effect()` over RxJS `BehaviorSubject` for local component state in Angular 16+15- **`inject()` function:** Use `inject()` for service injection in standalone components — not constructor parameter injection16- **Typed HTTP:** Always provide a type parameter to `HttpClient` methods: `http.get<Customer[]>('/api/customers')`17- **Async pipe:** Use the `async` pipe in templates for Observables — never manually subscribe and unsubscribe in the component class unless the subscription has side effects that must be explicitly torn down18- **`OnPush` strategy:** All components must declare `changeDetection: ChangeDetectionStrategy.OnPush`19- **Reactive Forms:** Use `ReactiveFormsModule` and `FormBuilder` for any form with more than two fields or validation logic20- **Lazy loading:** All feature routes must use `loadComponent()` (standalone) or `loadChildren()` (module-based) — no eagerly loaded feature routes21- **No `any` type:** TypeScript `any` is forbidden — use `unknown` if the type is genuinely unknown, then narrow it22- **No direct DOM:** Never use `ElementRef.nativeElement` for DOM manipulation — use Angular directives and renderer23- **Accessibility:** All interactive elements (`button`, `input`, `select`, links) must have meaningful `aria-*` attributes or accessible labels24- **No inline styles:** Never bind `[style]` or `[ngStyle]` inline — use CSS classes and `[ngClass]`2526---2728## Preferred Patterns2930### Standalone Component3132```typescript33import { Component, ChangeDetectionStrategy, inject, signal, computed } from '@angular/core';34import { CommonModule } from '@angular/common';35import { CustomerService } from '../services/customer.service';36import { Customer } from '../models/customer.model';3738@Component({39 selector: 'app-customer-list',40 standalone: true,41 imports: [CommonModule],42 templateUrl: './customer-list.component.html',43 styleUrl: './customer-list.component.scss',44 changeDetection: ChangeDetectionStrategy.OnPush,45})46export class CustomerListComponent {47 private readonly customerService = inject(CustomerService);4849 readonly customers = signal<Customer[]>([]);50 readonly isLoading = signal(false);51 readonly activeCount = computed(() => this.customers().filter(c => c.active).length);5253 ngOnInit(): void {54 this.isLoading.set(true);55 this.customerService.getAll().subscribe({56 next: (data) => this.customers.set(data),57 error: (err) => console.error('Failed to load customers', err),58 complete: () => this.isLoading.set(false),59 });60 }61}62```6364### Angular HttpClient Service6566```typescript67import { Injectable, inject } from '@angular/core';68import { HttpClient, HttpParams } from '@angular/common/http';69import { Observable } from 'rxjs';70import { Customer, CreateCustomerRequest } from '../models/customer.model';7172@Injectable({ providedIn: 'root' })73export class CustomerService {74 private readonly http = inject(HttpClient);75 private readonly baseUrl = '/api/v1/customers';7677 getAll(activeOnly?: boolean): Observable<Customer[]> {78 const params = activeOnly ? new HttpParams().set('active', 'true') : undefined;79 return this.http.get<Customer[]>(this.baseUrl, { params });80 }8182 getById(id: string): Observable<Customer> {83 return this.http.get<Customer>(`${this.baseUrl}/${id}`);84 }8586 create(request: CreateCustomerRequest): Observable<Customer> {87 return this.http.post<Customer>(this.baseUrl, request);88 }8990 update(id: string, request: Partial<CreateCustomerRequest>): Observable<Customer> {91 return this.http.put<Customer>(`${this.baseUrl}/${id}`, request);92 }93}94```9596### Reactive Form9798```typescript99import { Component, ChangeDetectionStrategy, inject } from '@angular/core';100import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';101import { CommonModule } from '@angular/common';102103@Component({104 selector: 'app-customer-form',105 standalone: true,106 imports: [CommonModule, ReactiveFormsModule],107 templateUrl: './customer-form.component.html',108 changeDetection: ChangeDetectionStrategy.OnPush,109})110export class CustomerFormComponent {111 private readonly fb = inject(FormBuilder);112113 readonly form = this.fb.group({114 firstName: ['', [Validators.required, Validators.maxLength(100)]],115 lastName: ['', [Validators.required, Validators.maxLength(100)]],116 email: ['', [Validators.required, Validators.email]],117 });118119 onSubmit(): void {120 if (this.form.invalid) return;121 // handle valid form122 }123}124```125126### Lazy Loading Route127128```typescript129// app.routes.ts130export const APP_ROUTES: Routes = [131 {132 path: 'customers',133 loadComponent: () =>134 import('./features/customers/customer-list.component').then(m => m.CustomerListComponent),135 },136 {137 path: 'orders',138 loadChildren: () =>139 import('./features/orders/orders.routes').then(m => m.ORDER_ROUTES),140 },141];142```143144### NgRx Store (when shared state is needed)145146```typescript147// State defined with createFeature — colocated in one file148export const customerFeature = createFeature({149 name: 'customers',150 reducer: createReducer(151 initialState,152 on(CustomerActions.loadCustomers, state => ({ ...state, loading: true })),153 on(CustomerActions.loadCustomersSuccess, (state, { customers }) =>154 ({ ...state, customers, loading: false })),155 ),156});157```158159### Template: `*ngFor` with `trackBy`160161```html162<!-- CORRECT: always use trackBy to prevent unnecessary DOM re-renders -->163<ul>164 @for (customer of customers(); track customer.id) {165 <li class="customer-list__item">{{ customer.firstName }} {{ customer.lastName }}</li>166 }167</ul>168```169170### SCSS — BEM Naming171172```scss173// customer-list.component.scss174.customer-list {175 display: flex;176 flex-direction: column;177 gap: var(--spacing-md);178179 &__item {180 padding: var(--spacing-sm);181 border-bottom: 1px solid var(--color-border);182 }183184 &__item--active {185 font-weight: 600;186 color: var(--color-primary);187 }188189 &__empty-state {190 text-align: center;191 color: var(--color-text-muted);192 }193}194```195196---197198## Anti-Patterns — Do NOT Generate199200```typescript201// WRONG: no type on HttpClient call202this.http.get('/api/customers');203204// WRONG: any type205const data: any = response;206207// WRONG: manual subscription without takeUntil / takeUntilDestroyed208this.customerService.getAll().subscribe(data => this.customers = data);209// use async pipe in template instead, or takeUntilDestroyed(this.destroyRef)210211// WRONG: constructor injection in standalone component (use inject() instead)212constructor(private customerService: CustomerService) {}213214// WRONG: ElementRef DOM manipulation215this.el.nativeElement.style.display = 'none';216217// WRONG: Default change detection strategy218@Component({ selector: 'app-foo', template: '' })219// Missing changeDetection: ChangeDetectionStrategy.OnPush220221// WRONG: eager route loading222{ path: 'orders', component: OrderListComponent }223224// WRONG: NgModule for new standalone features225@NgModule({ declarations: [MyNewComponent], ... })226```227228```html229<!-- WRONG: inline styles -->230<div [style.color]="'red'">text</div>231232<!-- WRONG: no trackBy / track in ngFor -->233<li *ngFor="let item of items">{{ item.name }}</li>234235<!-- WRONG: no aria label on icon-only button -->236<button (click)="delete(item)"><mat-icon>delete</mat-icon></button>237```238239---240241## Dependencies & Versions242243| Library | Version | Notes |244|---------|---------|-------|245| Angular | 15+ (16+ for Signals) | `@angular/core`, `@angular/common` |246| RxJS | 7.x | Used for HTTP streams and complex async |247| NgRx | 17.x | Only for shared cross-feature state |248| Angular Material | 16+ | UI component library |249| TypeScript | 5.x | Strict mode enabled |250251---252253## Test Conventions254255- Use `TestBed.configureTestingModule` with `imports: [ComponentUnderTest]` for standalone components256- Mock services with `jasmine.createSpyObj('ServiceName', ['methodA', 'methodB'])`257- Use `HttpClientTestingModule` and `HttpTestingController` for HTTP service tests258- Use `fakeAsync` + `tick()` for async operations; `flush()` for Promises259- Test `signal()` values by calling the signal as a function: `expect(component.customers()).toEqual([...])`260- Each spec file mirrors the source file: `customer-list.component.spec.ts`261- Test `OnPush` components by calling `fixture.detectChanges()` after state mutations262
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| doubts-suplab/eeik-bootstrap.clinerules/golden-rules.md · 1 | Cline rules | gitsecuritydo-not | 61/100 | today | |
| doubts-suplab/eeik-bootstrap.clinerules/project.md · 1 | Cline rules | teststylegit | 63/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/architecture.mdc · 1 | Cursor rules | do-not | 52/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/capabilities.mdc · 1 | Cursor rules | teststylegit | 58/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/golden-rules.mdc · 1 | Cursor rules | gitsecuritydo-not | 61/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/python.mdc · 1 | Cursor rules | lint-formatstyletypesapi+1 | 77/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/security.mdc · 1 | Cursor rules | security | 39/100 | today | |
| doubts-suplab/eeik-bootstrap.github/copilot-instructions.md · 1 | Copilot instructions | lint-formatstyletesting-strategygit+2 | 54/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/a2a-protocol.instructions.md · 1 | Copilot instructions | styleagent-behaviour | 48/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/ai-governance.instructions.md · 1 | Copilot instructions | stylearchdo-notagent-behaviour | 61/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/architecture-governance.instructions.md · 1 | Copilot instructions | testlint-formatstylegit+4 | 65/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/autogen.instructions.md · 1 | Copilot instructions | typessecurityagent-behaviour | 50/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/aws-architecture.instructions.md · 1 | Copilot instructions | styletypessecurityperformance | 58/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/aws-data-ml-ai.instructions.md · 1 | Copilot instructions | deployment | 54/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/cdk-terraform.instructions.md · 1 | Copilot instructions | teststylearchtypes+2 | 96/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/cicd.instructions.md · 1 | Copilot instructions | stylesecuritydeploymentdo-not+1 | 65/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/containerisation.instructions.md · 1 | Copilot instructions | buildstylesecuritydo-not | 77/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/crewai.instructions.md · 1 | Copilot instructions | styleagent-behaviour | 48/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/data-engineering.instructions.md · 1 | Copilot instructions | teststyletypesgit+5 | 69/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/deployment.instructions.md · 1 | Copilot instructions | teststylegitdeployment | 77/100 | today |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| HerringtonDarkholme/megarepo.github/copilot-instructions.md · 17 | Copilot instructions | setupbuildtestlint-format+7 | 100/100 | 14 days ago | |
| louislam/uptime-kuma.github/copilot-instructions.md · 90k | Copilot instructions | setupbuildtestlint-format+9 | 100/100 | 14 days ago | |
| chihebnabil/lovable-boilerplate.github/instructions/global.instructions.md · 65 | Copilot instructions | buildlint-formatstylearch+4 | 100/100 | 14 days ago | |
| pytorch/pytorch.github/copilot-instructions.md · 102k | Copilot instructions | setupbuildteststyle+5 | 100/100 | 14 days ago | |
| JCodesMore/ai-website-cloner-template.github/copilot-instructions.md · 32k | Copilot instructions | buildlint-formatstylearch+3 | 97/100 | 7 days ago | |
| bagisto/bagisto.github/copilot-instructions.md · 28k | Copilot instructions | setupbuildteststyle+5 | 97/100 | 14 days ago | |
| hiyouga/LlamaFactory.github/copilot-instructions.md · 74k | Copilot instructions | setupbuildtestlint-format+5 | 97/100 | 13 days ago | |
| darkmatter/nixmac.github/copilot-instructions.md · 25 | Copilot instructions | setupbuildtestlint-format+8 | 96/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/doubts-suplab-eeik-bootstrap-github-instructions-angular-instructions)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.