Save, organize, search, and retrieve code snippets with tags, categories, and smart search capabi...
Saves and retrieves reusable code snippets with smart search, tags, and categories. Use it to quickly find and insert common patterns like React hooks, API handlers, or Python decorators when coding.
/plugin marketplace add CuriousLearner/devkit/plugin install devkit@devkit-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Save, organize, search, and retrieve code snippets with tags, categories, and smart search capabilities.
You are a code snippet management expert. When invoked:
Save Code Snippets:
Search and Retrieve:
Snippet Organization:
Snippet Enhancement:
@snippet-manager Save API error handler
@snippet-manager --search "react hooks"
@snippet-manager --category testing
@snippet-manager --language python
@snippet-manager --tag async
@snippet-manager --collection "authentication patterns"
# Snippet: Async Error Handler Wrapper
**Language**: JavaScript/TypeScript
**Category**: Error Handling
**Tags**: async, error-handling, middleware, express
**Framework**: Express.js
**Use Case**: Wrap async route handlers to catch errors
## Code
```javascript
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// Usage
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user);
}));
fn: Async function to wrap (Request, Response, NextFunction) => Promise<void>Express middleware function that handles promise rejections
## JavaScript/TypeScript Snippets
### Debounce Function
```javascript
// Snippet: Debounce
// Category: Performance
// Tags: debounce, performance, optimization
function debounce(func, wait, immediate = false) {
let timeout;
return function executedFunction(...args) {
const later = () => {
timeout = null;
if (!immediate) func.apply(this, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(this, args);
};
}
// Usage
const handleSearch = debounce((query) => {
fetchResults(query);
}, 300);
// In React
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useMemo(
() => debounce((term) => {
// Perform search
console.log('Searching for:', term);
}, 500),
[]
);
useEffect(() => {
debouncedSearch(searchTerm);
}, [searchTerm, debouncedSearch]);
// Snippet: Deep Clone
// Category: Data Structures
// Tags: clone, deep-copy, objects
// Method 1: JSON (simple objects only)
const deepClone = (obj) => JSON.parse(JSON.stringify(obj));
// Method 2: Structured Clone (modern browsers/Node.js)
const deepClone2 = (obj) => structuredClone(obj);
// Method 3: Custom recursive (handles complex types)
function deepClone3(obj, hash = new WeakMap()) {
if (Object(obj) !== obj) return obj; // primitives
if (hash.has(obj)) return hash.get(obj); // cyclic reference
const result = Array.isArray(obj)
? []
: obj.constructor
? new obj.constructor()
: Object.create(null);
hash.set(obj, result);
return Object.assign(
result,
...Object.keys(obj).map(key => ({
[key]: deepClone3(obj[key], hash)
}))
);
}
// Usage
const original = { a: 1, b: { c: 2 }, d: [3, 4] };
const cloned = deepClone(original);
cloned.b.c = 999; // original.b.c remains 2
// Snippet: Retry with Exponential Backoff
// Category: Error Handling
// Tags: retry, async, error-handling, resilience
async function retryWithBackoff<T>(
fn: () => Promise<T>,
options: {
maxRetries?: number;
initialDelay?: number;
maxDelay?: number;
factor?: number;
} = {}
): Promise<T> {
const {
maxRetries = 3,
initialDelay = 1000,
maxDelay = 30000,
factor = 2,
} = options;
let lastError: Error;
let delay = initialDelay;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
if (attempt === maxRetries) {
throw new Error(
`Failed after ${maxRetries} retries: ${lastError.message}`
);
}
console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
delay = Math.min(delay * factor, maxDelay);
}
}
throw lastError!;
}
// Usage
const data = await retryWithBackoff(
() => fetch('https://api.example.com/data').then(r => r.json()),
{ maxRetries: 5, initialDelay: 500 }
);
// Snippet: Local Storage with Expiry
// Category: Browser APIs
// Tags: localstorage, cache, expiry
const storage = {
set(key, value, expiryMs = null) {
const item = {
value,
expiry: expiryMs ? Date.now() + expiryMs : null,
};
localStorage.setItem(key, JSON.stringify(item));
},
get(key) {
const itemStr = localStorage.getItem(key);
if (!itemStr) return null;
const item = JSON.parse(itemStr);
if (item.expiry && Date.now() > item.expiry) {
localStorage.removeItem(key);
return null;
}
return item.value;
},
remove(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
},
};
// Usage
storage.set('user', { id: 1, name: 'John' }, 3600000); // 1 hour
const user = storage.get('user');
// Snippet: useDebounce Hook
// Category: React Hooks
// Tags: react, hooks, debounce, performance
import { useEffect, useState } from 'react';
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
// Usage
function SearchComponent() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearchTerm) {
// Perform search
fetchResults(debouncedSearchTerm);
}
}, [debouncedSearchTerm]);
return (
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
);
}
// Snippet: useAsync Hook
// Category: React Hooks
// Tags: react, hooks, async, data-fetching
import { useEffect, useState, useCallback } from 'react';
type Status = 'idle' | 'loading' | 'success' | 'error';
interface AsyncState<T> {
status: Status;
data: T | null;
error: Error | null;
}
function useAsync<T>(
asyncFunction: () => Promise<T>,
immediate = true
) {
const [state, setState] = useState<AsyncState<T>>({
status: 'idle',
data: null,
error: null,
});
const execute = useCallback(async () => {
setState({ status: 'loading', data: null, error: null });
try {
const data = await asyncFunction();
setState({ status: 'success', data, error: null });
return data;
} catch (error) {
setState({ status: 'error', data: null, error: error as Error });
throw error;
}
}, [asyncFunction]);
useEffect(() => {
if (immediate) {
execute();
}
}, [execute, immediate]);
return { ...state, execute };
}
// Usage
function UserProfile({ userId }) {
const { status, data, error } = useAsync(
() => fetch(`/api/users/${userId}`).then(r => r.json()),
true
);
if (status === 'loading') return <div>Loading...</div>;
if (status === 'error') return <div>Error: {error.message}</div>;
if (status === 'success') return <div>User: {data.name}</div>;
return null;
}
// Snippet: useLocalStorage Hook
// Category: React Hooks
// Tags: react, hooks, localstorage, persistence
import { useState, useEffect } from 'react';
function useLocalStorage<T>(
key: string,
initialValue: T
): [T, (value: T | ((val: T) => T)) => void] {
// Get from local storage then parse stored json or return initialValue
const readValue = (): T => {
if (typeof window === 'undefined') {
return initialValue;
}
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.warn(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
};
const [storedValue, setStoredValue] = useState<T>(readValue);
const setValue = (value: T | ((val: T) => T)) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
console.warn(`Error setting localStorage key "${key}":`, error);
}
};
useEffect(() => {
setStoredValue(readValue());
}, []);
return [storedValue, setValue];
}
// Usage
function App() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Current theme: {theme}
</button>
);
}
# Snippet: Retry Decorator
# Category: Error Handling
# Tags: python, decorator, retry, error-handling
import time
import functools
from typing import Callable, Type
def retry(
max_attempts: int = 3,
delay: float = 1.0,
backoff: float = 2.0,
exceptions: tuple[Type[Exception], ...] = (Exception,)
):
"""
Retry decorator with exponential backoff
Args:
max_attempts: Maximum number of retry attempts
delay: Initial delay between retries in seconds
backoff: Multiplier for delay after each retry
exceptions: Tuple of exceptions to catch
"""
def decorator(func: Callable):
@functools.wraps(func)
def wrapper(*args, **kwargs):
current_delay = delay
last_exception = None
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except exceptions as e:
last_exception = e
if attempt == max_attempts - 1:
raise
print(f"Attempt {attempt + 1} failed: {e}")
print(f"Retrying in {current_delay}s...")
time.sleep(current_delay)
current_delay *= backoff
raise last_exception
return wrapper
return decorator
# Usage
@retry(max_attempts=5, delay=0.5, exceptions=(ConnectionError, TimeoutError))
def fetch_data(url: str):
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()
# Snippet: Timing Context Manager
# Category: Performance
# Tags: python, context-manager, timing, profiling
import time
from contextlib import contextmanager
from typing import Optional
@contextmanager
def timer(name: Optional[str] = None):
"""
Context manager to time code execution
Usage:
with timer("Database query"):
result = db.query(...)
"""
start = time.perf_counter()
try:
yield
finally:
elapsed = time.perf_counter() - start
label = f"{name}: " if name else ""
print(f"{label}Elapsed time: {elapsed:.4f}s")
# Usage
with timer("API call"):
response = requests.get("https://api.example.com/data")
data = response.json()
# Alternative: As a decorator
def timed(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} took {elapsed:.4f}s")
return result
return wrapper
@timed
def process_data(data):
# Process data
pass
# Snippet: Memoization
# Category: Performance
# Tags: python, cache, memoization, optimization
from functools import lru_cache, wraps
import pickle
import hashlib
# Simple memoization with lru_cache
@lru_cache(maxsize=128)
def fibonacci(n: int) -> int:
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# Custom memoization for unhashable arguments
def memoize(func):
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
# Create hashable key from arguments
key = hashlib.md5(
pickle.dumps((args, tuple(sorted(kwargs.items()))))
).hexdigest()
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
wrapper.cache_clear = lambda: cache.clear()
wrapper.cache_info = lambda: f"Cache size: {len(cache)}"
return wrapper
# Usage with unhashable types (lists, dicts)
@memoize
def expensive_computation(data: list[int]) -> int:
return sum(x ** 2 for x in data)
result = expensive_computation([1, 2, 3, 4, 5])
// Snippet: Rate Limiter
// Category: Middleware
// Tags: nodejs, express, rate-limiting, security
class RateLimiter {
constructor(options = {}) {
this.windowMs = options.windowMs || 60000; // 1 minute
this.maxRequests = options.maxRequests || 100;
this.requests = new Map();
}
middleware() {
return (req, res, next) => {
const key = req.ip || req.connection.remoteAddress;
const now = Date.now();
if (!this.requests.has(key)) {
this.requests.set(key, []);
}
const userRequests = this.requests.get(key);
// Remove old requests outside the window
const validRequests = userRequests.filter(
timestamp => now - timestamp < this.windowMs
);
if (validRequests.length >= this.maxRequests) {
const oldestRequest = validRequests[0];
const resetTime = oldestRequest + this.windowMs;
const retryAfter = Math.ceil((resetTime - now) / 1000);
res.set('Retry-After', retryAfter.toString());
return res.status(429).json({
error: 'Too many requests',
retryAfter: retryAfter,
});
}
validRequests.push(now);
this.requests.set(key, validRequests);
res.set('X-RateLimit-Limit', this.maxRequests.toString());
res.set('X-RateLimit-Remaining',
(this.maxRequests - validRequests.length).toString()
);
next();
};
}
// Cleanup old entries periodically
cleanup() {
const now = Date.now();
for (const [key, timestamps] of this.requests.entries()) {
const valid = timestamps.filter(t => now - t < this.windowMs);
if (valid.length === 0) {
this.requests.delete(key);
} else {
this.requests.set(key, valid);
}
}
}
}
// Usage
const limiter = new RateLimiter({
windowMs: 15 * 60 * 1000, // 15 minutes
maxRequests: 100,
});
app.use('/api', limiter.middleware());
// Cleanup every 5 minutes
setInterval(() => limiter.cleanup(), 5 * 60 * 1000);
// Snippet: Stream Pipeline
// Category: Streams
// Tags: nodejs, streams, pipeline, files
const { pipeline } = require('stream');
const { promisify } = require('util');
const fs = require('fs');
const zlib = require('zlib');
const { Transform } = require('stream');
const pipelineAsync = promisify(pipeline);
// Custom transform stream
class LineCounter extends Transform {
constructor(options) {
super(options);
this.lineCount = 0;
}
_transform(chunk, encoding, callback) {
const lines = chunk.toString().split('\n').length - 1;
this.lineCount += lines;
this.push(chunk);
callback();
}
}
// Usage: Compress file and count lines
async function compressAndCount(inputFile, outputFile) {
const counter = new LineCounter();
await pipelineAsync(
fs.createReadStream(inputFile),
counter,
zlib.createGzip(),
fs.createWriteStream(outputFile)
);
console.log(`Processed ${counter.lineCount} lines`);
return counter.lineCount;
}
// Usage: Process large CSV
async function processCsv(inputFile) {
const processLine = new Transform({
transform(chunk, encoding, callback) {
const lines = chunk.toString().split('\n');
const processed = lines
.map(line => line.toUpperCase())
.join('\n');
callback(null, processed);
}
});
await pipelineAsync(
fs.createReadStream(inputFile),
processLine,
fs.createWriteStream('output.csv')
);
}
-- Snippet: Upsert (Insert or Update)
-- Category: Database
-- Tags: sql, upsert, postgresql
-- PostgreSQL
INSERT INTO users (id, email, name, updated_at)
VALUES (1, 'user@example.com', 'John Doe', NOW())
ON CONFLICT (id)
DO UPDATE SET
email = EXCLUDED.email,
name = EXCLUDED.name,
updated_at = NOW()
RETURNING *;
-- Multiple rows upsert
INSERT INTO products (sku, name, price)
VALUES
('SKU001', 'Product 1', 29.99),
('SKU002', 'Product 2', 39.99)
ON CONFLICT (sku)
DO UPDATE SET
name = EXCLUDED.name,
price = EXCLUDED.price,
updated_at = NOW();
-- Snippet: Efficient Pagination
-- Category: Database
-- Tags: sql, pagination, performance
-- Offset-based (simple but slower for large offsets)
SELECT *
FROM posts
ORDER BY created_at DESC
LIMIT 20 OFFSET 40; -- Page 3
-- Cursor-based (more efficient)
SELECT *
FROM posts
WHERE created_at < '2024-01-01 12:00:00'
ORDER BY created_at DESC
LIMIT 20;
-- Keyset pagination (best performance)
SELECT *
FROM posts
WHERE (created_at, id) < ('2024-01-01 12:00:00', 12345)
ORDER BY created_at DESC, id DESC
LIMIT 20;
snippets/
├── javascript/
│ ├── async/
│ │ ├── retry.js
│ │ └── debounce.js
│ └── react/
│ ├── hooks/
│ └── components/
├── python/
│ ├── decorators/
│ └── context-managers/
└── sql/
├── queries/
└── migrations/
---
title: "Async Retry with Backoff"
language: javascript
category: error-handling
tags: [async, retry, error-handling, resilience]
framework: nodejs
version: 1.2.0
author: team
created: 2024-01-15
updated: 2024-01-20
---
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.