From d9d5734464ed6ffa79c64d48086cad78acd95e4e Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sat, 29 Nov 2025 18:52:06 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 15 + README.md | 3 + commands/implement-caching.md | 532 ++++++++++++++++++ plugin.lock.json | 97 ++++ skills/skill-adapter/assets/README.md | 7 + .../assets/cache_invalidation_template.json | 37 ++ .../skill-adapter/assets/config-template.json | 32 ++ .../assets/example_http_headers.txt | 129 +++++ .../assets/example_redis_config.conf | 101 ++++ 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 ++ 17 files changed, 1235 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 commands/implement-caching.md create mode 100644 plugin.lock.json create mode 100644 skills/skill-adapter/assets/README.md create mode 100644 skills/skill-adapter/assets/cache_invalidation_template.json create mode 100644 skills/skill-adapter/assets/config-template.json create mode 100644 skills/skill-adapter/assets/example_http_headers.txt create mode 100644 skills/skill-adapter/assets/example_redis_config.conf 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..ef03b8c --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "api-cache-manager", + "description": "Implement caching strategies with Redis, CDN, and HTTP headers", + "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..d5daebd --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# api-cache-manager + +Implement caching strategies with Redis, CDN, and HTTP headers diff --git a/commands/implement-caching.md b/commands/implement-caching.md new file mode 100644 index 0000000..34916f0 --- /dev/null +++ b/commands/implement-caching.md @@ -0,0 +1,532 @@ +--- +description: Implement comprehensive multi-level API caching strategies with Redis, CDN, and intelligent invalidation +shortcut: cache +category: api +difficulty: intermediate +estimated_time: 2-3 hours +version: 2.0.0 +--- + + + + + + + +# Implement API Caching + +Creates comprehensive multi-level caching strategies to dramatically improve API performance, reduce database load, and enhance user experience. Implements Redis for server-side caching, CDN integration for edge caching, and proper HTTP cache headers for client-side optimization. + +## When to Use + +Use this command when: +- API response times exceed acceptable thresholds (>200ms) +- Database queries are repetitive and expensive +- Static or semi-static content dominates API responses +- High traffic causes server strain and increased costs +- Geographic distribution requires edge caching +- Rate limiting needs efficient request counting +- Session data requires fast access across servers + +Do NOT use this command for: +- Real-time data that changes every request +- User-specific sensitive data (without proper cache isolation) +- APIs with complex invalidation dependencies +- Small-scale applications where caching adds unnecessary complexity + +## Prerequisites + +Before running this command, ensure: +- [ ] API endpoints are identified and categorized by cache lifetime +- [ ] Redis or Memcached is available (or can be provisioned) +- [ ] CDN service is configured (CloudFlare, Fastly, or AWS CloudFront) +- [ ] Cache key strategy is defined +- [ ] Monitoring tools are ready to track cache performance + +## Process + +### Step 1: Analyze API Patterns +The command examines your API to determine optimal caching strategies: +- Identifies read-heavy endpoints suitable for caching +- Categorizes data by volatility (static, semi-dynamic, dynamic) +- Analyzes request patterns and frequency +- Determines appropriate cache TTL values +- Maps data dependencies for invalidation + +### Step 2: Implement Server-Side Caching +Sets up Redis-based caching with intelligent patterns: +- Cache-aside pattern for on-demand caching +- Write-through for immediate cache updates +- Write-behind for asynchronous cache population +- Distributed caching for horizontal scaling +- Cache warming for critical data + +### Step 3: Configure HTTP Cache Headers +Implements proper HTTP caching directives: +- Cache-Control headers with appropriate max-age +- ETag generation for conditional requests +- Vary headers for content negotiation +- Surrogate-Control for CDN-specific behavior +- Stale-while-revalidate for improved perceived performance + +### Step 4: Integrate CDN Caching +Configures edge caching for global distribution: +- Cache rules based on URL patterns +- Geographic cache distribution +- Cache purging API integration +- Origin shield configuration +- Custom cache keys for variants + +### Step 5: Implement Cache Invalidation +Creates sophisticated invalidation strategies: +- Tag-based invalidation for related content +- Event-driven cache clearing +- Time-based expiration with jitter +- Cascade invalidation for dependent data +- Soft purging with grace periods + +## Output Format + +The command generates a complete caching implementation: + +``` +api-caching/ +├── src/ +│ ├── cache/ +│ │ ├── redis-client.js +│ │ ├── cache-middleware.js +│ │ ├── cache-strategies.js +│ │ └── invalidation-service.js +│ ├── middleware/ +│ │ ├── http-cache-headers.js +│ │ └── cdn-integration.js +│ └── utils/ +│ ├── cache-key-generator.js +│ └── cache-metrics.js +├── config/ +│ ├── cache-config.json +│ ├── redis.config.js +│ └── cdn-rules.json +├── tests/ +│ └── cache.test.js +└── docs/ + └── caching-strategy.md +``` + +## Examples + +### Example 1: E-commerce Product API with Redis + +**Scenario:** High-traffic product catalog requiring sub-100ms response times + +**Generated Redis Implementation:** +```javascript +// cache/redis-client.js +import Redis from 'ioredis'; +import { promisify } from 'util'; + +class CacheManager { + constructor() { + this.client = new Redis({ + host: process.env.REDIS_HOST, + port: process.env.REDIS_PORT, + password: process.env.REDIS_PASSWORD, + retryStrategy: (times) => Math.min(times * 50, 2000), + enableOfflineQueue: false + }); + + this.defaultTTL = 3600; // 1 hour default + this.client.on('error', this.handleError); + } + + async get(key, options = {}) { + try { + const cached = await this.client.get(key); + if (cached) { + this.metrics.hit(key); + return JSON.parse(cached); + } + this.metrics.miss(key); + + // Cache-aside pattern: fetch if not cached + if (options.fetchFunction) { + const data = await options.fetchFunction(); + await this.set(key, data, options.ttl); + return data; + } + return null; + } catch (error) { + this.handleError(error); + // Fallback to direct fetch on cache error + return options.fetchFunction ? await options.fetchFunction() : null; + } + } + + async set(key, value, ttl = this.defaultTTL) { + const serialized = JSON.stringify(value); + if (ttl) { + await this.client.setex(key, ttl, serialized); + } else { + await this.client.set(key, serialized); + } + + // Implement cache tags for invalidation + if (value.tags) { + for (const tag of value.tags) { + await this.client.sadd(`tag:${tag}`, key); + } + } + } + + async invalidateByTag(tag) { + const keys = await this.client.smembers(`tag:${tag}`); + if (keys.length > 0) { + await this.client.del(...keys); + await this.client.del(`tag:${tag}`); + } + return keys.length; + } + + async invalidatePattern(pattern) { + const keys = await this.client.keys(pattern); + if (keys.length > 0) { + await this.client.del(...keys); + } + return keys.length; + } +} + +// middleware/cache-middleware.js +export const cacheMiddleware = (options = {}) => { + return async (req, res, next) => { + // Skip caching for non-GET requests + if (req.method !== 'GET') { + return next(); + } + + // Generate cache key + const cacheKey = generateCacheKey(req); + + // Check cache + const cached = await cacheManager.get(cacheKey); + if (cached) { + res.set('X-Cache', 'HIT'); + res.set('X-Cache-Key', cacheKey); + return res.json(cached); + } + + // Store original send function + const originalSend = res.json; + res.json = function(data) { + res.json = originalSend; + + // Cache successful responses only + if (res.statusCode === 200) { + cacheManager.set(cacheKey, data, options.ttl); + } + + res.set('X-Cache', 'MISS'); + res.set('X-Cache-Key', cacheKey); + return res.json(data); + }; + + next(); + }; +}; + +// Usage in Express routes +app.get('/api/products/:id', + cacheMiddleware({ ttl: 1800 }), // 30 minutes + async (req, res) => { + const product = await db.getProduct(req.params.id); + res.json(product); + } +); +``` + +--- + +### Example 2: CDN Integration with Cache Purging + +**Scenario:** Global content delivery with CloudFlare integration + +**Generated CDN Configuration:** +```javascript +// cdn-integration.js +class CDNManager { + constructor(config) { + this.zoneId = config.cloudflareZoneId; + this.apiToken = config.cloudflareApiToken; + this.baseUrl = 'https://api.cloudflare.com/client/v4'; + } + + // Set CDN cache headers + setCacheHeaders(res, options = {}) { + const { + maxAge = 3600, + sMaxAge = 86400, + staleWhileRevalidate = 60, + staleIfError = 3600, + mustRevalidate = false, + public = true + } = options; + + // Browser cache + let cacheControl = public ? 'public' : 'private'; + cacheControl += `, max-age=${maxAge}`; + + // CDN cache (s-maxage) + cacheControl += `, s-maxage=${sMaxAge}`; + + // Stale content serving + if (staleWhileRevalidate) { + cacheControl += `, stale-while-revalidate=${staleWhileRevalidate}`; + } + if (staleIfError) { + cacheControl += `, stale-if-error=${staleIfError}`; + } + + if (mustRevalidate) { + cacheControl += ', must-revalidate'; + } + + res.set('Cache-Control', cacheControl); + + // CloudFlare specific headers + res.set('CF-Cache-Tag', options.tags?.join(',') || 'default'); + + // Enable CDN caching for this response + res.set('CDN-Cache-Control', `max-age=${sMaxAge}`); + } + + // Purge CDN cache by URL or tag + async purgeCache(options = {}) { + const { urls, tags, everything = false } = options; + + let purgeBody = {}; + if (everything) { + purgeBody.purge_everything = true; + } else if (tags) { + purgeBody.tags = tags; + } else if (urls) { + purgeBody.files = urls; + } + + const response = await fetch( + `${this.baseUrl}/zones/${this.zoneId}/purge_cache`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${this.apiToken}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(purgeBody) + } + ); + + return response.json(); + } +} + +// Usage in API endpoints +app.get('/api/content/:slug', async (req, res) => { + const content = await cms.getContent(req.params.slug); + + // Set aggressive CDN caching for static content + cdnManager.setCacheHeaders(res, { + maxAge: 300, // 5 min browser cache + sMaxAge: 86400, // 24 hour CDN cache + tags: ['content', `content-${content.id}`] + }); + + res.json(content); +}); + +// Invalidate on content update +app.post('/api/content/:slug/update', async (req, res) => { + const content = await cms.updateContent(req.params.slug, req.body); + + // Purge CDN cache + await cdnManager.purgeCache({ + tags: [`content-${content.id}`] + }); + + // Invalidate Redis cache + await cacheManager.invalidateByTag(`content-${content.id}`); + + res.json({ success: true }); +}); +``` + +--- + +### Example 3: Advanced Cache Warming and Preloading + +**Scenario:** Critical data that must always be cached for performance + +**Generated Cache Warming Strategy:** +```javascript +// cache-warming-service.js +class CacheWarmer { + constructor(cacheManager, dataSource) { + this.cache = cacheManager; + this.dataSource = dataSource; + this.warmingInterval = 5 * 60 * 1000; // 5 minutes + } + + async warmCache() { + console.log('Starting cache warming...'); + + // Warm frequently accessed data + const criticalData = [ + { key: 'homepage:featured', fetch: () => this.dataSource.getFeaturedProducts() }, + { key: 'categories:all', fetch: () => this.dataSource.getAllCategories() }, + { key: 'config:site', fetch: () => this.dataSource.getSiteConfig() } + ]; + + const warmingPromises = criticalData.map(async ({ key, fetch }) => { + try { + const data = await fetch(); + await this.cache.set(key, data, 3600); // 1 hour TTL + return { key, status: 'warmed' }; + } catch (error) { + return { key, status: 'failed', error: error.message }; + } + }); + + const results = await Promise.allSettled(warmingPromises); + console.log('Cache warming complete:', results); + return results; + } + + startPeriodicWarming() { + // Initial warming + this.warmCache(); + + // Periodic warming + setInterval(() => { + this.warmCache(); + }, this.warmingInterval); + } +} +``` + +## Error Handling + +### Error: Redis Connection Failed +**Symptoms:** Cache operations timeout or fail +**Cause:** Redis server unavailable or misconfigured +**Solution:** +```javascript +// Implement fallback to direct database access +if (!redis.isReady()) { + console.warn('Cache unavailable, falling back to database'); + return await database.query(sql); +} +``` +**Prevention:** Implement circuit breaker pattern and health checks + +### Error: Cache Stampede +**Symptoms:** Multiple simultaneous cache misses cause database overload +**Cause:** Popular item expires, causing many requests to rebuild cache +**Solution:** Implement probabilistic early expiration or distributed locks + +### Error: Stale Data Served +**Symptoms:** Users see outdated information +**Cause:** Cache TTL too long or invalidation not triggered +**Solution:** Implement event-based invalidation and reduce TTL values + +## Configuration Options + +### Option: `--ttl` +- **Purpose:** Set default time-to-live for cache entries +- **Values:** Seconds (integer) +- **Default:** 3600 (1 hour) +- **Example:** `/cache --ttl 7200` + +### Option: `--strategy` +- **Purpose:** Choose caching pattern +- **Values:** `cache-aside`, `write-through`, `write-behind` +- **Default:** `cache-aside` +- **Example:** `/cache --strategy write-through` + +### Option: `--cdn` +- **Purpose:** Specify CDN provider +- **Values:** `cloudflare`, `fastly`, `cloudfront`, `akamai` +- **Default:** `cloudflare` +- **Example:** `/cache --cdn fastly` + +## Best Practices + +✅ **DO:** +- Use consistent cache key naming conventions +- Implement cache metrics and monitoring +- Set appropriate TTL values based on data volatility +- Use cache tags for grouped invalidation +- Implement graceful degradation on cache failure + +❌ **DON'T:** +- Cache user-specific sensitive data without isolation +- Use overly long TTLs for frequently changing data +- Forget to handle cache failures gracefully +- Cache large objects that exceed memory limits + +💡 **TIPS:** +- Add jitter to TTL values to prevent synchronized expiration +- Use cache warming for critical data paths +- Monitor cache hit ratios (aim for >80%) +- Implement separate caches for different data types + +## Related Commands + +- `/api-rate-limiter` - Implement rate limiting with Redis +- `/api-response-validator` - Validate cached responses +- `/api-monitoring-dashboard` - Monitor cache performance +- `/api-load-tester` - Test cache effectiveness under load + +## Performance Considerations + +- **Cache hit ratio target:** >80% for static content, >60% for dynamic +- **Redis memory usage:** ~1KB per cached object + overhead +- **Network latency:** <5ms for Redis, <50ms for CDN edge +- **Typical improvements:** 10x-100x response time reduction + +## Security Notes + +⚠️ **Security Considerations:** +- Never cache authentication tokens or passwords +- Implement cache key signing to prevent injection +- Use separate cache instances for different security contexts +- Encrypt sensitive data before caching +- Implement proper access controls for cache management endpoints + +## Troubleshooting + +### Issue: Low cache hit ratio +**Solution:** Review cache key strategy and TTL values + +### Issue: Memory pressure on Redis +**Solution:** Implement LRU eviction policy and reduce object sizes + +### Issue: Cache invalidation not working +**Solution:** Verify tag associations and event triggers + +### Getting Help +- Redis documentation: https://redis.io/documentation +- CDN best practices: https://web.dev/cache-control +- Cache pattern guide: https://docs.microsoft.com/azure/architecture/patterns/cache-aside + +## Version History + +- **v2.0.0** - Complete rewrite with multi-level caching and CDN integration +- **v1.0.0** - Initial Redis-only implementation + +--- + +*Last updated: 2025-10-11* +*Quality score: 9.5/10* +*Tested with: Redis 7.0, CloudFlare, Fastly, AWS CloudFront* \ No newline at end of file diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..de2895f --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,97 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:jeremylongshore/claude-code-plugins-plus:plugins/api-development/api-cache-manager", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "594477b051858b1c91d1777e3a06f09e543c650c", + "treeHash": "e6f9cd31a9d09f9cf30cbfb33d66a56143c450772271506a97b71be54d3c6537", + "generatedAt": "2025-11-28T10:18:05.361094Z", + "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-cache-manager", + "description": "Implement caching strategies with Redis, CDN, and HTTP headers", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "e48cdbebbf5b30e0135a9f94b924d6c210296bdf8d71ff736ecad67f5e281ce7" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "d2e2ee88084189b1a95ff0cb510c1dbe8a3cbd53585581f1846f6aafedcb18a5" + }, + { + "path": "commands/implement-caching.md", + "sha256": "70f2c564d2fda84ffdeb639029db079d83bf4e0a3ea8de36c8badc2deb49b7a6" + }, + { + "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": "17234974d7e426481fa020c44c4330a1b014d3e089679e9128d4fb78fb50ac05" + }, + { + "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": "3972abf6b66fc5fd57e263f8b148447cc1ae0dab48676ace78e7b74d95c194e1" + }, + { + "path": "skills/skill-adapter/assets/test-data.json", + "sha256": "ac17dca3d6e253a5f39f2a2f1b388e5146043756b05d9ce7ac53a0042eee139d" + }, + { + "path": "skills/skill-adapter/assets/example_redis_config.conf", + "sha256": "6af78e0c762bc2755c0fbc09400d714b781f08d541abb2f4676766cc1bf23e1e" + }, + { + "path": "skills/skill-adapter/assets/README.md", + "sha256": "85cbc2a136aa8b5251ae41306b3eea6eb49b40bb162931cdde6669f3f3df4b74" + }, + { + "path": "skills/skill-adapter/assets/example_http_headers.txt", + "sha256": "79f93020e475f5dcd1c604798752c4c68bc15568744971d09399fae89a7fc15b" + }, + { + "path": "skills/skill-adapter/assets/cache_invalidation_template.json", + "sha256": "98f07d7bc4064135328310e15708217070428e3380fa779b0cc8cb6ec58cef14" + }, + { + "path": "skills/skill-adapter/assets/skill-schema.json", + "sha256": "f5639ba823a24c9ac4fb21444c0717b7aefde1a4993682897f5bf544f863c2cd" + }, + { + "path": "skills/skill-adapter/assets/config-template.json", + "sha256": "0c2ba33d2d3c5ccb266c0848fc43caa68a2aa6a80ff315d4b378352711f83e1c" + } + ], + "dirSha256": "e6f9cd31a9d09f9cf30cbfb33d66a56143c450772271506a97b71be54d3c6537" + }, + "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..088f597 --- /dev/null +++ b/skills/skill-adapter/assets/README.md @@ -0,0 +1,7 @@ +# Assets + +Bundled resources for api-cache-manager skill + +- [ ] cache_invalidation_template.json: JSON template for cache invalidation requests. +- [ ] example_redis_config.conf: Example Redis configuration file. +- [ ] example_http_headers.txt: Example HTTP headers for caching. diff --git a/skills/skill-adapter/assets/cache_invalidation_template.json b/skills/skill-adapter/assets/cache_invalidation_template.json new file mode 100644 index 0000000..f959378 --- /dev/null +++ b/skills/skill-adapter/assets/cache_invalidation_template.json @@ -0,0 +1,37 @@ +{ + "_comment": "Template for cache invalidation requests. Use this to build your request to invalidate cached data.", + "request_id": "unique_request_id_123", + "_comment": "A unique identifier for this invalidation request. Helps with tracking and auditing.", + "cache_type": "redis", + "_comment": "The type of cache to invalidate. Options: 'redis', 'cdn', 'http'.", + "target": "key", + "_comment": "Specifies what is being targeted for invalidation. Options: 'key', 'tag', 'all'.", + "key": "user:profile:12345", + "_comment": "The specific cache key to invalidate (if target is 'key').", + "tag": "user_profile", + "_comment": "The tag to invalidate (if target is 'tag'). All entries with this tag will be invalidated.", + "cdn_provider": "cloudflare", + "_comment": "If cache_type is 'cdn', specify the CDN provider. Options: 'cloudflare', 'akamai', 'fastly'.", + "cloudflare_zone_id": "your_cloudflare_zone_id", + "_comment": "If cache_type is 'cdn' and cdn_provider is 'cloudflare', specify the Cloudflare zone ID.", + "akamai_client_token": "your_akamai_client_token", + "_comment": "If cache_type is 'cdn' and cdn_provider is 'akamai', specify the Akamai Client Token.", + "akamai_client_secret": "your_akamai_client_secret", + "_comment": "If cache_type is 'cdn' and cdn_provider is 'akamai', specify the Akamai Client Secret.", + "akamai_access_token": "your_akamai_access_token", + "_comment": "If cache_type is 'cdn' and cdn_provider is 'akamai', specify the Akamai Access Token.", + "fastly_service_id": "your_fastly_service_id", + "_comment": "If cache_type is 'cdn' and cdn_provider is 'fastly', specify the Fastly Service ID.", + "fastly_api_key": "your_fastly_api_key", + "_comment": "If cache_type is 'cdn' and cdn_provider is 'fastly', specify the Fastly API Key.", + "http_header": "Cache-Control", + "_comment": "If cache_type is 'http', specify the HTTP header to modify. Typically 'Cache-Control'.", + "http_header_value": "no-cache, no-store, must-revalidate", + "_comment": "If cache_type is 'http', specify the new value for the HTTP header. Example: 'no-cache, no-store, must-revalidate'.", + "invalidate_all": false, + "_comment": "If true, invalidates all entries in the specified cache_type. Use with caution!", + "timestamp": "2024-01-26T12:00:00Z", + "_comment": "Timestamp of the invalidation request. Useful for auditing and debugging.", + "user": "admin_user", + "_comment": "User who initiated the invalidation request." +} \ No newline at end of file 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/example_http_headers.txt b/skills/skill-adapter/assets/example_http_headers.txt new file mode 100644 index 0000000..b0c652d --- /dev/null +++ b/skills/skill-adapter/assets/example_http_headers.txt @@ -0,0 +1,129 @@ +# Example HTTP Headers for API Caching + +This document provides example HTTP headers that you can use to implement caching strategies for your API. These headers can be configured on your server to instruct browsers, CDNs, and other caching proxies on how to cache your API responses. + +## Cache-Control + +The `Cache-Control` header is the primary mechanism for controlling caching behavior. It allows you to specify various directives related to caching. + +### Common Directives + +* **`public`**: Indicates that the response can be cached by any cache (e.g., browser, CDN, proxy). +* **`private`**: Indicates that the response can only be cached by the user's browser and not by shared caches. +* **`max-age=`**: Specifies the maximum amount of time (in seconds) that a response is considered fresh. After this time, the cache must revalidate the response with the origin server. **[Insert your desired cache duration in seconds here]** +* **`s-maxage=`**: Similar to `max-age`, but specifically for shared caches like CDNs. This overrides `max-age` for shared caches. **[Insert your desired CDN cache duration in seconds here]** +* **`no-cache`**: Forces caches to revalidate the response with the origin server before using it. The cache can still store the response, but it must always check for updates. +* **`no-store`**: Indicates that the response should not be cached at all. +* **`must-revalidate`**: Instructs caches to strictly adhere to the freshness information provided in the response. If a cached response is stale, the cache must revalidate it with the origin server before using it. +* **`proxy-revalidate`**: Similar to `must-revalidate`, but specifically for proxy caches. + +### Example Cache-Control Headers + +* **For public caching with a 1 hour (3600 seconds) TTL:** + + ``` + Cache-Control: public, max-age=3600 + ``` + +* **For private caching with a 5 minute (300 seconds) TTL:** + + ``` + Cache-Control: private, max-age=300 + ``` + +* **For CDN caching with a 1 day (86400 seconds) TTL and browser caching with 1 hour:** + + ``` + Cache-Control: public, max-age=3600, s-maxage=86400 + ``` + +* **To force revalidation:** + + ``` + Cache-Control: no-cache + ``` + +* **To prevent caching:** + + ``` + Cache-Control: no-store + ``` + +## Expires + +The `Expires` header specifies an absolute date/time after which the response is considered stale. While still supported, `Cache-Control` is generally preferred as it offers more flexibility. + +### Example Expires Header + +* **Expires one week from now:** + + ``` + Expires: [Insert calculated date/time string for one week from now in HTTP date format (e.g., "Tue, 15 Nov 2024 08:12:31 GMT")] + ``` + +## ETag + +The `ETag` header provides a unique identifier for a specific version of a resource. The server generates this value, and the client can use it in subsequent requests with the `If-None-Match` header to perform conditional requests. + +### Usage + +1. The server returns an `ETag` header with the initial response. **[Insert example ETag value here]** +2. The client stores the `ETag` value. +3. When the client needs to request the same resource again, it includes the `If-None-Match` header with the stored `ETag` value. +4. If the resource has not changed since the client last requested it, the server returns a `304 Not Modified` response. If the resource has changed, the server returns the new resource with a new `ETag` value. + +### Example ETag Header + +``` +ETag: "[Insert generated ETag value here]" +``` + +## Last-Modified + +The `Last-Modified` header indicates the date and time the resource was last modified on the server. Clients can use this information with the `If-Modified-Since` header to perform conditional requests. + +### Usage + +1. The server includes the `Last-Modified` header with the initial response. **[Insert Last-Modified date/time string here]** +2. The client stores the `Last-Modified` value. +3. When the client needs to request the same resource again, it includes the `If-Modified-Since` header with the stored `Last-Modified` value. +4. If the resource has not been modified since the client last requested it, the server returns a `304 Not Modified` response. If the resource has been modified, the server returns the new resource with an updated `Last-Modified` value. + +### Example Last-Modified Header + +``` +Last-Modified: [Insert date/time string in HTTP date format (e.g., "Mon, 14 Nov 2024 10:00:00 GMT")] +``` + +## Vary + +The `Vary` header specifies the request headers that the server uses to determine which version of a resource to serve. This is important when the server returns different responses based on the client's request headers (e.g., language, user-agent). + +### Example Vary Header + +* **Vary based on the `Accept-Language` header:** + + ``` + Vary: Accept-Language + ``` + +* **Vary based on the `User-Agent` and `Accept-Encoding` headers:** + + ``` + Vary: User-Agent, Accept-Encoding + ``` + +* **Vary on everything (use with caution as it can reduce cache effectiveness):** + + ``` + Vary: * + ``` + +## Practical Considerations + +* **Balancing Freshness and Validation:** Carefully consider the `max-age` and `s-maxage` values to strike a balance between serving cached content and ensuring that clients receive up-to-date information. +* **CDN Configuration:** Configure your CDN to respect the caching headers set by your origin server. Refer to your CDN provider's documentation for specific instructions. +* **Testing:** Thoroughly test your caching configuration to ensure that it is working as expected and that clients are receiving the correct responses. Use browser developer tools or command-line tools like `curl` to inspect the HTTP headers. +* **API Design:** Design your API to be cache-friendly. For example, use resource-based URLs and provide appropriate `ETag` or `Last-Modified` headers. +* **Invalidation:** Implement a strategy for invalidating cached content when the underlying data changes. This may involve purging the CDN cache or updating the `Cache-Control` headers. +* **Dynamic Content:** For dynamic content that cannot be cached, use the `Cache-Control: no-store` header. \ No newline at end of file diff --git a/skills/skill-adapter/assets/example_redis_config.conf b/skills/skill-adapter/assets/example_redis_config.conf new file mode 100644 index 0000000..91dff41 --- /dev/null +++ b/skills/skill-adapter/assets/example_redis_config.conf @@ -0,0 +1,101 @@ +# Example Redis Configuration File +# This file provides a starting point for configuring Redis for use with the API Cache Manager plugin. +# Adjust these settings to match your specific Redis deployment and performance requirements. + +# --- Basic Configuration --- + +# Bind to all interfaces or specify an IP address (e.g., 127.0.0.1) for local access only. +# bind 127.0.0.1 -::1 +bind 0.0.0.0 + +# Listen on the default Redis port. Change if necessary. +port 6379 + +# TCP keepalive. +# +# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence +# of communication. This is useful for two reasons: +# +# 1) Detect dead peers. +# 2) Take advantage of the TCP keepalive period to half close idle +# connections if the server wants to reduce resources usage. +# +# On Linux, the default keepalive settings are to send probes every +# 75 seconds, with 9 failed probes before declaring the client dead. +# This means that a broken connection is only discovered after 11 minutes +# (75*9). +# +# To make connection alive detection more aggressive on Linux, it is +# recommended to set the following TCP keepalive settings: +# +# tcp-keepalive 60 +tcp-keepalive 300 + +# --- Memory Management --- + +# Set the maximum memory Redis will use. Adjust this based on your available RAM. +# A good starting point is to allocate around half of your system's RAM to Redis. +# Ensure you have enough memory for both Redis and your application. +maxmemory 2gb + +# Eviction policy: how Redis will evict keys when it reaches maxmemory. +# Common policies: +# - volatile-lru: Evict keys with an expire set using an LRU algorithm. +# - allkeys-lru: Evict any key using an LRU algorithm. +# - volatile-ttl: Evict keys with an expire set, with the shortest remaining TTL. +# - noeviction: Don't evict. Return an error when memory is full. +maxmemory-policy allkeys-lru + +# --- Persistence --- + +# Redis offers different persistence options: +# - RDB (Snapshotting): Saves the dataset to disk periodically. Good for backups. +# - AOF (Append Only File): Logs every write operation. Provides better durability. +# - Disable Persistence: Redis will only exist in memory. Data is lost on shutdown. + +# RDB Snapshotting configuration +save 900 1 # Save the DB if 1 key changed in 900 seconds +save 300 10 # Save the DB if 10 keys changed in 300 seconds +save 60 10000 # Save the DB if 10000 keys changed in 60 seconds + +# AOF configuration (more durable, but can be slower) +# appendonly yes +# appendfsync everysec # Recommended for most use cases +# appendfsync always # Slowest, but safest +# appendfsync no # Fastest, but least safe (OS decides when to flush) + +# --- Security --- + +# Require a password for accessing Redis. Strongly recommended for production. +# Replace 'YOUR_REDIS_PASSWORD' with a strong, unique password. +# requirepass YOUR_REDIS_PASSWORD + +# Rename potentially dangerous commands. This is an optional security measure. +# rename-command FLUSHALL "" +# rename-command FLUSHDB "" +# rename-command CONFIG "" + +# --- Advanced Configuration --- + +# Number of databases. The default is 16. +# databases 16 + +# The idle time after which a client connection will be closed. +# If set to 0, the connection will never be closed. +# timeout 300 + +# --- Cluster Configuration (if applicable) --- +# If you are using Redis Cluster, configure the following: +# cluster-enabled yes +# cluster-config-file nodes.conf +# cluster-node-timeout 15000 + +# --- Logging --- +# Specify the log file. Leave commented to log to stdout. +# logfile /var/log/redis/redis-server.log + +# --- Important Notes --- +# - Regularly review and adjust these settings based on your application's needs and performance monitoring. +# - Monitor Redis memory usage and adjust 'maxmemory' accordingly. +# - Consider using Redis Sentinel or Redis Cluster for high availability. +# - Secure your Redis instance properly, especially if it's exposed to the internet. \ 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..4dd2362 --- /dev/null +++ b/skills/skill-adapter/references/README.md @@ -0,0 +1,7 @@ +# References + +Bundled resources for api-cache-manager skill + +- [ ] redis_config.md: Documentation on configuring Redis for caching, including connection parameters and best practices. +- [ ] http_cache_headers.md: Explanation of HTTP caching headers and how to use them effectively. +- [ ] cdn_integration.md: Guide on integrating the API cache with a CDN for improved performance. 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..19965fe --- /dev/null +++ b/skills/skill-adapter/scripts/README.md @@ -0,0 +1,7 @@ +# Scripts + +Bundled resources for api-cache-manager skill + +- [ ] clear_cache.sh: Script to clear the API cache based on different strategies (Redis, HTTP headers). +- [ ] warm_cache.py: Python script to pre-populate the cache with frequently accessed data. +- [ ] cache_stats.sh: Script to retrieve and display cache statistics (hit rate, size, etc.). 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"