Is there anyway that I can remove grep, glob, write_todos, task from deepagents?

I’m working on integrating file system operations (e.g., ls, write_file, edit_file) with a Postgres database, alongside some custom tools like search_by_tags.

However, I’m running into a problem: I can’t find a way to remove built-in tools such as grep, glob, write_todos, and task. These tools are always included, which unnecessarily consumes context and sometimes misleads the LLM during execution.

hi @LucienShui

Deep Agents ships with a default set of built-in tools (ls, read_file, write_file, edit_file, glob, grep, execute, write_todos, task), and AFAIK right now there is no public, first-class parameter on create_deep_agent() to selectively exclude specific built-in tools. The tools parameter only adds custom tools on top of the built-in ones - it doesn’t replace them.

However, there is a clean, supported way to achieve this using custom middleware. Here are two approaches, from simplest to most advanced:

Custom tool-exclusion middleware

The LangChain AgentMiddleware system allows you to intercept model requests and filter tools before the LLM sees them. You can write a simple middleware that strips unwanted tools using wrap_model_call:

from langchain.agents.middleware import wrap_model_call

TOOLS_TO_EXCLUDE = {"grep", "glob", "write_todos", "task"}

@wrap_model_call
def exclude_tools(request, handler):
    """Remove unwanted built-in tools before the model sees them."""
    filtered_tools = [
        t for t in request.tools
        if getattr(t, "name", None) not in TOOLS_TO_EXCLUDE
    ]
    return handler(request.override(tools=filtered_tools))

agent = create_deep_agent(
    model="anthropic:claude-sonnet-4-6",
    tools=[search_by_tags],  # your custom tools
    middleware=[exclude_tools],
)

This works because:

  1. All built-in tools (from FilesystemMiddleware, TodoListMiddleware, SubAgentMiddleware) are injected into request.tools via their respective middleware before your custom middleware runs.
  2. Your middleware sits in the stack after the tool-injecting middleware, so it can filter them out.
  3. request.override(tools=filtered_tools) returns a new immutable request with only the tools you want - the LLM never sees the excluded ones.

Source: The Deep Agents customization guide documents custom middleware with wrap_model_call and wrap_tool_call decorators. The request.override() pattern is part of LangChain’s ModelRequest API.

Class-based middleware (more control)

If you need async support or more fine-grained control, subclass AgentMiddleware directly:

from langchain.agents.middleware.types import AgentMiddleware, ModelRequest, ModelResponse

class ToolExclusionMiddleware(AgentMiddleware):
    """Remove specific tools from the model's tool set."""

    def __init__(self, exclude: set[str]):
        self._exclude = exclude

    def wrap_model_call(self, request, handler):
        filtered = [
            t for t in request.tools
            if getattr(t, "name", None) not in self._exclude
        ]
        return handler(request.override(tools=filtered))

    async def awrap_model_call(self, request, handler):
        filtered = [
            t for t in request.tools
            if getattr(t, "name", None) not in self._exclude
        ]
        return await handler(request.override(tools=filtered))


agent = create_deep_agent(
    model="anthropic:claude-sonnet-4-6",
    tools=[search_by_tags],
    middleware=[
        ToolExclusionMiddleware(exclude={"grep", "glob", "write_todos", "task"}),
    ],
)

This is essentially what Deep Agents does internally - the framework has a private _ToolExclusionMiddleware class (source: deepagents/middleware/_tool_exclusion.py) that does exactly this, but it’s not part of the public API.

How built-in tools are injected (under the hood)

For context, here’s what happens inside create_deep_agent() when it builds the middleware stack (source: deepagents/graph.py):

Middleware Stack Order (simplified):
1. TodoListMiddleware        → injects `write_todos`
2. SkillsMiddleware          → (if skills provided)
3. FilesystemMiddleware      → injects `ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep`, `execute`
4. SubAgentMiddleware        → injects `task`
5. SummarizationMiddleware
6. PatchToolCallsMiddleware
7. YOUR CUSTOM MIDDLEWARE    ← this is where your exclusion middleware runs
8. `_ToolExclusionMiddleware`  ← (internal, driven by harness profiles)
9. AnthropicPromptCachingMiddleware
10. MemoryMiddleware         ← (if memory provided)
11. HumanInTheLoopMiddleware ← (if `interrupt_on` provided)
12. `_PermissionMiddleware`    ← (if permissions provided, always last)

Your custom middleware at position 7 runs after all the tool-injecting middleware (positions 1-4) have added their tools to request.tools, so you can filter them all.

Available built-in tool names

For reference, here are the exact tool names you can exclude:

Tool Name Source Middleware Description
ls FilesystemMiddleware List files in a directory
read_file FilesystemMiddleware Read file contents
write_file FilesystemMiddleware Create new files
edit_file FilesystemMiddleware Edit files (string replacement)
glob FilesystemMiddleware Find files matching patterns
grep FilesystemMiddleware Search text in files
execute FilesystemMiddleware Run shell commands (sandbox backends only)
write_todos TodoListMiddleware Manage a todo list
task SubAgentMiddleware Spawn and call subagents

Important notes

  1. Don’t remove task if you use subagents: The task tool is how the main agent delegates work to subagents. Removing it means no subagent spawning.

  2. write_todos comes from LangChain, not Deep Agents itself - it’s injected via TodoListMiddleware (imported from langchain.agents.middleware).

  3. Don’t mutate middleware state: As noted in the customization docs, do not mutate attributes after initialization. The exclusion set should be immutable (use frozenset if subclassing).

  4. Feature request: If you’d like a first-class excluded_tools parameter on create_deep_agent(), consider opening an issue at github.com/langchain-ai/deepagents. Internally, the infrastructure already exists (_HarnessProfile.excluded_tools and _ToolExclusionMiddleware) - it’s just not exposed publicly yet.

Hi @pawel-twardziak

Thanks a lot for the super detailed explanation — really appreciate it!

Your middleware approach makes total sense, and it completely solves my problem.

Also, if the team is open to it, I’d be happy to submit a PR to make things like system_message and tool configuration more customizable when creating an agent.

Thanks again!