Automatically validates Cloudflare Durable Objects usage patterns, ensuring correct state management, hibernation, and strong consistency practices
Automatically validates Cloudflare Durable Objects usage patterns, ensuring correct state management, hibernation, and strong consistency practices. Activates when detecting DO imports, state management, ID generation patterns, or hibernation implementations.
/plugin marketplace add hirefrank/hirefrank-marketplace/plugin install edge-stack@hirefrank-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This SKILL automatically activates when:
idFromName, newUniqueId)// These patterns trigger immediate alerts:
// Using DOs for stateless operations
export default {
async fetch(request: Request, env: Env) {
const id = env.COUNTER.newUniqueId(); // New DO every request!
const stub = env.COUNTER.get(id);
return stub.fetch(request); // Overkill for simple counter
}
}
// Missing hibernation for long-lived DOs
export class ChatRoom {
constructor(state, env) {
this.state = state;
// Missing this.state.storage.setAlarm() for hibernation
}
}
// These patterns are validated as correct:
// Reuse DO instances for stateful coordination
export default {
async fetch(request: Request, env: Env) {
const ip = request.headers.get('CF-Connecting-IP');
const id = env.RATE_LIMITER.idFromName(ip); // Reuse same DO
const stub = env.RATE_LIMITER.get(id);
return stub.fetch(request);
}
}
// Proper hibernation implementation
export class ChatRoom {
constructor(state, env) {
this.state = state;
this.env = env;
// Set alarm for hibernation after inactivity
this.state.storage.setAlarm(Date.now() + 30000); // 30 seconds
}
alarm() {
// DO will hibernate after alarm
}
}
cloudflare-architecture-strategist agentedge-performance-oracle agentcloudflare-architecture-strategist agentnewUniqueId when idFromName is appropriate// ❌ Critical: New DO for every request (expensive and wrong)
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
// Creates new DO instance for every request!
const id = env.USER_SESSION.newUniqueId();
const stub = env.USER_SESSION.get(id);
return stub.fetch(request);
}
}
// ✅ Correct: Reuse DO for same entity
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
// Reuse same DO for this user
const id = env.USER_SESSION.idFromName(userId);
const stub = env.USER_SESSION.get(id);
return stub.fetch(request);
}
}
// ❌ High: DO never hibernates (wastes resources)
export class ChatRoom {
constructor(state, env) {
this.state = state;
this.env = env;
this.messages = [];
}
async fetch(request) {
// Handle chat messages...
// But never hibernates - stays in memory forever!
}
}
// ✅ Correct: Implement hibernation
export class ChatRoom {
constructor(state, env) {
this.state = state;
this.env = env;
// Load persisted state
this.loadState();
// Set alarm for hibernation after inactivity
this.resetHibernationTimer();
}
async loadState() {
const messages = await this.state.storage.get('messages');
this.messages = messages || [];
}
resetHibernationTimer() {
// Reset alarm for 30 seconds from now
this.state.storage.setAlarm(Date.now() + 30000);
}
async fetch(request) {
// Reset timer on activity
this.resetHibernationTimer();
// Handle chat messages...
return new Response('Message processed');
}
async alarm() {
// Persist state before hibernation
await this.state.storage.put('messages', this.messages);
// DO will hibernate after this method returns
}
}
// ❌ High: Using newUniqueId for named resources
export default {
async fetch(request: Request, env: Env) {
const roomId = new URL(request.url).searchParams.get('room');
// Wrong: Creates new DO for same room name
const id = env.CHAT_ROOM.newUniqueId();
const stub = env.CHAT_ROOM.get(id);
return stub.fetch(request);
}
}
// ✅ Correct: Use idFromName for named resources
export default {
async fetch(request: Request, env: Env) {
const roomId = new URL(request.url).searchParams.get('room');
// Correct: Same DO for same room name
const id = env.CHAT_ROOM.idFromName(roomId);
const stub = env.CHAT_ROOM.get(id);
return stub.fetch(request);
}
}
// ❌ Critical: State not persisted (lost on hibernation)
export class Counter {
constructor(state, env) {
this.state = state;
this.count = 0; // Not persisted!
}
async fetch(request) {
if (request.url.endsWith('/increment')) {
this.count++; // Lost when DO hibernates!
return new Response(`Count: ${this.count}`);
}
}
}
// ✅ Correct: Persist state to storage
export class Counter {
constructor(state, env) {
this.state = state;
}
async fetch(request) {
if (request.url.endsWith('/increment')) {
// Persist to storage
const currentCount = (await this.state.storage.get('count')) || 0;
const newCount = currentCount + 1;
await this.state.storage.put('count', newCount);
return new Response(`Count: ${newCount}`);
}
if (request.url.endsWith('/get')) {
const count = await this.state.storage.get('count') || 0;
return new Response(`Count: ${count}`);
}
}
}
// ❌ High: Using DO for stateless operation (overkill)
export default {
async fetch(request: Request, env: Env) {
// Using DO for simple API call - unnecessary!
const id = env.API_PROXY.newUniqueId();
const stub = env.API_PROXY.get(id);
return stub.fetch(request);
}
}
// ✅ Correct: Handle stateless operations in Worker
export default {
async fetch(request: Request, env: Env) {
// Simple API call - handle directly in Worker
const response = await fetch('https://api.example.com/data');
return response;
}
}
// ✅ Correct: Use DO for actual stateful coordination
export default {
async fetch(request: Request, env: Env) {
const ip = request.headers.get('CF-Connecting-IP');
// Rate limiting needs state - perfect for DO
const id = env.RATE_LIMITER.idFromName(ip);
const stub = env.RATE_LIMITER.get(id);
return stub.fetch(request);
}
}
When Cloudflare MCP server is available:
// Developer types: const id = env.MY_DO.newUniqueId();
// SKILL immediately activates: "⚠️ HIGH: Using newUniqueId for every request. Consider idFromName for named resources or if this should be stateless."
// Developer types: this.count = 0; in constructor
// SKILL immediately activates: "❌ CRITICAL: State not persisted to storage. Use this.state.storage.put() to persist data."
// Developer types: DO without alarm() method
// SKILL immediately activates: "⚠️ HIGH: Durable Object missing hibernation. Add alarm() method and setAlarm() for resource efficiency."
This SKILL ensures Durable Objects are used correctly by providing immediate, autonomous validation of DO patterns, preventing common mistakes and ensuring efficient state management.
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.