commit 19fda5657048269cc7f05e431a3465ce6d37aa49 Author: Zhongwei Li Date: Sat Nov 29 18:52:38 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..5ab7fc5 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "api-schema-validator", + "description": "Validate API schemas with JSON Schema, Joi, Yup, or Zod", + "version": "1.0.0", + "author": { + "name": "Jeremy Longshore", + "email": "[email protected]" + }, + "skills": [ + "./skills" + ], + "commands": [ + "./commands" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..41ade45 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# api-schema-validator + +Validate API schemas with JSON Schema, Joi, Yup, or Zod diff --git a/commands/validate-schemas.md b/commands/validate-schemas.md new file mode 100644 index 0000000..9634396 --- /dev/null +++ b/commands/validate-schemas.md @@ -0,0 +1,598 @@ +--- +description: Validate API schemas +shortcut: schema +--- + +# Validate API Schemas + +Implement comprehensive schema validation using modern validation libraries like JSON Schema, Joi, Yup, or Zod to ensure type safety, data integrity, and contract compliance across your API. + +## When to Use This Command + +Use `/validate-schemas` when you need to: +- Enforce strict data types and formats in API requests and responses +- Create reusable validation schemas across multiple endpoints +- Generate TypeScript types from validation schemas +- Implement complex conditional validation logic +- Provide detailed validation error messages to clients +- Ensure data consistency before database operations + +DON'T use this when: +- Working with unstructured or highly dynamic data (use runtime checks instead) +- Building quick prototypes without formal contracts (premature optimization) +- Validation logic is trivial (simple type checks may suffice) + +## Design Decisions + +This command implements **Zod** as the primary approach because: +- TypeScript-first with automatic type inference +- Composable schemas with chaining syntax +- Zero runtime dependencies +- Excellent error messages out of the box +- Schema transformation and parsing capabilities +- Works seamlessly with modern frameworks + +**Alternative considered: Joi** +- More mature with extensive ecosystem +- Better for JavaScript-only projects +- More verbose API +- Recommended for legacy Node.js applications + +**Alternative considered: JSON Schema** +- Language-agnostic standard +- Better for cross-platform validation +- More complex to write and maintain +- Recommended when sharing schemas across different languages + +## Prerequisites + +Before running this command: +1. Choose validation library based on your tech stack +2. Define validation requirements for each endpoint +3. Plan error response format +4. Consider performance impact for complex schemas +5. Determine validation strategy (fail-fast vs. collect-all-errors) + +## Implementation Process + +### Step 1: Define Base Schemas +Create reusable schema primitives for common data types and patterns. + +### Step 2: Compose Endpoint Schemas +Build complex schemas by composing base schemas with business rules. + +### Step 3: Integrate with Middleware +Set up validation middleware to automatically validate requests and responses. + +### Step 4: Generate Types +Generate TypeScript types from schemas for compile-time safety. + +### Step 5: Implement Error Handling +Create consistent error formatting and reporting mechanisms. + +## Output Format + +The command generates: +- `schemas/` - Schema definitions organized by domain +- `validators/` - Compiled validation functions +- `types/` - Generated TypeScript types from schemas +- `middleware/validation.ts` - Request/response validation middleware +- `tests/schema.test.ts` - Schema validation test suites +- `docs/validation-rules.md` - Documentation of all validation rules + +## Code Examples + +### Example 1: Zod Schema Validation (TypeScript) + +```typescript +// schemas/user.schema.ts +import { z } from 'zod'; + +// Base schemas for reuse +const emailSchema = z.string().email().toLowerCase(); +const passwordSchema = z.string() + .min(8, 'Password must be at least 8 characters') + .regex(/[A-Z]/, 'Password must contain uppercase letter') + .regex(/[a-z]/, 'Password must contain lowercase letter') + .regex(/[0-9]/, 'Password must contain number') + .regex(/[^A-Za-z0-9]/, 'Password must contain special character'); + +const phoneSchema = z.string().regex( + /^\+?[1-9]\d{1,14}$/, + 'Invalid phone number format (E.164)' +); + +const addressSchema = z.object({ + street: z.string().min(1).max(100), + city: z.string().min(1).max(50), + state: z.string().length(2).toUpperCase(), + zipCode: z.string().regex(/^\d{5}(-\d{4})?$/), + country: z.string().length(2).toUpperCase().default('US') +}); + +// User schemas +export const createUserSchema = z.object({ + body: z.object({ + email: emailSchema, + password: passwordSchema, + firstName: z.string().min(1).max(50), + lastName: z.string().min(1).max(50), + dateOfBirth: z.string().datetime().refine( + (date) => { + const age = new Date().getFullYear() - new Date(date).getFullYear(); + return age >= 18; + }, + { message: 'Must be at least 18 years old' } + ), + phone: phoneSchema.optional(), + address: addressSchema.optional(), + preferences: z.object({ + newsletter: z.boolean().default(false), + notifications: z.enum(['email', 'sms', 'push', 'none']).default('email'), + theme: z.enum(['light', 'dark', 'auto']).default('auto') + }).default({}), + metadata: z.record(z.string(), z.any()).optional() + }) +}); + +export const updateUserSchema = z.object({ + params: z.object({ + id: z.string().uuid() + }), + body: createUserSchema.shape.body.partial().extend({ + // Can't update email without verification + email: z.never().optional() + }) +}); + +export const getUserSchema = z.object({ + params: z.object({ + id: z.string().uuid() + }) +}); + +export const listUsersSchema = z.object({ + query: z.object({ + page: z.coerce.number().int().positive().default(1), + limit: z.coerce.number().int().min(1).max(100).default(20), + sort: z.enum(['createdAt', 'email', 'name']).default('createdAt'), + order: z.enum(['asc', 'desc']).default('desc'), + filter: z.object({ + email: z.string().optional(), + status: z.enum(['active', 'inactive', 'suspended']).optional(), + createdAfter: z.string().datetime().optional(), + createdBefore: z.string().datetime().optional() + }).optional() + }) +}); + +// Type inference +export type CreateUserInput = z.infer; +export type UpdateUserInput = z.infer; +export type GetUserInput = z.infer; +export type ListUsersInput = z.infer; + +// Validation middleware +import { Request, Response, NextFunction } from 'express'; + +export function validate(schema: z.ZodSchema) { + return async (req: Request, res: Response, next: NextFunction) => { + try { + const validated = await schema.parseAsync({ + body: req.body, + query: req.query, + params: req.params + }); + + // Replace request properties with validated/transformed data + req.body = validated.body || req.body; + req.query = validated.query || req.query; + req.params = validated.params || req.params; + + next(); + } catch (error) { + if (error instanceof z.ZodError) { + return res.status(400).json({ + error: 'Validation failed', + details: error.errors.map(err => ({ + path: err.path.join('.'), + message: err.message, + code: err.code + })) + }); + } + next(error); + } + }; +} + +// Usage in routes +import express from 'express'; + +const router = express.Router(); + +router.post('/users', + validate(createUserSchema), + async (req, res) => { + // req.body is now typed and validated + const user = await createUser(req.body); + res.json(user); + } +); + +router.put('/users/:id', + validate(updateUserSchema), + async (req, res) => { + const user = await updateUser(req.params.id, req.body); + res.json(user); + } +); +``` + +### Example 2: Joi Schema Validation (JavaScript) + +```javascript +// schemas/product.schema.js +const Joi = require('joi'); + +// Custom validators +const customValidators = { + sku: Joi.string().pattern(/^[A-Z]{3}-\d{6}$/), + price: Joi.number().precision(2).positive().max(999999.99), + url: Joi.string().uri({ scheme: ['http', 'https'] }) +}; + +// Product schemas +const productSchema = { + create: Joi.object({ + sku: customValidators.sku.required(), + name: Joi.string().min(3).max(200).required(), + description: Joi.string().max(2000).required(), + price: customValidators.price.required(), + compareAtPrice: customValidators.price + .greater(Joi.ref('price')) + .optional(), + category: Joi.string().valid( + 'electronics', + 'clothing', + 'food', + 'books', + 'other' + ).required(), + tags: Joi.array() + .items(Joi.string().min(2).max(20)) + .max(10) + .unique(), + inventory: Joi.object({ + quantity: Joi.number().integer().min(0).required(), + trackInventory: Joi.boolean().default(true), + allowBackorder: Joi.boolean().default(false), + lowStockThreshold: Joi.number().integer().min(0).default(10) + }).required(), + images: Joi.array() + .items(Joi.object({ + url: customValidators.url.required(), + alt: Joi.string().max(200), + isPrimary: Joi.boolean().default(false) + })) + .min(1) + .max(10) + .unique('url') + .required(), + shipping: Joi.object({ + weight: Joi.number().positive().required(), + dimensions: Joi.object({ + length: Joi.number().positive().required(), + width: Joi.number().positive().required(), + height: Joi.number().positive().required() + }).required(), + requiresShipping: Joi.boolean().default(true), + shippingClass: Joi.string().valid('standard', 'fragile', 'oversized') + }).when('category', { + is: 'electronics', + then: Joi.required(), + otherwise: Joi.optional() + }), + variants: Joi.array() + .items(Joi.object({ + name: Joi.string().required(), + options: Joi.array() + .items(Joi.string()) + .min(1) + .required() + })) + .optional(), + metadata: Joi.object().pattern( + Joi.string(), + Joi.alternatives().try( + Joi.string(), + Joi.number(), + Joi.boolean() + ) + ).optional() + }).custom((value, helpers) => { + // Custom validation: ensure at least one primary image + const primaryImages = value.images.filter(img => img.isPrimary); + if (primaryImages.length !== 1) { + return helpers.error('any.invalid', { + message: 'Exactly one image must be marked as primary' + }); + } + return value; + }), + + update: Joi.object({ + name: Joi.string().min(3).max(200), + description: Joi.string().max(2000), + price: customValidators.price, + // ... partial schema + }).min(1), // At least one field required + + list: Joi.object({ + page: Joi.number().integer().positive().default(1), + limit: Joi.number().integer().min(1).max(100).default(20), + category: Joi.string(), + minPrice: Joi.number().positive(), + maxPrice: Joi.number().positive().greater(Joi.ref('minPrice')), + search: Joi.string().max(100), + inStock: Joi.boolean() + }) +}; + +// Validation middleware +function validateRequest(schemaName) { + return async (req, res, next) => { + const schema = productSchema[schemaName]; + if (!schema) { + return next(new Error(`Schema ${schemaName} not found`)); + } + + const dataToValidate = { + ...req.body, + ...req.query, + ...req.params + }; + + try { + const validated = await schema.validateAsync(dataToValidate, { + abortEarly: false, // Return all errors + stripUnknown: true, // Remove unknown keys + convert: true // Type coercion + }); + + // Merge validated data back + Object.keys(validated).forEach(key => { + if (req.body.hasOwnProperty(key)) req.body[key] = validated[key]; + if (req.query.hasOwnProperty(key)) req.query[key] = validated[key]; + if (req.params.hasOwnProperty(key)) req.params[key] = validated[key]; + }); + + next(); + } catch (error) { + if (error.isJoi) { + return res.status(400).json({ + error: 'Validation failed', + details: error.details.map(detail => ({ + field: detail.path.join('.'), + message: detail.message, + type: detail.type + })) + }); + } + next(error); + } + }; +} + +module.exports = { + productSchema, + validateRequest +}; +``` + +### Example 3: Pydantic Schema Validation (Python) + +```python +# schemas/order_schema.py +from pydantic import BaseModel, Field, validator, root_validator +from typing import List, Optional, Dict, Any +from datetime import datetime, date +from decimal import Decimal +from enum import Enum +import re + +class OrderStatus(str, Enum): + PENDING = "pending" + PROCESSING = "processing" + SHIPPED = "shipped" + DELIVERED = "delivered" + CANCELLED = "cancelled" + +class PaymentMethod(str, Enum): + CREDIT_CARD = "credit_card" + DEBIT_CARD = "debit_card" + PAYPAL = "paypal" + STRIPE = "stripe" + BANK_TRANSFER = "bank_transfer" + +class Address(BaseModel): + street: str = Field(..., min_length=1, max_length=200) + city: str = Field(..., min_length=1, max_length=100) + state: str = Field(..., regex="^[A-Z]{2}$") + zip_code: str = Field(..., regex=r"^\d{5}(-\d{4})?$") + country: str = Field(default="US", regex="^[A-Z]{2}$") + + @validator('state', 'country') + def uppercase_codes(cls, v): + return v.upper() + +class OrderItem(BaseModel): + product_id: str = Field(..., regex="^[A-Z]{3}-\d{6}$") + quantity: int = Field(..., gt=0, le=100) + unit_price: Decimal = Field(..., decimal_places=2, ge=0) + discount: Optional[Decimal] = Field(None, decimal_places=2, ge=0, le=1) + + @validator('discount') + def validate_discount(cls, v, values): + if v and v >= 1: + raise ValueError('Discount must be less than 100%') + return v + + @property + def subtotal(self) -> Decimal: + discount_amount = self.discount or Decimal('0') + return self.quantity * self.unit_price * (1 - discount_amount) + +class CreateOrderSchema(BaseModel): + customer_email: str = Field(..., regex=r"^[\w\.-]+@[\w\.-]+\.\w+$") + items: List[OrderItem] = Field(..., min_items=1, max_items=50) + shipping_address: Address + billing_address: Optional[Address] = None + payment_method: PaymentMethod + notes: Optional[str] = Field(None, max_length=500) + coupon_code: Optional[str] = Field(None, regex="^[A-Z0-9]{4,12}$") + + @validator('customer_email') + def validate_email(cls, v): + # Additional email validation + if not re.match(r"^[\w\.-]+@[\w\.-]+\.\w+$", v.lower()): + raise ValueError('Invalid email format') + return v.lower() + + @validator('billing_address', always=True) + def set_billing_address(cls, v, values): + # Use shipping address if billing not provided + return v or values.get('shipping_address') + + @root_validator + def validate_order(cls, values): + items = values.get('items', []) + + # Check for duplicate products + product_ids = [item.product_id for item in items] + if len(product_ids) != len(set(product_ids)): + raise ValueError('Duplicate products in order') + + # Calculate total + total = sum(item.subtotal for item in items) + if total <= 0: + raise ValueError('Order total must be positive') + + # Validate coupon if provided + coupon = values.get('coupon_code') + if coupon and not cls.validate_coupon(coupon): + raise ValueError('Invalid coupon code') + + return values + + @staticmethod + def validate_coupon(code: str) -> bool: + # Implement coupon validation logic + valid_coupons = ['SAVE10', 'FREESHIP', 'WELCOME20'] + return code in valid_coupons + +class UpdateOrderSchema(BaseModel): + status: Optional[OrderStatus] = None + shipping_address: Optional[Address] = None + notes: Optional[str] = Field(None, max_length=500) + tracking_number: Optional[str] = Field(None, regex=r"^[A-Z0-9]{10,30}$") + + class Config: + use_enum_values = True + +# FastAPI integration +from fastapi import FastAPI, HTTPException, Depends +from fastapi.encoders import jsonable_encoder + +app = FastAPI() + +@app.post("/orders", response_model=Dict[str, Any]) +async def create_order(order: CreateOrderSchema): + # Validation happens automatically + order_dict = jsonable_encoder(order) + # Process order + return {"id": "ORD-123456", **order_dict} + +@app.patch("/orders/{order_id}") +async def update_order( + order_id: str, + updates: UpdateOrderSchema +): + # Only provided fields will be updated + update_dict = updates.dict(exclude_unset=True) + # Update order + return {"id": order_id, **update_dict} + +# Custom validation endpoint +@app.post("/validate/order") +async def validate_order(order: CreateOrderSchema): + # Just validate without processing + return {"valid": True, "data": order.dict()} +``` + +## Error Handling + +| Error | Cause | Solution | +|-------|-------|----------| +| "Invalid type" | Wrong data type provided | Check schema definition and input data | +| "Required field missing" | Mandatory field not provided | Ensure all required fields are present | +| "Validation failed" | Business rule violation | Review custom validators and constraints | +| "Schema not found" | Referenced schema doesn't exist | Verify schema imports and definitions | +| "Circular dependency" | Schema references itself | Refactor to break circular references | + +## Configuration Options + +**Validation Strategies** +- `fail-fast`: Stop at first error (faster) +- `collect-all`: Gather all errors (better UX) +- `partial`: Allow partial validation for updates + +**Type Coercion** +- `strict`: No type conversion +- `loose`: Attempt type conversion +- `smart`: Context-aware conversion + +## Best Practices + +DO: +- Create reusable base schemas for common patterns +- Use descriptive error messages for custom validators +- Generate TypeScript types from schemas +- Version schemas with your API +- Document all validation rules +- Test edge cases and boundary conditions + +DON'T: +- Duplicate validation logic across layers +- Use overly complex nested schemas +- Ignore performance impact of complex validations +- Mix validation with business logic +- Trust client-side validation alone + +## Performance Considerations + +- Compile schemas once at startup +- Cache validated results for identical inputs +- Use async validation for external checks +- Limit regex complexity to prevent ReDoS attacks +- Consider schema complexity for large payloads + +## Security Considerations + +- Sanitize error messages to prevent information leakage +- Implement rate limiting on validation endpoints +- Use strict type checking to prevent injection attacks +- Validate file uploads separately with size limits +- Never expose internal schema structure to clients + +## Related Commands + +- `/api-response-validator` - Validate API responses +- `/api-contract-generator` - Generate schemas from code +- `/api-testing-framework` - Test with schema validation +- `/api-documentation-generator` - Document schemas + +## Version History + +- v1.0.0 (2024-10): Initial implementation with Zod, Joi, and Pydantic support +- Planned v1.1.0: Add support for Yup and JSON Schema generation \ No newline at end of file diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..b02c942 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,85 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:jeremylongshore/claude-code-plugins-plus:plugins/api-development/api-schema-validator", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "6fe99a526667bc7dd391d56742a23288b3bd1d53", + "treeHash": "b459f932e847d68e0e05b35c5895225bc94d064291e4b9f5270a8ef65918b307", + "generatedAt": "2025-11-28T10:18:08.393637Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "api-schema-validator", + "description": "Validate API schemas with JSON Schema, Joi, Yup, or Zod", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "964deefdc89c0c6afb1af808195fbe152019a4c1bfffc8f3afc0d73245dcfc44" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "ee709d51ea913c41f0b22736ce467df18dc635d400156c703d512ee4c248c5f1" + }, + { + "path": "commands/validate-schemas.md", + "sha256": "4b90ff709dc69abb52eacb253f61603dfe9d00ab397507a8729f789fde9293be" + }, + { + "path": "skills/skill-adapter/references/examples.md", + "sha256": "922bbc3c4ebf38b76f515b5c1998ebde6bf902233e00e2c5a0e9176f975a7572" + }, + { + "path": "skills/skill-adapter/references/best-practices.md", + "sha256": "c8f32b3566252f50daacd346d7045a1060c718ef5cfb07c55a0f2dec5f1fb39e" + }, + { + "path": "skills/skill-adapter/references/README.md", + "sha256": "792835f31b3849b180d74f135ac6fe79cc3ed93b6c826b2ea62d6d6703724dab" + }, + { + "path": "skills/skill-adapter/scripts/helper-template.sh", + "sha256": "0881d5660a8a7045550d09ae0acc15642c24b70de6f08808120f47f86ccdf077" + }, + { + "path": "skills/skill-adapter/scripts/validation.sh", + "sha256": "92551a29a7f512d2036e4f1fb46c2a3dc6bff0f7dde4a9f699533e446db48502" + }, + { + "path": "skills/skill-adapter/scripts/README.md", + "sha256": "f2f6a48cd8eb28031af2c6040a6bf96d1f8fa3a9780e8f4bf884ea16bfd3b89d" + }, + { + "path": "skills/skill-adapter/assets/test-data.json", + "sha256": "ac17dca3d6e253a5f39f2a2f1b388e5146043756b05d9ce7ac53a0042eee139d" + }, + { + "path": "skills/skill-adapter/assets/README.md", + "sha256": "784881a613b5da6273956467a368958c1c73d156a8122cbe93d85d62a6c83978" + }, + { + "path": "skills/skill-adapter/assets/skill-schema.json", + "sha256": "f5639ba823a24c9ac4fb21444c0717b7aefde1a4993682897f5bf544f863c2cd" + }, + { + "path": "skills/skill-adapter/assets/config-template.json", + "sha256": "0c2ba33d2d3c5ccb266c0848fc43caa68a2aa6a80ff315d4b378352711f83e1c" + } + ], + "dirSha256": "b459f932e847d68e0e05b35c5895225bc94d064291e4b9f5270a8ef65918b307" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/skill-adapter/assets/README.md b/skills/skill-adapter/assets/README.md new file mode 100644 index 0000000..c0252c5 --- /dev/null +++ b/skills/skill-adapter/assets/README.md @@ -0,0 +1,7 @@ +# Assets + +Bundled resources for api-schema-validator skill + +- [ ] example_schemas/: A directory containing example schemas in various formats (JSON Schema, Joi, Yup, Zod). +- [ ] test_data/: A directory containing example data files to validate against the schemas. +- [ ] schema_templates/: Templates for creating new schemas in different formats. diff --git a/skills/skill-adapter/assets/config-template.json b/skills/skill-adapter/assets/config-template.json new file mode 100644 index 0000000..16f1712 --- /dev/null +++ b/skills/skill-adapter/assets/config-template.json @@ -0,0 +1,32 @@ +{ + "skill": { + "name": "skill-name", + "version": "1.0.0", + "enabled": true, + "settings": { + "verbose": false, + "autoActivate": true, + "toolRestrictions": true + } + }, + "triggers": { + "keywords": [ + "example-trigger-1", + "example-trigger-2" + ], + "patterns": [] + }, + "tools": { + "allowed": [ + "Read", + "Grep", + "Bash" + ], + "restricted": [] + }, + "metadata": { + "author": "Plugin Author", + "category": "general", + "tags": [] + } +} diff --git a/skills/skill-adapter/assets/skill-schema.json b/skills/skill-adapter/assets/skill-schema.json new file mode 100644 index 0000000..8dc154c --- /dev/null +++ b/skills/skill-adapter/assets/skill-schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Claude Skill Configuration", + "type": "object", + "required": ["name", "description"], + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "maxLength": 64, + "description": "Skill identifier (lowercase, hyphens only)" + }, + "description": { + "type": "string", + "maxLength": 1024, + "description": "What the skill does and when to use it" + }, + "allowed-tools": { + "type": "string", + "description": "Comma-separated list of allowed tools" + }, + "version": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$", + "description": "Semantic version (x.y.z)" + } + } +} diff --git a/skills/skill-adapter/assets/test-data.json b/skills/skill-adapter/assets/test-data.json new file mode 100644 index 0000000..f0cd871 --- /dev/null +++ b/skills/skill-adapter/assets/test-data.json @@ -0,0 +1,27 @@ +{ + "testCases": [ + { + "name": "Basic activation test", + "input": "trigger phrase example", + "expected": { + "activated": true, + "toolsUsed": ["Read", "Grep"], + "success": true + } + }, + { + "name": "Complex workflow test", + "input": "multi-step trigger example", + "expected": { + "activated": true, + "steps": 3, + "toolsUsed": ["Read", "Write", "Bash"], + "success": true + } + } + ], + "fixtures": { + "sampleInput": "example data", + "expectedOutput": "processed result" + } +} diff --git a/skills/skill-adapter/references/README.md b/skills/skill-adapter/references/README.md new file mode 100644 index 0000000..3f02015 --- /dev/null +++ b/skills/skill-adapter/references/README.md @@ -0,0 +1,9 @@ +# References + +Bundled resources for api-schema-validator skill + +- [ ] json_schema_spec.md: A markdown file containing a summary of the JSON Schema specification. +- [ ] joi_documentation.md: A markdown file containing key excerpts from the Joi documentation. +- [ ] yup_documentation.md: A markdown file containing key excerpts from the Yup documentation. +- [ ] zod_documentation.md: A markdown file containing key excerpts from the Zod documentation. +- [ ] schema_best_practices.md: A guide to writing effective and maintainable schemas. diff --git a/skills/skill-adapter/references/best-practices.md b/skills/skill-adapter/references/best-practices.md new file mode 100644 index 0000000..3505048 --- /dev/null +++ b/skills/skill-adapter/references/best-practices.md @@ -0,0 +1,69 @@ +# Skill Best Practices + +Guidelines for optimal skill usage and development. + +## For Users + +### Activation Best Practices + +1. **Use Clear Trigger Phrases** + - Match phrases from skill description + - Be specific about intent + - Provide necessary context + +2. **Provide Sufficient Context** + - Include relevant file paths + - Specify scope of analysis + - Mention any constraints + +3. **Understand Tool Permissions** + - Check allowed-tools in frontmatter + - Know what the skill can/cannot do + - Request appropriate actions + +### Workflow Optimization + +- Start with simple requests +- Build up to complex workflows +- Verify each step before proceeding +- Use skill consistently for related tasks + +## For Developers + +### Skill Development Guidelines + +1. **Clear Descriptions** + - Include explicit trigger phrases + - Document all capabilities + - Specify limitations + +2. **Proper Tool Permissions** + - Use minimal necessary tools + - Document security implications + - Test with restricted tools + +3. **Comprehensive Documentation** + - Provide usage examples + - Document common pitfalls + - Include troubleshooting guide + +### Maintenance + +- Keep version updated +- Test after tool updates +- Monitor user feedback +- Iterate on descriptions + +## Performance Tips + +- Scope skills to specific domains +- Avoid overlapping trigger phrases +- Keep descriptions under 1024 chars +- Test activation reliability + +## Security Considerations + +- Never include secrets in skill files +- Validate all inputs +- Use read-only tools when possible +- Document security requirements diff --git a/skills/skill-adapter/references/examples.md b/skills/skill-adapter/references/examples.md new file mode 100644 index 0000000..b1d8bd2 --- /dev/null +++ b/skills/skill-adapter/references/examples.md @@ -0,0 +1,70 @@ +# Skill Usage Examples + +This document provides practical examples of how to use this skill effectively. + +## Basic Usage + +### Example 1: Simple Activation + +**User Request:** +``` +[Describe trigger phrase here] +``` + +**Skill Response:** +1. Analyzes the request +2. Performs the required action +3. Returns results + +### Example 2: Complex Workflow + +**User Request:** +``` +[Describe complex scenario] +``` + +**Workflow:** +1. Step 1: Initial analysis +2. Step 2: Data processing +3. Step 3: Result generation +4. Step 4: Validation + +## Advanced Patterns + +### Pattern 1: Chaining Operations + +Combine this skill with other tools: +``` +Step 1: Use this skill for [purpose] +Step 2: Chain with [other tool] +Step 3: Finalize with [action] +``` + +### Pattern 2: Error Handling + +If issues occur: +- Check trigger phrase matches +- Verify context is available +- Review allowed-tools permissions + +## Tips & Best Practices + +- ✅ Be specific with trigger phrases +- ✅ Provide necessary context +- ✅ Check tool permissions match needs +- ❌ Avoid vague requests +- ❌ Don't mix unrelated tasks + +## Common Issues + +**Issue:** Skill doesn't activate +**Solution:** Use exact trigger phrases from description + +**Issue:** Unexpected results +**Solution:** Check input format and context + +## See Also + +- Main SKILL.md for full documentation +- scripts/ for automation helpers +- assets/ for configuration examples diff --git a/skills/skill-adapter/scripts/README.md b/skills/skill-adapter/scripts/README.md new file mode 100644 index 0000000..cb30799 --- /dev/null +++ b/skills/skill-adapter/scripts/README.md @@ -0,0 +1,7 @@ +# Scripts + +Bundled resources for api-schema-validator skill + +- [ ] validate_schema.py: Script to validate a given schema against a data file or API endpoint. +- [ ] generate_schema.py: Script to generate a basic schema from a data file or API endpoint response. +- [ ] convert_schema.py: Script to convert between different schema formats (e.g., JSON Schema to Yup). diff --git a/skills/skill-adapter/scripts/helper-template.sh b/skills/skill-adapter/scripts/helper-template.sh new file mode 100755 index 0000000..c4aae90 --- /dev/null +++ b/skills/skill-adapter/scripts/helper-template.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Helper script template for skill automation +# Customize this for your skill's specific needs + +set -e + +function show_usage() { + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " -h, --help Show this help message" + echo " -v, --verbose Enable verbose output" + echo "" +} + +# Parse arguments +VERBOSE=false + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_usage + exit 0 + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + *) + echo "Unknown option: $1" + show_usage + exit 1 + ;; + esac +done + +# Your skill logic here +if [ "$VERBOSE" = true ]; then + echo "Running skill automation..." +fi + +echo "✅ Complete" diff --git a/skills/skill-adapter/scripts/validation.sh b/skills/skill-adapter/scripts/validation.sh new file mode 100755 index 0000000..590af58 --- /dev/null +++ b/skills/skill-adapter/scripts/validation.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Skill validation helper +# Validates skill activation and functionality + +set -e + +echo "🔍 Validating skill..." + +# Check if SKILL.md exists +if [ ! -f "../SKILL.md" ]; then + echo "❌ Error: SKILL.md not found" + exit 1 +fi + +# Validate frontmatter +if ! grep -q "^---$" "../SKILL.md"; then + echo "❌ Error: No frontmatter found" + exit 1 +fi + +# Check required fields +if ! grep -q "^name:" "../SKILL.md"; then + echo "❌ Error: Missing 'name' field" + exit 1 +fi + +if ! grep -q "^description:" "../SKILL.md"; then + echo "❌ Error: Missing 'description' field" + exit 1 +fi + +echo "✅ Skill validation passed"