Skip to main content
As agents take on more complex tasks, the context they need grows with them. Loading all instructions into the system prompt wastes tokens on information irrelevant to the current task, and providing the same guidance manually across sessions does not scale. Skills solve this by packaging domain expertise, such as workflows, best practices, scripts, reference docs, and templates, into reusable directories. The agent gets a summary of the contents on startup and discovers and reads the contained files only when relevant. Deep agent skills follow the Agent Skills specification.
For ready-to-use skills that improve your agent’s performance on LangChain ecosystem tasks, see the LangChain Skills repository.

What are skills

Each skill is a directory containing a SKILL.md file: a markdown file with YAML frontmatter (name and description) followed by instructions the agent follows when the skill is activated. A skill directory can also include supporting files such as scripts, reference docs, and templates.
skills/
└── langgraph-docs/
    └── SKILL.md
The SKILL.md starts with YAML frontmatter followed by markdown instructions:
---
name: langgraph-docs
description: Use this skill for requests related to LangGraph in order to fetch relevant documentation to provide accurate, up-to-date guidance.
---

# langgraph-docs

## Overview

This skill explains how to access LangGraph documentation to help answer questions and guide implementation.

## Instructions

### 1. Fetch the documentation index

Use the fetch_url tool to read the following URL:
https://docs.langchain.com/llms.txt

This provides a structured list of all available documentation with descriptions.

### 2. Select relevant documentation

Based on the question, identify 2-4 most relevant documentation URLs from the index. Prioritize:

- Specific how-to guides for implementation questions
- Core concept pages for understanding questions
- Tutorials for end-to-end examples
- Reference docs for API details

### 3. Fetch and synthesize

Use the fetch_url tool to read the selected documentation URLs, then answer the user's question. Give a direct answer first, include the minimum necessary context, and link to the source pages rather than quoting long passages.
Reference any supporting files in your SKILL.md with a description of what each file contains and when to use it. The agent discovers these files through the references in the skill instructions.
Skills use progressive disclosure: the agent loads skill information in layers, pulling in more detail only when the task calls for it. In Deep Agents, SkillsMiddleware handles this in three stages:
  1. Discovery: At agent start, the middleware scans the configured skill paths, parses each SKILL.md frontmatter, and injects skill names and descriptions into the system prompt.
  2. Read: When the agent determines a skill matches the current task, it reads the full SKILL.md content via read_file. There is no dedicated activation mechanism.
  3. Execute: The agent follows the skill’s instructions and reads any supporting files (scripts, references, assets) as needed.
The Agent Skills specification recommends keeping frontmatter concise and the SKILL.md body under 5,000 tokens. Following these guidelines matters because every skill’s frontmatter is added to the system prompt at discovery, while the full body is only read when activated. Keeping both layers small means you can load many skills without crowding the context window.
Write clear, specific descriptions in your SKILL.md frontmatter. The agent decides whether to activate a skill based on the description alone. Include specific keywords and use cases so the agent can match accurately.

Usage

Create a top level skills directory. Then create a directory inside that with a SKILL.md file for your first skill. Finally, pass the path to the top level skills directory when creating your agent:
from deepagents import create_deep_agent
from deepagents.backends.filesystem import FilesystemBackend

backend = FilesystemBackend(root_dir="./my-project")

agent = create_deep_agent(
    model="anthropic:claude-sonnet-4-6",
    backend=backend,
    skills=["./my-project/skills/"],
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What is LangGraph?"}]},
    config={"configurable": {"thread_id": "1"}},
)
This example uses FilesystemBackend to load skills from disk. For other storage options, including loading skills from remote sources, see Backends and remote skill loading.
skills
list[str]
List of skill source paths.Paths must be specified using forward slashes and are relative to the backend’s root.
  • If omitted, no skills are loaded.
  • When using StateBackend (default), provide skill files with invoke(files={...}). Use create_file_data() from deepagents.backends.utils to format file contents; raw strings are not supported.
  • With FilesystemBackend, skills are loaded from disk relative to the backend’s root_dir.
Later sources override earlier ones for skills with the same name (last one wins).
When multiple skill sources contain a skill with the same name, the skill from the source listed later in the skills array takes precedence (last one wins). This lets you layer skills from different origins, such as base skills overridden by project-specific versions.

Write effective skills

The Agent Skills specification includes guidance on structuring skills for reliable discovery and activation. The following recommendations build on that foundation with practical patterns for Deep Agents. Write specific descriptions. During discovery, the description field is the only information the agent sees for each skill. A good description tells the agent both what the skill does and when to activate it, with specific keywords the agent can match against:
# Good: specific about what and when
description: >-
  Extract text and tables from PDF files, fill PDF forms, and merge
  multiple PDFs. Use when working with PDF documents or when the user
  mentions PDFs, forms, or document extraction.

# Poor: too vague for reliable matching
description: Helps with PDFs.
When you have multiple skills in related domains, differentiate their descriptions clearly. Overlapping descriptions cause the agent to activate the wrong skill or hesitate between options. If two skills serve similar purposes, consolidate them into one. Keep instructions focused. The Agent Skills specification recommends keeping your SKILL.md under 500 lines. When instructions grow longer, move detailed reference material into separate files and reference them from the main SKILL.md:
skills/
└── data-pipeline/
    ├── SKILL.md
    └── references/
        ├── schema-reference.md
        └── error-codes.md
The agent loads reference files only when the instructions call for them, keeping each layer of progressive disclosure appropriately sized. Keep file references one level deep from SKILL.md and avoid deeply nested reference chains, which force the agent through multiple reads to reach the information it needs. Structure instructions for the agent. Write your SKILL.md body as clear instructions the agent can follow:
  • Step-by-step procedures for multi-step workflows
  • Decision criteria for choosing between approaches
  • Examples of expected inputs and outputs so the agent knows what success looks like
  • Edge cases the agent should handle or flag to the user
Manage skill count. Fewer well-scoped skills outperform many overlapping ones. As the number of skills with similar descriptions grows, the agent’s ability to select the right one degrades. If you find yourself with many related skills, consider:
  • Consolidating related capabilities into a single skill with sections for each sub-task
  • Using reference files to keep the main SKILL.md concise while covering multiple sub-tasks
Use the skills-ref validation tool to check that your SKILL.md frontmatter follows the Agent Skills specification naming and format conventions.

Backends and remote skill loading

Deep Agents supports different backends depending on how you want to store and manage skill files:
  • StateBackend: Stores files in LangGraph agent state for the current thread.
  • StoreBackend: Stores files in a LangGraph store for durable, cross-thread storage.
  • FilesystemBackend: Reads and writes skill files from disk under a configurable root_dir.
from urllib.request import urlopen
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.backends.utils import create_file_data
from langchain_quickjs import CodeInterpreterMiddleware
from langgraph.checkpoint.memory import MemorySaver

checkpointer = MemorySaver()
backend = StateBackend()

skill_url = "https://raw.githubusercontent.com/langchain-ai/deepagents/refs/heads/main/libs/cli/examples/skills/langgraph-docs/SKILL.md"
with urlopen(skill_url) as response:
    skill_content = response.read().decode('utf-8')

skills_files = {
    "/skills/langgraph-docs/SKILL.md": create_file_data(skill_content),
}

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    backend=backend,
    skills=["/skills/"],
    checkpointer=checkpointer,
    middleware=[CodeInterpreterMiddleware(skills_backend=backend)], # for interpreter skills
)

result = agent.invoke(
    {
        "messages": [{"role": "user", "content": "What is langgraph?"}],
        # Seed the default StateBackend's in-state filesystem (virtual paths must start with "/").
        "files": skills_files,
    },
    config={"configurable": {"thread_id": "12345"}},
)

Load skills at runtime

When you have a large collection of skills but only a subset is relevant for a given run, select which skills to load based on runtime context such as user role, tenant, or request type. There are two main approaches:

Dynamic skill lists

The simplest approach is to construct the skills array before creating the agent. Choose which skill paths to include based on whatever runtime context you have:
from deepagents import create_deep_agent

SKILLS_BY_ROLE = {
    "engineering": ["/skills/code-review/", "/skills/testing/", "/skills/deployment/"],
    "data": ["/skills/sql-analysis/", "/skills/visualization/", "/skills/data-pipeline/"],
    "support": ["/skills/ticket-triage/", "/skills/runbook/"],
}

def create_agent_for_user(user_role: str):
    return create_deep_agent(
        model="anthropic:claude-sonnet-4-6",
        skills=SKILLS_BY_ROLE.get(user_role, []),
    )
This works well when skills live on disk or in a shared backend and you just need to control which ones the agent sees. The skills themselves are not duplicated — you maintain one copy and vary the paths passed to each run.

Namespaced skills

For multi-tenant applications where each user’s skill set is managed independently, route /skills/ to a StoreBackend with a namespace factory. Populate each namespace with only the skills that user should have access to, and the middleware resolves to the correct set at runtime:
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    model="anthropic:claude-sonnet-4-6",
    skills=["/skills/"],
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/skills/": StoreBackend(
                namespace=lambda rt: (
                    rt.server_info.assistant_id,
                    rt.server_info.user.identity,
                ),
            ),
        },
    ),
)
This pattern is useful when different users or tenants need fully independent skill libraries that can be updated separately. For a managed solution that handles skill access, sharing, and workspace-level visibility out of the box, see Fleet skills.

Skills for subagents

When you use subagents, you can configure which skills each type has access to:
  • General-purpose subagent: Automatically inherits skills from the main agent when you pass skills to create_deep_agent. No additional configuration is needed.
  • Custom subagents: Do not inherit the main agent’s skills. Add a skills parameter to each subagent definition with that subagent’s skill source paths.
Skill state is fully isolated: the main agent’s skills are not visible to subagents, and subagent skills are not visible to the main agent.
from deepagents import create_deep_agent

research_subagent = {
    "name": "researcher",
    "description": "Research assistant with specialized skills",
    "system_prompt": "You are a researcher.",
    "tools": [web_search],
    "skills": ["/skills/research/", "/skills/web-search/"],  # Subagent-specific skills
}

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    skills=["/skills/main/"],  # Main agent and GP subagent get these
    subagents=[research_subagent],  # Researcher gets only its own skills
)
For more information on subagent configuration and skills inheritance, see Subagents.

Skill permissions

By default, agents can write to skill files if the backend permits it. Use these mechanisms to control that behavior:
  • Read-only skills: Use filesystem permissions to deny write operations under skill paths.
  • Scoped permissions: Allow writes to user-scoped skill paths while keeping workspace or shared skills read-only, so agents can personalize their own skills without modifying shared ones.
  • Human-in-the-loop: Use interrupt_on to require approval before the agent executes write operations, adding a review step without fully blocking writes.

Read-only skills

A common production pattern is to give agents access to a curated skills library without allowing them to change it. Route /skills/ to a shared StoreBackend, pass that route in skills, and deny write operations under /skills/** with filesystem permissions. The agent can discover and read skills, while only your application code or an admin workflow updates the store.
from deepagents import FilesystemPermission, create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()  # Good for local dev; omit for LangSmith Deployment

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/skills/": StoreBackend(
                namespace=lambda rt: ("curated-skills", rt.context.org_id),
            ),
        },
    ),
    skills=["/skills/"],
    permissions=[
        FilesystemPermission(
            operations=["write"],
            paths=["/skills/**"],
            mode="deny",
        ),
    ],
    store=store,
)
Seed the store under the same namespace with keys like /company-policies/SKILL.md and values that include content and encoding fields. The /skills/ route prefix is stripped before records are read from the store. Use this for enterprise knowledge bases, approved tool instructions, or shared skill packs where the agent should benefit from centrally managed context but should not rewrite the source of truth. If you want agents to save their own learnings, route a separate path such as /memories/ to another backend with write permissions enabled. See Backends for routing and store setup.

Execute code with skills

Without code execution, skills are passive: the agent reads instructions and follows them using its available tools. Code execution turns skills into active capabilities. A skill can ship a tested script that calls an API, transforms data, validates output, or runs a pipeline — and the agent executes it deterministically rather than regenerating the logic from instructions each time. This is especially valuable for workflows that require exact behavior (data transformations, API integrations, compliance checks) or that depend on libraries the agent cannot use through tool calls alone. Skills support code execution in two ways:
  • Sandbox scripts when the agent needs to install dependencies, run tests, call CLIs, or work with an operating-system filesystem.
  • Interpreter skills when the agent needs reusable, importable helpers available from interpreter code.

Sandbox scripts

Skills can include scripts alongside the SKILL.md file. Reference scripts in your SKILL.md so the agent knows they exist and when to run them:
skills/
└── arxiv-search/
    ├── SKILL.md
    └── scripts/
        └── search.py
---
name: arxiv-search
description: Search the arXiv preprint repository for research papers. Use when the user asks about academic papers, recent research, or scientific literature.
---

# arxiv-search

Search arXiv for papers matching the user's query.

## Instructions

1. Run `scripts/search.py` with the user's query as an argument.
2. Parse the results and present them with title, authors, abstract summary, and link.
3. If the user asks for more detail on a specific paper, fetch the full abstract.
The agent can read scripts from any backend, but to execute them, the agent needs access to a shell, which only sandbox backends provide. Sandbox backends run in isolated containers. Skill files stored outside the sandbox are not available inside it, which means the agent cannot execute skill scripts or access skill resources unless they are transferred in first. Use custom middleware to handle this transfer:
  • before_agent: Read skill files from the backend and upload them into the sandbox so the agent can execute scripts from the start.
  • after_agent: Download any updated or newly created skill files from the sandbox and write them back to the backend so changes persist across runs.
import asyncio
from pathlib import Path
from typing import Any

from daytona import Daytona
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StoreBackend
from deepagents.backends.utils import create_file_data
from langchain.agents.middleware import AgentMiddleware, AgentState

from langchain_daytona import DaytonaSandbox
from langgraph.runtime import Runtime
from langgraph.store.memory import InMemoryStore

# Identical skill bundles for every user: one shared store namespace.
SKILLS_SHARED_NAMESPACE = ("skills", "builtin")


class SkillSandboxSyncMiddleware(AgentMiddleware[AgentState, Any, Any]):
    """Copy shared skill files from the store into the sandbox before each agent run."""

    def __init__(self, backend: CompositeBackend) -> None:
        super().__init__()
        self.backend = backend

    async def abefore_agent(self, state: AgentState, runtime: Runtime[Any]) -> None:
        store = runtime.store

        files: list[tuple[str, bytes]] = []
        for item in await store.asearch(SKILLS_SHARED_NAMESPACE):
            key = str(item.key)
            if ".." in key or any(c in key for c in ("*", "?")):
                msg = f"Invalid key: {key}"
                raise ValueError(msg)
            normalized = key if key.startswith("/") else f"/{key}"
            # CompositeBackend routes paths and batches uploads to the right backend.
            files.append((f"/skills{normalized}", item.value["content"].encode()))

        if files:
            await self.backend.aupload_files(files)


async def seed_skill_store(store: InMemoryStore) -> None:
    """Load canonical skill files from disk into the shared store namespace (run once at deploy).
    You can retrieve skills from any source (local filesystem, remote URL, etc.).
    """
    skills_dir = Path(__file__).resolve().parent / "skills"
    for file_path in sorted(p for p in skills_dir.rglob("*") if p.is_file()):
        rel = file_path.relative_to(skills_dir).as_posix()
        key = f"/{rel}"
        await store.aput(
            SKILLS_SHARED_NAMESPACE,
            key,
            create_file_data(file_path.read_text(encoding="utf-8")),
        )


async def main() -> None:
    store = InMemoryStore()
    await seed_skill_store(store)

    daytona = Daytona()
    sandbox = daytona.create()
    sandbox_backend = DaytonaSandbox(sandbox=sandbox)

    backend = CompositeBackend(
        default=sandbox_backend,
        routes={
            "/skills/": StoreBackend(
                store=store,
                namespace=lambda _rt: SKILLS_SHARED_NAMESPACE,
            ),
        },
    )

    try:
        agent = create_deep_agent(
            model="google_genai:gemini-3.5-flash",
            backend=backend,
            skills=["/skills/"],
            store=store,
            middleware=[SkillSandboxSyncMiddleware(backend)],
        )

    finally:
        sandbox.stop()


if __name__ == "__main__":
    asyncio.run(main())
For a complete example that seeds both skills and memories before execution and syncs both back afterward, see syncing skills and memories with custom middleware.

Interpreter skills

Interpreter skills expose code modules to an interpreter. Regular skills give the agent instructions and context. Interpreter skills also give the agent importable functions it can call from interpreter code. This lets you package domain-specific logic once and make it available as a deterministic building block. Instead of asking the model to re-create a parser, validator, or aggregation routine from scratch, the agent can import a tested helper and compose it with tools, subagents, and runtime state. Use interpreter skills for code that should be:
  • Reusable across prompts, agents, or projects
  • Deterministic enough that you want the same behavior every time
  • Too detailed to keep in the model context as instructions
To make a skill importable:
1

Add an entrypoint

Add a metadata.entrypoint key to the skill’s SKILL.md frontmatter. The value is a JavaScript or TypeScript file path relative to the skill directory.
2

Configure skills normally

Pass the skill source path with the skills argument when creating the agent.
3

Use the same backend

Configure the interpreter middleware with the same backend that SkillsMiddleware uses to load skill files.
4

Import from interpreter code

The agent imports the helper module with await import("@/skills/<name>").
Minimal skill layout:
skills/
`-- order-helpers/
    |-- SKILL.md
    `-- scripts/
        `-- index.ts
---
name: order-helpers
description: Helper functions for normalizing and grouping order records.
metadata:
  entrypoint: scripts/index.ts
---

# order-helpers

Use this skill when order records need deterministic cleanup or aggregation.

Import these utilities into the REPL in order to interact with order data:

```typescript
const { groupByStatus } = await import("@/skills/order-helpers");
groupByStatus(...);
```
// skills/order-helpers/scripts/index.ts
interface Order {
  id: string;
  status: string;
}

export function groupByStatus(orders: Order[]) {
  return orders.reduce((acc, order) => {
    acc[order.status] = acc[order.status] ?? [];
    acc[order.status].push(order);
    return acc;
  }, {});
}
Then configure the agent:
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from langchain_quickjs import CodeInterpreterMiddleware

backend = StateBackend()

agent = create_deep_agent(
    model="openai:gpt-5.4",
    backend=backend,
    skills=["/skills/"],
    middleware=[CodeInterpreterMiddleware(skills_backend=backend)],
)
The agent can now import the module from interpreter code:
const { groupByStatus } = await import("@/skills/order-helpers");

const grouped = groupByStatus(orders);
grouped;

Reference

Skills, memory, and tools

Skills, memory (AGENTS.md files), and tools all provide context or capabilities to the agent. The following table summarizes when to reach for each:
SkillsMemoryTools
PurposeOn-demand capabilities discovered through progressive disclosurePersistent context loaded at startupProgrammatic actions the agent can call
LoadingRead only when the agent determines relevanceLoaded at agent startAvailable every turn
FormatSKILL.md in named directoriesAGENTS.md filesFunctions bound to the agent
LayeringUser, then project (last wins)User, then project (combined)Defined at agent creation
Use whenInstructions are task-specific and potentially largeContext is always relevant (project conventions, preferences)The agent needs a programmatic action, or does not have access to the file system
These are guidelines, not hard boundaries. In practice, skills and memory sit on a spectrum. An agent can update its own skills as it works, capturing new procedures and refining instructions over time. In this way, skills can function as a form of progressive-disclosure memory: context the agent builds up and retrieves on demand rather than loading on every prompt.

Frontmatter fields

The Agent Skills specification defines the following frontmatter fields:
FieldRequiredDescription
nameYesLowercase alphanumeric with hyphens, 1-64 characters. Must match the parent directory name.
descriptionYesWhat the skill does and when to use it. Max 1,024 characters.
licenseNoLicense name or reference to a bundled license file.
compatibilityNoEnvironment requirements (system packages, network access). Max 500 characters.
metadataNoArbitrary key-value pairs for additional properties.
allowed-toolsNoSpace-separated list of pre-approved tools the skill can use. Experimental.
---
name: langgraph-docs
description: Use this skill for requests related to LangGraph in order to fetch relevant documentation to provide accurate, up-to-date guidance.
license: MIT
compatibility: Requires internet access for fetching documentation URLs
metadata:
  author: langchain
  version: "1.0"
allowed-tools: fetch_url
---

# langgraph-docs

Instructions for the agent go here. See the [langgraph-docs example](#what-are-skills) for a complete example of skill instructions.
Refer to the full Agent Skills specification for detailed constraints and validation rules. In Deep Agents, SKILL.md files must be under 10 MB. Files exceeding this limit are skipped during skill loading.
For more example skills, see Deep Agents example skills.
Trace how your agent discovers and executes skills with LangSmith. Follow the observability quickstart to get set up.We recommend you also set up LangSmith Engine, which monitors your traces, detects issues, and proposes fixes.