Skip to content

Tools

Tools are how Ash takes actions. They let Ash run commands, read and write files, search the web, and call specialized agents or skills.

Tools In 30 Seconds

Use tools when the task needs action, not just text generation.

  • Need terminal execution: use bash
  • Need web discovery: use web_search
  • Need page content: use web_fetch
  • Need file access: use read_file and write_file
  • Need deep autonomous work: use use_agent
  • Need instruction-based workflow: use use_skill

Every tool has three parts:

  1. Name and description
  2. Input schema (JSON Schema)
  3. Async execution that returns structured output

Quick Start

Enable web search, then run a prompt that requires tools:

~/.ash/config.toml
[brave_search]
api_key = "BSA..." # Required for web_search
Terminal window
# Run Ash with one prompt
uv run ash chat "Find the latest release notes for Python 3.13 and summarize key changes"

If tool usage is healthy, Ash will call web_search and/or web_fetch before replying.

Core Toolset

Bash (bash)

Runs shell commands in the sandbox.

Use for:

  • running scripts
  • inspecting repos
  • generating or validating files

See Sandbox for isolation and security controls.

Searches the web via Brave Search.

Use for:

  • finding current facts
  • finding official docs or release notes
  • gathering source links before answering

Web Fetch (web_fetch)

Fetches and extracts content from a URL.

Use for:

  • turning a single URL into readable text
  • pulling article/doc body content after search

File Tools (read_file, write_file)

Access project files in workspace scope.

Use for:

  • reading code/config/docs with line context
  • applying targeted file edits

Browser (browser)

Controls a real browser session when browser integration is enabled.

Use for:

  • UI workflows that need page interaction
  • screenshot-based verification

See Browser for provider/runtime setup.

Agent Delegation (use_agent)

Runs a specialized autonomous agent.

Use for:

  • multi-step workflows that benefit from an isolated loop
  • longer tasks where you want focused agent behavior

See Agents.

Skill Delegation (use_skill)

Runs a reusable skill from your skill registry.

Use for:

  • instruction-driven workflows you want to reuse
  • project/team conventions encoded in SKILL.md

See Skills.

Configure Tools

Most tool behavior is controlled by subsystem config.

~/.ash/config.toml
# Workspace path used by file tools
workspace = "~/.ash/workspace"
# Enable web search tool
[brave_search]
api_key = "BSA..."
# Browser tool is available when browser subsystem is enabled
[browser]
enabled = true
provider = "sandbox" # or "kernel"
timeout_seconds = 20.0

Troubleshooting

Tool did not run when expected

Terminal window
# Verify config is valid
uv run ash config validate
# Run with a concrete tool-requiring prompt
uv run ash chat "Read README.md and list setup steps"

If Ash can answer from existing context, it may skip tools. Ask for source-backed or file-backed output to force tool use.

web_search fails

Terminal window
# Confirm Brave key exists in config
uv run ash config show
# Run environment diagnostics
uv run ash doctor

Common fix: add a valid [brave_search].api_key.

bash or file tools fail

Terminal window
# Check sandbox health
uv run ash sandbox status
# Rebuild sandbox image if needed
uv run ash sandbox build

See Sandbox for runtime and mount rules.

Build A Custom Tool

For Python contributors extending Ash:

  1. Implement Tool (name, description, input_schema, execute).
  2. Return ToolResult.success(...) or ToolResult.error(...).
  3. Register the tool through integration wiring.

Minimal skeleton:

from typing import Any
from ash.tools.base import Tool, ToolContext, ToolResult
class WeatherTool(Tool):
@property
def name(self) -> str:
return "weather"
@property
def description(self) -> str:
return "Get current weather for a location"
@property
def input_schema(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City or region"},
},
"required": ["location"],
}
async def execute(self, input_data: dict[str, Any], context: ToolContext) -> ToolResult:
location = input_data["location"]
return ToolResult.success(f"Weather for {location}: TODO")

Reference (Advanced)

Primary implementation files:

  • src/ash/tools/base.py - core Tool, ToolContext, ToolResult
  • src/ash/tools/registry.py - registration and lookup
  • src/ash/tools/executor.py - tool-call execution path
  • src/ash/tools/builtin/*.py - built-in tool implementations

Tool definitions are passed to the model from the registry. At runtime, the executor resolves tool calls by name and executes with ToolContext.