Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Standardized guidelines for implementing Clean Architecture in frontend applications. Use when building maintainable, testable applications with clear separation of concerns and dependency rules.
.claude/skills/valec3-frontend-architecture-clean/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 13% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-08 | ✗→✓ | ▲ Improved | -19% | 0% |
| case-12 | ✗→✓ | ▲ Improved | -32% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 4% | 0% |
src/
├── domain/
│ ├── entities/
│ │ └── User.ts # Pure business objects
│ ├── repositories/
│ │ └── IUserRepository.ts # Interfaces
│ └── usecases/
│ └── GetUserProfile.ts
├── application/
│ ├── ports/ # Interfaces for adapters
│ └── services/
├── infrastructure/
│ ├── api/
│ │ └── UserApiRepository.ts # Implements IUserRepository
│ ├── storage/
│ └── config/
└── presentation/
├── components/
├── pages/
└── hooks/1. Dependency Rule Dependencies point inward only:
Presentation → Application → Domain
Infrastructure → Application → Domain2. Domain Layer (Core)
typescript// domain/entities/User.ts export class User { constructor( public readonly id: string, public readonly email: string, private _name: string ) {} updateName(newName: string): void { if (newName.length < 2) { throw new Error('Name too short'); } this._name = newName; } get name(): string { return this._name; } }
3. Repository Interface
typescript// domain/repositories/IUserRepository.ts export interface IUserRepository { findById(id: string): Promise<User | null>; save(user: User): Promise<void>; }
4. Use Case
typescript// domain/usecases/GetUserProfile.ts export class GetUserProfile { constructor(private userRepo: IUserRepository) {} async execute(userId: string): Promise<User> { const user = await this.userRepo.findById(userId); if (!user) throw new Error('User not found'); return user; } }
5. Infrastructure Adapter
typescript// infrastructure/api/UserApiRepository.ts export class UserApiRepository implements IUserRepository { async findById(id: string): Promise<User | null> { const response = await fetch(`/api/users/${id}`); const data = await response.json(); return new User(data.id, data.email, data.name); } async save(user: User): Promise<void> { await fetch(`/api/users/${user.id}`, { method: 'PUT', body: JSON.stringify(user) }); } }
6. Presentation (React Hook)
typescript// presentation/hooks/useUserProfile.ts export function useUserProfile(userId: string) { const [user, setUser] = useState<User | null>(null); useEffect(() => { const useCase = new GetUserProfile(new UserApiRepository()); useCase.execute(userId).then(setUser); }, [userId]); return user; }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-15 | pass→pass | 11,395 | 7,613 | -33% | 1 | 1 | 0% | 2,509 | 2,483 | -1% | 0 | 0 | — |
case-01 | fail→pass | 14,776 | 12,520 | -15% | 1 | 1 | 0% | 3,241 | 3,675 | +13% | 0 | 0 | — |
case-02 | fail→fail | 18,949 | 13,780 | -27% | 1 | 1 | 0% | 4,105 | 3,814 | -7% | 0 | 0 | — |
case-03 | pass→pass | 18,015 | 14,023 | -22% | 1 | 1 | 0% | 2,983 | 3,249 | +9% | 0 | 0 | — |
case-04 | pass→pass | 13,837 | 9,743 | -30% | 1 | 1 | 0% | 2,712 | 2,798 | +3% | 0 | 0 | — |
case-05 | pass→pass | 13,907 | 9,556 | -31% | 1 | 1 | 0% | 2,679 | 2,841 | +6% | 0 | 0 | — |
case-06 | fail→pass | 10,336 | 4,250 | -59% | 1 | 1 | 0% | 1,526 | 1,594 | +4% | 0 | 0 | — |
case-07 | pass→pass | 11,520 | 11,550 | +0% | 1 | 1 | 0% | 2,206 | 2,872 | +30% | 0 | 0 | — |
case-08 | fail→pass | 9,077 | 3,281 | -64% | 1 | 1 | 0% | 1,743 | 1,417 | -19% | 0 | 0 | — |
case-09 | pass→pass | 12,915 | 8,760 | -32% | 1 | 1 | 0% | 2,671 | 2,871 | +7% | 0 | 0 | — |
case-10 | pass→pass | 11,652 | 8,980 | -23% | 1 | 1 | 0% | 2,141 | 2,693 | +26% | 0 | 0 | — |
case-11 | pass→pass | 9,742 | 4,106 | -58% | 1 | 1 | 0% | 1,519 | 1,559 | +3% | 0 | 0 | — |
case-12 | fail→pass | 14,235 | 5,881 | -59% | 1 | 1 | 0% | 2,851 | 1,931 | -32% | 0 | 0 | — |
case-13 | pass→pass | 11,555 | 4,202 | -64% | 1 | 1 | 0% | 1,709 | 1,628 | -5% | 0 | 0 | — |
case-14 | fail→pass | 8,310 | 4,885 | -41% | 1 | 1 | 0% | 1,489 | 1,554 | +4% | 0 | 0 | — |
case-16 | fail→pass | 8,926 | 2,294 | -74% | 1 | 1 | 0% | 1,684 | 1,204 | -29% | 0 | 0 | — |
case-17 | fail→pass | 13,531 | 3,826 | -72% | 1 | 1 | 0% | 2,413 | 1,549 | -36% | 0 | 0 | — |
case-18 | pass→pass | 11,523 | 8,038 | -30% | 1 | 1 | 0% | 2,210 | 2,175 | -2% | 0 | 0 | — |
case-19 | pass→pass | 9,137 | 5,049 | -45% | 1 | 1 | 0% | 1,745 | 1,601 | -8% | 0 | 0 | — |
case-20 | fail→pass | 14,549 | 11,586 | -20% | 1 | 1 | 0% | 2,352 | 3,249 | +38% | 0 | 0 | — |
case-21 | pass→pass | 11,284 | 4,188 | -63% | 1 | 1 | 0% | 1,956 | 1,609 | -18% | 0 | 0 | — |
case-22 | pass→pass | 10,881 | 9,921 | -9% | 1 | 1 | 0% | 2,008 | 2,894 | +44% | 0 | 0 | — |
case-23 | pass→pass | 9,794 | 6,461 | -34% | 1 | 1 | 0% | 1,678 | 2,042 | +22% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +35 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.