Install any skill in seconds. Free to start, no credit card required.
Get Started Free →INVOKE THIS SKILL when your Deep Agent needs memory, persistence, or filesystem access. Covers StateBackend (ephemeral), StoreBackend (persistent), FilesystemMiddleware, and CompositeBackend for routing.
.claude/skills/bilal140202-deep-agents-memory/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 1% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 34% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 83% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 21% | 0% |
<overview> Deep Agents use pluggable backends for file operations and memory:
Short-term (StateBackend): Persists within a single thread, lost when thread ends Long-term (StoreBackend): Persists across threads and sessions Hybrid (CompositeBackend): Route different paths to different backends
FilesystemMiddleware provides tools: ls, read_file, write_file, edit_file, glob, grep </overview>
<backend-selection>
| Use Case | Backend | Why | |----------|---------|-----| | Temporary working files | StateBackend | Default, no setup | | Local development CLI | FilesystemBackend | Direct disk access | | Cross-session memory | StoreBackend | Persists across threads | | Hybrid storage | CompositeBackend | Mix ephemeral + persistent |
</backend-selection>
<ex-default-state-backend> <python> Default StateBackend stores files ephemerally within a thread.
pythonfrom deepagents import create_deep_agent agent = create_deep_agent() # Default: StateBackend result = agent.invoke({ "messages": [{"role": "user", "content": "Write notes to /draft.txt"}] }, config={"configurable": {"thread_id": "thread-1"}}) # /draft.txt is lost when thread ends
</python> <typescript> Default StateBackend stores files ephemerally within a thread.
typescriptimport { createDeepAgent } from "deepagents"; const agent = await createDeepAgent(); // Default: StateBackend const result = await agent.invoke({ messages: [{ role: "user", content: "Write notes to /draft.txt" }] }, { configurable: { thread_id: "thread-1" } }); // /draft.txt is lost when thread ends
</typescript> </ex-default-state-backend>
<ex-composite-backend-for-hybrid> <python> Configure CompositeBackend to route paths to different storage backends.
pythonfrom deepagents import create_deep_agent from deepagents.backends import CompositeBackend, StateBackend, StoreBackend from langgraph.store.memory import InMemoryStore store = InMemoryStore() composite_backend = lambda rt: CompositeBackend( default=StateBackend(rt), routes={"/memories/": StoreBackend(rt)} ) agent = create_deep_agent(backend=composite_backend, store=store) # /draft.txt -> ephemeral (StateBackend) # /memories/user-prefs.txt -> persistent (StoreBackend)
</python> <typescript> Configure CompositeBackend to route paths to different storage backends.
typescriptimport { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents"; import { InMemoryStore } from "@langchain/langgraph"; const store = new InMemoryStore(); const agent = await createDeepAgent({ backend: (config) => new CompositeBackend( new StateBackend(config), { "/memories/": new StoreBackend(config) } ), store }); // /draft.txt -> ephemeral (StateBackend) // /memories/user-prefs.txt -> persistent (StoreBackend)
</typescript> </ex-composite-backend-for-hybrid>
<ex-cross-session-memory> <python> Files in /memories/ persist across threads via StoreBackend routing.
python# Using CompositeBackend from previous example config1 = {"configurable": {"thread_id": "thread-1"}} agent.invoke({"messages": [{"role": "user", "content": "Save to /memories/style.txt"}]}, config=config1) config2 = {"configurable": {"thread_id": "thread-2"}} agent.invoke({"messages": [{"role": "user", "content": "Read /memories/style.txt"}]}, config=config2) # Thread 2 can read file saved by Thread 1
</python> <typescript> Files in /memories/ persist across threads via StoreBackend routing.
typescript// Using CompositeBackend from previous example const config1 = { configurable: { thread_id: "thread-1" } }; await agent.invoke({ messages: [{ role: "user", content: "Save to /memories/style.txt" }] }, config1); const config2 = { configurable: { thread_id: "thread-2" } }; await agent.invoke({ messages: [{ role: "user", content: "Read /memories/style.txt" }] }, config2); // Thread 2 can read file saved by Thread 1
</typescript> </ex-cross-session-memory>
<ex-filesystem-backend-local-dev> <python> Use FilesystemBackend for local development with real disk access and human-in-the-loop.
pythonfrom deepagents import create_deep_agent from deepagents.backends import FilesystemBackend from langgraph.checkpoint.memory import MemorySaver agent = create_deep_agent( backend=FilesystemBackend(root_dir=".", virtual_mode=True), # Restrict access interrupt_on={"write_file": True, "edit_file": True}, checkpointer=MemorySaver() ) # Agent can read/write actual files on disk
</python> <typescript> Use FilesystemBackend for local development with real disk access and human-in-the-loop.
typescriptimport { createDeepAgent, FilesystemBackend } from "deepagents"; import { MemorySaver } from "@langchain/langgraph"; const agent = await createDeepAgent({ backend: new FilesystemBackend({ rootDir: ".", virtualMode: true }), interruptOn: { write_file: true, edit_file: true }, checkpointer: new MemorySaver() });
</typescript>
Security: Never use FilesystemBackend in web servers - use StateBackend or sandbox instead. </ex-filesystem-backend-local-dev>
<ex-store-in-custom-tools> <python> Access the store directly in custom tools for long-term memory operations.
pythonfrom langchain.tools import tool, ToolRuntime from langchain.agents import create_agent from langgraph.store.memory import InMemoryStore @tool def get_user_preference(key: str, runtime: ToolRuntime) -> str: """Get a user preference from long-term storage.""" store = runtime.store result = store.get(("user_prefs",), key) return str(result.value) if result else "Not found" @tool def save_user_preference(key: str, value: str, runtime: ToolRuntime) -> str: """Save a user preference to long-term storage.""" store = runtime.store store.put(("user_prefs",), key, {"value": value}) return f"Saved {key}={value}" store = InMemoryStore() agent = create_agent( model="gpt-4.1", tools=[get_user_preference, save_user_preference], store=store )
</python> </ex-store-in-custom-tools>
<boundaries>
</boundaries>
<fix-storebackend-requires-store> <python> StoreBackend requires a store instance.
python# WRONG agent = create_deep_agent(backend=lambda rt: StoreBackend(rt)) # CORRECT agent = create_deep_agent(backend=lambda rt: StoreBackend(rt), store=InMemoryStore())
</python> <typescript> StoreBackend requires a store instance.
typescript// WRONG const agent = await createDeepAgent({ backend: (c) => new StoreBackend(c) }); // CORRECT const agent = await createDeepAgent({ backend: (c) => new StoreBackend(c), store: new InMemoryStore() });
</typescript> </fix-storebackend-requires-store>
<fix-statebackend-files-dont-persist> <python> StateBackend files are thread-scoped - use same thread_id or StoreBackend for cross-thread access.
python# WRONG: thread-2 can't read file from thread-1 agent.invoke({"messages": [...]}, config={"configurable": {"thread_id": "thread-1"}}) # Write agent.invoke({"messages": [...]}, config={"configurable": {"thread_id": "thread-2"}}) # File not found!
</python> <typescript> StateBackend files are thread-scoped - use same thread_id or StoreBackend for cross-thread access.
typescript// WRONG: thread-2 can't read file from thread-1 await agent.invoke({ messages: [...] }, { configurable: { thread_id: "thread-1" } }); // Write await agent.invoke({ messages: [...] }, { configurable: { thread_id: "thread-2" } }); // File not found!
</typescript> </fix-statebackend-files-dont-persist>
<fix-path-prefix-for-persistence> <python> Path must match CompositeBackend route prefix for persistence.
python# With routes={"/memories/": StoreBackend(rt)}: agent.invoke(...) # /prefs.txt -> ephemeral (no match) agent.invoke(...) # /memories/prefs.txt -> persistent (matches route)
</python> <typescript> Path must match CompositeBackend route prefix for persistence.
typescript// With routes: { "/memories/": StoreBackend }: await agent.invoke(...); // /prefs.txt -> ephemeral (no match) await agent.invoke(...); // /memories/prefs.txt -> persistent (matches route)
</typescript> </fix-path-prefix-for-persistence>
<fix-production-store> <python> Use PostgresStore for production (InMemoryStore lost on restart).
python# WRONG # CORRECT store = InMemoryStore() store = PostgresStore(connection_string="postgresql://...")
</python> <typescript> Use PostgresStore for production (InMemoryStore lost on restart).
typescript// WRONG // CORRECT const store = new InMemoryStore(); const store = new PostgresStore({ connectionString: "..." });
</typescript> </fix-production-store>
<fix-filesystem-backend-needs-virtual-mode> <python> Enable virtual_mode=True to restrict path access (prevents ../ and ~/ escapes).
pythonbackend = FilesystemBackend(root_dir="/project", virtual_mode=True) # Secure
</python> </fix-filesystem-backend-needs-virtual-mode>
<fix-longest-prefix-match> <python> CompositeBackend matches longest prefix first.
pythonroutes = {"/mem/": StoreBackend(rt), "/mem/temp/": StateBackend(rt)} # /mem/file.txt -> StoreBackend, /mem/temp/file.txt -> StateBackend (longer match)
</python> </fix-longest-prefix-match>
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 18,763 | 8,749 | -53% | 1 | 1 | 0% | 3,862 | 4,309 | +12% | 0 | 0 | — |
case-02 | fail→pass | 19,661 | 7,016 | -64% | 1 | 1 | 0% | 3,878 | 3,909 | +1% | 0 | 0 | — |
case-03 | fail→pass | 14,715 | 5,656 | -62% | 1 | 1 | 0% | 2,813 | 3,758 | +34% | 0 | 0 | — |
case-04 | fail→pass | 9,697 | 4,034 | -58% | 1 | 1 | 0% | 1,802 | 3,298 | +83% | 0 | 0 | — |
case-05 | fail→pass | 16,654 | 6,916 | -58% | 1 | 1 | 0% | 3,223 | 3,889 | +21% | 0 | 0 | — |
case-06 | fail→pass | 13,109 | 6,092 | -54% | 1 | 1 | 0% | 2,302 | 3,665 | +59% | 0 | 0 | — |
case-07 | pass→pass | 16,823 | 8,767 | -48% | 1 | 1 | 0% | 2,874 | 4,304 | +50% | 0 | 0 | — |
case-08 | pass→pass | 5,719 | 3,381 | -41% | 1 | 1 | 0% | 966 | 3,221 | +233% | 0 | 0 | — |
case-09 | fail→pass | 11,465 | 6,781 | -41% | 1 | 1 | 0% | 2,035 | 3,985 | +96% | 0 | 0 | — |
case-10 | pass→pass | 6,855 | 5,634 | -18% | 1 | 1 | 0% | 1,270 | 3,745 | +195% | 0 | 0 | — |
case-11 | pass→pass | 14,282 | 9,938 | -30% | 1 | 1 | 0% | 2,401 | 4,355 | +81% | 0 | 0 | — |
case-12 | fail→pass | 8,481 | 2,547 | -70% | 1 | 1 | 0% | 1,398 | 3,070 | +120% | 0 | 0 | — |
case-13 | pass→pass | 6,388 | 4,211 | -34% | 1 | 1 | 0% | 1,291 | 3,414 | +164% | 0 | 0 | — |
case-14 | pass→pass | 6,049 | 5,052 | -16% | 1 | 1 | 0% | 1,043 | 3,678 | +253% | 0 | 0 | — |
case-15 | pass→pass | 9,253 | 4,222 | -54% | 1 | 1 | 0% | 1,643 | 3,295 | +101% | 0 | 0 | — |
case-16 | fail→pass | 8,435 | 4,197 | -50% | 1 | 1 | 0% | 1,634 | 3,384 | +107% | 0 | 0 | — |
case-17 | pass→pass | 15,792 | 4,672 | -70% | 1 | 1 | 0% | 2,789 | 3,561 | +28% | 0 | 0 | — |
case-18 | pass→pass | 15,131 | 3,584 | -76% | 1 | 1 | 0% | 2,630 | 3,343 | +27% | 0 | 0 | — |
case-19 | pass→pass | 7,852 | 3,716 | -53% | 1 | 1 | 0% | 1,420 | 3,244 | +128% | 0 | 0 | — |
case-20 | pass→pass | 10,754 | 8,703 | -19% | 1 | 1 | 0% | 2,432 | 4,591 | +89% | 0 | 0 | — |
case-21 | pass→pass | 11,591 | 7,529 | -35% | 1 | 1 | 0% | 2,201 | 4,181 | +90% | 0 | 0 | — |
case-22 | pass→pass | 6,617 | 5,345 | -19% | 1 | 1 | 0% | 1,245 | 3,665 | +194% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.