
gptr runs language model agents inside your live R session, using
in-memory compute. They work with objects you already loaded and
reuse your variables and intermediate results across turns. With enough
available memory, this includes datasets around 4 GB or larger. Load
a dataset once, analyze it by name, and rerun the step you want to
change. One function, peter(), is an interactive chat in the console
and a programmable call that you put in scripts, loops and if
statements.
The model receives bounded descriptions, previews and tool output; the R
tool computes on the full object in your session. See
vignette("execution-model", package = "gptr") for memory and
data-sharing details.
peter() with no prompt opens a chat at the
console; with a prompt it runs the agent and returns the session,
which the pipe steers: peter("...") |> peter("...").if and for..R, .Rmd, .qmd or .ipynb document. Fresh recorded
blocks replay without model calls; supply their required input data
and packages when replaying in a fresh session.manual mode runs read-only actions
and asks before changes. The permission gate is not a sandbox; see
?gptr_security.Read the guides and function reference online.
Install gptr from GitHub's main branch with R 4.2 or later:
install.packages("pak") # if pak is not installed
pak::pak("Broccolito/gptr@main")
This README documents gptr 1.0. CRAN submission is being prepared.
install.packages("gptr") installs the CRAN version, which may still
expose the older 0.7 API. Check packageVersion("gptr") before
following these examples. No model server or CLI is required for the
offline examples below.
For an interactive first session, sign in to the Claude Code CLI or the
Codex CLI outside R, then call peter(); with no default model it
offers to save one. See
vignette("interactive-console", package = "gptr").
Choose a provider explicitly before your first real call. API
credentials and CLI sign-in are separate routes; see
vignette("language-models").
gptr_env("~/keys/.env") # provider keys, e.g. OPENAI_API_KEY
gptr_providers() # what is configured
gptr_config(model = "openai/gpt-6-sol", .scope = "session")
peter() # chat in the console
With a configured model, tell Peter what to do:
library(gptr)
session = peter("Fit mpg from wt in mtcars. Save the model as fit.", mtcars)
session |> peter("Plot fit's residuals and explain what they show.")
The pipe continues the same session. The usual permission checks apply.
Run this pattern offline
This scripted model needs no key or server. It supplies the tool code rather than generating it.
library(gptr)
fake = gptr_fake_provider(list(
list(tool = "r", input = list(code = "fit = lm(mpg ~ wt, data = mtcars)\ncoef(fit)")),
"Each 1000 lb of weight lowers mpg by about 5.3.",
list(tool = "r", input = list(code = "predicted = predict(fit)\nhead(predicted)")),
"The predictions are stored in predicted."
))
work = new.env()
session = peter("Fit mpg from wt in mtcars. Save the model as fit.", mtcars,
model = fake, envir = work, mode = auto)
session$text
#> [1] "Each 1000 lb of weight lowers mpg by about 5.3."
ls(work)
#> [1] "fit"
session |> peter("Reuse fit to predict mpg for the same cars.")
#> The predictions are stored in predicted.
#> idle . fake/fake-1 . 2 turns . 6.9k tokens . $0.0000 . s782cbc40a3
head(work$predicted)
#> Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
#> 23.28261 21.91977 24.88595 20.10265
#> Hornet Sportabout Valiant
#> 18.90014 18.79325
session$turns
#> [1] 2
The second turn reuses fit.
The same pattern works with a large object already in your workspace. This recipe does not allocate or load a 4 GB dataset:
# counts is a numeric matrix, around 4 GB, already loaded in this R session.
session = peter(
"Compute colSums(counts) as totals and return the six largest totals.",
counts
)
session |> peter("Reuse totals to plot their distribution.")
A System 1 question returns a typed R vector with the probabilities attached:
Offline typed-decision example
judge = gptr_fake_provider(list(0.93, 0.08), name = "judge", type = "classifier")
abstracts = c(a = "We randomized 200 adults to drug or placebo.",
b = "We followed a cohort of nurses for 20 years.")
is_rct = peter("Is this abstract about a randomized controlled trial?", abstracts,
model = judge)
as.logical(is_rct)
#> a b
#> TRUE FALSE
gptr_prob(is_rct)
#> a b
#> 0.93 0.08
Installed Ollama chat models run agents, for example
model = "ollama/qwen3:1.7b". Clef and Clef Flash (Ollama 0.35.1 or
later) return typed decisions, for example
model = "ollama/clef-flash". gptr never installs Ollama or downloads
models, and by default never falls back to a cloud model; a workflow
stays local only if every model and tool it uses is local.
A synchronized .R history can become an ordinary R script or a script
of peter() calls:
gptr_doc("analysis.R", sync = TRUE)
gptr_export("analysis.R", "analysis-raw.R")
gptr_export("analysis.R", "analysis-peter.R", format = "peter")
The default keeps recorded R executable and turns peter() calls into
comments. The format = "peter" output keeps calls active and recorded
code inert, with bounded output and notes beside the turns. Both
preserve ordinary source and refuse stale or ambiguous records. Export
does not run or verify the result, recover unrecorded console work, or
save your input objects. See
vignette("script-as-history", package = "gptr") for interleaved R and
a second session.
Start with vignette("getting-started", package = "gptr"). Most guides
include a runnable offline example. Recipes that need a real provider,
MCP server or external program are shown without running them.
| Task | Guide |
|---|---|
| Understand the name and ideas behind Peter | vignette("why-peter") |
| Choose a language model; call Peter from functions and scripts | vignette("language-models") |
| Make logical, choice and score decisions | vignette("system-one") |
Chat, use slash commands, or run inline R with !
|
vignette("interactive-console") |
| Set defaults, permissions, paths and runtime options | vignette("configuration") |
| Record, replay and summarize a workflow | vignette("script-as-history") |
| Run teams, fan-outs, background sessions and the session SDK | vignette("teams-and-background") |
| Use R, files, shell, Python, SQL and Shiny apps | vignette("tools-and-artifacts") |
| Reuse skills, templates, agent files and plugins | vignette("skills-and-plugins") |
| Connect MCP servers or expose an R session | vignette("mcp") |
| Write tools, providers, policies and hooks | vignette("extending-gptr") |
| Understand execution, environments and result objects | vignette("execution-model") |
| Inspect usage, budgets, caching and compaction | vignette("token-efficiency") |
The function reference documents the exported APIs. In R, use
help(package = "gptr"), ?peter, ?gptr_export, ?gptr_options,
?gptr_security and ?gptr_egress.
The package is gptr; you talk to its agent through peter(). The name
honors two Peters:
gptr calls typed decision models "System 1" and conversational agents
"System 2". These are software roles; they do not imply human cognition
or that Wason introduced those labels. The
vignette("why-peter", package = "gptr") guide gives the history and
primary sources.
gptr 1.0.0 is a complete rewrite. get_response() and
dataframe_to_text() were removed: use peter("your prompt")$text
instead of get_response(), and pass a data frame to peter() as
context instead of converting it to text. See NEWS.md.
gptr was inspired by Mario Zechner's 'pi' coding agent; its tool
descriptions, edit semantics and prompt-template grammar are derived
from 'pi' (MIT license). The model catalog is derived from models.dev
(MIT license) and the secret patterns from gitleaks (MIT license); see
inst/COPYRIGHTS. Ideas were borrowed from 'ellmer', 'tidyllm', 'btw'
and 'mcptools', none of which gptr depends on. Anthropic, OpenAI,
Google, TypeSafe AI, Ollama and the vendors of the command-line tools
are third-party services; gptr is not affiliated with or endorsed by
them.