Model entity validator
Skill smicolon/ai-kit/packs/django/skills/model-entity-validator
Convention packs for any AI coding tool - agents, skills, commands, and rules for 15 tools including Claude Code, Cursor, Windsurf, and Copilot
npx -y skills add smicolon/ai-kit --skill model-entity-validatorAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
This skill should be used when the user asks to "create a model", "add a Django model", "create database table", "add entity", "define schema", or when writing class definitions inheriting from models.Model. Validates BaseModel inheritance pattern.
SKILL.md
7.8 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it
Model/Entity Validator
Enforces Smicolon's BaseModel inheritance pattern for all Django models.
Activation Triggers
This skill activates when:
- Creating new model files
- Modifying existing models
- Mentioning "model", "database", "schema", "table"
- Writing class inheriting from
models.Model - Running migrations
- Discussing data structure
Core Principle: BaseModel Inheritance
NEVER repeat UUID/timestamp fields. All models inherit from BaseModel.
# ❌ WRONG - Repeating fields
class User(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_deleted = models.BooleanField(default=False)
email = models.EmailField()
# ✅ CORRECT - Inherit from BaseModel
import core.models as _core_models
class User(_core_models.BaseModel):
email = models.EmailField(unique=True)
Validation Process
Step 1: Check if BaseModel Exists
Before any action, check if the project has a BaseModel:
# Search for BaseModel in (in order):
# 1. core/models.py
# 2. shared/models.py
# 3. common/models.py
# 4. {app}/base.py
If BaseModel found: Suggest inheritance (Step 2a) If BaseModel NOT found: Create BaseModel first (Step 2b)
Step 2a: BaseModel Exists - Suggest Inheritance
When seeing:
class Product(models.Model):
name = models.CharField(max_length=255)
Fix to:
import core.models as _core_models
class Product(_core_models.BaseModel):
"""Product model - inherits id, timestamps, soft delete from BaseModel."""
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=10, decimal_places=2)
class Meta:
db_table = 'products'
Step 2b: BaseModel NOT Found - Create It First
If no BaseModel exists, create it:
# core/models.py
import uuid
from django.db import models
class BaseModel(models.Model):
"""
Abstract base model providing:
- UUID primary key
- Automatic timestamps (created_at, updated_at)
- Soft delete support (is_deleted)
All models MUST inherit from this class.
"""
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_deleted = models.BooleanField(default=False)
class Meta:
abstract = True
ordering = ['-created_at']
def soft_delete(self) -> None:
"""Soft delete the record."""
self.is_deleted = True
self.save(update_fields=['is_deleted', 'updated_at'])
def restore(self) -> None:
"""Restore a soft-deleted record."""
self.is_deleted = False
self.save(update_fields=['is_deleted', 'updated_at'])
class ActiveManager(models.Manager):
"""Manager that excludes soft-deleted records."""
def get_queryset(self):
return super().get_queryset().filter(is_deleted=False)
Report to developer:
BaseModel Created
Created
core/models.pywith BaseModel. All models should now inherit from it:import core.models as _core_models class YourModel(_core_models.BaseModel): # Your fields here - DO NOT add id, created_at, updated_at, is_deleted
Step 3: Detect Duplicate Fields
If seeing a model with explicit id/timestamp fields that inherits from BaseModel:
# ❌ WRONG - Duplicate fields
class User(_core_models.BaseModel):
id = models.UUIDField(...) # Already in BaseModel!
created_at = models.DateTimeField(...) # Already in BaseModel!
email = models.EmailField()
Remove them:
# ✅ CORRECT - Only custom fields
class User(_core_models.BaseModel):
email = models.EmailField(unique=True)
Step 4: Validate Indexes
Check if appropriate indexes exist:
class Product(_core_models.BaseModel):
name = models.CharField(max_length=255)
sku = models.CharField(max_length=100, unique=True)
class Meta:
db_table = 'products'
indexes = [
models.Index(fields=['sku']), # Suggest for unique lookups
models.Index(fields=['name']), # Suggest for search
]
Complete Model Examples
Standard Model
# products/models.py
from django.db import models
import core.models as _core_models
class Product(_core_models.BaseModel):
"""Product model."""
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
sku = models.CharField(max_length=100, unique=True, db_index=True)
is_active = models.BooleanField(default=True)
class Meta:
db_table = 'products'
verbose_name = 'Product'
verbose_name_plural = 'Products'
indexes = [
models.Index(fields=['name']),
models.Index(fields=['is_active', 'is_deleted']),
]
def __str__(self):
return self.name
User Model (with AbstractUser)
# users/models.py
import uuid
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
"""
Custom User model with UUID and timestamps.
Note: For User, override AbstractUser directly since it has its own
ID handling. Add the standard fields manually.
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_deleted = models.BooleanField(default=False)
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
db_table = 'users'
Through Model (Many-to-Many)
# users/models.py
import core.models as _core_models
class UserOrganization(_core_models.BaseModel):
"""Through model for user-organization relationship."""
user = models.ForeignKey('User', on_delete=models.CASCADE)
organization = models.ForeignKey('Organization', on_delete=models.CASCADE)
role = models.CharField(max_length=50)
class Meta:
db_table = 'user_organizations'
unique_together = [['user', 'organization']]
Custom Managers
BaseModel provides soft delete. Add a custom manager for convenience:
import core.models as _core_models
class Product(_core_models.BaseModel):
name = models.CharField(max_length=255)
objects = models.Manager() # All records
active = _core_models.ActiveManager() # Excludes soft-deleted
# Usage
Product.active.all() # Only non-deleted
Product.objects.all() # All including deleted
Validation Checklist
When reviewing a model, check:
- ✅ Inherits from
BaseModel(or has explicit required fields for special cases) - ✅ Does NOT duplicate fields from BaseModel
- ✅ Uses absolute import:
import core.models as _core_models - ✅ Has appropriate
db_tablename (singular or plural, snake_case) - ✅ Has indexes on frequently queried fields
- ✅ Foreign keys have
on_deletespecified - ✅ Has docstring explaining the model
- ✅ Has
__str__method for admin display
Behavior
Proactive enforcement:
- Check if BaseModel exists FIRST
- Suggest inheritance instead of field duplication
- Remove duplicate fields automatically
- Create BaseModel if missing
- Explain WHY inheritance is better
Never:
- Add duplicate id/timestamp fields to models
- Let developers repeat base fields
- Ignore existing BaseModel in the project
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.