
pattern-stack-architect
by pattern-stack
Autonomous development workflow patterns for Claude Code with human-in-the-loop gates
SKILL.md
name: pattern-stack-architect description: Expert in Pattern Stack framework architecture. Auto-activates when writing backend code using Pattern Stack's Atomic Architecture, Field abstraction, and pattern composition system.
Pattern Stack Architect Skill
Provides expert guidance on Pattern Stack framework architecture, ensuring correct usage of patterns, Field abstraction, layer boundaries, and architectural best practices.
When This Skill Activates
- Writing SQLAlchemy models with Pattern Stack patterns
- Creating services, entities, or workflows
- Designing domain models for new features
- Reviewing code for Pattern Stack compliance
- Questions about pattern composition or layer structure
- Any mention of "pattern stack", "atomic architecture", "Field()", patterns
Core Principles
1. Atomic Architecture (v2.5)
Pattern Stack uses a four-layer architecture:
Atoms (Foundation)
↓
Features (Data Services)
↓
Molecules (Business Logic)
↓
Organisms (API Layer)
Layer Responsibilities:
Atoms: Foundation infrastructure
- Patterns (BasePattern, CatalogPattern, ActorPattern, etc.)
- Database setup and connections
- Cache subsystem
- Event system
- Configuration
- Shared utilities
Features: Data-focused services (one per model)
- CRUD operations
- Data validation
- Database queries
- Service-level logic
- NO cross-domain orchestration
Example:
# features/user_service.py
class UserService(BaseService):
async def create(self, data: UserCreate) -> User:
# Single-domain CRUD
user = User(**data.model_dump())
self.db.add(user)
await self.db.commit()
return user
Molecules: Business logic layer
- Entities: Single-domain business logic
- Workflows: Multi-domain orchestration
- Validation rules
- Business calculations
- Cross-service coordination
Example:
# molecules/entities/user_entity.py
class UserEntity(BaseEntity):
def _init_services(self):
self.user_service = UserService(self.db)
async def activate_user(self, user_id: UUID) -> User:
# Single-domain business logic
user = await self.user_service.get(user_id)
user.status = "active"
await self.user_service.update(user_id, user)
return user
# molecules/workflows/onboarding_workflow.py
class OnboardingWorkflow:
def _init_services(self):
self.user_entity = UserEntity(self.db)
self.notification_service = NotificationService(self.db)
async def complete_onboarding(self, user_id: UUID) -> dict:
# Multi-domain orchestration
user = await self.user_entity.activate_user(user_id)
await self.notification_service.send_welcome_email(user.email)
return {"user": user, "email_sent": True}
Organisms: API and external interfaces
- FastAPI routers and endpoints
- Request/response models (Pydantic schemas)
- Authentication/authorization checks
- Thin layer - delegates to Molecules
2. Field Abstraction - NEVER Use mapped_column
❌ WRONG - Don't do this:
from sqlalchemy.orm import Mapped, mapped_column
class User(BasePattern):
name: Mapped[str] = mapped_column(String(255), nullable=False)
email: Mapped[str] = mapped_column(String(320), unique=True)
✅ CORRECT - Use Field():
from pattern_stack.atoms.patterns.fields import Field
class User(BasePattern):
name = Field(str, required=True, max_length=255)
email = Field(str, unique=True, max_length=320, index=True)
Field() Benefits:
- Progressive enhancement: Start simple, add constraints as needed
- Type inference: Python types → SQLAlchemy types automatically
- Validation: Built-in min/max, choices, length constraints
- Cleaner syntax: Less boilerplate
Field() Examples:
# Simple fields
name = Field(str, required=True)
age = Field(int, min=0, max=150)
is_active = Field(bool, default=True)
# With validation
email = Field(str, max_length=320, unique=True, index=True)
price = Field(Decimal, min=0)
status = Field(str, choices=["draft", "published", "archived"])
# Relationships
user_id = Field(UUID, foreign_key="users.id", required=True)
category_id = Field(UUID, foreign_key="categories.id", nullable=True)
# JSON fields with defaults
tags = Field(list, default=[]) # Field() handles mutable defaults safely!
metadata = Field(dict, default={})
profile_data = Field(dict, default=dict) # Also works
# Dates and times
created_at = Field(datetime, required=True)
birth_date = Field(date, nullable=True)
3. Pattern Composition
Pattern Stack provides 5 core patterns that compose via multiple inheritance:
BasePattern (Always included via inheritance)
- Provides:
id(UUID),created_at,updated_at - Change tracking and event emission
- Validation hooks
CatalogPattern - Inventory/resource management
- Provides:
name,sku,stock_quantity,reserved_quantity,pricefields - Methods:
available_quantity,is_low_stock(),reserve_stock() - Use for: Products, equipment, digital assets
ActorPattern - Entities that perform actions
- Provides:
display_name,actor_type,email,phone,profile_data - Methods:
record_activity(),is_contactable(),get_activity_metrics() - Use for: Users, organizations, systems, services
EventPattern - State machines
- Provides:
state, state transition validation, state history - Define states in Pattern.states configuration
- Use for: Workflows, approval processes, lifecycle management
TemporalPattern - Time-based versioning
- Provides:
valid_from,valid_to,is_current, version tracking - Methods: Version queries, historical lookups
- Use for: Pricing history, deal stages, audit trails
HierarchicalPattern - Tree structures
- Provides:
parent_id,path,depth, tree traversal - Methods:
get_ancestors(),get_descendants(),get_siblings() - Use for: Categories, org charts, folder structures
Composition Example:
# Single pattern
class Product(CatalogPattern):
__tablename__ = "products"
class Pattern:
entity = "product"
# CatalogPattern provides: name, sku, stock_quantity, etc.
brand = Field(str, max_length=100, nullable=True)
# Multiple patterns
class User(ActorPattern, EventPattern):
__tablename__ = "users"
class Pattern:
entity = "user"
# EventPattern configuration
states = {
"pending": ["active", "rejected"],
"active": ["suspended", "archived"],
"suspended": ["active", "archived"]
}
initial_state = "pending"
# ActorPattern configuration
field_defaults = {"actor_type": "user"}
# ActorPattern provides: display_name, email, phone, profile_data
# EventPattern provides: state, state transitions
role = Field(str, choices=["user", "admin", "moderator"], default="user")
4. Pattern Configuration
The Pattern inner class configures pattern behavior:
class MyModel(BasePattern):
class Pattern:
# Entity name (used for events, table naming)
entity = "my_model"
# Reference number prefix (from ReferenceNumberMixin)
reference_prefix = "MDL"
# Change tracking
track_changes = True # Default: True
change_retention = "365d" # "365d", "2y", "forever"
track_changes_fields = ["*"] # Or specific fields
track_changes_exclude = ["updated_at", "metadata"]
# Field defaults (applied during __init__)
field_defaults = {
"status": "draft",
"priority": 1,
"created_date": lambda: datetime.now(UTC) # Callable defaults
}
# Activity tracking (for ActorPattern)
activity_triggers = ["login", "purchase", "upload"]
# Typed JSON profiles (advanced)
profile_type = "user_profile" # Use built-in profile schema
# OR
profile_schema = MyPydanticSchema # Custom Pydantic model
5. Automatic Features
Pattern Stack automatically provides:
Change Tracking (via EventPattern integration)
# Changes are tracked automatically
user.name = "New Name"
await db.commit() # Change event emitted automatically
# Query changes
changes = await user.get_changes(fields=["name"], limit=50)
history = await user.get_field_history("name")
Event Emission
# Events fired automatically on create/update/delete
# Custom events via EventPattern
user.emit_event("user.login", metadata={"ip": "1.2.3.4"})
Reference Numbers (via ReferenceNumberMixin)
# Automatically generated from prefix + sequential number
user.reference_number # "USR-00001"
product.reference_number # "PRD-00042"
Validation (always called before save)
class MyModel(BasePattern):
def validate(self):
if self.end_date < self.start_date:
raise ValueError("end_date must be after start_date")
Common Patterns
Creating a New Model
from pattern_stack.atoms.patterns.base import BasePattern
from pattern_stack.atoms.patterns.fields import Field
from uuid import UUID
class Account(BasePattern):
__tablename__ = "accounts"
class Pattern:
entity = "account"
reference_prefix = "ACC"
track_changes = True
change_retention = "365d"
# Fields
name = Field(str, required=True, max_length=255, index=True)
stage = Field(str, default="prospect", choices=[
"prospect", "qualifying", "demo", "proposal",
"closing", "closed_won", "closed_lost"
])
amount = Field(Decimal, min=0, nullable=True)
owner_id = Field(UUID, foreign_key="users.id", required=True, index=True)
metadata = Field(dict, default={})
def validate(self):
"""Custom validation logic."""
if self.stage == "closed_won" and self.amount is None:
raise ValueError("Closed won deals must have an amount")
Creating a Service (Features Layer)
from pattern_stack.atoms.patterns.services.base import BaseService
from sqlalchemy import select
class AccountService(BaseService):
"""Data service for Account model."""
model = Account # Links service to model
async def create(self, data: AccountCreate) -> Account:
"""Create new account."""
account = Account(**data.model_dump())
account.validate() # Always validate
self.db.add(account)
await self.db.commit()
await self.db.refresh(account)
return account
async def list_by_stage(self, stage: str) -> list[Account]:
"""Get accounts by stage."""
result = await self.db.execute(
select(Account).where(Account.stage == stage)
)
return list(result.scalars().all())
async def get_with_activities(self, account_id: UUID) -> dict:
"""Get account with related data."""
account = await self.get(account_id)
# Single domain - just fetch related activities
result = await self.db.execute(
select(Activity).where(Activity.account_id == account_id)
)
activities = list(result.scalars().all())
return {"account": account, "activities": activities}
Creating an Entity (Molecules Layer)
from pattern_stack.molecules.entities.base import BaseEntity
class AccountEntity(BaseEntity):
"""Business logic for accounts (single domain)."""
def _init_services(self):
"""Initialize required services."""
self.account_service = AccountService(self.db)
self.activity_service = ActivityService(self.db)
async def transition_stage(
self, account_id: UUID, new_stage: str
) -> Account:
"""Move account to new stage with validation."""
account = await self.account_service.get(account_id)
# Business rule: Can't skip stages
stage_order = ["prospect", "qualifying", "demo",
"proposal", "closing", "closed_won"]
current_idx = stage_order.index(account.stage)
new_idx = stage_order.index(new_stage)
if abs(new_idx - current_idx) != 1:
raise ValueError("Cannot skip stages")
# Apply change
account.stage = new_stage
await self.account_service.update(account_id, account)
# Create activity log
activity = Activity(
account_id=account_id,
type="stage_change",
title=f"Stage changed to {new_stage}",
occurred_at=datetime.now(UTC)
)
self.db.add(activity)
await self.db.commit()
return account
Creating a Workflow (Molecules Layer)
class SalesWorkflow:
"""Multi-domain orchestration for sales processes."""
def __init__(self, db: AsyncSession):
self.db = db
# Initialize entities (not services directly)
self.account_entity = AccountEntity(db)
self.user_entity = UserEntity(db)
self.notification_service = NotificationService(db)
async def close_deal(
self, account_id: UUID, amount: Decimal
) -> dict:
"""Close a deal - orchestrates multiple domains."""
# 1. Update account
account = await self.account_entity.transition_stage(
account_id, "closed_won"
)
account.amount = amount
await self.account_entity.account_service.update(account_id, account)
# 2. Update owner's metrics
owner = await self.user_entity.user_service.get(account.owner_id)
owner.total_sales += amount
owner.deals_closed += 1
await self.user_entity.user_service.update(owner.id, owner)
# 3. Send notifications
await self.notification_service.send(
user_id=owner.id,
message=f"Congratulations! {account.name} closed at ${amount}"
)
# 4. Create celebration activity
activity = Activity(
account_id=account_id,
type="deal_closed",
title=f"Deal closed: ${amount}",
occurred_at=datetime.now(UTC)
)
self.db.add(activity)
await self.db.commit()
return {
"account": account,
"owner": owner,
"notification_sent": True
}
Anti-Patterns to Avoid
❌ Don't: Use mapped_column
# WRONG
from sqlalchemy.orm import mapped_column
name: Mapped[str] = mapped_column(String(255))
✅ Do: Use Field()
# CORRECT
name = Field(str, max_length=255, required=True)
❌ Don't: Put business logic in services
# WRONG - Service doing orchestration
class AccountService(BaseService):
async def close_deal(self, account_id: UUID):
account = await self.get(account_id)
account.stage = "closed_won"
# Calling other services - WRONG LAYER!
owner = await self.user_service.get(account.owner_id)
await self.notification_service.send(...)
✅ Do: Put orchestration in Workflows
# CORRECT - Workflow orchestrates
class SalesWorkflow:
async def close_deal(self, account_id: UUID):
# Orchestrates across domains
account = await self.account_entity.transition_stage(...)
owner = await self.user_entity.update_metrics(...)
await self.notification_service.send(...)
❌ Don't: Directly access db in Entities/Workflows
# WRONG - Entity bypassing service
class AccountEntity:
async def get_account(self, account_id: UUID):
result = await self.db.execute( # Don't query directly!
select(Account).where(Account.id == account_id)
)
return result.scalar_one()
✅ Do: Use Services for all data access
# CORRECT - Entity uses service
class AccountEntity:
async def get_account(self, account_id: UUID):
return await self.account_service.get(account_id) # Via service
❌ Don't: Forget validation
# WRONG - No validation
async def create(self, data: AccountCreate):
account = Account(**data.model_dump())
self.db.add(account) # What if data is invalid?
await self.db.commit()
✅ Do: Always validate
# CORRECT - Validation before commit
async def create(self, data: AccountCreate):
account = Account(**data.model_dump())
account.validate() # Always validate!
self.db.add(account)
await self.db.commit()
❌ Don't: Mix concerns across layers
# WRONG - API logic in service
class AccountService:
async def create_from_request(self, request: Request):
user = request.user # API concerns in service!
data = await request.json()
...
✅ Do: Keep layers focused
# CORRECT - API layer handles requests
# Organism layer
@router.post("/accounts")
async def create_account(
data: AccountCreate,
user: User = Depends(get_current_user)
):
# Delegate to workflow/entity
return await workflow.create_account(data, user.id)
# Service layer just handles data
class AccountService:
async def create(self, data: AccountCreate):
# Pure data operation
...
Quick Reference
Field Types
Field(str, max_length=255) # String
Field(int, min=0, max=100) # Integer with range
Field(bool, default=False) # Boolean
Field(Decimal, min=0) # Decimal (for money)
Field(UUID, foreign_key="...") # Foreign key
Field(datetime) # Datetime
Field(date) # Date only
Field(dict, default={}) # JSON object
Field(list, default=[]) # JSON array
Pattern Selection
- Need inventory tracking? →
CatalogPattern - Need users/orgs? →
ActorPattern - Need state machine? →
EventPattern - Need version history? →
TemporalPattern - Need tree structure? →
HierarchicalPattern - None of the above? → Just
BasePattern
Layer Checklist
- Atoms: Database, cache, events, config ✓
- Features: CRUD, queries, data validation ✓
- Molecules/Entities: Single-domain business logic ✓
- Molecules/Workflows: Multi-domain orchestration ✓
- Organisms: APIs, auth, request/response ✓
Final Reminders
- Always use Field(), never mapped_column
- Compose patterns via multiple inheritance
- Respect layer boundaries - no shortcuts
- Services = data, Entities = single-domain, Workflows = multi-domain
- Always validate before committing
- Change tracking is automatic - just modify and commit
- Events fire automatically - leverage the event system
When in doubt, follow the examples above and trust the patterns. Pattern Stack handles the complexity so you can focus on business logic.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon

