[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DAEM5N22EFV0490KNJK4WR":3,"skill-same:01M6DAEM5N22EFV0490KNJK4WR":355},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":14,"repositoryHtmlUrl":48,"repositoryHomepageUrl":6,"ownerHtmlUrl":49,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":50,"install":51,"resources":64},"01M6DAEM5N22EFV0490KNJK4WR","django-security",null,"Django security best practices, authentication, authorization, CSRF protection, SQL injection prevention, XSS prevention, and secure deployment configurations.","Prekzursil\u002Fagent-skills-toolchain","Prekzursil","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F54636077?v=4","01M6DACZ1PCQHD99SCR1YXG28B","Andrei Mihai Visalon","01M6DACZ670WZF535V3WYYSS4Z",0,"MIT","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fdjango-security\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"security","django","django security","sql","secure","deployment","authentication","best practices","security best practices","authorization","injection","xss","prevention","csrf","protection","2026-11-10 10:12:30",false,"---\nname: django-security\ndescription: Django security best practices, authentication, authorization, CSRF protection, SQL injection prevention, XSS prevention, and secure deployment configurations.\norigin: ECC\n---\n\n# Django Security Best Practices\n\nComprehensive security guidelines for Django applications to protect against common vulnerabilities.\n\n## When to Activate\n\n- Setting up Django authentication and authorization\n- Implementing user permissions and roles\n- Configuring production security settings\n- Reviewing Django application for security issues\n- Deploying Django applications to production\n\n## Core Security Settings\n\n### Production Settings Configuration\n\n```python\n# settings\u002Fproduction.py\nimport os\n\nDEBUG = False  # CRITICAL: Never use True in production\n\nALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')\n\n# Security headers\nSECURE_SSL_REDIRECT = True\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SECURE = True\nSECURE_HSTS_SECONDS = 31536000  # 1 year\nSECURE_HSTS_INCLUDE_SUBDOMAINS = True\nSECURE_HSTS_PRELOAD = True\nSECURE_CONTENT_TYPE_NOSNIFF = True\nSECURE_BROWSER_XSS_FILTER = True\nX_FRAME_OPTIONS = 'DENY'\n\n# HTTPS and Cookies\nSESSION_COOKIE_HTTPONLY = True\nCSRF_COOKIE_HTTPONLY = True\nSESSION_COOKIE_SAMESITE = 'Lax'\nCSRF_COOKIE_SAMESITE = 'Lax'\n\n# Secret key (must be set via environment variable)\nSECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')\nif not SECRET_KEY:\n    raise ImproperlyConfigured('DJANGO_SECRET_KEY environment variable is required')\n\n# Password validation\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n        'OPTIONS': {\n            'min_length': 12,\n        }\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n```\n\n## Authentication\n\n### Custom User Model\n\n```python\n# apps\u002Fusers\u002Fmodels.py\nfrom django.contrib.auth.models import AbstractUser\nfrom django.db import models\n\nclass User(AbstractUser):\n    \"\"\"Custom user model for better security.\"\"\"\n\n    email = models.EmailField(unique=True)\n    phone = models.CharField(max_length=20, blank=True)\n\n    USERNAME_FIELD = 'email'  # Use email as username\n    REQUIRED_FIELDS = ['username']\n\n    class Meta:\n        db_table = 'users'\n        verbose_name = 'User'\n        verbose_name_plural = 'Users'\n\n    def __str__(self):\n        return self.email\n\n# settings\u002Fbase.py\nAUTH_USER_MODEL = 'users.User'\n```\n\n### Password Hashing\n\n```python\n# Django uses PBKDF2 by default. For stronger security:\nPASSWORD_HASHERS = [\n    'django.contrib.auth.hashers.Argon2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',\n    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',\n]\n```\n\n### Session Management\n\n```python\n# Session configuration\nSESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # Or 'db'\nSESSION_CACHE_ALIAS = 'default'\nSESSION_COOKIE_AGE = 3600 * 24 * 7  # 1 week\nSESSION_SAVE_EVERY_REQUEST = False\nSESSION_EXPIRE_AT_BROWSER_CLOSE = False  # Better UX, but less secure\n```\n\n## Authorization\n\n### Permissions\n\n```python\n# models.py\nfrom django.db import models\nfrom django.contrib.auth.models import Permission\n\nclass Post(models.Model):\n    title = models.CharField(max_length=200)\n    content = models.TextField()\n    author = models.ForeignKey(User, on_delete=models.CASCADE)\n\n    class Meta:\n        permissions = [\n            ('can_publish', 'Can publish posts'),\n            ('can_edit_others', 'Can edit posts of others'),\n        ]\n\n    def user_can_edit(self, user):\n        \"\"\"Check if user can edit this post.\"\"\"\n        return self.author == user or user.has_perm('app.can_edit_others')\n\n# views.py\nfrom django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin\nfrom django.views.generic import UpdateView\n\nclass PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):\n    model = Post\n    permission_required = 'app.can_edit_others'\n    raise_exception = True  # Return 403 instead of redirect\n\n    def get_queryset(self):\n        \"\"\"Only allow users to edit their own posts.\"\"\"\n        return Post.objects.filter(author=self.request.user)\n```\n\n### Custom Permissions\n\n```python\n# permissions.py\nfrom rest_framework import permissions\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow only owners to edit objects.\"\"\"\n\n    def has_object_permission(self, request, view, obj):\n        # Read permissions allowed for any request\n        if request.method in permissions.SAFE_METHODS:\n            return True\n\n        # Write permissions only for owner\n        return obj.author == request.user\n\nclass IsAdminOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow admins to do anything, others read-only.\"\"\"\n\n    def has_permission(self, request, view):\n        if request.method in permissions.SAFE_METHODS:\n            return True\n        return request.user and request.user.is_staff\n\nclass IsVerifiedUser(permissions.BasePermission):\n    \"\"\"Allow only verified users.\"\"\"\n\n    def has_permission(self, request, view):\n        return request.user and request.user.is_authenticated and request.user.is_verified\n```\n\n### Role-Based Access Control (RBAC)\n\n```python\n# models.py\nfrom django.contrib.auth.models import AbstractUser, Group\n\nclass User(AbstractUser):\n    ROLE_CHOICES = [\n        ('admin', 'Administrator'),\n        ('moderator', 'Moderator'),\n        ('user', 'Regular User'),\n    ]\n    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')\n\n    def is_admin(self):\n        return self.role == 'admin' or self.is_superuser\n\n    def is_moderator(self):\n        return self.role in ['admin', 'moderator']\n\n# Mixins\nclass AdminRequiredMixin:\n    \"\"\"Mixin to require admin role.\"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        if not request.user.is_authenticated or not request.user.is_admin():\n            from django.core.exceptions import PermissionDenied\n            raise PermissionDenied\n        return super().dispatch(request, *args, **kwargs)\n```\n\n## SQL Injection Prevention\n\n### Django ORM Protection\n\n```python\n# GOOD: Django ORM automatically escapes parameters\ndef get_user(username):\n    return User.objects.get(username=username)  # Safe\n\n# GOOD: Using parameters with raw()\ndef search_users(query):\n    return User.objects.raw('SELECT * FROM users WHERE username = %s', [query])\n\n# BAD: Never directly interpolate user input\ndef get_user_bad(username):\n    return User.objects.raw(f'SELECT * FROM users WHERE username = {username}')  # VULNERABLE!\n\n# GOOD: Using filter with proper escaping\ndef get_users_by_email(email):\n    return User.objects.filter(email__iexact=email)  # Safe\n\n# GOOD: Using Q objects for complex queries\nfrom django.db.models import Q\ndef search_users_complex(query):\n    return User.objects.filter(\n        Q(username__icontains=query) |\n        Q(email__icontains=query)\n    )  # Safe\n```\n\n### Extra Security with raw()\n\n```python\n# If you must use raw SQL, always use parameters\nUser.objects.raw(\n    'SELECT * FROM users WHERE email = %s AND status = %s',\n    [user_input_email, status]\n)\n```\n\n## XSS Prevention\n\n### Template Escaping\n\n```django\n{# Django auto-escapes variables by default - SAFE #}\n{{ user_input }}  {# Escaped HTML #}\n\n{# Explicitly mark safe only for trusted content #}\n{{ trusted_html|safe }}  {# Not escaped #}\n\n{# Use template filters for safe HTML #}\n{{ user_input|escape }}  {# Same as default #}\n{{ user_input|striptags }}  {# Remove all HTML tags #}\n\n{# JavaScript escaping #}\n\u003Cscript>\n    var username = {{ username|escapejs }};\n\u003C\u002Fscript>\n```\n\n### Safe String Handling\n\n```python\nfrom django.utils.safestring import mark_safe\nfrom django.utils.html import escape\n\n# BAD: Never mark user input as safe without escaping\ndef render_bad(user_input):\n    return mark_safe(user_input)  # VULNERABLE!\n\n# GOOD: Escape first, then mark safe\ndef render_good(user_input):\n    return mark_safe(escape(user_input))\n\n# GOOD: Use format_html for HTML with variables\nfrom django.utils.html import format_html\n\ndef greet_user(username):\n    return format_html('\u003Cspan class=\"user\">{}\u003C\u002Fspan>', escape(username))\n```\n\n### HTTP Headers\n\n```python\n# settings.py\nSECURE_CONTENT_TYPE_NOSNIFF = True  # Prevent MIME sniffing\nSECURE_BROWSER_XSS_FILTER = True  # Enable XSS filter\nX_FRAME_OPTIONS = 'DENY'  # Prevent clickjacking\n\n# Custom middleware\nfrom django.conf import settings\n\nclass SecurityHeaderMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['X-Content-Type-Options'] = 'nosniff'\n        response['X-Frame-Options'] = 'DENY'\n        response['X-XSS-Protection'] = '1; mode=block'\n        response['Content-Security-Policy'] = \"default-src 'self'\"\n        return response\n```\n\n## CSRF Protection\n\n### Default CSRF Protection\n\n```python\n# settings.py - CSRF is enabled by default\nCSRF_COOKIE_SECURE = True  # Only send over HTTPS\nCSRF_COOKIE_HTTPONLY = True  # Prevent JavaScript access\nCSRF_COOKIE_SAMESITE = 'Lax'  # Prevent CSRF in some cases\nCSRF_TRUSTED_ORIGINS = ['https:\u002F\u002Fexample.com']  # Trusted domains\n\n# Template usage\n\u003Cform method=\"post\">\n    {% csrf_token %}\n    {{ form.as_p }}\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n\n# AJAX requests\nfunction getCookie(name) {\n    let cookieValue = null;\n    if (document.cookie && document.cookie !== '') {\n        const cookies = document.cookie.split(';');\n        for (let i = 0; i \u003C cookies.length; i++) {\n            const cookie = cookies[i].trim();\n            if (cookie.substring(0, name.length + 1) === (name + '=')) {\n                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                break;\n            }\n        }\n    }\n    return cookieValue;\n}\n\nfetch('\u002Fapi\u002Fendpoint\u002F', {\n    method: 'POST',\n    headers: {\n        'X-CSRFToken': getCookie('csrftoken'),\n        'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify(data)\n});\n```\n\n### Exempting Views (Use Carefully)\n\n```python\nfrom django.views.decorators.csrf import csrf_exempt\n\n@csrf_exempt  # Only use when absolutely necessary!\ndef webhook_view(request):\n    # Webhook from external service\n    pass\n```\n\n## File Upload Security\n\n### File Validation\n\n```python\nimport os\nfrom django.core.exceptions import ValidationError\n\ndef validate_file_extension(value):\n    \"\"\"Validate file extension.\"\"\"\n    ext = os.path.splitext(value.name)[1]\n    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.pdf']\n    if not ext.lower() in valid_extensions:\n        raise ValidationError('Unsupported file extension.')\n\ndef validate_file_size(value):\n    \"\"\"Validate file size (max 5MB).\"\"\"\n    filesize = value.size\n    if filesize > 5 * 1024 * 1024:\n        raise ValidationError('File too large. Max size is 5MB.')\n\n# models.py\nclass Document(models.Model):\n    file = models.FileField(\n        upload_to='documents\u002F',\n        validators=[validate_file_extension, validate_file_size]\n    )\n```\n\n### Secure File Storage\n\n```python\n# settings.py\nMEDIA_ROOT = '\u002Fvar\u002Fwww\u002Fmedia\u002F'\nMEDIA_URL = '\u002Fmedia\u002F'\n\n# Use a separate domain for media in production\nMEDIA_DOMAIN = 'https:\u002F\u002Fmedia.example.com'\n\n# Don't serve user uploads directly\n# Use whitenoise or a CDN for static files\n# Use a separate server or S3 for media files\n```\n\n## API Security\n\n### Rate Limiting\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_THROTTLE_CLASSES': [\n        'rest_framework.throttling.AnonRateThrottle',\n        'rest_framework.throttling.UserRateThrottle'\n    ],\n    'DEFAULT_THROTTLE_RATES': {\n        'anon': '100\u002Fday',\n        'user': '1000\u002Fday',\n        'upload': '10\u002Fhour',\n    }\n}\n\n# Custom throttle\nfrom rest_framework.throttling import UserRateThrottle\n\nclass BurstRateThrottle(UserRateThrottle):\n    scope = 'burst'\n    rate = '60\u002Fmin'\n\nclass SustainedRateThrottle(UserRateThrottle):\n    scope = 'sustained'\n    rate = '1000\u002Fday'\n```\n\n### Authentication for APIs\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': [\n        'rest_framework.authentication.TokenAuthentication',\n        'rest_framework.authentication.SessionAuthentication',\n        'rest_framework_simplejwt.authentication.JWTAuthentication',\n    ],\n    'DEFAULT_PERMISSION_CLASSES': [\n        'rest_framework.permissions.IsAuthenticated',\n    ],\n}\n\n# views.py\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\n\n@api_view(['GET', 'POST'])\n@permission_classes([IsAuthenticated])\ndef protected_view(request):\n    return Response({'message': 'You are authenticated'})\n```\n\n## Security Headers\n\n### Content Security Policy\n\n```python\n# settings.py\nCSP_DEFAULT_SRC = \"'self'\"\nCSP_SCRIPT_SRC = \"'self' https:\u002F\u002Fcdn.example.com\"\nCSP_STYLE_SRC = \"'self' 'unsafe-inline'\"\nCSP_IMG_SRC = \"'self' data: https:\"\nCSP_CONNECT_SRC = \"'self' https:\u002F\u002Fapi.example.com\"\n\n# Middleware\nclass CSPMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['Content-Security-Policy'] = (\n            f\"default-src {CSP_DEFAULT_SRC}; \"\n            f\"script-src {CSP_SCRIPT_SRC}; \"\n            f\"style-src {CSP_STYLE_SRC}; \"\n            f\"img-src {CSP_IMG_SRC}; \"\n            f\"connect-src {CSP_CONNECT_SRC}\"\n        )\n        return response\n```\n\n## Environment Variables\n\n### Managing Secrets\n\n```python\n# Use python-decouple or django-environ\nimport environ\n\nenv = environ.Env(\n    # set casting, default value\n    DEBUG=(bool, False)\n)\n\n# reading .env file\nenviron.Env.read_env()\n\nSECRET_KEY = env('DJANGO_SECRET_KEY')\nDATABASE_URL = env('DATABASE_URL')\nALLOWED_HOSTS = env.list('ALLOWED_HOSTS')\n\n# .env file (never commit this)\nDEBUG=False\nSECRET_KEY=your-secret-key-here\nDATABASE_URL=postgresql:\u002F\u002Fuser:password@localhost:5432\u002Fdbname\nALLOWED_HOSTS=example.com,www.example.com\n```\n\n## Logging Security Events\n\n```python\n# settings.py\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'handlers': {\n        'file': {\n            'level': 'WARNING',\n            'class': 'logging.FileHandler',\n            'filename': '\u002Fvar\u002Flog\u002Fdjango\u002Fsecurity.log',\n        },\n        'console': {\n            'level': 'INFO',\n            'class': 'logging.StreamHandler',\n        },\n    },\n    'loggers': {\n        'django.security': {\n            'handlers': ['file', 'console'],\n            'level': 'WARNING',\n            'propagate': True,\n        },\n        'django.request': {\n            'handlers': ['file'],\n            'level': 'ERROR',\n            'propagate': False,\n        },\n    },\n}\n```\n\n## Quick Security Checklist\n\n| Check | Description |\n|-------|-------------|\n| `DEBUG = False` | Never run with DEBUG in production |\n| HTTPS only | Force SSL, secure cookies |\n| Strong secrets | Use environment variables for SECRET_KEY |\n| Password validation | Enable all password validators |\n| CSRF protection | Enabled by default, don't disable |\n| XSS prevention | Django auto-escapes, don't use `&#124;safe` with user input |\n| SQL injection | Use ORM, never concatenate strings in queries |\n| File uploads | Validate file type and size |\n| Rate limiting | Throttle API endpoints |\n| Security headers | CSP, X-Frame-Options, HSTS |\n| Logging | Log security events |\n| Updates | Keep Django and dependencies updated |\n\nRemember: Security is a process, not a product. Regularly review and update your security practices.\n","# Django Security Best Practices\n\nComprehensive security guidelines for Django applications to protect against common vulnerabilities.\n\n## When to Activate\n\n- Setting up Django authentication and authorization\n- Implementing user permissions and roles\n- Configuring production security settings\n- Reviewing Django application for security issues\n- Deploying Django applications to production\n\n## Core Security Settings\n\n### Production Settings Configuration\n\n```python\n# settings\u002Fproduction.py\nimport os\n\nDEBUG = False  # CRITICAL: Never use True in production\n\nALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')\n\n# Security headers\nSECURE_SSL_REDIRECT = True\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SECURE = True\nSECURE_HSTS_SECONDS = 31536000  # 1 year\nSECURE_HSTS_INCLUDE_SUBDOMAINS = True\nSECURE_HSTS_PRELOAD = True\nSECURE_CONTENT_TYPE_NOSNIFF = True\nSECURE_BROWSER_XSS_FILTER = True\nX_FRAME_OPTIONS = 'DENY'\n\n# HTTPS and Cookies\nSESSION_COOKIE_HTTPONLY = True\nCSRF_COOKIE_HTTPONLY = True\nSESSION_COOKIE_SAMESITE = 'Lax'\nCSRF_COOKIE_SAMESITE = 'Lax'\n\n# Secret key (must be set via environment variable)\nSECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')\nif not SECRET_KEY:\n    raise ImproperlyConfigured('DJANGO_SECRET_KEY environment variable is required')\n\n# Password validation\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n        'OPTIONS': {\n            'min_length': 12,\n        }\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n```\n\n## Authentication\n\n### Custom User Model\n\n```python\n# apps\u002Fusers\u002Fmodels.py\nfrom django.contrib.auth.models import AbstractUser\nfrom django.db import models\n\nclass User(AbstractUser):\n    \"\"\"Custom user model for better security.\"\"\"\n\n    email = models.EmailField(unique=True)\n    phone = models.CharField(max_length=20, blank=True)\n\n    USERNAME_FIELD = 'email'  # Use email as username\n    REQUIRED_FIELDS = ['username']\n\n    class Meta:\n        db_table = 'users'\n        verbose_name = 'User'\n        verbose_name_plural = 'Users'\n\n    def __str__(self):\n        return self.email\n\n# settings\u002Fbase.py\nAUTH_USER_MODEL = 'users.User'\n```\n\n### Password Hashing\n\n```python\n# Django uses PBKDF2 by default. For stronger security:\nPASSWORD_HASHERS = [\n    'django.contrib.auth.hashers.Argon2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',\n    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',\n]\n```\n\n### Session Management\n\n```python\n# Session configuration\nSESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # Or 'db'\nSESSION_CACHE_ALIAS = 'default'\nSESSION_COOKIE_AGE = 3600 * 24 * 7  # 1 week\nSESSION_SAVE_EVERY_REQUEST = False\nSESSION_EXPIRE_AT_BROWSER_CLOSE = False  # Better UX, but less secure\n```\n\n## Authorization\n\n### Permissions\n\n```python\n# models.py\nfrom django.db import models\nfrom django.contrib.auth.models import Permission\n\nclass Post(models.Model):\n    title = models.CharField(max_length=200)\n    content = models.TextField()\n    author = models.ForeignKey(User, on_delete=models.CASCADE)\n\n    class Meta:\n        permissions = [\n            ('can_publish', 'Can publish posts'),\n            ('can_edit_others', 'Can edit posts of others'),\n        ]\n\n    def user_can_edit(self, user):\n        \"\"\"Check if user can edit this post.\"\"\"\n        return self.author == user or user.has_perm('app.can_edit_others')\n\n# views.py\nfrom django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin\nfrom django.views.generic import UpdateView\n\nclass PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):\n    model = Post\n    permission_required = 'app.can_edit_others'\n    raise_exception = True  # Return 403 instead of redirect\n\n    def get_queryset(self):\n        \"\"\"Only allow users to edit their own posts.\"\"\"\n        return Post.objects.filter(author=self.request.user)\n```\n\n### Custom Permissions\n\n```python\n# permissions.py\nfrom rest_framework import permissions\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow only owners to edit objects.\"\"\"\n\n    def has_object_permission(self, request, view, obj):\n        # Read permissions allowed for any request\n        if request.method in permissions.SAFE_METHODS:\n            return True\n\n        # Write permissions only for owner\n        return obj.author == request.user\n\nclass IsAdminOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow admins to do anything, others read-only.\"\"\"\n\n    def has_permission(self, request, view):\n        if request.method in permissions.SAFE_METHODS:\n            return True\n        return request.user and request.user.is_staff\n\nclass IsVerifiedUser(permissions.BasePermission):\n    \"\"\"Allow only verified users.\"\"\"\n\n    def has_permission(self, request, view):\n        return request.user and request.user.is_authenticated and request.user.is_verified\n```\n\n### Role-Based Access Control (RBAC)\n\n```python\n# models.py\nfrom django.contrib.auth.models import AbstractUser, Group\n\nclass User(AbstractUser):\n    ROLE_CHOICES = [\n        ('admin', 'Administrator'),\n        ('moderator', 'Moderator'),\n        ('user', 'Regular User'),\n    ]\n    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')\n\n    def is_admin(self):\n        return self.role == 'admin' or self.is_superuser\n\n    def is_moderator(self):\n        return self.role in ['admin', 'moderator']\n\n# Mixins\nclass AdminRequiredMixin:\n    \"\"\"Mixin to require admin role.\"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        if not request.user.is_authenticated or not request.user.is_admin():\n            from django.core.exceptions import PermissionDenied\n            raise PermissionDenied\n        return super().dispatch(request, *args, **kwargs)\n```\n\n## SQL Injection Prevention\n\n### Django ORM Protection\n\n```python\n# GOOD: Django ORM automatically escapes parameters\ndef get_user(username):\n    return User.objects.get(username=username)  # Safe\n\n# GOOD: Using parameters with raw()\ndef search_users(query):\n    return User.objects.raw('SELECT * FROM users WHERE username = %s', [query])\n\n# BAD: Never directly interpolate user input\ndef get_user_bad(username):\n    return User.objects.raw(f'SELECT * FROM users WHERE username = {username}')  # VULNERABLE!\n\n# GOOD: Using filter with proper escaping\ndef get_users_by_email(email):\n    return User.objects.filter(email__iexact=email)  # Safe\n\n# GOOD: Using Q objects for complex queries\nfrom django.db.models import Q\ndef search_users_complex(query):\n    return User.objects.filter(\n        Q(username__icontains=query) |\n        Q(email__icontains=query)\n    )  # Safe\n```\n\n### Extra Security with raw()\n\n```python\n# If you must use raw SQL, always use parameters\nUser.objects.raw(\n    'SELECT * FROM users WHERE email = %s AND status = %s',\n    [user_input_email, status]\n)\n```\n\n## XSS Prevention\n\n### Template Escaping\n\n```django\n{# Django auto-escapes variables by default - SAFE #}\n{{ user_input }}  {# Escaped HTML #}\n\n{# Explicitly mark safe only for trusted content #}\n{{ trusted_html|safe }}  {# Not escaped #}\n\n{# Use template filters for safe HTML #}\n{{ user_input|escape }}  {# Same as default #}\n{{ user_input|striptags }}  {# Remove all HTML tags #}\n\n{# JavaScript escaping #}\n\u003Cscript>\n    var username = {{ username|escapejs }};\n\u003C\u002Fscript>\n```\n\n### Safe String Handling\n\n```python\nfrom django.utils.safestring import mark_safe\nfrom django.utils.html import escape\n\n# BAD: Never mark user input as safe without escaping\ndef render_bad(user_input):\n    return mark_safe(user_input)  # VULNERABLE!\n\n# GOOD: Escape first, then mark safe\ndef render_good(user_input):\n    return mark_safe(escape(user_input))\n\n# GOOD: Use format_html for HTML with variables\nfrom django.utils.html import format_html\n\ndef greet_user(username):\n    return format_html('\u003Cspan class=\"user\">{}\u003C\u002Fspan>', escape(username))\n```\n\n### HTTP Headers\n\n```python\n# settings.py\nSECURE_CONTENT_TYPE_NOSNIFF = True  # Prevent MIME sniffing\nSECURE_BROWSER_XSS_FILTER = True  # Enable XSS filter\nX_FRAME_OPTIONS = 'DENY'  # Prevent clickjacking\n\n# Custom middleware\nfrom django.conf import settings\n\nclass SecurityHeaderMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['X-Content-Type-Options'] = 'nosniff'\n        response['X-Frame-Options'] = 'DENY'\n        response['X-XSS-Protection'] = '1; mode=block'\n        response['Content-Security-Policy'] = \"default-src 'self'\"\n        return response\n```\n\n## CSRF Protection\n\n### Default CSRF Protection\n\n```python\n# settings.py - CSRF is enabled by default\nCSRF_COOKIE_SECURE = True  # Only send over HTTPS\nCSRF_COOKIE_HTTPONLY = True  # Prevent JavaScript access\nCSRF_COOKIE_SAMESITE = 'Lax'  # Prevent CSRF in some cases\nCSRF_TRUSTED_ORIGINS = ['https:\u002F\u002Fexample.com']  # Trusted domains\n\n# Template usage\n\u003Cform method=\"post\">\n    {% csrf_token %}\n    {{ form.as_p }}\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n\n# AJAX requests\nfunction getCookie(name) {\n    let cookieValue = null;\n    if (document.cookie && document.cookie !== '') {\n        const cookies = document.cookie.split(';');\n        for (let i = 0; i \u003C cookies.length; i++) {\n            const cookie = cookies[i].trim();\n            if (cookie.substring(0, name.length + 1) === (name + '=')) {\n                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                break;\n            }\n        }\n    }\n    return cookieValue;\n}\n\nfetch('\u002Fapi\u002Fendpoint\u002F', {\n    method: 'POST',\n    headers: {\n        'X-CSRFToken': getCookie('csrftoken'),\n        'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify(data)\n});\n```\n\n### Exempting Views (Use Carefully)\n\n```python\nfrom django.views.decorators.csrf import csrf_exempt\n\n@csrf_exempt  # Only use when absolutely necessary!\ndef webhook_view(request):\n    # Webhook from external service\n    pass\n```\n\n## File Upload Security\n\n### File Validation\n\n```python\nimport os\nfrom django.core.exceptions import ValidationError\n\ndef validate_file_extension(value):\n    \"\"\"Validate file extension.\"\"\"\n    ext = os.path.splitext(value.name)[1]\n    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.pdf']\n    if not ext.lower() in valid_extensions:\n        raise ValidationError('Unsupported file extension.')\n\ndef validate_file_size(value):\n    \"\"\"Validate file size (max 5MB).\"\"\"\n    filesize = value.size\n    if filesize > 5 * 1024 * 1024:\n        raise ValidationError('File too large. Max size is 5MB.')\n\n# models.py\nclass Document(models.Model):\n    file = models.FileField(\n        upload_to='documents\u002F',\n        validators=[validate_file_extension, validate_file_size]\n    )\n```\n\n### Secure File Storage\n\n```python\n# settings.py\nMEDIA_ROOT = '\u002Fvar\u002Fwww\u002Fmedia\u002F'\nMEDIA_URL = '\u002Fmedia\u002F'\n\n# Use a separate domain for media in production\nMEDIA_DOMAIN = 'https:\u002F\u002Fmedia.example.com'\n\n# Don't serve user uploads directly\n# Use whitenoise or a CDN for static files\n# Use a separate server or S3 for media files\n```\n\n## API Security\n\n### Rate Limiting\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_THROTTLE_CLASSES': [\n        'rest_framework.throttling.AnonRateThrottle',\n        'rest_framework.throttling.UserRateThrottle'\n    ],\n    'DEFAULT_THROTTLE_RATES': {\n        'anon': '100\u002Fday',\n        'user': '1000\u002Fday',\n        'upload': '10\u002Fhour',\n    }\n}\n\n# Custom throttle\nfrom rest_framework.throttling import UserRateThrottle\n\nclass BurstRateThrottle(UserRateThrottle):\n    scope = 'burst'\n    rate = '60\u002Fmin'\n\nclass SustainedRateThrottle(UserRateThrottle):\n    scope = 'sustained'\n    rate = '1000\u002Fday'\n```\n\n### Authentication for APIs\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': [\n        'rest_framework.authentication.TokenAuthentication',\n        'rest_framework.authentication.SessionAuthentication',\n        'rest_framework_simplejwt.authentication.JWTAuthentication',\n    ],\n    'DEFAULT_PERMISSION_CLASSES': [\n        'rest_framework.permissions.IsAuthenticated',\n    ],\n}\n\n# views.py\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\n\n@api_view(['GET', 'POST'])\n@permission_classes([IsAuthenticated])\ndef protected_view(request):\n    return Response({'message': 'You are authenticated'})\n```\n\n## Security Headers\n\n### Content Security Policy\n\n```python\n# settings.py\nCSP_DEFAULT_SRC = \"'self'\"\nCSP_SCRIPT_SRC = \"'self' https:\u002F\u002Fcdn.example.com\"\nCSP_STYLE_SRC = \"'self' 'unsafe-inline'\"\nCSP_IMG_SRC = \"'self' data: https:\"\nCSP_CONNECT_SRC = \"'self' https:\u002F\u002Fapi.example.com\"\n\n# Middleware\nclass CSPMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['Content-Security-Policy'] = (\n            f\"default-src {CSP_DEFAULT_SRC}; \"\n            f\"script-src {CSP_SCRIPT_SRC}; \"\n            f\"style-src {CSP_STYLE_SRC}; \"\n            f\"img-src {CSP_IMG_SRC}; \"\n            f\"connect-src {CSP_CONNECT_SRC}\"\n        )\n        return response\n```\n\n## Environment Variables\n\n### Managing Secrets\n\n```python\n# Use python-decouple or django-environ\nimport environ\n\nenv = environ.Env(\n    # set casting, default value\n    DEBUG=(bool, False)\n)\n\n# reading .env file\nenviron.Env.read_env()\n\nSECRET_KEY = env('DJANGO_SECRET_KEY')\nDATABASE_URL = env('DATABASE_URL')\nALLOWED_HOSTS = env.list('ALLOWED_HOSTS')\n\n# .env file (never commit this)\nDEBUG=False\nSECRET_KEY=your-secret-key-here\nDATABASE_URL=postgresql:\u002F\u002Fuser:password@localhost:5432\u002Fdbname\nALLOWED_HOSTS=example.com,www.example.com\n```\n\n## Logging Security Events\n\n```python\n# settings.py\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'handlers': {\n        'file': {\n            'level': 'WARNING',\n            'class': 'logging.FileHandler',\n            'filename': '\u002Fvar\u002Flog\u002Fdjango\u002Fsecurity.log',\n        },\n        'console': {\n            'level': 'INFO',\n            'class': 'logging.StreamHandler',\n        },\n    },\n    'loggers': {\n        'django.security': {\n            'handlers': ['file', 'console'],\n            'level': 'WARNING',\n            'propagate': True,\n        },\n        'django.request': {\n            'handlers': ['file'],\n            'level': 'ERROR',\n            'propagate': False,\n        },\n    },\n}\n```\n\n## Quick Security Checklist\n\n| Check | Description |\n|-------|-------------|\n| `DEBUG = False` | Never run with DEBUG in production |\n| HTTPS only | Force SSL, secure cookies |\n| Strong secrets | Use environment variables for SECRET_KEY |\n| Password validation | Enable all password validators |\n| CSRF protection | Enabled by default, don't disable |\n| XSS prevention | Django auto-escapes, don't use `&#124;safe` with user input |\n| SQL injection | Use ORM, never concatenate strings in queries |\n| File uploads | Validate file type and size |\n| Rate limiting | Throttle API endpoints |\n| Security headers | CSP, X-Frame-Options, HSTS |\n| Logging | Log security events |\n| Updates | Keep Django and dependencies updated |\n\nRemember: Security is a process, not a product. Regularly review and update your security practices.\n",{"name":5,"origin":44,"description":7},"ECC","main","a298c929b6cbd662e1fce54302ce520d5ceea1a5",".agents\u002Flibrary\u002Fskills\u002Fdjango-security","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain","https:\u002F\u002Fgithub.com\u002FPrekzursil","2026-11-02 14:30:57",{"source":8,"skillName":5,"commands":52,"prompt":62,"zipAvailable":63},[53,56,59],{"tool":54,"command":55},"npx","npx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-security",{"tool":57,"command":58},"bunx","bunx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-security",{"tool":60,"command":61},"pnpm","pnpm dlx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-security","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fdjango-security\u002FSKILL.md",true,[65,71,75,81,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,193,197,201,205,209,213,217,221,225,229,233,237,241,245,249,253,257,261,265,269,273,277,281,285,289,293,297,301,307,311,315,319,323,327,331,335,339,343,347,351],{"path":66,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":69,"sourceHtmlUrl":70},"azure-pipelines-template.yaml","REFERENCE","参考文档",5365,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fazure-pipelines-template.yaml",{"path":72,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":73,"sourceHtmlUrl":74},"checklist.md",8737,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fchecklist.md",{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"customize.toml","OTHER","其他",1550,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fcustomize.toml",{"path":82,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":83,"sourceHtmlUrl":84},"github-actions-template.yaml",10783,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fgithub-actions-template.yaml",{"path":86,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":87,"sourceHtmlUrl":88},"gitlab-ci-template.yaml",4680,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fgitlab-ci-template.yaml",{"path":90,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":91,"sourceHtmlUrl":92},"harness-pipeline-template.yaml",6473,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fharness-pipeline-template.yaml",{"path":94,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":95,"sourceHtmlUrl":96},"instructions.md",1111,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Finstructions.md",{"path":98,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":99,"sourceHtmlUrl":100},"jenkins-pipeline-template.groovy",5099,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fjenkins-pipeline-template.groovy",{"path":102,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":103,"sourceHtmlUrl":104},"resources\u002Fknowledge\u002Fadr-quality-readiness-checklist.md",25356,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fadr-quality-readiness-checklist.md",{"path":106,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":107,"sourceHtmlUrl":108},"resources\u002Fknowledge\u002Fapi-request.md",17129,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fapi-request.md",{"path":110,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":111,"sourceHtmlUrl":112},"resources\u002Fknowledge\u002Fapi-testing-patterns.md",26976,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fapi-testing-patterns.md",{"path":114,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":115,"sourceHtmlUrl":116},"resources\u002Fknowledge\u002Fauth-session.md",16215,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fauth-session.md",{"path":118,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":119,"sourceHtmlUrl":120},"resources\u002Fknowledge\u002Fburn-in.md",6503,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fburn-in.md",{"path":122,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":123,"sourceHtmlUrl":124},"resources\u002Fknowledge\u002Fci-burn-in.md",22486,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fci-burn-in.md",{"path":126,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":127,"sourceHtmlUrl":128},"resources\u002Fknowledge\u002Fcomponent-tdd.md",16149,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fcomponent-tdd.md",{"path":130,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":131,"sourceHtmlUrl":132},"resources\u002Fknowledge\u002Fcontract-testing.md",38991,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fcontract-testing.md",{"path":134,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":135,"sourceHtmlUrl":136},"resources\u002Fknowledge\u002Fdata-factories.md",15331,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fdata-factories.md",{"path":138,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":139,"sourceHtmlUrl":140},"resources\u002Fknowledge\u002Femail-auth.md",24553,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Femail-auth.md",{"path":142,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":143,"sourceHtmlUrl":144},"resources\u002Fknowledge\u002Ferror-handling.md",22959,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ferror-handling.md",{"path":146,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":147,"sourceHtmlUrl":148},"resources\u002Fknowledge\u002Ffeature-flags.md",23214,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ffeature-flags.md",{"path":150,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":151,"sourceHtmlUrl":152},"resources\u002Fknowledge\u002Ffile-utils.md",13745,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ffile-utils.md",{"path":154,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":155,"sourceHtmlUrl":156},"resources\u002Fknowledge\u002Ffixture-architecture.md",12414,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ffixture-architecture.md",{"path":158,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":159,"sourceHtmlUrl":160},"resources\u002Fknowledge\u002Ffixtures-composition.md",11249,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ffixtures-composition.md",{"path":162,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":163,"sourceHtmlUrl":164},"resources\u002Fknowledge\u002Fintercept-network-call.md",13489,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fintercept-network-call.md",{"path":166,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":167,"sourceHtmlUrl":168},"resources\u002Fknowledge\u002Flog.md",11281,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Flog.md",{"path":170,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":171,"sourceHtmlUrl":172},"resources\u002Fknowledge\u002Fnetwork-error-monitor.md",12277,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fnetwork-error-monitor.md",{"path":174,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":175,"sourceHtmlUrl":176},"resources\u002Fknowledge\u002Fnetwork-first.md",16327,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fnetwork-first.md",{"path":178,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":179,"sourceHtmlUrl":180},"resources\u002Fknowledge\u002Fnetwork-recorder.md",15499,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fnetwork-recorder.md",{"path":182,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":183,"sourceHtmlUrl":184},"resources\u002Fknowledge\u002Fnfr-criteria.md",26670,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fnfr-criteria.md",{"path":186,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":187,"sourceHtmlUrl":188},"resources\u002Fknowledge\u002Foverview.md",9663,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Foverview.md",{"path":190,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":191,"sourceHtmlUrl":192},"resources\u002Fknowledge\u002Fpact-broker-webhooks.md",13376,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpact-broker-webhooks.md",{"path":194,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":195,"sourceHtmlUrl":196},"resources\u002Fknowledge\u002Fpact-consumer-di.md",12005,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpact-consumer-di.md",{"path":198,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":199,"sourceHtmlUrl":200},"resources\u002Fknowledge\u002Fpact-consumer-framework-setup.md",35846,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpact-consumer-framework-setup.md",{"path":202,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":203,"sourceHtmlUrl":204},"resources\u002Fknowledge\u002Fpact-mcp.md",8977,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpact-mcp.md",{"path":206,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":207,"sourceHtmlUrl":208},"resources\u002Fknowledge\u002Fpactjs-utils-consumer-helpers.md",16029,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpactjs-utils-consumer-helpers.md",{"path":210,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":211,"sourceHtmlUrl":212},"resources\u002Fknowledge\u002Fpactjs-utils-overview.md",10481,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpactjs-utils-overview.md",{"path":214,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":215,"sourceHtmlUrl":216},"resources\u002Fknowledge\u002Fpactjs-utils-provider-verifier.md",18180,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpactjs-utils-provider-verifier.md",{"path":218,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":219,"sourceHtmlUrl":220},"resources\u002Fknowledge\u002Fpactjs-utils-request-filter.md",7275,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fpactjs-utils-request-filter.md",{"path":222,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":223,"sourceHtmlUrl":224},"resources\u002Fknowledge\u002Fplaywright-cli.md",14993,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fplaywright-cli.md",{"path":226,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":227,"sourceHtmlUrl":228},"resources\u002Fknowledge\u002Fplaywright-config.md",21457,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fplaywright-config.md",{"path":230,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":231,"sourceHtmlUrl":232},"resources\u002Fknowledge\u002Fprobability-impact.md",19200,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fprobability-impact.md",{"path":234,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":235,"sourceHtmlUrl":236},"resources\u002Fknowledge\u002Frecurse.md",12936,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Frecurse.md",{"path":238,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":239,"sourceHtmlUrl":240},"resources\u002Fknowledge\u002Frisk-governance.md",20965,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Frisk-governance.md",{"path":242,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":243,"sourceHtmlUrl":244},"resources\u002Fknowledge\u002Fselective-testing.md",21846,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fselective-testing.md",{"path":246,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":247,"sourceHtmlUrl":248},"resources\u002Fknowledge\u002Fselector-resilience.md",19784,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fselector-resilience.md",{"path":250,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":251,"sourceHtmlUrl":252},"resources\u002Fknowledge\u002Ftest-healing-patterns.md",21388,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ftest-healing-patterns.md",{"path":254,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":255,"sourceHtmlUrl":256},"resources\u002Fknowledge\u002Ftest-levels-framework.md",14756,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ftest-levels-framework.md",{"path":258,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":259,"sourceHtmlUrl":260},"resources\u002Fknowledge\u002Ftest-priorities-matrix.md",11454,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ftest-priorities-matrix.md",{"path":262,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":263,"sourceHtmlUrl":264},"resources\u002Fknowledge\u002Ftest-quality.md",24580,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ftest-quality.md",{"path":266,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":267,"sourceHtmlUrl":268},"resources\u002Fknowledge\u002Ftiming-debugging.md",14021,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Ftiming-debugging.md",{"path":270,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":271,"sourceHtmlUrl":272},"resources\u002Fknowledge\u002Fvisual-debugging.md",17480,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fvisual-debugging.md",{"path":274,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":275,"sourceHtmlUrl":276},"resources\u002Fknowledge\u002Fwebhook-module-setup.md",5834,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fwebhook-module-setup.md",{"path":278,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":279,"sourceHtmlUrl":280},"resources\u002Fknowledge\u002Fwebhook-providers.md",6440,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fwebhook-providers.md",{"path":282,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":283,"sourceHtmlUrl":284},"resources\u002Fknowledge\u002Fwebhook-risk-guidance.md",6474,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fwebhook-risk-guidance.md",{"path":286,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":287,"sourceHtmlUrl":288},"resources\u002Fknowledge\u002Fwebhook-template-matchers.md",6011,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fwebhook-template-matchers.md",{"path":290,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":291,"sourceHtmlUrl":292},"resources\u002Fknowledge\u002Fwebhook-testing-fundamentals.md",3185,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fwebhook-testing-fundamentals.md",{"path":294,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":295,"sourceHtmlUrl":296},"resources\u002Fknowledge\u002Fwebhook-timeout-error.md",5726,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fwebhook-timeout-error.md",{"path":298,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":299,"sourceHtmlUrl":300},"resources\u002Fknowledge\u002Fwebhook-waiting-querying.md",7074,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Fknowledge\u002Fwebhook-waiting-querying.md",{"path":302,"resourceType":303,"resourceTypeDesc":304,"sizeBytes":305,"sourceHtmlUrl":306},"resources\u002Ftea-index.csv","ASSET","资产文件",11002,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fresources\u002Ftea-index.csv",{"path":308,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":309,"sourceHtmlUrl":310},"steps-c\u002Fstep-01-preflight.md",5559,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-c\u002Fstep-01-preflight.md",{"path":312,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":313,"sourceHtmlUrl":314},"steps-c\u002Fstep-01b-resume.md",3747,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-c\u002Fstep-01b-resume.md",{"path":316,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":317,"sourceHtmlUrl":318},"steps-c\u002Fstep-02-generate-pipeline.md",14647,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-c\u002Fstep-02-generate-pipeline.md",{"path":320,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":321,"sourceHtmlUrl":322},"steps-c\u002Fstep-03-configure-quality-gates.md",5532,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-c\u002Fstep-03-configure-quality-gates.md",{"path":324,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":325,"sourceHtmlUrl":326},"steps-c\u002Fstep-04-validate-and-summary.md",2492,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-c\u002Fstep-04-validate-and-summary.md",{"path":328,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":329,"sourceHtmlUrl":330},"steps-e\u002Fstep-01-assess.md",1253,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-e\u002Fstep-01-assess.md",{"path":332,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":333,"sourceHtmlUrl":334},"steps-e\u002Fstep-02-apply-edit.md",1475,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-e\u002Fstep-02-apply-edit.md",{"path":336,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":337,"sourceHtmlUrl":338},"steps-v\u002Fstep-01-validate.md",2833,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fsteps-v\u002Fstep-01-validate.md",{"path":340,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":341,"sourceHtmlUrl":342},"validation-report-20260127-095021.md",2018,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fvalidation-report-20260127-095021.md",{"path":344,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":345,"sourceHtmlUrl":346},"validation-report-20260127-102401.md",3634,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fvalidation-report-20260127-102401.md",{"path":348,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":349,"sourceHtmlUrl":350},"workflow-plan.md",448,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fworkflow-plan.md",{"path":352,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":353,"sourceHtmlUrl":354},"workflow.yaml",1884,"https:\u002F\u002Fgithub.com\u002Ftonygomes-wq\u002Fevo\u002Fblob\u002Fmain\u002F.kiro\u002Fskills\u002Fbmad-testarch-ci\u002Fworkflow.yaml",[356,377,406,433,447,463],{"skillNo":357,"name":358,"nameZh":6,"description":359,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":360,"categories":361,"keywords":362,"publishedAt":39},"01M6DF7D7478R55P46REYH4QAC","clarify-requirements","Resolve genuine pre-execution ambiguity by scanning repo context, generating 1-6 grounded options, and asking 1-3 focused questions via AskUserQuestion. NOT for mid-task use (injection risk); NOT when the goal is already unambiguous; use to disambiguate vague prompts before any file edits.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fworkspace-hooks\u002Fskills\u002Fclarify-requirements\u002FSKILL.md",[],[363,364,365,366,367,368,369,370,371,372,373,374,34,375,376],"clarify requirements","clarify","requirements","risk","options","task","prompts","goal","scanning","use","context","repo","execution","file",{"skillNo":378,"name":379,"nameZh":6,"description":380,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":381,"categories":382,"keywords":386,"publishedAt":39},"01M6DF79CA4BHJS66J8EZDBPWJ","openmm-md","Run FREE, open-source, Windows-native GPU molecular dynamics via the openmm-md MCP (OpenMM + CUDA on the local NVIDIA GPU). Use for protein \u002F protein-ligand MD when you want a free stack or are on Windows without a Schrodinger license. Covers the full workflow (prepare, solvate, minimize, equilibrate, production, analyze, mmgbsa) AND an honest decision guide vs Schrodinger Desmond, including how to run Desmond legitimately on Linux or a cloud GPU with a real license. This is a deliberately LESSER free alternative and does NOT replace the schrodinger MCP tools. Do NOT use it to pick a free tool when a validated FEP+, WaterMap, IFD-MD, or Prime MM-GBSA result is actually required.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fmcp\u002Fopenmm-md-mcp\u002Fskill\u002Fopenmm-md\u002FSKILL.md",[383],{"categoryNo":384,"categoryName":385,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[387,388,389,390,391,392,393,394,395,396,397,398,399,400,372,401,402,403,404,405],"openmm md","how","decision","pick","linux","analyze","tool","stack","open","NVIDIA","gpu","license","workflow","windows","free","molecular dynamics","local","do","MCP",{"skillNo":407,"name":408,"nameZh":6,"description":409,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":410,"categories":411,"keywords":418,"publishedAt":39},"01M6DF76C1MG85VEWP8VZCBNMN","visual-review","Take screenshots of web pages and UI using Playwright for visual review and iteration","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fvisual-review\u002FSKILL.md",[412,415],{"categoryNo":413,"categoryName":414,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":416,"categoryName":417,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",[419,420,421,422,423,424,425,426,427,428,388,429,430,431,432],"review","visual","visual review","pages","web","false","iteration","take","check","slides","ui","screenshot","playwright","screenshots",{"skillNo":434,"name":435,"nameZh":6,"description":436,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":437,"categories":438,"keywords":439,"publishedAt":39},"01M6DF73AQVCBZKEN0YXEX9FXP","status","Diagnostic status report — shows metaswarm installation state, project setup, and potential issues","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstatus\u002FSKILL.md",[],[435,440,441,442,443,444,445,446],"setup","report","project","installation","project setup","issues","state",{"skillNo":448,"name":449,"nameZh":6,"description":450,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":451,"categories":452,"keywords":454,"publishedAt":39},"01M6DF6X6C2XB0P6GX76P7TTYV","start","Use when starting work on any task, when the user mentions metaswarm, or when the user wants to begin tracked development work","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstart\u002FSKILL.md",[453],{"categoryNo":384,"categoryName":385,"taxonomyType":21,"taxonomyTypeDesc":22},[449,455,368,456,457,458,372,459,460,461,462],"start issue","issue","ready","work on issue","user","work","work on","development",{"skillNo":464,"name":440,"nameZh":6,"description":465,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":466,"categories":467,"keywords":468,"publishedAt":39},"01M6DF6QMJ9AJKFKHHKRT005PQ","Interactive project setup — detects your project, configures metaswarm, writes project-local files","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fsetup\u002FSKILL.md",[],[440,442,403,469,444,470],"files","interactive"]