Agent tools

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = FALSE
)

hal connects to a coding agent with built-in tools for reading code, editing files, searching your codebase, and running commands. You can also register your own R functions as tools.

Built-in tools

Always available — no registration needed:

| Tool | What it does | |---|---| | view / Read | Read file contents | | grep / Grep | Search file contents | | glob / Glob | Find files by pattern | | edit / Edit | Edit an existing file | | create / Write | Create a new file | | bash / Bash | Run shell commands |

The agent decides when to use them — you just describe what you want:

hal("Find all functions that call the database and list them")
hal("Add error handling to the process_data function")
hal("Run the tests and fix any failures")

eval_r — the R bridge

hal registers eval_r in every session so the agent can run R code in your live session, not a subprocess copy:

df <- mtcars

hal("Which rows in df have mpg above the median?", use_env = TRUE)

use_env = TRUE injects names + types from your environment into the prompt; the agent reads actual values via eval_r. The default (use_env = NULL) auto-detects when prompt tokens match env objects.

Plot vision

When eval_r code draws a plot, hal captures it as a PNG and attaches it to the tool result as an image — the model sees the rendered chart, not just the code that made it:

df <- mtcars
hal("Plot mpg vs wt and tell me what stands out")
#> i hal: plot captured for the model.

| Backend | Plot vision | |---|---| | vscode | Yes (bundled hal-bridge >= 0.1.4; if the selected model rejects images, the bridge falls back to text automatically) | | claude | Yes (MCP image content blocks) | | copilot | No — text-only until the CLI's image forwarding is verified |

Details worth knowing:

Register your own tools

Turn any R function into a tool:

hal_register_tool(
  fun = function(city) paste("Sunny, 72F in", city),
  name = "get_weather",
  description = "Get current weather for a city",
  types = list(city = "string")
)

hal("What's the weather in Austin?")

Register tools before the first hal() / $chat() call — they're passed to the CLI at startup.

Bulk registration:

hal_register_package_tools("dplyr")
hal_register_tool_specs(winston::timelog_tool_specs())

ellmer ToolDef objects are accepted directly:

chat <- hal_chat()
chat$register_tool(my_ellmer_tool)

Permissions, in brief

Read tools auto-allow. Writes and shell commands trigger a permission request. The default policy auto-allows everything; switch to auto-deny for read-only behavior:

hal_configure(permission_policy = "auto-deny")

For custom logic (logging, interactive approval, selective allow), pass a function. See ?hal_configure for the full reference.

Next



Try the hal package in your browser

Any scripts or data that you put into this service are public.

hal documentation built on Oct. 6, 2026, 5:07 p.m.