durable-state-patterns
Implement persistent agent state that survives failures and restarts. Use this skill when building stateful agents, implementing checkpointing, persisting agent memory across sessions, or recovering from failures. Activate when: durable state, agent persistence, checkpointing, agent recovery, stateful agents, state persistence, cross-session memory, agent restart.
What this skill does
# Durable State Patterns
**Build agents that remember state across failures, restarts, and sessions.**
## Why Durable State?
Without durability:
- Long-running agents lose progress on crash
- Users can't resume conversations after timeout
- No audit trail of agent decisions
- Expensive recomputation on every restart
With durability:
- Resume from any checkpoint
- Survive infrastructure failures
- Debug by replaying history
- Share state across instances
## LangGraph Checkpointing
### Basic Setup
```python
from langgraph.graph import StateGraph
from langgraph.checkpoint.memory import MemorySaver
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.checkpoint.postgres import PostgresSaver
# In-memory (development only)
memory_checkpointer = MemorySaver()
# SQLite (single instance)
sqlite_checkpointer = SqliteSaver.from_conn_string("checkpoints.db")
# PostgreSQL (production, multi-instance)
postgres_checkpointer = PostgresSaver.from_conn_string(
"postgresql://user:pass@localhost/db"
)
# Compile with checkpointer
app = workflow.compile(checkpointer=postgres_checkpointer)
```
### Thread-Based State
```python
from uuid import uuid4
# Each conversation gets a unique thread_id
thread_id = str(uuid4())
# First invocation
config = {"configurable": {"thread_id": thread_id}}
result1 = app.invoke(
{"messages": [{"role": "user", "content": "My name is Alice"}]},
config
)
# Later invocation (same thread = same state)
result2 = app.invoke(
{"messages": [{"role": "user", "content": "What's my name?"}]},
config
)
# Agent remembers: "Your name is Alice"
# Different thread = fresh state
other_config = {"configurable": {"thread_id": str(uuid4())}}
result3 = app.invoke(
{"messages": [{"role": "user", "content": "What's my name?"}]},
other_config
)
# Agent doesn't know: "I don't have that information"
```
## State Schema Design
### Versioned State
```python
from typing import TypedDict, Annotated
import operator
class AgentStateV1(TypedDict):
"""Version 1 of agent state."""
messages: Annotated[list, operator.add]
user_id: str
class AgentStateV2(TypedDict):
"""Version 2 with preferences."""
messages: Annotated[list, operator.add]
user_id: str
preferences: dict # New field
state_version: int # Track version
def migrate_v1_to_v2(old_state: AgentStateV1) -> AgentStateV2:
"""Migrate old state to new schema."""
return {
**old_state,
"preferences": {}, # Default value
"state_version": 2
}
```
### Separate Concerns
```python
class ConversationState(TypedDict):
"""Short-term: current conversation."""
messages: Annotated[list, operator.add]
current_task: str
class UserProfileState(TypedDict):
"""Long-term: persists across conversations."""
user_id: str
name: str
preferences: dict
history_summary: str
class FullAgentState(TypedDict):
"""Combined state."""
conversation: ConversationState
profile: UserProfileState
```
## Memory Tiers
```
┌─────────────────────────────────────────────────────────────┐
│ Memory Architecture │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Working Memory (In-Graph) │ │
│ │ Current messages, tool results, intermediate │ │
│ │ Lifetime: Single invocation │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Short-Term Memory (Thread) │ │
│ │ Conversation history, session context │ │
│ │ Lifetime: Single conversation/session │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Long-Term Memory (User/Entity) │ │
│ │ User preferences, facts, relationship history │ │
│ │ Lifetime: Permanent │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
### Implementation
```python
import redis
from datetime import datetime
class ThreeTierMemory:
"""Three-tier memory system."""
def __init__(self, redis_client: redis.Redis, checkpointer):
self.redis = redis_client # Short-term
self.checkpointer = checkpointer # Working memory via LangGraph
self.db = PostgresDB() # Long-term
# Working memory: handled by LangGraph state
# Short-term: Redis with TTL
def get_session(self, session_id: str) -> dict:
data = self.redis.get(f"session:{session_id}")
return json.loads(data) if data else {}
def save_session(self, session_id: str, data: dict, ttl: int = 3600):
self.redis.setex(
f"session:{session_id}",
ttl,
json.dumps(data)
)
# Long-term: Persistent database
def get_user_profile(self, user_id: str) -> dict:
return self.db.query(
"SELECT * FROM user_profiles WHERE user_id = %s",
(user_id,)
)
def update_user_profile(self, user_id: str, updates: dict):
self.db.execute(
"UPDATE user_profiles SET data = data || %s WHERE user_id = %s",
(json.dumps(updates), user_id)
)
```
## Checkpoint Management
### Manual Checkpoints
```python
from langgraph.checkpoint import Checkpoint
# Get current checkpoint
checkpoint = app.get_state(config)
print(f"Checkpoint ID: {checkpoint.config['configurable']['checkpoint_id']}")
print(f"State: {checkpoint.values}")
# List all checkpoints for a thread
history = list(app.get_state_history(config))
for checkpoint in history:
print(f"{checkpoint.config['configurable']['checkpoint_id']}: {checkpoint.values}")
# Rewind to specific checkpoint
old_checkpoint_id = "some-checkpoint-id"
rewound_config = {
"configurable": {
"thread_id": thread_id,
"checkpoint_id": old_checkpoint_id
}
}
result = app.invoke(new_input, rewound_config)
```
### Checkpoint Cleanup
```python
async def cleanup_old_checkpoints(
checkpointer,
max_age_days: int = 30
):
"""Clean up checkpoints older than max_age_days."""
cutoff = datetime.now() - timedelta(days=max_age_days)
# Implementation depends on checkpointer
# For Postgres:
await checkpointer.conn.execute(
"DELETE FROM checkpoints WHERE created_at < $1",
cutoff
)
```
## Recovery Patterns
### Automatic Retry
```python
from tenacity import retry, stop_after_attempt, wait_exponential
class ResilientAgent:
def __init__(self, app, checkpointer):
self.app = app
self.checkpointer = checkpointer
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10)
)
async def invoke_with_retry(self, input_state: dict, config: dict):
"""Invoke with automatic retry on failure."""
try:
return await self.app.ainvoke(input_state, config)
except Exception as e:
# State is already checkpointed, will resume on retry
logger.error(f"Invocation failed, retrying: {e}")
raise
```
### Resume from Failure
```python
async def resume_or_start(
app,
thread_id: str,
input_state: dict
) -> dict:
"""Resume existing thread or start new one."""
config = {"configurable": {"Related in AI Agents
skill-development
IncludedComprehensive meta-skill for creating, managing, validating, auditing, and distributing Claude Code skills and slash commands (unified in v2.1.3+). Provides skill templates, creation workflows, validation patterns, audit checklists, naming conventions, YAML frontmatter guidance, progressive disclosure examples, and best practices lookup. Use when creating new skills, validating existing skills, auditing skill quality, understanding skill architecture, needing skill templates, learning about YAML frontmatter requirements, progressive disclosure patterns, tool restrictions (allowed-tools), skill composition, skill naming conventions, troubleshooting skill activation issues, creating custom slash commands, configuring command frontmatter, using command arguments ($ARGUMENTS, $1, $2), bash execution in commands, file references in commands, command namespacing, plugin commands, MCP slash commands, Skill tool configuration, or deciding between skills vs slash commands. Delegates to docs-management skill for official documentation.
reprompter
IncludedTransform messy prompts into well-structured, effective prompts — single or multi-agent. Use when: "reprompt", "reprompt this", "clean up this prompt", "structure my prompt", rough text needing XML tags and best practices, "reprompter teams", "repromptception", "run with quality", "smart run", "smart agents", multi-agent tasks, audits, parallel work, anything going to agent teams. Don't use when: simple Q&A, pure chat, immediate execution-only tasks. See "Don't Use When" section for details. Outputs: Structured XML/Markdown prompt, quality score (before/after), optional team brief + per-agent sub-prompts, agent team output files. Success criteria: Single mode quality score ≥ 7/10; Repromptception per-agent prompt quality score 8+/10; all required sections present, actionable and specific.
adaptive-compaction
IncludedAdaptive add-on policy and recovery layer that decides WHEN to compact, prune, snapshot, or fork -- replacing fixed-percent auto-compaction across Claude Code, Codex, and MCP-capable hosts. Trigger on auto-compact timing or damage: "when should I compact", "is it safe to compact now or start a fresh session", "auto-compact fires too early/mid-task", "switching to an unrelated task but the window still has space", "context rot", "answers get worse the longer the session runs", "the agent forgot the plan or my decisions after it summarized", "add a layer on top that manages context without changing the agent", raising autoCompactWindow to give the policy room, or installing/tuning a cross-tool compaction policy or PreCompact hook -- even when "compaction" is never said but the problem is context-window pressure or post-summarization memory loss. Do NOT use to summarize a conversation, build RAG, write a summarization prompt (decides WHEN not HOW), or answer max-context-length trivia.
agent-skill-creator
IncludedCreate cross-platform agent skills from workflow descriptions. Activates when users ask to create an agent, automate a repetitive workflow, create a custom skill, or need advanced agent creation. Triggers on phrases like create agent for, automate workflow, create skill for, every day I have to, daily I need to, turn process into agent, need to automate, create a cross-platform skill, validate this skill, export this skill, migrate this skill. Supports single skills, multi-agent suites, transcript processing, template-based creation, interactive configuration, cross-platform export, and spec validation.
llm-wiki
IncludedUse when building or maintaining a persistent personal knowledge base (second brain) in Obsidian where an LLM incrementally ingests sources, updates entity/concept pages, maintains cross-references, and keeps a synthesis current. Triggers include "second brain", "Obsidian wiki", "personal knowledge management", "ingest this paper/article/book", "build a research wiki", "compound knowledge", "Memex", or whenever the user wants knowledge to accumulate across sessions instead of being re-derived by RAG on every query.
skill-master
IncludedAgent Skills authoring, evaluation, and optimization. Create, edit, validate, benchmark, and improve skills following the agentskills.io specification. Use when designing SKILL.md files, structuring skill folders (references, scripts, assets), ingesting external documentation into skills, running trigger evals, benchmarking skill quality, optimizing descriptions, or performing blind A/B comparisons. Keywords: agentskills.io, SKILL.md, skill authoring, eval, benchmark, trigger optimization.