Omni Tools

Hex.pmLicenseBuild Status

Ready-to-use tools for Omni-powered agents — files, shell, REPL, web fetch, and web search. Built on Omni.

Tools

Installation

Add Omni Tools to your dependencies:

def deps do
[
{:omni_tools, "~> 0.4"}
]
end

Omni Tools depends on omni, which provides the LLM API layer. Configure your provider API keys as described in the Omni README.

The tools

ModuleWhat it does
Omni.Tools.FilesCRUD over a scoped directory with read-only and flat modes
Omni.Tools.BashExecutes shell commands with timeout and output capture
Omni.Tools.ReplEvaluates Elixir code in a sandboxed peer node
Omni.Tools.WebFetchFetches URLs, simplifies content for LLM consumption
Omni.Tools.WebSearchWeb search via pluggable providers (Brave, Serper, Tavily)

Each tool is created with new/1 and returns an %Omni.Tool{} struct:

Files

Read, write, patch, list, and delete files within a scoped directory:

# Full access with nested paths
Omni.Tools.Files.new(base_dir: "/data/workspace")
# Read-only, flat (no subdirectories)
Omni.Tools.Files.new(base_dir: "/data/docs", read_only: true, nested: false)

Bash

Execute shell commands in a configured working directory:

Omni.Tools.Bash.new(dir: "/app", timeout: 60_000, env: [{"NODE_ENV", "test"}])

Repl

Evaluate Elixir code in a fresh peer node with optional extensions:

alias Omni.Tools.Repl.Extension
Omni.Tools.Repl.new(
extensions: [
{MyApp.ReplExtension, api_key: "sk-..."},
Extension.new(description: "Req and Jason are available.")
]
)

WebFetch

Fetch URLs and extract content appropriate for LLM consumption:

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, []}])

WebSearch

Search the web via pluggable provider backends. API keys resolve from environment variables by default:

# Uses BRAVE_API_KEY env var
Omni.Tools.WebSearch.new(provider: Omni.Tools.WebSearch.Providers.Brave)
# Explicit key
alias Omni.Tools.WebSearch.Providers.Tavily
Omni.Tools.WebSearch.new(provider: {Tavily, api_key: "tvly-..."})
# Custom env var
alias Omni.Tools.WebSearch.Providers.Serper
Omni.Tools.WebSearch.new(provider: {Serper, api_key: {:system, "MY_SERPER_KEY"}})

Providers can also be configured via application config:

config :omni_tools, Omni.Tools.WebSearch.Providers.Brave, api_key: "..."

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.Files.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 defaultsapplication configexplicit opts

Explicit 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.

Documentation

Full API reference is available on HexDocs.

License

This package is open source and released under the Apache-2 License.

© Copyright 2026 Push Code Ltd.