Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the mobile repository has no theme tokens or component library yet (a new app, an "Apply design system" task, or a task that asks for one), before building any screen - writes the approved design system's generated files from get_design_system (files true) and builds the theme from them when there is one.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
A screen built before tokens and an atomic component library exist turns into Color(0x…), one-off paddings, and a library that never forms. This skill lays the foundation once, in order, so every screen after it is composition, not invention.
Core principle: Lay the foundation before the first screen — tokens, folders, and the first atoms come before any feature work.
get_design_system with files: true for this repository before anything else. When it returns a design system, the direction is already decided and approved: skip the design direction below and materialize it instead. Write every file in files verbatim at its path — DESIGN.md, design/tokens.json, design/tokens.css, design/INVENTORY.md; each carries a generated-file header and is never edited by hand, never transcribed. Then build the stack's theme from design/tokens.json by role (Flutter: ColorScheme light and dark plus ThemeExtensions for spacing, radius and sizes; SwiftUI: asset-catalog colour sets with Any/Dark appearances plus Theme.swift for type, spacing and radius; Compose: Color.kt / Theme.kt / Type.kt / Shape.kt with a light and a dark ColorScheme), each value exactly as its token holds it and named after it (color.light.primary → primary). Use the colours as given — no ColorScheme.fromSeed that would recompute them. The repository's own INVENTORY.md lists its components under the names design/INVENTORY.md gives them. A theme that already exists but differs from it gets its VALUES updated to the design system's, its structure kept. Only an empty answer leaves the direction to you.
A ThemeData/ThemeExtension, an asset-catalog colour set, a MaterialTheme wrapper, or an INVENTORY.md already present (and, when get_design_system returned a design system, the generated design/ files present and matching it) means this skill doesn't apply — stop, map and follow the existing structure (flutter-atomic-components / mobile-ui-ux) instead.
Only when get_design_system returned nothing. One line each, from the task brief (the brief's own words win over any default below): audience + tone; 4–6 named brand colours mapped onto semantic roles (primary/secondary/error at minimum); type pairing; radius choice; ASCII wireframe of the key screen at phone (360) and tablet (768) width.
Flutter (verified: flutter analyze clean):
@immutable
class AppSpacing extends ThemeExtension<AppSpacing> {
const AppSpacing({this.xs = 4, this.sm = 8, this.md = 16, this.lg = 24, this.xl = 32});
final double xs, sm, md, lg, xl;
@override AppSpacing copyWith({double? xs, double? sm, double? md, double? lg, double? xl}) =>
AppSpacing(xs: xs ?? this.xs, sm: sm ?? this.sm, md: md ?? this.md, lg: lg ?? this.lg, xl: xl ?? this.xl);
@override AppSpacing lerp(AppSpacing? other, double t) => this;
}
ThemeData buildTheme(Brightness b) => ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF2F5BEA), brightness: b), // brand colour lives ONLY here
extensions: const [AppSpacing()],
);
extension AppThemeX on BuildContext {
AppSpacing get space => Theme.of(this).extension<AppSpacing>()!;
ColorScheme get colors => Theme.of(this).colorScheme;
}
Folders: lib/ui/core/{theme,atoms,molecules,organisms} + lib/ui/features/<f>/ — this is the official Flutter architecture layout; follow the repo's existing layout if it already has one (e.g. lib/ui/atoms).
SwiftUI: asset-catalog colour sets with Any/Dark appearances, enum Space { static let xs: CGFloat = 4; static let sm: CGFloat = 8; static let md: CGFloat = 16; static let lg: CGFloat = 24 }, semantic Font text styles (never .system(size:) outside the theme), @ScaledMetric for any custom sizing so it still follows Dynamic Type.
Compose: data class AppSpacing(val xs: Dp = 4.dp, val sm: Dp = 8.dp, val md: Dp = 16.dp, val lg: Dp = 24.dp), val LocalSpacing = staticCompositionLocalOf { AppSpacing() }, val MaterialTheme.spacing @Composable get() = LocalSpacing.current; wrap the app in MaterialTheme(colorScheme = …) with dynamic colour on API 12+ and a static fallback below it.
Create the atomic folders (atoms/molecules/organisms, or the repo's existing naming) plus INVENTORY.md — header line One line per component: level · name · purpose · variants, one bullet per component added in the same commit that creates it.
Base atoms to start from: AppButton, AppTextField, AppIcon, StatusChip, Skeleton, EmptyState, ErrorView.
Wire a guard that runs inside the ordinary test command, so the build gate enforces it — not a separate CI step that can be skipped.
Flutter (verified: flags 4 violations in a raw-styled atom, passes on the token version):
// test/ui_guard_test.dart — runs inside `flutter test`, so the build gate enforces it
final banned = <String, RegExp>{
'raw colour (use context.colors / ColorScheme)': RegExp(r'Color\(0x|Colors\.(?!transparent)'),
'raw font size (use textTheme)': RegExp(r'fontSize:\s*\d'),
'raw spacing (use context.space)': RegExp(r'EdgeInsets\.(all|symmetric|only|fromLTRB)\([^)]*\d'),
};
// walks lib/ui/**.dart except lib/ui/**/theme/**, collects "path:line reason", expect(offenders, isEmpty)
Compose: a JVM unit test scanning src/main/**/ui/** (except ui/theme) for Color(0x and a numeric literal inside .padding(.
iOS: SwiftLint custom_rules (Color\(red:, \.font\(\.system\(size:, \.padding\(\d) when the repo already uses SwiftLint; skip if it doesn't rather than introducing a new lint dependency for this alone.
❌ Start writing a screen straight away: Color(0xFF2196F3) inline, EdgeInsets.all(16)
scattered across three widgets, no INVENTORY.md.
✅ 1. Detect: no ThemeData/ThemeExtension found → this skill applies.
2. Design direction (one paragraph) → 3. buildTheme() + AppSpacing extension
→ 4. lib/ui/core/{theme,atoms,...} folders + INVENTORY.md → 5. AppButton,
StatusChip, Skeleton atoms + widget tests → 6. ui_guard_test.dart green
→ 7. first screen, built entirely from atoms already in INVENTORY.md.
INVENTORY.md — the next task re-invents a Button.Color(0x…), Colors.*, or a numeric EdgeInsets/.padding( literal anywhere in the diff outside the theme files.lib/ui/ (or the repo's component folder) with no INVENTORY.md.아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.