Built-in Tools Reference
View SourcePrerequisites: Getting Started
Jido Action includes 25+ pre-built tools for common operations. All tools follow the same action patterns and can be used individually or composed into workflows.
Basic Tools
Sleep
Pause execution for a specified duration.
# Sleep for 1 second
{:ok, result} = Jido.Tools.Basic.Sleep.run(%{duration_ms: 1000}, %{})
# => {:ok, %{duration_ms: 1000}}
# Use in workflows for delays
plan = Jido.Plan.new()
|> Jido.Plan.add("process", MyApp.Actions.ProcessData, %{}, [])
|> Jido.Plan.add("wait", Jido.Tools.Basic.Sleep, %{duration_ms: 5000}, ["process"])
|> Jido.Plan.add("notify", MyApp.Actions.SendNotification, %{}, ["wait"])Parameters:
duration_ms(non-negative integer, default: 1000): Milliseconds to sleep
Log
Log a message with a specified level.
{:ok, result} = Jido.Tools.Basic.Log.run(%{level: :info, message: "Hello"}, %{})
# => {:ok, %{level: :info, message: "Hello"}}Parameters:
level(atom, default: :info): Log level (:debug, :info, :warning, :error)message(string, required): Message to log
Todo
Log a todo item as a placeholder.
{:ok, result} = Jido.Tools.Basic.Todo.run(%{todo: "Implement this feature"}, %{})
# => {:ok, %{todo: "Implement this feature"}}Parameters:
todo(string, required): Todo item description
RandomSleep
Introduce a random delay within a specified range.
{:ok, result} = Jido.Tools.Basic.RandomSleep.run(%{min_ms: 100, max_ms: 500}, %{})
# => {:ok, %{min_ms: 100, max_ms: 500, actual_delay: 342}}Parameters:
min_ms(non-negative integer, required): Minimum sleep duration in millisecondsmax_ms(non-negative integer, required): Maximum sleep duration in milliseconds
Increment
Increment a value by 1.
{:ok, result} = Jido.Tools.Basic.Increment.run(%{value: 5}, %{})
# => {:ok, %{value: 6}}Parameters:
value(integer, required): Value to increment
Decrement
Decrement a value by 1.
{:ok, result} = Jido.Tools.Basic.Decrement.run(%{value: 5}, %{})
# => {:ok, %{value: 4}}Parameters:
value(integer, required): Value to decrement
Noop
No operation, returns input unchanged.
{:ok, result} = Jido.Tools.Basic.Noop.run(%{foo: "bar"}, %{})
# => {:ok, %{foo: "bar"}}Inspect
Inspect a value using IO.inspect.
{:ok, result} = Jido.Tools.Basic.Inspect.run(%{value: [1, 2, 3]}, %{})
# => {:ok, %{value: [1, 2, 3]}}Parameters:
value(any, required): Value to inspect
Today
Returns today's date in the specified format.
{:ok, result} = Jido.Tools.Basic.Today.run(%{format: :iso8601}, %{})
# => {:ok, %{format: :iso8601, date: "2024-01-15"}}
{:ok, result} = Jido.Tools.Basic.Today.run(%{format: :human}, %{})
# => {:ok, %{format: :human, date: "January 15, 2024"}}Parameters:
format(atom, default: :iso8601): Format for the date (:iso8601, :basic, or :human)
Arithmetic Tools
Add
Add a value to a number.
{:ok, result} = Jido.Tools.Arithmetic.Add.run(%{value: 10, amount: 5}, %{})
# => {:ok, %{result: 15}}Parameters:
value(number, required): Base valueamount(number, required): Amount to add
Subtract
Subtract a value from a number.
{:ok, result} = Jido.Tools.Arithmetic.Subtract.run(%{value: 10, amount: 3}, %{})
# => {:ok, %{result: 7}}Multiply
Multiply two numbers.
{:ok, result} = Jido.Tools.Arithmetic.Multiply.run(%{value: 6, amount: 4}, %{})
# => {:ok, %{result: 24}}Parameters:
value(integer, required): The first number to multiplyamount(integer, required): The second number to multiply
Divide
Divide one number by another.
{:ok, result} = Jido.Tools.Arithmetic.Divide.run(%{value: 20, amount: 4}, %{})
# => {:ok, %{result: 5.0}}
# Division by zero returns error
{:error, error} = Jido.Tools.Arithmetic.Divide.run(%{value: 10, amount: 0}, %{})
# => {:error, "Cannot divide by zero"}Parameters:
value(integer, required): The number to be divided (dividend)amount(integer, required): The number to divide by (divisor)
Square
Square a number.
{:ok, result} = Jido.Tools.Arithmetic.Square.run(%{value: 5.0}, %{})
# => {:ok, %{result: 25.0}}Parameters:
value(float, required): The number to be squared
File Operations
Read File
Read contents from a file.
{:ok, result} = Jido.Tools.Files.ReadFile.run(%{path: "/tmp/data.txt"}, %{})
# => {:ok, %{path: "/tmp/data.txt", content: "file contents"}}
# Handle missing files
{:error, error} = Jido.Tools.Files.ReadFile.run(%{path: "/nonexistent.txt"}, %{})
# => {:error, "Failed to read file: :enoent"}Parameters:
path(string, required): Path to the file to be read
Write File
Write content to a file.
{:ok, result} = Jido.Tools.Files.WriteFile.run(%{
path: "/tmp/output.txt",
content: "Hello, World!",
create_dirs: true,
mode: :write
}, %{})
# => {:ok, %{path: "/tmp/output.txt", bytes_written: 13}}Parameters:
path(string, required): Path to the file to be writtencontent(string, required): Content to be written to the filecreate_dirs(boolean, default: false): Create parent directories if they don't existmode(atom, default: :write): Write mode - :write overwrites, :append adds to end
Delete File
Delete a file or directory.
{:ok, result} = Jido.Tools.Files.DeleteFile.run(%{path: "/tmp/temp.txt", recursive: false, force: false}, %{})
# => {:ok, %{path: "/tmp/temp.txt"}}
# Recursive deletion
{:ok, result} = Jido.Tools.Files.DeleteFile.run(%{path: "/tmp/mydir", recursive: true}, %{})
# => {:ok, %{deleted: ["/tmp/mydir/file.txt", "/tmp/mydir"]}}Parameters:
path(string, required): Path to deleterecursive(boolean, default: false): Recursively delete directories and contentsforce(boolean, default: false): Force deletion even if file is read-only
Copy File
Copy a file from source to destination.
{:ok, result} = Jido.Tools.Files.CopyFile.run(%{source: "/tmp/a.txt", destination: "/tmp/b.txt"}, %{})
# => {:ok, %{source: "/tmp/a.txt", destination: "/tmp/b.txt", bytes_copied: 1234}}Parameters:
source(string, required): Path to the source filedestination(string, required): Path to the destination file
Move File
Move/rename a file from source to destination.
{:ok, result} = Jido.Tools.Files.MoveFile.run(%{source: "/tmp/a.txt", destination: "/tmp/b.txt"}, %{})
# => {:ok, %{source: "/tmp/a.txt", destination: "/tmp/b.txt"}}Parameters:
source(string, required): Path to the source filedestination(string, required): Path to the destination file
Make Directory
Create a new directory.
{:ok, result} = Jido.Tools.Files.MakeDirectory.run(%{path: "/tmp/newdir", recursive: true}, %{})
# => {:ok, %{path: "/tmp/newdir"}}Parameters:
path(string, required): Path to the directory to createrecursive(boolean, default: false): Create parent directories if they don't exist
List Directory
List directory contents.
{:ok, result} = Jido.Tools.Files.ListDirectory.run(%{
path: "/tmp",
recursive: false
}, %{})
# => {:ok, %{entries: ["file1.txt", "file2.txt"]}}
# With pattern matching
{:ok, result} = Jido.Tools.Files.ListDirectory.run(%{
path: "/tmp",
pattern: "*.txt",
recursive: true
}, %{})
# => {:ok, %{entries: ["/tmp/file1.txt", "/tmp/subdir/file2.txt"]}}Parameters:
path(string, required): Path to the directory to listpattern(string, optional): Glob pattern for filtering filesrecursive(boolean, default: false): Include subdirectories recursively
HTTP Tools
ReqTool (HTTP Request Builder)
A behavior and macro for creating HTTP request actions using the Req library.
# Define a custom HTTP action module
defmodule MyApp.GetUser do
use Jido.Tools.ReqTool,
name: "get_user",
description: "Fetch a user from the API",
url: "https://api.example.com/users",
method: :get,
headers: %{"Authorization" => "Bearer token123"}
end
# Use the generated action
{:ok, response} = MyApp.GetUser.run(%{id: "123"}, %{})
# => {:ok, %{
# request: %{url: "https://api.example.com/users", method: :get, params: %{id: "123"}},
# response: %{status: 200, body: %{"id" => "123", "name" => "John"}, headers: [...]}
# }}
# POST with body
defmodule MyApp.CreateUser do
use Jido.Tools.ReqTool,
name: "create_user",
description: "Create a new user",
url: "https://api.example.com/users",
method: :post,
headers: %{"Content-Type" => "application/json"}
end
{:ok, response} = MyApp.CreateUser.run(%{name: "Jane", email: "jane@example.com"}, %{})Configuration Options (in use statement):
url(string, required): The URL to make requests tomethod(atom, required): HTTP method (:get, :post, :put, :delete)headers(map, default: %{}): HTTP headers to includejson(boolean, default: true): Whether to parse the response as JSON
Optional Callback:
transform_result/1: Override to transform the HTTP response result
GitHub Tools
These tools use the Tentacat library to interact with the GitHub API. Requires a Tentacat client.
List Issues
List all issues from a GitHub repository.
client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.List.run(%{
client: client,
owner: "octocat",
repo: "Hello-World"
}, %{})
# => {:ok, %{status: "success", data: [...], raw: [...]}}Parameters:
client(any): The Tentacat clientowner(string): Repository ownerrepo(string): Repository name
Create Issue
Create a new GitHub issue.
client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Create.run(%{
client: client,
owner: "octocat",
repo: "Hello-World",
title: "Bug Report",
body: "Description of the bug...",
labels: ["bug", "priority-high"],
assignee: "username",
milestone: "v1.0"
}, %{})
# => {:ok, %{status: "success", data: {...}, raw: {...}}}Parameters:
client(any): The Tentacat clientowner(string): Repository ownerrepo(string): Repository nametitle(string): Issue titlebody(string): Issue bodyassignee(string): Issue assigneemilestone(string): Issue milestonelabels(array): Issue labels
Update Issue
Update an existing GitHub issue.
client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Update.run(%{
client: client,
owner: "octocat",
repo: "Hello-World",
number: 123,
state: "closed",
labels: ["bug", "resolved"]
}, %{})
# => {:ok, %{status: "success", data: {...}, raw: {...}}}Parameters:
client(any): The Tentacat clientowner(string): Repository ownerrepo(string): Repository namenumber(integer): Issue numbertitle(string): New titlebody(string): New bodyassignee(string): New assigneestate(string): New state (open, closed)milestone(string): New milestonelabels(array): New labels
Find Issue
Find a specific issue by number.
client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Find.run(%{
client: client,
owner: "octocat",
repo: "Hello-World",
number: 123
}, %{})
# => {:ok, %{status: "success", data: {...}, raw: {...}}}Parameters:
client(any): The Tentacat clientowner(string): Repository ownerrepo(string): Repository namenumber(integer): Issue number
Filter Issues
Filter repository issues by various criteria.
client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Filter.run(%{
client: client,
owner: "octocat",
repo: "Hello-World",
state: "open",
assignee: "username",
labels: "bug,enhancement",
sort: "created",
direction: "desc"
}, %{})
# => {:ok, %{status: "success", data: [...], raw: [...]}}Parameters:
client(any): The Tentacat clientowner(string): Repository ownerrepo(string): Repository namestate(string): Issue state (open, closed, all)assignee(string): Filter by assigneecreator(string): Filter by creatorlabels(string): Filter by labels (comma-separated)sort(string): Sort by (created, updated, comments)direction(string): Sort direction (asc, desc)since(string): Only show issues updated after this time
Weather Tools
Get Weather
Fetch weather forecast using the National Weather Service API (no API key required).
# Default format (text) - returns forecast string
{:ok, forecast} = Jido.Tools.Weather.run(%{
location: "41.8781,-87.6298", # Chicago coordinates
periods: 5,
format: :text
}, %{})
# => {:ok, "Tonight: Mostly Clear, Low: 45°F..."}
# Map format - returns structured data
{:ok, weather} = Jido.Tools.Weather.run(%{
location: "34.0522,-118.2437", # Los Angeles
format: :map
}, %{})
# => {:ok, %{periods: [%{name: "Tonight", temperature: 65, ...}, ...]}}
# Detailed format - includes all NWS data
{:ok, weather} = Jido.Tools.Weather.run(%{
location: "40.7128,-74.0060", # New York
format: :detailed,
periods: 3
}, %{})Parameters:
location(string, default: "41.8781,-87.6298"): Location as coordinates (lat,lng)periods(integer, default: 5): Number of forecast periods to returnformat(atom, default: :text): Output format (:text, :map, or :detailed)
Workflow Tools
ActionPlan
A behavior and macro for creating actions that execute Jido Plans (DAG-based workflows).
# Define a workflow action
defmodule MyApp.MyWorkflowAction do
use Jido.Tools.ActionPlan,
name: "my_workflow",
description: "Executes a multi-step workflow"
@impl Jido.Tools.ActionPlan
def build(params, context) do
Jido.Plan.new(context: context)
|> Jido.Plan.add(:fetch, MyApp.FetchAction, params)
|> Jido.Plan.add(:validate, MyApp.ValidateAction, depends_on: :fetch)
|> Jido.Plan.add(:save, MyApp.SaveAction, depends_on: :validate)
end
# Optional: transform the result
@impl Jido.Tools.ActionPlan
def transform_result(result) do
{:ok, %{workflow_result: result}}
end
end
# Execute the workflow action
{:ok, results} = MyApp.MyWorkflowAction.run(%{input: "data"}, %{user_id: "123"})
# => {:ok, %{workflow_result: %{fetch: %{...}, validate: %{...}, save: %{...}}}}Required Callback:
build/2: Build a Plan struct from params and context
Optional Callback:
transform_result/1: Transform the execution result
Workflow
A behavior and macro for creating actions that execute sequential workflow steps.
defmodule MyApp.MySequentialWorkflow do
use Jido.Tools.Workflow,
name: "my_sequential_workflow",
description: "A workflow that performs multiple steps",
workflow: [
{:step, [name: "step_1"], [{LogAction, message: "Step 1"}]},
{:branch, [name: "branch_1"], [
true, # Condition (can override execute_step/3 for dynamic)
{:step, [name: "true_branch"], [{LogAction, message: "Condition true"}]},
{:step, [name: "false_branch"], [{LogAction, message: "Condition false"}]}
]},
{:step, [name: "final_step"], [{LogAction, message: "Completed"}]}
]
end
{:ok, result} = MyApp.MySequentialWorkflow.run(%{input: "start"}, %{})Supported Step Types:
:step- Execute a single instruction:branch- Conditional branching based on a boolean value:converge- Converge branch paths:parallel- Execute instructions in parallel
Advanced Tools
Simplebot
A collection of simple robot simulation actions for testing and examples.
Available actions:
Move- Move to a destinationIdle- Idle/waitDoWork- Perform work (decreases battery)Report- Report statusRecharge- Recharge battery to 100%
{:ok, result} = Jido.Tools.Simplebot.Move.run(%{destination: :warehouse}, %{})
# => {:ok, %{destination: :warehouse, location: :warehouse}}
{:ok, result} = Jido.Tools.Simplebot.DoWork.run(%{battery_level: 80}, %{})
# => {:ok, %{battery_level: 60}} # Battery decreased by 15-25
{:ok, result} = Jido.Tools.Simplebot.Recharge.run(%{battery_level: 20}, %{})
# => {:ok, %{battery_level: 100}}LuaEval
Execute Lua code in a sandboxed VM.
# Simple arithmetic
{:ok, result} = Jido.Tools.LuaEval.run(%{code: "return 2 + 2"}, %{})
# => {:ok, %{results: [4]}}
# With global variables
{:ok, result} = Jido.Tools.LuaEval.run(%{
code: "return x + 5",
globals: %{"x" => 10}
}, %{})
# => {:ok, %{results: [15]}}
# Return first value only
{:ok, result} = Jido.Tools.LuaEval.run(%{
code: "return 1, 2, 3",
return_mode: :first
}, %{})
# => {:ok, %{result: 1}}Parameters:
code(string, required): Lua code to executeglobals(map, default: %{}): Global variables to injectreturn_mode(atom, default: :list): :list returns all values, :first returns only firstenable_unsafe_libs(boolean, default: false): Enable unsafe libs (os/io/package)timeout_ms(integer, default: 1000): Execution timeout in millisecondsmax_heap_bytes(integer, default: 0): Per-process heap limit (0 = disabled)
ZoiExample
A production-quality example demonstrating Zoi schema features. Use this as a reference for building actions with complex validation.
# Example with nested objects, transformations, and refinements
params = %{
user: %{
email: " JOHN@EXAMPLE.COM ", # Will be trimmed and lowercased
password: "SecurePass123!",
name: "John Doe"
},
priority: :high
}
{:ok, result} = Jido.Exec.run(Jido.Tools.ZoiExample, params)
result.user.email # => "john@example.com"
result.status # => :approvedSee the Schemas & Validation Guide for more on Zoi schemas.
Tool Composition
Chaining Tools
# Chain multiple tools together
{:ok, final_result} = Jido.Exec.Chain.chain([
# Read data from file
{Jido.Tools.Files.ReadFile, %{path: "/tmp/input.txt"}},
# Process with custom action
{MyApp.Actions.ProcessText, %{}},
# Write result to new file
{Jido.Tools.Files.WriteFile, %{
path: "/tmp/output.txt",
create_dirs: true
}}
], %{}, %{user_id: "123"})Parallel Tool Execution
# Create a workflow action for parallel execution
defmodule MyApp.WeatherComparison do
use Jido.Tools.ActionPlan,
name: "weather_comparison",
description: "Compare weather across cities"
@impl Jido.Tools.ActionPlan
def build(_params, _context) do
Jido.Plan.new()
|> Jido.Plan.add(:weather_sf, Jido.Tools.Weather, %{location: "41.8781,-87.6298"})
|> Jido.Plan.add(:weather_ny, Jido.Tools.Weather, %{location: "40.7128,-74.0060"})
|> Jido.Plan.add(:weather_la, Jido.Tools.Weather, %{location: "34.0522,-118.2437"})
|> Jido.Plan.add(:compare, MyApp.Actions.CompareWeather,
depends_on: [:weather_sf, :weather_ny, :weather_la])
end
end
{:ok, results} = MyApp.WeatherComparison.run(%{}, %{})Conditional Tool Usage
defmodule MyApp.Actions.ConditionalFileOp do
use Jido.Action,
name: "conditional_file_op",
description: "Read or delete a file based on operation",
schema: [
file_path: [type: :string, required: true],
operation: [type: {:in, [:read, :delete]}, required: true]
]
def run(params, context) do
case params.operation do
:read ->
Jido.Tools.Files.ReadFile.run(%{path: params.file_path}, context)
:delete ->
Jido.Tools.Files.DeleteFile.run(%{path: params.file_path, recursive: false, force: false}, context)
end
end
endError Handling with Tools
All built-in tools follow consistent error handling patterns:
case Jido.Tools.Files.ReadFile.run(%{path: "/nonexistent.txt"}, %{}) do
{:ok, result} ->
handle_success(result)
{:error, %{type: :execution_error} = error} ->
Logger.error("File operation failed: #{error.message}")
handle_file_error(error)
{:error, error} ->
handle_other_error(error)
endAI Integration
All tools automatically work with AI systems:
# Get tool definitions for AI
tools = [
Jido.Tools.Weather.to_tool(),
Jido.Tools.Files.ReadFile.to_tool(),
Jido.Tools.Arithmetic.Add.to_tool()
]
# Tools are now available to AI for function calling
# The AI can invoke: weather, read_file, addBest Practices
Tool Selection
- Right Tool for Job: Choose the most specific tool available
- Composition: Combine tools for complex operations
- Error Handling: Always handle tool errors gracefully
- Context Propagation: Pass context through tool chains
Performance
- Parallel Execution: Use plans for independent operations
- Resource Management: Be mindful of file handles and network connections
- Caching: Cache expensive operations when appropriate
- Timeouts: Set appropriate timeouts for external tools
Security
- Path Validation: Validate file paths in file operations
- Input Sanitization: Sanitize inputs to external services
- Credential Management: Handle API keys and tokens securely
- Access Control: Restrict tool usage based on user permissions
Next Steps
→ AI Integration - Using tools with AI systems
→ Instructions & Plans - Composing tools into workflows
→ Actions Guide - Creating your own tools
← Security Guide | Next: AI Integration →