Skip to content

Toolnexus.Builtin.tools

Elixir · package toolnexus · SPEC §4A · elixir/lib/toolnexus/builtin.ex

@spec tools() :: [Toolnexus.Tool.t()]
def tools()

Builds all ten built-in tools — bash, read, write, edit, grep, glob, webfetch, question, apply_patch, todowrite — in fixed order, every time, with no config and no filtering. This is what Toolnexus.Builtin.load/1 calls internally before applying the on/off and per-tool toggles.

  • You want the full set, unconditionally — no enabled/disabled check, no tools allowlist to reason about, just the ten tools.
  • Testing or inspecting a single builtintools/0 is the shortest path to a real bash or read tool struct you can call execute.(args, ctx) on directly.
  • Building your own selection logic — if Builtin.load/1’s toggle shape doesn’t fit your config format, call tools/0 and filter the list yourself.
alias Toolnexus.Builtin
tools = Builtin.tools()
true =
Enum.map(tools, & &1.name) ==
["bash", "read", "write", "edit", "grep", "glob", "webfetch", "question", "apply_patch", "todowrite"]
true = Enum.all?(tools, &(&1.source == "builtin"))
# Calling it again returns the same shape — no memoization surprises, no shared state.
true = Enum.map(Builtin.tools(), & &1.name) == Enum.map(tools, & &1.name)
IO.puts("ok: #{length(tools)} builtins, fixed order")

2. Executing one directly — no toolkit, no agent, just the tool

Section titled “2. Executing one directly — no toolkit, no agent, just the tool”
alias Toolnexus.{Builtin, Context}
tools = Builtin.tools()
write = Enum.find(tools, &(&1.name == "write"))
read = Enum.find(tools, &(&1.name == "read"))
dir = Path.join(System.tmp_dir!(), "toolnexus-docs-builtins-#{System.unique_integer([:positive])}")
path = Path.join(dir, "note.txt")
wrote = write.execute.(%{"path" => path, "content" => "hello from tools/0"}, %Context{})
false = wrote.is_error
true = wrote.metadata.bytes == byte_size("hello from tools/0")
got = read.execute.(%{"path" => path}, %Context{})
false = got.is_error
true = got.output == "hello from tools/0"
File.rm_rf!(dir)
IO.puts("ok: wrote #{wrote.metadata.bytes} bytes, read back #{byte_size(got.output)}")

3. tools/0 ignores config entirely — unlike load/1

Section titled “3. tools/0 ignores config entirely — unlike load/1”

Same underlying ten tools, but tools/0 never looks at a config map — passing one to load/1 still narrows the set; there is no equivalent argument to tools/0.

alias Toolnexus.Builtin
full = Builtin.tools()
10 = length(full)
# load/1 with a `tools` toggle narrows the set...
narrowed = Builtin.load(%{"tools" => %{"bash" => false}})
9 = length(narrowed)
# ...but tools/0 has no config argument at all — always the full ten.
true = length(Builtin.tools()) == length(full)
true = Enum.map(Builtin.tools(), & &1.name) == Enum.map(full, & &1.name)
IO.puts("ok: tools/0 always #{length(full)}, load/1 narrowed to #{length(narrowed)}")