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
- An OpenReward account
- An OpenReward API key
- Completion of the Your First Environment tutorial
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().
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.
- Multiple-choice tasks:
submit_answer+select_option - Open-book tasks:
submit_answer+search - Closed-book tasks:
submit_answeronly
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 differentlist_tools() methods depending on whether you have a session:
environment.list_tools()calls the/toolsendpoint, which returns only shared toolssession.list_tools()calls the/task_toolsendpoint, which returns shared tools combined with task-specific tools (both@tool(shared=False)and those fromlist_task_tools())
Next Steps
Using Toolsets
Create reusable tool collections and compose them into environments

