From 5aa901f301136478415577525ed7043a6bf1a472 Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sat, 29 Nov 2025 18:52:14 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 15 + README.md | 3 + commands/implement-error-handling.md | 550 ++++++++++++++++++ plugin.lock.json | 93 +++ skills/skill-adapter/assets/README.md | 6 + .../skill-adapter/assets/config-template.json | 32 + .../assets/error_code_prefix_mapping.json | 68 +++ .../assets/error_response_template.json | 56 ++ skills/skill-adapter/assets/skill-schema.json | 28 + skills/skill-adapter/assets/test-data.json | 27 + skills/skill-adapter/references/README.md | 7 + .../references/best-practices.md | 69 +++ skills/skill-adapter/references/examples.md | 70 +++ skills/skill-adapter/scripts/README.md | 7 + .../skill-adapter/scripts/helper-template.sh | 42 ++ skills/skill-adapter/scripts/validation.sh | 32 + 16 files changed, 1105 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 commands/implement-error-handling.md create mode 100644 plugin.lock.json create mode 100644 skills/skill-adapter/assets/README.md create mode 100644 skills/skill-adapter/assets/config-template.json create mode 100644 skills/skill-adapter/assets/error_code_prefix_mapping.json create mode 100644 skills/skill-adapter/assets/error_response_template.json create mode 100644 skills/skill-adapter/assets/skill-schema.json create mode 100644 skills/skill-adapter/assets/test-data.json create mode 100644 skills/skill-adapter/references/README.md create mode 100644 skills/skill-adapter/references/best-practices.md create mode 100644 skills/skill-adapter/references/examples.md create mode 100644 skills/skill-adapter/scripts/README.md create mode 100755 skills/skill-adapter/scripts/helper-template.sh create mode 100755 skills/skill-adapter/scripts/validation.sh diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..9053e61 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "api-error-handler", + "description": "Implement standardized error handling with proper HTTP status codes", + "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..113caa9 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# api-error-handler + +Implement standardized error handling with proper HTTP status codes diff --git a/commands/implement-error-handling.md b/commands/implement-error-handling.md new file mode 100644 index 0000000..af160ce --- /dev/null +++ b/commands/implement-error-handling.md @@ -0,0 +1,550 @@ +--- +description: Implement standardized API error handling +shortcut: errors +--- + +# Implement Error Handling + +Create standardized, production-ready error handling middleware with proper HTTP status codes, consistent error formats, and comprehensive logging. This command generates custom error classes, middleware, and error recovery strategies for Node.js, Python, and other backend frameworks. + +## Design Decisions + +**Why standardized error handling matters:** +- **Client experience**: Consistent error formats make client integration predictable +- **Debugging**: Structured errors with context accelerate troubleshooting +- **Security**: Proper error handling prevents information leakage in production +- **Monitoring**: Standardized errors integrate cleanly with observability tools + +**Alternatives considered:** +- **HTTP-only errors**: Simpler but lacks context for debugging +- **Framework defaults**: Inconsistent across endpoints, lacks business context +- **Exception-based only**: Can leak sensitive information, harder to test + +**This approach balances**: Developer experience, security, debugging, and API consistency. + +## When to Use + +Use this command when: +- Starting a new API project that needs error handling +- Refactoring inconsistent error responses across endpoints +- Adding error monitoring and alerting to an existing API +- Migrating from generic framework errors to business-specific errors +- Implementing error handling for microservices that need consistency + +Don't use when: +- Your framework's default error handling already meets your needs +- Building proof-of-concept code without production requirements +- Working with legacy systems that can't adopt new error formats + +## Prerequisites + +- Node.js 16+ (for Express/Fastify examples) or Python 3.8+ (for Flask/FastAPI) +- Existing API project structure +- Basic understanding of HTTP status codes (4xx client errors, 5xx server errors) +- (Optional) Logging framework installed (Winston, Pino, Structlog) +- (Optional) Monitoring service (Sentry, DataDog, New Relic) + +## Process + +1. **Generate Custom Error Classes** + - Create base error class with HTTP status codes + - Define specific error types (ValidationError, NotFoundError, AuthError) + - Add error codes for programmatic handling + +2. **Build Error Middleware** + - Catch all errors in centralized handler + - Format errors consistently (RFC 7807 Problem Details or custom) + - Handle both operational and programmer errors + +3. **Configure Environment-Specific Behavior** + - Development: Include stack traces, detailed messages + - Production: Sanitize errors, log internally, return safe messages + +4. **Integrate Logging** + - Log all errors with context (request ID, user, endpoint) + - Add severity levels (error, warning, critical) + - Include metadata for troubleshooting + +5. **Add Error Recovery** + - Graceful degradation strategies + - Retry logic for transient failures + - Circuit breaker integration + +## Output Format + +### Express.js Error Handler + +```javascript +// errors/AppError.js +class AppError extends Error { + constructor(message, statusCode, errorCode = null) { + super(message); + this.statusCode = statusCode; + this.errorCode = errorCode; + this.isOperational = true; + this.timestamp = new Date().toISOString(); + Error.captureStackTrace(this, this.constructor); + } +} + +class ValidationError extends AppError { + constructor(message, errors = []) { + super(message, 400, 'VALIDATION_ERROR'); + this.errors = errors; + } +} + +class NotFoundError extends AppError { + constructor(resource) { + super(`${resource} not found`, 404, 'NOT_FOUND'); + this.resource = resource; + } +} + +class UnauthorizedError extends AppError { + constructor(message = 'Unauthorized') { + super(message, 401, 'UNAUTHORIZED'); + } +} + +class ForbiddenError extends AppError { + constructor(message = 'Forbidden') { + super(message, 403, 'FORBIDDEN'); + } +} + +module.exports = { AppError, ValidationError, NotFoundError, UnauthorizedError, ForbiddenError }; + +// middleware/errorHandler.js +const logger = require('../utils/logger'); + +const errorHandler = (err, req, res, next) => { + // Default to 500 server error + let statusCode = err.statusCode || 500; + let message = err.message || 'Internal Server Error'; + + // Log error with context + logger.error({ + message: err.message, + statusCode, + errorCode: err.errorCode, + stack: err.stack, + path: req.path, + method: req.method, + requestId: req.id, + userId: req.user?.id, + ip: req.ip + }); + + // Production: Don't leak error details + if (process.env.NODE_ENV === 'production' && !err.isOperational) { + message = 'An unexpected error occurred'; + statusCode = 500; + } + + // Send error response + res.status(statusCode).json({ + error: { + message, + code: err.errorCode, + statusCode, + timestamp: err.timestamp || new Date().toISOString(), + path: req.path, + ...(process.env.NODE_ENV === 'development' && { stack: err.stack }), + ...(err.errors && { details: err.errors }) + } + }); +}; + +module.exports = errorHandler; +``` + +### FastAPI (Python) Error Handler + +```python +# errors/exceptions.py +from typing import Optional, Any, Dict +from fastapi import HTTPException +from datetime import datetime + +class AppError(HTTPException): + def __init__( + self, + status_code: int, + message: str, + error_code: Optional[str] = None, + details: Optional[Dict[str, Any]] = None + ): + self.status_code = status_code + self.message = message + self.error_code = error_code + self.details = details or {} + self.timestamp = datetime.utcnow().isoformat() + super().__init__(status_code=status_code, detail=message) + +class ValidationError(AppError): + def __init__(self, message: str, errors: list = None): + super().__init__( + status_code=400, + message=message, + error_code="VALIDATION_ERROR", + details={"errors": errors or []} + ) + +class NotFoundError(AppError): + def __init__(self, resource: str): + super().__init__( + status_code=404, + message=f"{resource} not found", + error_code="NOT_FOUND", + details={"resource": resource} + ) + +class UnauthorizedError(AppError): + def __init__(self, message: str = "Unauthorized"): + super().__init__( + status_code=401, + message=message, + error_code="UNAUTHORIZED" + ) + +# main.py +from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse +import logging + +app = FastAPI() +logger = logging.getLogger(__name__) + +@app.exception_handler(AppError) +async def app_error_handler(request: Request, exc: AppError): + logger.error( + f"AppError: {exc.message}", + extra={ + "status_code": exc.status_code, + "error_code": exc.error_code, + "path": request.url.path, + "method": request.method + } + ) + + return JSONResponse( + status_code=exc.status_code, + content={ + "error": { + "message": exc.message, + "code": exc.error_code, + "statusCode": exc.status_code, + "timestamp": exc.timestamp, + "path": str(request.url.path), + **exc.details + } + } + ) + +@app.exception_handler(Exception) +async def generic_error_handler(request: Request, exc: Exception): + logger.exception("Unhandled exception", exc_info=exc) + + return JSONResponse( + status_code=500, + content={ + "error": { + "message": "Internal server error", + "code": "INTERNAL_ERROR", + "statusCode": 500, + "timestamp": datetime.utcnow().isoformat() + } + } + ) +``` + +## Example Usage + +### Example 1: Handling Validation Errors + +```javascript +const { ValidationError } = require('./errors/AppError'); +const { body, validationResult } = require('express-validator'); + +router.post('/users', + [ + body('email').isEmail().normalizeEmail(), + body('password').isLength({ min: 8 }), + body('name').trim().notEmpty() + ], + async (req, res, next) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + throw new ValidationError('Validation failed', errors.array()); + } + + const user = await createUser(req.body); + res.status(201).json(user); + } catch (error) { + next(error); + } + } +); + +// Response for invalid input: +// { +// "error": { +// "message": "Validation failed", +// "code": "VALIDATION_ERROR", +// "statusCode": 400, +// "timestamp": "2025-10-11T12:00:00.000Z", +// "path": "/users", +// "details": [ +// { "field": "email", "message": "Invalid email format" }, +// { "field": "password", "message": "Password must be at least 8 characters" } +// ] +// } +// } +``` + +### Example 2: Resource Not Found + +```python +from fastapi import APIRouter +from errors.exceptions import NotFoundError + +router = APIRouter() + +@router.get("/users/{user_id}") +async def get_user(user_id: int): + user = await db.get_user(user_id) + if not user: + raise NotFoundError("User") + return user + +# Response: +# { +# "error": { +# "message": "User not found", +# "code": "NOT_FOUND", +# "statusCode": 404, +# "timestamp": "2025-10-11T12:00:00.000Z", +# "path": "/users/123", +# "details": { +# "resource": "User" +# } +# } +# } +``` + +### Example 3: Error with Retry Strategy + +```javascript +const { AppError } = require('./errors/AppError'); +const retry = require('async-retry'); + +async function callExternalAPI(endpoint) { + return retry(async (bail, attempt) => { + try { + const response = await fetch(endpoint); + if (!response.ok) { + // Don't retry client errors + if (response.status >= 400 && response.status < 500) { + bail(new AppError('External API error', response.status)); + return; + } + // Retry server errors + throw new Error(`API returned ${response.status}`); + } + return response.json(); + } catch (error) { + console.log(`Attempt ${attempt} failed: ${error.message}`); + throw error; + } + }, { + retries: 3, + minTimeout: 1000, + maxTimeout: 5000 + }); +} +``` + +## Error Handling + +**Common issues and solutions:** + +**Problem**: Errors logged multiple times +- **Cause**: Error handlers at multiple middleware layers +- **Solution**: Log only in the central error handler, not in route handlers + +**Problem**: Stack traces visible in production +- **Cause**: Environment check not working correctly +- **Solution**: Verify `NODE_ENV=production` is set, check conditional logic + +**Problem**: Lost error context (request ID, user info) +- **Cause**: Context not attached to request object +- **Solution**: Use middleware to attach request ID, user before error handler + +**Problem**: Async errors not caught +- **Cause**: Missing try-catch or next() in async routes +- **Solution**: Use express-async-errors or wrap all async routes + +**Problem**: Database connection errors crashing app +- **Cause**: Uncaught promise rejections +- **Solution**: Add process-level error handlers: + +```javascript +process.on('unhandledRejection', (reason, promise) => { + logger.error('Unhandled Rejection', { reason, promise }); + // Optionally exit: process.exit(1); +}); + +process.on('uncaughtException', (error) => { + logger.error('Uncaught Exception', { error }); + process.exit(1); // Must exit, app is in undefined state +}); +``` + +## Configuration + +### Error Handler Options + +```javascript +const errorHandlerOptions = { + // Include stack traces + showStack: process.env.NODE_ENV === 'development', + + // Log level for different error types + logLevel: { + operational: 'error', + programmer: 'critical' + }, + + // Send errors to monitoring service + reportToMonitoring: process.env.NODE_ENV === 'production', + + // Sanitize sensitive fields + sanitizeFields: ['password', 'ssn', 'creditCard'], + + // Custom error formatters + formatters: { + json: (err) => ({ error: err.toJSON() }), + xml: (err) => convertToXML(err) + } +}; +``` + +## Best Practices + +DO: +- Log all errors with sufficient context for debugging +- Use specific error classes for different failure scenarios +- Return consistent error format across all endpoints +- Sanitize errors in production (no stack traces, no sensitive data) +- Include correlation IDs for tracing errors across services +- Test error handling as thoroughly as success cases +- Document error codes and responses in API documentation + +DON'T: +- Expose internal implementation details in error messages +- Log sensitive data (passwords, tokens, PII) +- Ignore errors or swallow exceptions silently +- Use generic "Error occurred" messages without context +- Return different error formats from different endpoints +- Forget to handle async errors (use try-catch or error middleware) +- Let programmer errors (bugs) be handled the same as operational errors + +TIPS: +- Use error codes clients can handle programmatically (`INSUFFICIENT_FUNDS`, `RATE_LIMIT_EXCEEDED`) +- Provide actionable error messages ("Email already registered, try logging in" not "Duplicate entry") +- Group related errors with similar status codes (all validation = 400, all auth = 401/403) +- Consider RFC 7807 Problem Details format for standardization +- Add request IDs to errors for log correlation +- Monitor error rates and alert on anomalies + +## Related Commands + +- `/validate-api-responses` - Validate API responses match schemas +- `/setup-logging` - Configure structured logging for errors +- `/scan-api-security` - Scan for security vulnerabilities in error handling +- `/create-monitoring` - Set up error monitoring dashboards +- `/generate-rest-api` - Generate REST API with built-in error handling + +## Performance Considerations + +- **Error creation overhead**: Custom error classes add minimal overhead (~1-2ms) +- **Stack trace capture**: Can be expensive in hot paths, consider disabling in production +- **Logging**: Use async logging to avoid blocking request threads +- **Monitoring**: Batch error reports to external services (Sentry, DataDog) +- **Memory leaks**: Ensure errors don't hold references to large objects + +**Optimization strategies:** +```javascript +// Disable stack traces in production for performance +if (process.env.NODE_ENV === 'production') { + Error.stackTraceLimit = 0; +} + +// Use structured logging with async writes +const logger = winston.createLogger({ + transports: [ + new winston.transports.File({ + filename: 'error.log', + level: 'error' + }) + ] +}); +``` + +## Security Considerations + +- **Information disclosure**: Never expose database errors, file paths, or internal IDs +- **Error-based enumeration**: Avoid revealing if resources exist ("Invalid credentials" not "User not found") +- **DoS via errors**: Rate limit error-triggering requests +- **Log injection**: Sanitize user input before logging +- **Sensitive data in logs**: Redact passwords, tokens, SSNs before logging + +**Security checklist:** +```javascript +// BAD: Exposes internal structure +throw new Error(`User ${userId} not found in users table`); + +// GOOD: Generic message +throw new NotFoundError('User'); + +// BAD: Reveals existence +if (!user) throw new Error('User not found'); +if (password !== user.password) throw new Error('Wrong password'); + +// GOOD: Generic auth failure +if (!user || password !== user.password) { + throw new UnauthorizedError('Invalid credentials'); +} +``` + +## Troubleshooting + +**Error handler not catching errors:** +1. Ensure error handler is registered AFTER all routes +2. Check async routes call `next(error)` or use express-async-errors +3. Verify middleware order: routes → 404 handler → error handler + +**Errors not logged:** +1. Check logger configuration and file permissions +2. Verify log level settings (error should be logged at all levels) +3. Test logger independently before integration + +**Production errors too verbose:** +1. Verify NODE_ENV=production environment variable +2. Check conditional stack trace logic +3. Test with actual production config locally + +**Error monitoring not working:** +1. Verify API keys for Sentry/DataDog/New Relic +2. Check network connectivity to monitoring service +3. Test error reporting independently + +## Version History + +- **1.0.0** (2025-10-11): Initial release with Express and FastAPI examples + - Custom error classes (ValidationError, NotFoundError, AuthError) + - Environment-specific error formatting + - Structured logging integration + - Error recovery patterns diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..33bf886 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,93 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:jeremylongshore/claude-code-plugins-plus:plugins/api-development/api-error-handler", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "049c0462691b54459056b3b96342bb183be55818", + "treeHash": "2ce1da5b86546879cbdd232f16338e0311ec8b9fb15b37c31d89a8be696daee2", + "generatedAt": "2025-11-28T10:18:06.016976Z", + "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-error-handler", + "description": "Implement standardized error handling with proper HTTP status codes", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "175e0b7b984822779cacb43294a19114800d5218a77751ecfb0a6d8861310837" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "38304e3313bd5450d8cd9c3e9dd1b2d708d5522e88e2f69b7de3dcdc8bd71175" + }, + { + "path": "commands/implement-error-handling.md", + "sha256": "0cd7ce652ff8f4c0da73a9990e731712d9633c108307e6af5d9d8ed877854f09" + }, + { + "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": "cc46b97f6435d5e3f0b9f6dd4dd83d687af4af7ffc5e247fcb3616e9816be5c1" + }, + { + "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": "1b82d8761fbd8f2fd92b3d00a35f64543a245d8f30ba200f36ff8f2f2de5d629" + }, + { + "path": "skills/skill-adapter/assets/test-data.json", + "sha256": "ac17dca3d6e253a5f39f2a2f1b388e5146043756b05d9ce7ac53a0042eee139d" + }, + { + "path": "skills/skill-adapter/assets/README.md", + "sha256": "6f9615ffa1ebf4e6950135055bb60b6dd8ddd6412312f84a19c25ec33f0a8f80" + }, + { + "path": "skills/skill-adapter/assets/error_response_template.json", + "sha256": "2f563aeece90c9a65d0fc4fbab364bcdc1ab56ee479da914a14e32839e275c48" + }, + { + "path": "skills/skill-adapter/assets/skill-schema.json", + "sha256": "f5639ba823a24c9ac4fb21444c0717b7aefde1a4993682897f5bf544f863c2cd" + }, + { + "path": "skills/skill-adapter/assets/error_code_prefix_mapping.json", + "sha256": "c047172ca542b73118334dbbea54a679f655791bceb7752ab33085627d807b94" + }, + { + "path": "skills/skill-adapter/assets/config-template.json", + "sha256": "0c2ba33d2d3c5ccb266c0848fc43caa68a2aa6a80ff315d4b378352711f83e1c" + } + ], + "dirSha256": "2ce1da5b86546879cbdd232f16338e0311ec8b9fb15b37c31d89a8be696daee2" + }, + "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..c52ae63 --- /dev/null +++ b/skills/skill-adapter/assets/README.md @@ -0,0 +1,6 @@ +# Assets + +Bundled resources for api-error-handler skill + +- [ ] error_response_template.json: A JSON template for consistent error responses. +- [ ] error_code_prefix_mapping.json: A mapping of error code prefixes to specific API modules or services. 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/error_code_prefix_mapping.json b/skills/skill-adapter/assets/error_code_prefix_mapping.json new file mode 100644 index 0000000..b0405e2 --- /dev/null +++ b/skills/skill-adapter/assets/error_code_prefix_mapping.json @@ -0,0 +1,68 @@ +{ + "_comment": "Mapping of error code prefixes to API modules/services. Used for determining the origin and handling strategy for different error types.", + "mappings": { + "AUTH": { + "_comment": "Authentication-related errors", + "module": "AuthenticationService", + "http_status_code": 401, + "description": "Errors related to user authentication, authorization, or session management.", + "handling_strategy": "Retry with re-authentication if possible, otherwise log and return a 401 Unauthorized error." + }, + "USER": { + "_comment": "User management errors", + "module": "UserService", + "http_status_code": 400, + "description": "Errors related to user creation, modification, or deletion.", + "handling_strategy": "Return a 400 Bad Request error with specific details about the invalid user data or operation." + }, + "PROD": { + "_comment": "Product catalog errors", + "module": "ProductCatalogService", + "http_status_code": 500, + "description": "Errors related to retrieving or managing product information.", + "handling_strategy": "Retry a limited number of times. If still failing, log the error and return a 500 Internal Server Error with a generic message. Monitor for widespread issues." + }, + "ORD": { + "_comment": "Order processing errors", + "module": "OrderProcessingService", + "http_status_code": 409, + "description": "Errors related to order placement, modification, or fulfillment.", + "handling_strategy": "Return a 409 Conflict error if the order is in an invalid state. For other errors, attempt to automatically correct the order if possible, otherwise notify support and return a 500 Internal Server Error." + }, + "PAY": { + "_comment": "Payment processing errors", + "module": "PaymentGatewayService", + "http_status_code": 402, + "description": "Errors related to payment authorization, capture, or refund.", + "handling_strategy": "Return a 402 Payment Required error. Provide specific instructions to the user on how to resolve the payment issue." + }, + "RATE": { + "_comment": "Rate limiting errors", + "module": "RateLimiter", + "http_status_code": 429, + "description": "Errors indicating that the client has exceeded their rate limit.", + "handling_strategy": "Return a 429 Too Many Requests error with a 'Retry-After' header indicating when the client can retry." + }, + "DATA": { + "_comment": "Data validation or database errors", + "module": "DatabaseService", + "http_status_code": 503, + "description": "Errors related to accessing or manipulating data in the database. Includes validation failures.", + "handling_strategy": "Retry database operations with exponential backoff. If persistent, return a 503 Service Unavailable error, indicating a temporary issue. Alert the database administrators." + }, + "INTEG": { + "_comment": "Integration errors with external services", + "module": "IntegrationService", + "http_status_code": 502, + "description": "Errors encountered when communicating with external APIs or services.", + "handling_strategy": "Implement circuit breaker pattern to prevent cascading failures. Return a 502 Bad Gateway error if the external service is unavailable." + }, + "NOTF": { + "_comment": "Notification service errors", + "module": "NotificationService", + "http_status_code": 500, + "description": "Errors related to sending emails, SMS messages, or push notifications.", + "handling_strategy": "Queue failed notifications for retry. Log errors and monitor for persistent failures. Return a 500 Internal Server Error to the client, indicating a temporary issue with notifications." + } + } +} \ No newline at end of file diff --git a/skills/skill-adapter/assets/error_response_template.json b/skills/skill-adapter/assets/error_response_template.json new file mode 100644 index 0000000..9aa7a02 --- /dev/null +++ b/skills/skill-adapter/assets/error_response_template.json @@ -0,0 +1,56 @@ +{ + "_comment": "Template for a standardized error response.", + "error": { + "_comment": "Top-level key indicating an error occurred.", + "code": "ERR_INVALID_INPUT", + "_comment": "A unique error code for programmatic handling. Should be stable and not change even if the message changes.", + "message": "Invalid input provided.", + "_comment": "A human-readable error message. Should be helpful to the user.", + "status": 400, + "_comment": "The HTTP status code associated with the error.", + "details": { + "_comment": "Optional details about the error. Can be an object or an array.", + "field": "email", + "issue": "Email address is not valid." + }, + "timestamp": "2024-10-27T10:00:00Z", + "_comment": "Timestamp of when the error occurred (ISO 8601 format)." + }, + "_comment": "Example of a different error scenario (Internal Server Error)", + "example_internal_server_error": { + "error": { + "code": "ERR_INTERNAL_SERVER_ERROR", + "message": "An unexpected error occurred on the server.", + "status": 500, + "details": { + "_comment": "This can be omitted or contain sensitive information that should not be exposed to the client.", + "errorId": "a1b2c3d4e5f6g7h8" + }, + "timestamp": "2024-10-27T10:01:00Z" + } + }, + "_comment": "Example of a different error scenario (Unauthorized)", + "example_unauthorized": { + "error": { + "code": "ERR_UNAUTHORIZED", + "message": "Unauthorized: Invalid credentials.", + "status": 401, + "details": null, + "_comment": "Details are often omitted for unauthorized errors.", + "timestamp": "2024-10-27T10:02:00Z" + } + }, + "_comment": "Example of a different error scenario (Not Found)", + "example_not_found": { + "error": { + "code": "ERR_NOT_FOUND", + "message": "Resource not found.", + "status": 404, + "details": { + "resource": "user", + "id": "123" + }, + "timestamp": "2024-10-27T10:03:00Z" + } + } +} \ No newline at end of file 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..03da9d2 --- /dev/null +++ b/skills/skill-adapter/references/README.md @@ -0,0 +1,7 @@ +# References + +Bundled resources for api-error-handler skill + +- [ ] http_status_codes.md: A comprehensive list of HTTP status codes with descriptions and when to use them. +- [ ] error_handling_best_practices.md: Best practices for API error handling, including security considerations. +- [ ] example_error_responses.json: Examples of well-structured error responses in JSON format. 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..a3c5d6f --- /dev/null +++ b/skills/skill-adapter/scripts/README.md @@ -0,0 +1,7 @@ +# Scripts + +Bundled resources for api-error-handler skill + +- [ ] validate_status_code.py: Validates if a given HTTP status code is valid according to standards. +- [ ] format_error_response.py: Formats an error response into a consistent JSON structure. +- [ ] generate_error_code.py: Generates a unique error code for internal tracking. 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"