Ready-to-use tools for Omni-powered agents — filesystem, shell, REPL, and web fetch. Built on Omni.
Omni Tools is a small set of reference Omni.Tool implementations that
ship ready-to-use and serve as worked examples of how to build tools for
LLMs. Each tool validates configuration at construction time and works
with any Omni provider that supports tool use.
Installation
Add Omni Tools to your dependencies:
{:omni_tools, "~> 0.1"}Omni Tools depends on omni, which provides the LLM API layer. Configure
your provider API keys as described in the
Omni README.
The tools
| Module | What it does |
|---|---|
Omni.Tools.FileSystem | CRUD over a scoped directory with read-only and flat modes |
Omni.Tools.Bash | Executes shell commands with timeout and output capture |
Omni.Tools.Repl | Evaluates Elixir code in a sandboxed peer node |
Omni.Tools.WebFetch | Fetches URLs, simplifies content for LLM consumption |
Each tool is created with new/1 and returns an %Omni.Tool{} struct
ready to pass into an Omni context:
fs = Omni.Tools.FileSystem.new(base_dir: "/data/workspace")
bash = Omni.Tools.Bash.new(dir: "/app")
repl = Omni.Tools.Repl.new()
web = Omni.Tools.WebFetch.new()FileSystem
Read, write, patch, list, and delete files within a scoped directory. Configuration controls read-only access and whether subdirectories are allowed:
# Full access with nested paths
Omni.Tools.FileSystem.new(base_dir: "/data/workspace")
# Read-only, flat (no subdirectories)
Omni.Tools.FileSystem.new(base_dir: "/data/docs", read_only: true, nested: false)See Omni.Tools.FileSystem for all options. The underlying operations
are also available standalone via Omni.Tools.FileSystem.FS.
Bash
Executes shell commands in a configured working directory with environment variables, timeout, and output truncation:
Omni.Tools.Bash.new(dir: "/app", timeout: 60_000, env: [{"NODE_ENV", "test"}])See Omni.Tools.Bash for all options. The command runner is also
available standalone via Omni.Tools.Bash.Runner.
Repl
Evaluates Elixir code in a fresh peer node — clean slate per execution, with IO capture and configurable extensions:
alias Omni.Tools.Repl.Extension
Omni.Tools.Repl.new(
extensions: [
{MyApp.ReplExtension, api_key: "sk-..."},
Extension.new(description: "Req and Jason are available.")
]
)See Omni.Tools.Repl for all options and Omni.Tools.Repl.Extension
for the extension API.
WebFetch
Fetches one or more URLs and extracts content appropriate for LLM consumption — HTML to Markdown, JSON to pretty-printed, plain text passthrough:
Omni.Tools.WebFetch.new(max_output: 30_000, timeout: 10_000)Three strategies are always active — GitHub (blob URLs to raw content), Reddit (JSON API to formatted Markdown), and a default catch-all. Custom strategies are prepended and matched first, so they can override or extend the built-ins:
Omni.Tools.WebFetch.new(strategies: [{MyApp.WikiStrategy, []}])See Omni.Tools.WebFetch for all options and
Omni.Tools.WebFetch.Strategy for the strategy behaviour.
Using tools in a conversation
Pass tools to Omni.generate_text/3 or Omni.stream_text/3 — the tool
loop executes uses automatically and feeds results back to the model:
fs = Omni.Tools.FileSystem.new(base_dir: "/data/workspace")
bash = Omni.Tools.Bash.new(dir: "/data/workspace")
context = Omni.context(
system: "You are a coding assistant with access to a project workspace.",
messages: [Omni.message("List all Elixir files and count the lines in each.")],
tools: [fs, bash]
)
{:ok, response} = Omni.generate_text({:anthropic, "claude-sonnet-4-6"}, context)Tools work the same way with Omni.Agent — pass them as start options
or set them in your agent's init/1 callback:
{:ok, agent} = Omni.Agent.start_link(
model: {:anthropic, "claude-sonnet-4-6"},
tools: [fs, bash],
subscribe: true
)Configuration
Every tool supports a three-layer configuration merge:
module defaults → application config → explicit optsExplicit opts to new/1 always win. Application config provides
per-environment defaults. Module defaults are sensible out of the box.
# config/runtime.exs
config :omni_tools, Omni.Tools.Bash,
timeout: 60_000,
max_output: 100_000
# At call site — :dir is required, :timeout overrides the app config
Omni.Tools.Bash.new(dir: "/app", timeout: 10_000)No application config is required — every tool works with zero config and sensible defaults.
Writing custom tools
These tools implement the Omni.Tool behaviour from the omni package.
To build your own, see Omni.Tool — or read any of the tools in this
package as worked examples.