Scale is architecturally sound, and this scan can now say so with the components read: 95 Stencil web components, generated React, Vue and Angular wrappers, and a real composition core where scale-dropdown-select-item, scale-combobox and scale-button do the heavy lifting. The findings below are not quality problems. They are the residue of a token migration that was started and never closed out.
The headline is still the token migration. One font, TeleNeo, is declared 14 different ways across the component source, and the token traffic tells the same story in numbers: roughly 2,000 references answer to the current --telekom-* namespace while around 100 still call --scl-*, whose definitions sit in the in-repo @telekom/scale-design-tokens package that is itself marked deprecated in favour of the separate @telekom/design-tokens. The source of truth moved; about a tenth of the calls have not followed it yet. The 69 off-scale spacing values and the 6 near-identical colour pairs are the same unfinished move wearing different clothes.
Where the specificity fights are. The 27 !important declarations cluster instead of spreading: data-grid carries 8, then tag with 4, switch and tab-header with 3 each. The composite components are where the cascade is being argued with, and those are also the components consumers can least work around.
Three names are defined twice. TelekomNavItem, Logo and Shell each have two implementations. In a system whose whole promise is one canonical answer per question, an agent asked for the nav item has a coin to flip. Small list, cheap fix, outsized signal.
Two colour findings worth separating. #cb0068, the pressed state of Telekom magenta, appears hardcoded rather than derived from the brand token, and it is the one colour the licence specifically ring-fences: the clearest commercial argument for a real token boundary. Separately, the near-identical dark pair #1b1b1b next to #191919 is copy-paste, not a decision.
What is genuinely working. 302 colours sounds alarming and is not: the palette is token-led, greys are disciplined at 24, and there are zero arbitrary bracket values and zero unimported components in the design-system scope. The web component core with generated framework wrappers remains the right call for an organisation with this many product estates.
One gap that grows monthly. No CLAUDE.md, no AGENTS.md. For a design system whose entire job is telling people which component is canonical, every agent-written UI change is currently a guess. The rules file this scan can generate would name the canonical components, the --telekom-* namespace and the duplicates to avoid, in one page.
Three tweaks · 49 → 78
so you get a present.
## Design system rules
<!-- Generated by roast-my-design-system from a scan of telekom/scale on 2026-09-01.
Paste into CLAUDE.md, .cursor/rules or AGENTS.md. Regenerate after big refactors:
npx roast-my-design-system@latest --rules -->
Follow these rules when writing or editing UI in this repo. Every rule below was derived from a scan of this codebase, with real paths and usage counts.
### Colours and tokens
- This system's tokens answer to the `--telekom-*` namespace. Reach for an existing `var(--...)` from them before inventing any value.
- `--scl-*` is also present in the code. Before writing new references to it, check whether this repo treats it as current or as a migration source; when unsure, prefer `--telekom-*`.
- Design tokens live in `packages/components/src/global/legacy-scale-design-tokens.css`. Reach for an existing token before inventing any value.
- Never hardcode colour values in components. The palette already has 297 tokens; the scan still found 5 hardcoded colours sitting next to them. Do not add more.
- Never eyeball a colour from memory: the scan found 6 nearly identical pairs (like #1b1b1b next to #191919). Look the exact value up, or better, use its token.
### Canonical components
- Use these existing components instead of writing new ones, the way this repo already uses them:
- `<DropdownSelectItem>` from `packages/components/src/components/dropdown-select-item/dropdown-select-item.tsx` (used 21x)
- `<Combobox>` from `packages/components/src/components/combobox/combobox.tsx` (used 15x)
- `<Tag>` from `packages/components/src/components/tag/tag.tsx` (used 11x)
- `<Button>` from `packages/components/src/components/button/button.tsx` (used 10x)
- `<HelperText>` from `packages/components/src/components/helper-text/helper-text.tsx` (used 9x)
- `<AppNavigationUserMenu>` from `packages/components/src/components/telekom/app-navigation-user-menu/app-navigation-user-menu.tsx` (used 8x)
- `<Checkbox>` from `packages/components/src/components/checkbox/checkbox.tsx` (used 8x)
- `<Breadcrumb>` from `packages/components/src/components/breadcrumb/breadcrumb.tsx` (used 6x)
### Known duplicates: do not make it worse
- `<TelekomNavItem>` exists in 2 places (`packages/components/src/components/telekom/telekom-nav-item/telekom-nav-item.tsx`, `packages/components/src/components/telekom/telekom-nav-flyout/telekom-nav-flyout.tsx`). Match whichever the surrounding code already imports, and never create another.
- `<Logo>` exists in 2 places (`packages/components/src/components/telekom/logo/logo.tsx`, `packages/components/src/components/telekom/app-logo/app-logo.tsx`). Match whichever the surrounding code already imports, and never create another.
- `<Shell>` exists in 2 places (`packages/components/src/components/telekom/app-shell/app-shell.tsx`, `packages/components/src/components/telekom/telekom-app-shell/telekom-app-shell.tsx`). Match whichever the surrounding code already imports, and never create another.
### Spacing and sizing
- Avoid new one-off CSS spacing values; 69 off-scale values are already in play.
### Typography
- The repo uses 1 typeface: TeleNeoWeb. Do not introduce another, and do not re-declare font stacks by hand; use the existing setup.
### Styling discipline
- Never write `style={{ ... }}` for static values; styling belongs to classes and tokens where the system can see it.
(7 static inline blocks already exist; do not add to them.)
- Never write !important; the scan found 27 declarations already. When a style does not apply, fix the selector or the source of the conflict instead of shouting over it.
- Before styling anything new, look at a neighbouring component and match how it does it. Consistency with the repo beats personal preference.
---
*Generated by [roast-my-design-system](https://github.com/gregkozakiewicz/roast-my-design-system) ver. 5.7.2. Rescan after refactors to keep these rules honest.*
1 package with enough UI to judge · the repo score above is the whole thing blended, and 6 packages were too small or too backend to score
| package | score | worst finding | size |
|---|---|---|---|
| packages/components | 60 | 27 !important declarations | 162 files |
A repo scores below its own packages by arithmetic, not by accident: distinct values add up across packages, so the whole always carries more than any part. Read the package scores for where each team stands, and the repo score for what your agent sees when it looks at everything at once.
No CLAUDE.md, no AGENTS.md, no .cursorrules. Every time your AI builds UI here, it guesses, from everything below. This is why its output looks almost-but-not-quite right.
A healthy product palette is up to ~24 colours: one brand hue with a few tints, one accent, up to 13 greys, and status colours.
a disciplined repo keeps these around a dozen · on-scale Tailwind steps (·) shown for context · off-scale in coral
every distinct declaration is a chance for the next one to be wrong
the 5 files carrying the most off-system styling
an agent asking which one is canonical gets several plausible answers. Paths open in VS Code
styling no system can see
95 components defined · tile area is internal use: how the system builds from itself, downstream consumers invisible from here · the real system, drawn to scale
9 more adopted components below the top 24, not drawn.
30 components are imported exactly once: <Accordion>, <Carousel>, <ChartStackCard>, <Collapsible>, <Divider>, <Dropdown> and 24 more. Quiet corners, not yet a system.
| component | used | defined in | props |
|---|---|---|---|
| <DropdownSelectItem> | 21× | packages/components/src/components/dropdown-select-item/dropdown-select-item.tsx | none |
| <Combobox> | 15× | packages/components/src/components/combobox/combobox.tsx | none |
| <Tag> | 11× | packages/components/src/components/tag/tag.tsx | none |
| <TelekomNavItem> | 11× | packages/components/src/components/telekom/telekom-nav-item/telekom-nav-item.tsx | none |
| <Button> | 10× | packages/components/src/components/button/button.tsx | none |
| <Link> | 10× | packages/components/src/components/link/link.tsx | none |
| <HelperText> | 9× | packages/components/src/components/helper-text/helper-text.tsx | none |
| <AppNavigationUserMenu> | 8× | packages/components/src/components/telekom/app-navigation-user-menu/app-navigation-user-menu.tsx | none |
| <Checkbox> | 8× | packages/components/src/components/checkbox/checkbox.tsx | none |
| <Breadcrumb> | 6× | packages/components/src/components/breadcrumb/breadcrumb.tsx | none |