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.
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")
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.
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:
ggplot/lattice objects are printed to your device first,
so they appear in your plots pane as usual — and a ggplot that fails
to render reports the error to the model instead of failing silently.par(mfrow = ...) grid is one
page and is captured whole).png(),
pdf()) are not echoed.hal_configure(plot_vision = FALSE).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)
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.
?hal_register_tool — full tool builder reference?hal_configure — governance settings (policies, denylist, timeout)Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.