Skip to main content

Goals

  • Understand the difference between shared tools and task-specific tools
  • Use @tool(shared=False) for tools that should only be available within a session
  • Use list_task_tools() for fully dynamic tools generated based on the current task

Prerequisites

Introduction

By default, all methods decorated with @tool are shared — they are returned by environment.list_tools() and are available to any client before a session even starts. This works well for tools like bash or read_file that are the same regardless of the task. But some environments need to present different tool interfaces depending on the task. For example, an environment that tests an agent’s ability across multiple different configurations might give the agent a bash tool for some tasks, a select_option tool for multiple-choice tasks, and a completely different set of tools for other task types. The tool interface itself is part of what varies across tasks. Task-specific tools solve this by making tools available only through session.list_tools(), which requires an active session with a task loaded. This lets you vary the set of tools an agent sees on a per-task basis.

Using @tool(shared=False)

The simplest way to create a task-specific tool is to pass shared=False to the @tool decorator. These tools are not returned by environment.list_tools() but are returned by session.list_tools().
In this example, submit_answer is shared and always visible. The search tool is task-specific — it only appears when a session is active. Combined with list_task_tools() (below), you can control exactly which task-specific tools appear for each task.

Using list_task_tools()

For fully dynamic tools whose definitions depend on the task, override the list_task_tools() instance method. This lets you generate tool specifications at runtime based on self.task_spec — controlling exactly which tools the agent sees for each task.
In this example, the agent sees different tool interfaces depending on the task:
  • Multiple-choice tasks: submit_answer + select_option
  • Open-book tasks: submit_answer + search
  • Closed-book tasks: submit_answer only
Note that list_task_tools() is an instance method (not a classmethod) because it needs access to self.task_spec to determine which tools to generate. When list_task_tools() is used, the returned tools are combined with any @tool(shared=False) tools and all shared tools when a client calls session.list_tools(). For a real-world example of this pattern, see GeneralReasoning/toolathon-gym — an environment that presents different tool configurations per task to test agents across varied interfaces.

How Clients Access Task-Specific Tools

The SDK provides two different list_tools() methods depending on whether you have a session:
Under the hood:
  • environment.list_tools() calls the /tools endpoint, which returns only shared tools
  • session.list_tools() calls the /task_tools endpoint, which returns shared tools combined with task-specific tools (both @tool(shared=False) and those from list_task_tools())

Next Steps

Using Toolsets

Create reusable tool collections and compose them into environments