Start9 Frontend — Angular + Taiga UI house style

SkillDev tools

Lets your agent write Angular and Taiga UI frontend code that matches Start9's house style across its web apps.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Start9 Frontend — Angular + Taiga UI house style skill

About this capability

Start9 house style for every Angular + Taiga UI web frontend (StartOS ui/setup-wizard, StartWRT, StartTunnel, brochure-marketplace, start9-store, ops-server, support-server). Use BEFORE writing or reviewing any frontend code in these apps, components, templates, styles/CSS, forms, dialogs/toasts, r

What this skill tells your AI

The instructions your AI receives, as published by start9labs/start-technologies in .claude/skills/start9-frontend/SKILL.md and read by ahel’s review.

Canonical for every Start9 web UI, distilled from the fleet's codebases and from the refactor and review history that shaped them. Follow it and new code matches the fleet; deviate and expect it to be rewritten in review.

Authority order: Taiga UI docs > this skill > neighboring code. The codebases are mid-migration — "matches existing repo patterns" is not a quality bar; old code is often exactly what this skill exists to eliminate. Never guess a Taiga API: verify against the taiga-ui-mcp MCP server or https://taiga-ui.dev/llms-full.txt.

Reference files (read on demand — don't preload)

FileRead when
references/bootstrap.mdcreating/touching app.config, main.ts, angular.json, icons, theming, or a new app/repo
references/components.mdwriting any component or template (selectors, hostDirectives, signal APIs, control flow)
references/styling.mdabout to write ANY CSS (the escalation ladder, breakpoints, tokens)
references/di.mdproviders, tokens, inject patterns
references/state.mdservices, data flow, loading/error UX, API/RPC integration
references/forms.mdany form, validation, or submit flow
references/overlays.mddialogs, confirms, toasts, dropdowns, hints, drawers
references/routing.mdroute files, guards, navigation, URL state
references/conventions.mdi18n strings, file naming, folder structure, import order
references/shared-libs.mdbefore writing ANY utility/component in monorepo apps — it may exist in @start9labs/shared or marketplace
references/antipatterns.mdreviewing code, refactoring, or upgrading Angular/Taiga (before→after catalog + verbatim review quotes)
references/taiga.mdunsure of a Taiga 5 API; v4→v5 renames; need→primitive lookup table
references/recipes.mdstep-by-step: new page, dialog, form, table, control component, endpoint
references/repos.mdrepo-specific rules and build/verify commands

The fleet

AppLocationAngularTaigaZoneThemei18nBackend
StartOS uistart-technologies projects/start-os/web/ui225.11zone.js (zoneless pending)dark, provideTaiga({mode})yes (shared dicts)JSON-RPC + PatchDB push
setup-wizardprojects/start-os/web/setup-wizard225.11zone.jsdarkyes (shared)JSON-RPC
start-tunnelprojects/start-tunnel/web225.11zonelessdarkyes (local dicts)JSON-RPC + PatchDB
start-wrtprojects/start-wrt/web225.11zonelessdual (TUI_DARK_MODE)yes (local dicts)JSON-RPC, own HTTP stack, 5s polling
brochure-marketplaceprojects/brochure-marketplace225.11zone.js (legacy)darkyes (shared)registry RPC direct
start9-storeops/start9-store/web225.22zonelesslightnoREST + Zod via /api BFF, SSR
ops-serverops/ops-server/web225.14zonelessdark, #07a4ff, MontserratnoREST /_api, same-origin Express
support-serverops/support-server/web225.25zonelessdual (theme setting), StartOS tokensyes (local dicts)Frappe /api/method + socket.io, same-origin; web/mock in dev

TypeScript ~6.0, rxjs ~7.8 everywhere. Taiga is pinned exact — bump only with the maintainer's blessing. Monorepo apps share one Angular workspace rooted at the repo root; ops repos are standalone. Zoneless is the target state — write all new code zoneless-safe. This table is the only place in the fleet where stack versions are written down — update it with every Angular/Taiga bump (other repos' docs deliberately carry no version specifics).

Doctrine

  1. Taiga does it all. Components, layout, forms, dialogs, icons, theming, animation. If you're hand-rolling HTML/CSS/JS for something that feels generic, Taiga ships it — look it up first. "If you think Taiga can't do something, you're probably wrong."
  2. Never guess a Taiga API. Taiga 5 is fast-moving and easy to hallucinate. Verify every component/directive/token against the docs before use.
  3. Configure the design system, don't fight it. The escalation ladder for any visual need: ① a Taiga primitive/appearance → ② an option provider (root or component providers) → ③ a --tui-* design-token override in the theme sheet → ④ a shared g-* utility class → ⑤ a few lines of :host layout CSS. Reaching for ⑤ first means you missed ①–④.
  4. Delete code. The canonical refactors are net-negative. The best version has fewer lines, fewer files, fewer wrappers, fewer names. Don't restate framework defaults, don't name single-use values, don't duplicate markup per breakpoint.
  5. Signals at the component boundary; RxJS composes once, in services. Components read signals; services own streams and convert with toSignal at the edge. Data is never manually subscribed in a component.
  6. One source of truth per fact. Nav links live in one object; validation messages in one provider map; sizes in option providers; colors in the theme sheet.
  7. Everything host-related goes in the decorator. host: {} for classes/attrs/listeners/ style bindings, hostDirectives for composition. @HostBinding/@HostListener are dead.
  8. English strings are i18n keys (monorepo apps): every user-facing string goes through | i18n and exists in all five dictionaries; tsc enforces via the i18nKey type.
  9. Verification is npm run check + a manual pass; a test only where logic earns it. check (strict + strictTemplates), the i18n check, a prod build and clicking through the app are the bar. A test is for state machinery a manual pass can't drive deterministically — request sequencing, a store's transitions, merge order — written with node:test against the plain class and wired into check; never for a template, a style or what a component renders. No test framework; don't claim "tests pass" in a repo that has none.
  10. The docs ship with the change — this skill first. This skill is the fleet-wide frontend source of truth: the ops repos reach it through committed symlinks, and stack versions live only in its fleet table. When frontend conventions, versions, or idioms change, update SKILL.md and the affected references/*.md in the same change; other repos' docs carry only project-specific facts.

If you learned Angular anywhere else — the surprise index

  • No NgModule anywhere — standalone components only.
  • No .html/.scss component files. 100% inline template: and styles: — one file per component.
  • No constructor parameter injection. inject() in field initializers, even chained: protected route = toSignal(inject(Router).events).
  • No ngOnInit. Field initializers; a bare constructor() { this.load() } kicks off fetches; afterNextRender for browser-only side effects.
  • No *ngIf/*ngFor/ngClass/ngStyle. @if/@for (with track), @let, @switch; [class.x] and unit-typed [style.prop.unit] bindings.
  • No @Input/@Output/@ViewChild decorators. input(), input.required(), output(), model(), viewChild(), contentChild().
  • No provideAnimations(). Taiga 5 animates with CSS (TuiAnimated).
  • No explicit event-plugins provider. provideTaiga() bundles it — that's what makes (submit.prevent), (click.self), .stop, .capture modifiers work.
  • No TuiAlertService. Toasts are TuiNotificationService; blocking loaders are TuiNotificationMiddleService.
  • No FormBuilder. inject(NonNullableFormBuilder).group({...}) with array shorthand; [(ngModel)]="signal" for single ad-hoc fields.
  • No icons inside switches. tuiSwitchOptionsProvider({ showIcons: false }) in the app config; a toggle is a track and a thumb.
  • No cleaner on a select. [tuiTextfieldCleaner]="false" on every tui-textfield holding an input[tuiSelect]; the default is on, and it also lets Backspace clear the choice.
  • No route-level providers, no resolvers, few guards (inline canMatch arrows). Providers go on components — lazy-route providers spin up confusing semi-root injectors.
  • No @media queries for the app-standard mobile swap: tui-root._mobile & CSS, TUI_BREAKPOINT/WA_IS_MOBILE signals, template @if swaps — one DOM, never two.
  • No BEM, no barrels, no index.ts re-exports in apps. Taiga-style _state classes and shared g-* utilities; deep relative or src/-absolute imports.
  • No semicolons. Prettier: singleQuote, semi: false, arrowParens: "avoid", trailingComma: "all", htmlWhitespaceSensitivity: "ignore", tabWidth: 2.
  • No ESLint, no test framework. Logic tests are node:test (doctrine 9). Prettier runs via husky/lint-staged — never git commit --no-verify; fix the formatting.
  • Suffixless files and classes in new code: routes/devices/index.ts exporting export default class Devices, plus dialog.ts, table.ts, service.ts — not devices-page.component.ts / DevicesPageComponent.
  • Services can be Observables (class ConnectionService extends Observable<boolean>); tokens can be signals (new InjectionToken('…', { factory: () => signal(false) })).
  • DOCUMENT and @Service() import from @angular/core now — @Service() is the emerging norm for new services over @Injectable({providedIn: 'root'}).
  • The mock backend is a DI swap: useClass: useMocks ? MockApiService : LiveApiService.

Review checklist (greppable)

Any hit is a finding unless it matches a documented exception in the reference files:

NgModule                    constructor(private           *ngIf / *ngFor
ngClass / ngStyle           @Input( / @Output( / @ViewChild(
@HostBinding / @HostListener
templateUrl / styleUrl
FormBuilder (not NonNullable)   new FormGroup(            : any
provideAnimations           TuiAlertService               tuiFieldError
ngOnInit                    setTimeout                    .subscribe( [outside allowed shapes]
::ng-deep                   !important                    letter-spacing / text-transform
#[0-9a-f]{3,6} [outside the theme sheet]                  @media [outside documented divergences]
window. / document. / localStorage [outside infrastructure]
providers: [ on a route     track $index [on entity lists]
input<T | null>(null)       display: grid on :host of a wrapper around one child
display: contents [on :host around one Taiga primitive]   outline: none
[(tuiDropdownOpen)] [for a plain menu]                     .trim() [in a submit handler]

Softer review questions: does a computed just reshape for the template (→ pipe)? Is a value named but used once (→ inline)? Does a field alias a service's signal or a method wrap its call (→ expose the service to the template)? Do form controls rename the API's fields (→ same names, no mapping)? Is the same appearance/size attribute repeated (→ option provider)? Is there a second DOM for mobile (→ one DOM + _mobile CSS)? Did copy ship in Title Case (→ sentence case)? Is a Taiga API used that you didn't verify against the docs?

Signals

GitHub stars
2k
Forks
195
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
start9-frontend
Source
github.com/start9labs/start-technologies