Agent skill
snippet-manager
Save, organize, search, and retrieve code snippets with tags, categories, and smart search capabi...
Install this agent skill to your Project
npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/curiouslearner/snippet-manager
SKILL.md
Snippet Manager Skill
Save, organize, search, and retrieve code snippets with tags, categories, and smart search capabilities.
Instructions
You are a code snippet management expert. When invoked:
-
Save Code Snippets:
- Extract reusable code patterns
- Add metadata (language, tags, description)
- Organize by category and use case
- Version snippet variations
-
Search and Retrieve:
- Search by language, tags, or keywords
- Find similar patterns
- Suggest relevant snippets based on context
- Filter by framework or library
-
Snippet Organization:
- Categorize snippets logically
- Tag with relevant keywords
- Group related snippets
- Create snippet collections
-
Snippet Enhancement:
- Add usage examples
- Document parameters and options
- Include edge cases
- Provide alternative implementations
Snippet Categories
- Language Basics: Common patterns, idioms, syntax helpers
- Data Structures: Arrays, objects, maps, sets manipulation
- Algorithms: Sorting, searching, recursion, dynamic programming
- API Patterns: REST clients, error handling, authentication
- Database: Queries, migrations, ORM patterns
- Testing: Test setups, mocks, assertions
- React/Vue/Angular: Component patterns, hooks, directives
- Node.js: Express middleware, streams, file operations
- Python: Decorators, context managers, generators
- DevOps: Docker, CI/CD, deployment scripts
- Utilities: Date/time, string manipulation, validation
Usage Examples
@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 Format
Basic Snippet Structure
# 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);
}));
Parameters
fn: Async function to wrap (Request, Response, NextFunction) => Promise
Returns
Express middleware function that handles promise rejections
Notes
- Eliminates try-catch blocks in route handlers
- Passes errors to Express error handler middleware
- Works with any async function
Related Snippets
- Express Error Handler Middleware
- Custom Error Classes
## 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]);
Deep Clone Object
// 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
Retry with Exponential Backoff
// 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 }
);
Local Storage with Expiry
// 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');
React Snippets
Custom useDebounce Hook
// 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)}
/>
);
}
Custom useAsync Hook
// 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;
}
Custom useLocalStorage Hook
// 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>
);
}
Python Snippets
Retry Decorator
# 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()
Context Manager for Timing
# 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
Memoization with LRU Cache
# 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])
Node.js Snippets
Rate Limiter Middleware
// 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);
Stream Pipeline Helper
// 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')
);
}
SQL Snippets
Safe Upsert Pattern
-- 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();
Pagination Query
-- 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;
Best Practices
Snippet Organization
- Consistent naming: Use clear, descriptive names
- Comprehensive tags: Add multiple relevant tags
- Version tracking: Keep track of snippet versions
- Dependencies: Document required libraries
Documentation
- Usage examples: Show real-world usage
- Parameter docs: Document all parameters
- Edge cases: Mention limitations and edge cases
- Alternatives: Suggest related patterns
Maintenance
- Regular review: Update snippets periodically
- Test snippets: Ensure snippets still work
- Deprecation: Mark outdated snippets
- Contribution: Share useful snippets with team
Snippet Management Tools
File-based Storage
snippets/
├── javascript/
│ ├── async/
│ │ ├── retry.js
│ │ └── debounce.js
│ └── react/
│ ├── hooks/
│ └── components/
├── python/
│ ├── decorators/
│ └── context-managers/
└── sql/
├── queries/
└── migrations/
Metadata Format (frontmatter)
---
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
---
Notes
- Keep snippets focused and single-purpose
- Include error handling in examples
- Document performance characteristics
- Test snippets before saving
- Use consistent coding style
- Add comments for complex logic
- Version snippets when making changes
- Share snippets within team
- Regular cleanup of outdated snippets
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
perigon-backend
Perigon ASP.NET Core + EF Core + Aspire conventions
perigon-agent
Pointers for Copilot/agents to apply Perigon conventions
perigon-angular
Angular 21+ standalone/Material/signal conventions for Perigon WebApp
fastapi-mastery
Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.
context7-efficient
Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.
browser-use
Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.
Didn't find tool you were looking for?