Clean Architecture — community Clean Architecture, crossfire, community, ide skills, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Ideal for Software Development Agents requiring modular and scalable system design through separation of concerns. Crossfire - But in website version

harrytran998 harrytran998
[0]
[0]
Updated: 3/5/2026

Agent Capability Analysis

The Clean Architecture skill by harrytran998 is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance.

Ideal Agent Persona

Ideal for Software Development Agents requiring modular and scalable system design through separation of concerns.

Core Value

Empowers agents to implement concentric layers, including entities, use cases, and interface adapters, ensuring business logic independence from external frameworks and tools like databases and UI components, using protocols such as REST or gRPC.

Capabilities Granted for Clean Architecture

Designing modular monolithic applications
Implementing microservices architecture with clean boundaries
Refactoring legacy codebases for improved maintainability

! Prerequisites & Limits

  • Requires thorough understanding of system requirements and business logic
  • May introduce additional complexity in small-scale applications
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

Clean Architecture

Install Clean Architecture, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command setup.

SKILL.md
Readonly

Overview

Clean Architecture emphasizes separation of concerns through concentric layers. The innermost layers (entities, use cases) contain business logic independent of external frameworks and tools. Outer layers handle UI, database, and infrastructure concerns.

Key Concepts

Concentric Layers

  1. Entities: Core business rules (innermost)
  2. Use Cases: Application-specific business rules
  3. Interface Adapters: Translates between use cases and external systems
  4. Frameworks & Drivers: Web frameworks, databases, etc. (outermost)

Dependency Rule

Dependencies point inward only. Inner layers never depend on outer layers.

Independence

  • Independent of frameworks
  • Testable
  • Independent of UI
  • Independent of database
  • Independent of external agencies

Modularity

Organize code by business domain rather than technical layer.

Code Examples

Project Structure

src/
├── domain/                  # Core business entities
│   ├── User/
│   │   └── User.ts
│   ├── Post/
│   │   └── Post.ts
│   └── Comment/
│       └── Comment.ts
├── usecases/               # Application business rules
│   ├── User/
│   │   ├── CreateUserUseCase.ts
│   │   └── GetUserUseCase.ts
│   ├── Post/
│   │   ├── CreatePostUseCase.ts
│   │   └── ListPostsUseCase.ts
│   └── Comment/
│       └── CreateCommentUseCase.ts
├── adapters/               # Interface adapters
│   ├── http/
│   │   ├── UserController.ts
│   │   ├── PostController.ts
│   │   └── routes.ts
│   ├── persistence/
│   │   ├── UserRepository.ts
│   │   ├── PostRepository.ts
│   │   └── CommentRepository.ts
│   └── presenters/
│       ├── UserPresenter.ts
│       └── PostPresenter.ts
├── frameworks/             # External frameworks
│   ├── database/
│   │   └── PostgresDatabase.ts
│   ├── http/
│   │   └── ExpressServer.ts
│   └── cache/
│       └── RedisCache.ts
└── di/                     # Dependency Injection
    └── Container.ts

Domain Layer - Entities

typescript
1// src/domain/User/User.ts 2export interface IUser { 3 id: string 4 email: string 5 username: string 6 passwordHash: string 7 createdAt: Date 8 updatedAt: Date 9} 10 11export class User implements IUser { 12 id: string 13 email: string 14 username: string 15 passwordHash: string 16 createdAt: Date 17 updatedAt: Date 18 19 constructor( 20 id: string, 21 email: string, 22 username: string, 23 passwordHash: string, 24 createdAt: Date, 25 updatedAt: Date 26 ) { 27 this.id = id 28 this.email = email 29 this.username = username 30 this.passwordHash = passwordHash 31 this.createdAt = createdAt 32 this.updatedAt = updatedAt 33 } 34 35 // Business logic methods 36 updateEmail(newEmail: string): void { 37 if (!this.isValidEmail(newEmail)) { 38 throw new Error('Invalid email format') 39 } 40 this.email = newEmail 41 this.updatedAt = new Date() 42 } 43 44 private isValidEmail(email: string): boolean { 45 return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) 46 } 47} 48 49// src/domain/User/UserRepository.ts 50export interface IUserRepository { 51 findById(id: string): Promise<User | null> 52 findByEmail(email: string): Promise<User | null> 53 save(user: User): Promise<void> 54 delete(id: string): Promise<void> 55 findAll(): Promise<User[]> 56}

Use Case Layer

typescript
1// src/usecases/User/CreateUserUseCase.ts 2import { User, IUserRepository } from '../../domain/User' 3 4export interface CreateUserRequest { 5 email: string 6 username: string 7 password: string 8} 9 10export interface CreateUserResponse { 11 id: string 12 email: string 13 username: string 14} 15 16export class CreateUserUseCase { 17 constructor(private userRepository: IUserRepository) {} 18 19 async execute(request: CreateUserRequest): Promise<CreateUserResponse> { 20 // Check if user already exists 21 const existingUser = await this.userRepository.findByEmail(request.email) 22 if (existingUser) { 23 throw new Error('User with this email already exists') 24 } 25 26 // Create user entity 27 const user = new User( 28 this.generateId(), 29 request.email, 30 request.username, 31 this.hashPassword(request.password), 32 new Date(), 33 new Date() 34 ) 35 36 // Save to repository 37 await this.userRepository.save(user) 38 39 // Return response 40 return { 41 id: user.id, 42 email: user.email, 43 username: user.username, 44 } 45 } 46 47 private generateId(): string { 48 return Math.random().toString(36).substring(7) 49 } 50 51 private hashPassword(password: string): string { 52 // In production, use bcrypt or similar 53 return Buffer.from(password).toString('base64') 54 } 55} 56 57// src/usecases/User/GetUserUseCase.ts 58export interface GetUserResponse { 59 id: string 60 email: string 61 username: string 62 createdAt: Date 63} 64 65export class GetUserUseCase { 66 constructor(private userRepository: IUserRepository) {} 67 68 async execute(userId: string): Promise<GetUserResponse | null> { 69 const user = await this.userRepository.findById(userId) 70 if (!user) { 71 return null 72 } 73 74 return { 75 id: user.id, 76 email: user.email, 77 username: user.username, 78 createdAt: user.createdAt, 79 } 80 } 81}

Adapter Layer - Controllers

typescript
1// src/adapters/http/UserController.ts 2import { CreateUserUseCase, CreateUserRequest } from '../../usecases/User' 3import { GetUserUseCase } from '../../usecases/User/GetUserUseCase' 4import { IUserPresenter } from './presenters/UserPresenter' 5 6export class UserController { 7 constructor( 8 private createUserUseCase: CreateUserUseCase, 9 private getUserUseCase: GetUserUseCase, 10 private userPresenter: IUserPresenter 11 ) {} 12 13 async createUser(req: any, res: any): Promise<void> { 14 try { 15 const request: CreateUserRequest = { 16 email: req.body.email, 17 username: req.body.username, 18 password: req.body.password, 19 } 20 21 const response = await this.createUserUseCase.execute(request) 22 res.status(201).json(this.userPresenter.present(response)) 23 } catch (error: any) { 24 res.status(400).json({ error: error.message }) 25 } 26 } 27 28 async getUser(req: any, res: any): Promise<void> { 29 try { 30 const userId = req.params.id 31 const response = await this.getUserUseCase.execute(userId) 32 33 if (!response) { 34 res.status(404).json({ error: 'User not found' }) 35 return 36 } 37 38 res.json(this.userPresenter.present(response)) 39 } catch (error: any) { 40 res.status(500).json({ error: error.message }) 41 } 42 } 43} 44 45// src/adapters/http/routes.ts 46import { Router } from 'express' 47import { UserController } from './UserController' 48 49export function setupRoutes(router: Router, userController: UserController) { 50 router.post('/users', (req, res) => userController.createUser(req, res)) 51 router.get('/users/:id', (req, res) => userController.getUser(req, res)) 52}

Adapter Layer - Repository Implementation

typescript
1// src/adapters/persistence/UserRepository.ts 2import { User, IUserRepository } from '../../domain/User' 3import { Kysely } from 'kysely' 4 5interface UserRow { 6 id: string 7 email: string 8 username: string 9 password_hash: string 10 created_at: Date 11 updated_at: Date 12} 13 14export class UserRepository implements IUserRepository { 15 constructor(private db: Kysely<any>) {} 16 17 async findById(id: string): Promise<User | null> { 18 const row = await this.db 19 .selectFrom('users') 20 .selectAll() 21 .where('id', '=', id) 22 .executeTakeFirst() 23 24 if (!row) return null 25 return this.mapRowToUser(row) 26 } 27 28 async findByEmail(email: string): Promise<User | null> { 29 const row = await this.db 30 .selectFrom('users') 31 .selectAll() 32 .where('email', '=', email) 33 .executeTakeFirst() 34 35 if (!row) return null 36 return this.mapRowToUser(row) 37 } 38 39 async save(user: User): Promise<void> { 40 await this.db 41 .insertInto('users') 42 .values({ 43 id: user.id, 44 email: user.email, 45 username: user.username, 46 password_hash: user.passwordHash, 47 created_at: user.createdAt, 48 updated_at: user.updatedAt, 49 }) 50 .execute() 51 } 52 53 async delete(id: string): Promise<void> { 54 await this.db.deleteFrom('users').where('id', '=', id).execute() 55 } 56 57 async findAll(): Promise<User[]> { 58 const rows = await this.db.selectFrom('users').selectAll().execute() 59 60 return rows.map((row) => this.mapRowToUser(row)) 61 } 62 63 private mapRowToUser(row: UserRow): User { 64 return new User( 65 row.id, 66 row.email, 67 row.username, 68 row.password_hash, 69 row.created_at, 70 row.updated_at 71 ) 72 } 73}

Presenter

typescript
1// src/adapters/http/presenters/UserPresenter.ts 2export interface IUserPresenter { 3 present(data: any): any 4} 5 6export class UserPresenter implements IUserPresenter { 7 present(userData: any) { 8 return { 9 id: userData.id, 10 email: userData.email, 11 username: userData.username, 12 createdAt: userData.createdAt, 13 } 14 } 15}

Dependency Injection Container

typescript
1// src/di/Container.ts 2import { Kysely } from 'kysely' 3import { CreateUserUseCase } from '../usecases/User' 4import { GetUserUseCase } from '../usecases/User/GetUserUseCase' 5import { UserRepository } from '../adapters/persistence/UserRepository' 6import { UserController } from '../adapters/http/UserController' 7import { UserPresenter } from '../adapters/http/presenters/UserPresenter' 8 9export class Container { 10 private static instance: Container 11 private services: Map<string, any> = new Map() 12 13 static getInstance(): Container { 14 if (!Container.instance) { 15 Container.instance = new Container() 16 } 17 return Container.instance 18 } 19 20 registerService(key: string, factory: () => any): void { 21 this.services.set(key, factory) 22 } 23 24 getService(key: string): any { 25 const factory = this.services.get(key) 26 if (!factory) { 27 throw new Error(`Service ${key} not found`) 28 } 29 return factory() 30 } 31 32 setupDefaultServices(db: Kysely<any>): void { 33 // Repositories 34 this.registerService('userRepository', () => new UserRepository(db)) 35 36 // Use Cases 37 this.registerService( 38 'createUserUseCase', 39 () => new CreateUserUseCase(this.getService('userRepository')) 40 ) 41 this.registerService( 42 'getUserUseCase', 43 () => new GetUserUseCase(this.getService('userRepository')) 44 ) 45 46 // Presenters 47 this.registerService('userPresenter', () => new UserPresenter()) 48 49 // Controllers 50 this.registerService( 51 'userController', 52 () => 53 new UserController( 54 this.getService('createUserUseCase'), 55 this.getService('getUserUseCase'), 56 this.getService('userPresenter') 57 ) 58 ) 59 } 60}

Best Practices

1. Layer Separation

  • Keep business logic in domain and use cases
  • Controllers should be thin and delegate to use cases
  • Don't leak framework details into inner layers

2. Dependency Direction

  • Always point dependencies inward
  • Use dependency injection for external dependencies
  • Define interfaces at the layer that needs them

3. Testing

  • Domain entities are easily testable (no dependencies)
  • Use case tests mock repositories
  • Integration tests verify adapter/framework layer

4. Module Organization

  • Group by business domain, not technical layer
  • Keep related entities and use cases together
  • Each module should have clear responsibility

5. Error Handling

  • Define domain-specific exceptions
  • Let use cases throw application exceptions
  • Controllers translate to HTTP responses

Common Patterns

Request/Response Objects

Use DTOs to decouple between layers:

typescript
1// Request and Response are independent of HTTP framework 2interface CreateUserRequest { 3 email: string 4 username: string 5 password: string 6} 7 8interface CreateUserResponse { 9 id: string 10 email: string 11 username: string 12}

Entity Validation

typescript
1export class User { 2 static create(email: string, username: string, passwordHash: string): User | Error { 3 if (!this.isValidEmail(email)) { 4 return new Error('Invalid email') 5 } 6 return new User(generateId(), email, username, passwordHash, new Date(), new Date()) 7 } 8}

Use Case Composition

typescript
1export class UpdateUserAndNotifyUseCase { 2 constructor( 3 private updateUserUseCase: UpdateUserUseCase, 4 private notifyUserUseCase: NotifyUserUseCase 5 ) {} 6 7 async execute(request: any) { 8 const updateResponse = await this.updateUserUseCase.execute(request) 9 await this.notifyUserUseCase.execute(updateResponse.id) 10 return updateResponse 11 } 12}

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is Clean Architecture?

Ideal for Software Development Agents requiring modular and scalable system design through separation of concerns. Crossfire - But in website version

How do I install Clean Architecture?

Run the command: npx killer-skills add harrytran998/crossfire. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for Clean Architecture?

Key use cases include: Designing modular monolithic applications, Implementing microservices architecture with clean boundaries, Refactoring legacy codebases for improved maintainability.

Which IDEs are compatible with Clean Architecture?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for Clean Architecture?

Requires thorough understanding of system requirements and business logic. May introduce additional complexity in small-scale applications.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add harrytran998/crossfire. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use Clean Architecture immediately in the current project.

Related Skills

Looking for an alternative to Clean Architecture or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI