| Title: | Language Model Agents Inside the Live 'R' Session |
|---|---|
| Description: | Runs large language model agents inside the running 'R' session, so that models inspect and modify objects that are already in memory instead of re-running scripts from scratch. A single function, peter(), opens an interactive chat in the console or, given a prompt, runs the agent loop and returns a value that can be piped into further prompts. Supports the 'Anthropic', 'OpenAI' and 'Google Gemini' application programming interfaces, 'OpenAI'-compatible endpoints, the 'Claude Code' and 'Codex' command line tools, local 'Ollama' conversational models, and System One typed-decision models such as 'Jev', 'Clef' and 'Clef Flash' <https://typesafe.ai/blog/introducing-system-one-models-and-jev>, whose typed yes/no, choice and score answers can be used directly in if() and for() statements. Tools for reading, writing, editing and searching files and for evaluating 'R' code are implemented in 'R'; skills, extensions, Model Context Protocol ('MCP') servers, sub-agents and 'shiny' apps are supported. Sessions are recorded as 'R' scripts, 'R Markdown', 'Quarto' or 'Jupyter' documents that can be re-run. Writing files and evaluating model-generated code require the user's permission by default. |
| Authors: | Wanjun Gu [aut, cre, cph] (ORCID: <https://orcid.org/0000-0002-7342-7000>), Mario Zechner [ctb, cph] (Author of 'pi' (MIT), from which tool texts and templates are derived) |
| Maintainer: | Wanjun Gu <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.0 |
| Built: | 2026-10-16 07:41:58 UTC |
| Source: | https://github.com/broccolito/gptr |
Convert a session summary to a data frame
## S3 method for class 'gptr_session_summary' as.data.frame(x, ...)## S3 method for class 'gptr_session_summary' as.data.frame(x, ...)
x |
A |
... |
Further arguments, such as |
An ordinary data.frame containing the complete history.
Format a risk classification
## S3 method for class 'gptr_risk' format(x, ...) ## S3 method for class 'gptr_risk' print(x, ...)## S3 method for class 'gptr_risk' format(x, ...) ## S3 method for class 'gptr_risk' print(x, ...)
x |
A |
... |
Unused. |
format() returns a character vector: the level line, then one line per flagged
call (control, bidi and zero-width characters escaped); print() returns x invisibly.
r = gptr_risk("x = 1; unlink('data', recursive = TRUE)") format(r) print(r)r = gptr_risk("x = 1; unlink('data', recursive = TRUE)") format(r) print(r)
Format a session as its text
## S3 method for class 'gptr_session' format(x, ...) ## S3 method for class 'gptr_session' as.character(x, ...)## S3 method for class 'gptr_session' format(x, ...) ## S3 method for class 'gptr_session' as.character(x, ...)
x |
A |
... |
Unused. |
x$text.
An adapter turns gptr's request context into one provider's wire format and its stream back
into gptr events. HTTP and process adapters give build() and parse(); inprocess adapters
give stream(), a generator factory; classifier adapters give classify.
gptr_adapter( api, transport = c("http_sse", "http_ndjson", "http_json", "process_jsonl", "inprocess"), build = NULL, parse = NULL, stream = NULL, classify = NULL, capabilities = list() )gptr_adapter( api, transport = c("http_sse", "http_ndjson", "http_json", "process_jsonl", "inprocess"), build = NULL, parse = NULL, stream = NULL, classify = NULL, capabilities = list() )
api |
The wire api this adapter implements (the name providers bind to). |
transport |
|
build |
|
parse |
|
stream |
|
classify |
Named list for classifier adapters: |
capabilities |
Named list of adapter capabilities. |
A spec of class c("gptr_adapter", "gptr_spec").
gptr_adapter("echo", transport = "inprocess", stream = function(model, context, opts) { state = new.env() state$done = FALSE function() { if (state$done) return(NULL) state$done = TRUE list(events = list()) } })gptr_adapter("echo", transport = "inprocess", stream = function(model, context, opts) { state = new.env() state$done = FALSE function() { if (state$done) return(NULL) state$done = TRUE list(events = list()) } })
An agent definition names a specialist for peter(agents = ...): its model, tools, skills,
system text, backend, preset and limits. model and skills may be bare identifiers; they are
stored unevaluated (as written) and resolved by the gateway. gptr_agent("name") alone (or
with only file) loads a saved definition. Package code should pass strings.
gptr_agent( name = NULL, description = NULL, model = NULL, tools = NULL, skills = NULL, system = NULL, backend = c("auto", "inline", "worker", "cli"), preset = "minimal", max_turns = NULL, mode = NULL, objects = NULL, export = NULL, returns = NULL, file = NULL )gptr_agent( name = NULL, description = NULL, model = NULL, tools = NULL, skills = NULL, system = NULL, backend = c("auto", "inline", "worker", "cli"), preset = "minimal", max_turns = NULL, mode = NULL, objects = NULL, export = NULL, returns = NULL, file = NULL )
name |
Agent name. |
description |
One line describing the specialist. |
model |
Model reference: a string, a bare identifier or a provider spec. |
tools |
Tool names (or specs) the agent may use. |
skills |
Skills to preload. |
system |
System text of the agent. |
backend |
|
preset |
Tool preset of the agent's session. |
max_turns |
Turn limit, or |
mode |
Permission mode ( |
objects |
Names of objects the agent may see. |
export |
Names of objects the agent returns. |
returns |
JSON Schema of a structured answer, or |
file |
Path of an agent definition file. |
A spec of class c("gptr_agent", "gptr_spec").
gptr_agent("stats", description = "Statistical reviewer", model = "anthropic/claude-opus-5-5", skills = "statistics")gptr_agent("stats", description = "Statistical reviewer", model = "anthropic/claude-opus-5-5", skills = "statistics")
The version of gptr's public extension API (independent of the package version) and the
features this build offers: kind.<name> for every registered kind, event.<name> for every
cataloged event, and the named features lazy_activation, declarations, ctx.decide,
ctx.secret, route and services. Plugins test features instead of comparing versions.
gptr_api()gptr_api()
A gptr_api list with version (a package_version) and features (character).
gptr_api()$version "kind.router" %in% gptr_api()$featuresgptr_api()$version "kind.router" %in% gptr_api()$features
Artifacts are Shiny apps the agent builds from objects in your session. It writes
.gptr/artifacts/<id>/app.R and launches it with peter$app("<id>", data = c("obj")), which
snapshots the named objects into an immutable version directory (v001/, v002/, ...) and
serves it from a supervised background R process on 127.0.0.1, so the console stays free.
gptr_artifacts() lists the artifacts of the workspace (.gptr/, else a temporary
directory) and manages their processes.
gptr_artifacts(id = NULL, open = FALSE, stop = FALSE, version = NULL)gptr_artifacts(id = NULL, open = FALSE, stop = FALSE, version = NULL)
id |
|
open |
|
stop |
|
version |
The number of a stored version ( |
The built-in kind = "html" uses a working page.html and a Shiny serving wrapper.
Both built-in kinds need Shiny to launch. peter$app(..., launch = FALSE) creates a version
without launching it; startup and browser checks therefore remain unperformed. Browser
session checks and screenshots additionally need chromote and Chrome. A check value of
NA means it was skipped. Separate processes organize execution but are not OS sandboxes.
Without id, a gptr_artifacts data frame with the columns id, title, version
(the current version), status (running, stopped or failed), url, pid, bytes
(disk use of the artifact directory) and path (the working copy). With id, the
gptr_artifact handle: a list with id, title, kind, version, url (it carries the
launch's access token), path, status, checks (parse, launch, http and session,
each TRUE, FALSE or NA, plus messages), screenshot and session; it is returned
invisibly after open, stop or version.
An artifact runs model-written code in a separate R process whose environment holds none of
your registered secrets. It listens only on 127.0.0.1, and every launch gets a new 128-bit
access token that its URL carries (?gptr_token=); without the openssl package on Windows
there is no token and a notice says so. The data snapshot in vNNN/data/ is a copy of the
objects named in data; the .gptr/.gitignore that gptr_init() writes keeps it and run/
out of git.
gptr.artifact_max_bytes (default 5e8): the largest total object.size() of the objects
one version may snapshot; above it peter$app() signals gptr_error_artifact_too_large.
vignette("tools-and-artifacts", package = "gptr") for working files, data
snapshots, checks and lifecycle examples.
gptr_artifacts() # an empty listing when no artifact existsgptr_artifacts() # an empty listing when no artifact exists
A backend runs child sessions: start(spec, ctx) returns a handle the reactor can poll,
cancel(handle) stops it and every process it started. Backends never block the reactor for
more than 50 ms.
gptr_backend(name, start, poll = NULL, cancel, capabilities = list())gptr_backend(name, start, poll = NULL, cancel, capabilities = list())
name |
Backend name, usable as |
start |
|
poll |
|
cancel |
|
capabilities |
Named list: |
A spec of class c("gptr_backend", "gptr_spec").
gptr_backend("echo", start = function(spec, ctx) NULL, cancel = function(handle) NULL)gptr_backend("echo", start = function(spec, ctx) NULL, cancel = function(handle) NULL)
Reads an .R, .Rmd, .qmd or .ipynb document and lists its gptr blocks with their
status: fresh (the owning call's prompt matches), stale (the prompt changed, or no call
owns the block), user-edited (the body no longer matches its sha) or undone (made inert
by a rewind). Interpolated values are only known when the call runs, so they are not checked
here. It reads the document; the only write is that blocks an Rscript run queued before it
was killed are applied first (never over your edits).
gptr_blocks(file)gptr_blocks(file)
file |
Path of the document. |
A gptr_blocks data frame with columns id, lines, prompt, status, model,
date, tokens, cost, session.
f = tempfile(fileext = ".R") writeLines(c('peter("add one")', "# >>> gptr:7f3a21 model=fake/fake-1 date=2026-09-29 prompt=3b1c9a0e77d2", "x = 1 + 1", "# <<< gptr:7f3a21"), f) gptr_blocks(f)f = tempfile(fileext = ".R") writeLines(c('peter("add one")', "# >>> gptr:7f3a21 model=fake/fake-1 date=2026-09-29 prompt=3b1c9a0e77d2", "x = 1 + 1", "# <<< gptr:7f3a21"), f) gptr_blocks(f)
info lists the System 1 answer cache, the System 2 answer cache used for replay, temporary
spill files and unapplied document sidecars (deferred or pending blocks; they are never
removed here: apply them with gptr_doc(path, sync = TRUE)). prune removes System 2 answers
whose block is neither in its document nor queued for it in a sidecar, System 1 answers unused
for 90 days, temporary files older than getOption("gptr.spill_days", 7) days and older
refreshed model catalogs; clear removes a kind entirely.
gptr_cache( action = c("info", "prune", "clear"), kind = c("all", "s1", "s2", "tmp") )gptr_cache( action = c("info", "prune", "clear"), kind = c("all", "s1", "s2", "tmp") )
action |
|
kind |
|
Clearing the System 2 answer cache does not remove the R code of document blocks, but saved answers needed to reconstruct a replayed call may no longer be available.
info: a gptr_cache_info data frame with columns kind, entries, bytes,
oldest, path. prune and clear: the number of files removed, invisibly.
gptr_cache() gptr_cache("prune", "tmp")gptr_cache() gptr_cache("prune", "tmp")
Aborts the run of a session (or of each session in a list): transfers are canceled, child
processes stopped, the partial turn recorded as aborted, queued items moved to dropped, and
the status set to aborted. Idle sessions are left alone.
gptr_cancel(x)gptr_cancel(x)
x |
A session or a list of sessions. |
x, invisibly.
session = peter("long task", model = gptr_fake_provider(list(list(hang = TRUE))), .run = FALSE) gptr_cancel(session)session = peter("long task", model = gptr_fake_provider(list(list(hang = TRUE))), .run = FALSE) gptr_cancel(session)
Runs gptr's conformance suite, offline, in a scratch registry. For a spec: its fields and kind
validator, schema validity, direct tool descriptions of at most 400 tokens, prompt-section
budgets, empty-input handling of tools, the permission matrix for policies, start and cancel
for backends, and wire-fixture replay for adapters when the adapter checker is available. For
a factory function(gptr): it loads, registers something, takes no action at load, and each
registered spec passes. For an installed package name: its inst/gptr/plugin.json manifest,
API requirement, factory, every provided capability, and bare gptr identifiers in its code.
gptr_check(x, error = FALSE, tokens = FALSE)gptr_check(x, error = FALSE, tokens = FALSE)
x |
A spec, a factory |
error |
|
tokens |
|
A gptr_check data frame with columns target, check, ok and message.
gptr_check(gptr_tool("add", "Add two numbers", parameters = list(type = "object", required = I(c("a", "b")), properties = list(a = list(type = "number"), b = list(type = "number"))), fun = function(a, b) a + b, exposure = "r", namespace = "demo"))gptr_check(gptr_tool("add", "Add two numbers", parameters = list(type = "object", required = I(c("a", "b")), properties = list(a = list(type = "number"), b = list(type = "number"))), fun = function(a, b) a + b, exposure = "r", namespace = "demo"))
A console command /name args: handler(args, ctx) gets the raw text after the name and
returns NULL, a character vector (printed) or list(prompt = "...") (sent as a prompt).
gptr_command(name, handler, description = NULL, complete = NULL)gptr_command(name, handler, description = NULL, complete = NULL)
name |
Command name without the leading |
handler |
|
description |
One line for |
complete |
Optional |
A spec of class c("gptr_command", "gptr_spec").
gptr_command("rows", function(args, ctx) paste("rows:", nrow(mtcars)), description = "Show rows")gptr_command("rows", function(args, ctx) paste("rows:", nrow(mtcars)), description = "Show rows")
With no arguments, returns the effective settings with the layer each value came from:
package defaults < user settings.json < project .gptr/settings.json (an untrusted project
only tightens mode, context, record, permission rules and local-only inference) < the
user-level project file < options(gptr.*) < this R session. With named arguments, sets
those keys in one scope.
gptr_config(..., .scope = NULL)gptr_config(..., .scope = NULL)
... |
Named settings, e.g. |
.scope |
|
model, small_model, system1, mode and preset take bare names (mode = plan); NULL
removes a key from the scope. egress (the providers you allow automatic context to go to) is
accepted only at user scope. Local-only Ollama inference (providers = list(ollama = list(local_only = FALSE))) can be turned off only at user or session scope; a project can only
keep it on. Called from model code during a run, it is refused.
The "session" scope means this R process, not one conversation. User settings live at
tools::R_user_dir("gptr", "config")/settings.json; project settings live in .gptr/.
A no-argument call always reads effective values, even when .scope is supplied. Inspect
attr(gptr_config(), "sources") to see their origins. Named lists merge with lower layers;
protected objects such as providers must be set as a whole named list.
Without arguments, a gptr_config list. Otherwise the previous values in that scope,
invisibly (a named list; NULL where the key was unset).
Use settings for defaults such as model, mode, context, budget, record, replay
and registered extension selections. Use gptr_options for transport timeouts, output caps,
undo retention and concurrency. Arguments to peter() choose values for one call, within
inherited safety restrictions. vignette("configuration", package = "gptr") groups all
core settings and options and explains trust and scope.
gptr_init(), gptr_trust(), gptr_permissions() and gptr_options.
old = gptr_config(mode = plan, .scope = "session") gptr_config()$mode gptr_config(mode = old$mode, .scope = "session")old = gptr_config(mode = plan, .scope = "session") gptr_config()$mode gptr_config(mode = old$mode, .scope = "session")
A block of context the model receives in user messages: provide(ctx, budget) returns text (or
NULL to skip). placement puts it in the first message, in later turns, or both; turn blocks
equal to their previous text are skipped. authority = "operator" is accepted only from user,
plugin and built-in records.
gptr_context_block( name, provide, placement = c("turn", "first", "both"), authority = c("data", "operator"), budget = 300L, order = 650L )gptr_context_block( name, provide, placement = c("turn", "first", "both"), authority = c("data", "operator"), budget = 300L, order = 650L )
name |
Block name (the tag it is wrapped in). |
provide |
|
placement |
|
authority |
|
budget |
Token budget; longer text is truncated. |
order |
Position among blocks. |
A spec of class c("gptr_context_block", "gptr_spec").
gptr_context_block("lab_notebook", function(ctx, budget) "Experiment 12: cohort B only.", placement = "first", order = 650L)gptr_context_block("lab_notebook", function(ctx, budget) "Experiment 12: cohort B only.", placement = "first", order = 650L)
An S3 generic used for the <attached> and <workspace> context blocks, peter$describe()
and console mentions. Methods return successively richer levels of detail and the richest
level whose estimated size fits budget is returned. Methods never force promises, never do
I/O (no dbListTables(), no collect()) and never call str() on the object. Packages add
methods with a delayed S3method(gptr::gptr_describe, <class>).
gptr_describe(x, budget = 150L, ...) ## Default S3 method: gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'data.frame' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'matrix' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'list' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'environment' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class ''function'' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'formula' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'lm' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'dgCMatrix' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'Seurat' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'SingleCellExperiment' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'ArrowTabular' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'Dataset' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'DBIConnection' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'ggplot' gptr_describe(x, budget = 150L, ..., level = NULL)gptr_describe(x, budget = 150L, ...) ## Default S3 method: gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'data.frame' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'matrix' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'list' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'environment' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class ''function'' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'formula' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'lm' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'dgCMatrix' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'Seurat' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'SingleCellExperiment' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'ArrowTabular' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'Dataset' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'DBIConnection' gptr_describe(x, budget = 150L, ..., level = NULL) ## S3 method for class 'ggplot' gptr_describe(x, budget = 150L, ..., level = NULL)
x |
Any R object. |
budget |
Estimated tokens, at least 20 (default 150). |
... |
Passed to methods; built-in methods accept |
level |
Built-in methods: the detail level to return (default: the richest that fits). |
A character vector of lines; the first is a header <class> shape, size.
gptr_describe(mtcars, budget = 60) gptr_describe(as.Date("2026-01-01") + 0:9)gptr_describe(mtcars, budget = 60) gptr_describe(as.Date("2026-01-01") + 0:9)
gptr_doc(path) binds every peter() call of this R process, at the console and in scripts,
to a history document, and is your explicit consent that gptr writes agent blocks into it.
Nothing is written until a block is recorded. gptr_doc(FALSE) removes the binding and
gptr_doc() shows it. sync = TRUE writes the blocks that were recorded while the document
could not be written: a Jupyter notebook that was open, or the deferred writes of an Rscript
run that was killed.
gptr_doc(path = NULL, format = NULL, sync = FALSE)gptr_doc(path = NULL, format = NULL, sync = FALSE)
path |
|
format |
|
sync |
|
Eligible top-level calls and pipe chains own document blocks; calls nested inside loops
or functions do not. Binding supplies recording consent even when automatic recording is
off, but .opts = list(record = FALSE) suppresses recording for that call. Binding does
not reconstruct earlier unrecorded turns. A narrative summary or model-generated script
draft needs review and execution checks before it can serve as a reproducible workflow.
With path = NULL, the binding list(path, format) or NULL, visibly. Otherwise the
previous binding, invisibly.
Options of history documents (?gptr_options collects every option):
gptr.record (settings, "ask"): "auto" records into documents without asking, "off"
prevents automatic recording; an explicit binding supplies consent. Also the settings key
record, which a project can only tighten. A call's .opts = list(record = FALSE) opts out
even when bound; .opts = list(record = TRUE) retains the usual consent checks.
gptr.replay (settings, "auto"): the replay mode "auto", "replay", "live" or
"record" (also the GPTR_REPLAY environment variable); a call's replay = argument wins.
gptr.doc_output_lines (12): #> output lines recorded per execution.
gptr.doc_source_frames (TRUE): FALSE stops gptr from reading source() frames to find
calls in scripts sourced without srcrefs.
gptr.spill_days (7): gptr_cache("prune") removes temporary files older than this.
f = tempfile(fileext = ".R") writeLines("library(gptr)", f) gptr_doc(f) gptr_doc() gptr_doc(FALSE)f = tempfile(fileext = ".R") writeLines("library(gptr)", f) gptr_doc(f) gptr_doc() gptr_doc(FALSE)
gptr sends data to a model provider only when you run a prompt with that provider's model. The package itself collects nothing: there is no telemetry, no usage reporting and no network access when the package loads. This page lists what a request contains so that you can decide what may leave your machine.
R tools compute on objects already in memory; a large dataset does not need to be uploaded in full for a conversational agent to analyze it. Descriptions and tool results can still contain data values. Native typed decision inputs use the separate encoding described below.
Your prompt and the conversation so far.
With summary context, a budgeted description of each attached object (its class, dimensions, column names and types and a few values); a small object can appear in full.
Automatic context: a short listing of the objects in the evaluation environment (names,
classes and sizes), the R version, platform and available packages, and the project
instruction files (AGENTS.md, CLAUDE.md, .gptr/vignette.Rmd).
Tool results: the printed output of R code the model ran, the parts of files it read, and
images of plots it made. In manual mode every action that is not known to be read-only
needs your approval before its result can be sent.
A System 1 question (a classifier model such as Jev) sends the inputs themselves: each
element of a vector (text up to 100,000 characters), each row of a data frame as a record, a
description of larger objects, and for a piped session its last answer (at most
gptr.s1_state_max characters). Do not ask System 1 questions about data that may not leave
your machine.
Registered secrets are replaced by markers before anything is sent.
.opts = list(context = "names") sends workspace object names and attached-object headers,
and .opts = list(context = "none") suppresses workspace and attached-object descriptions.
Prompts, tool results and native typed decision inputs have their own paths. Attach only the
objects the task needs. The plan mode permits actions classified as read-only so you can
inspect a proposed workflow before allowing changes to your workspace.
The first time you use a provider (or a command-line route such as claude_code or codex)
in an interactive session, gptr shows what automatic context is sent and records your
acknowledgment in your user settings. A non-interactive run with a provider that was never
acknowledged stops with a gptr_error_egress condition. Record the acknowledgment once with
gptr_config(egress = list(anthropic = "ack"), .scope = "user") (this replaces the stored
list, so name every provider you use), or run with .opts = list(context = "none"). Offline
providers such as gptr_fake_provider() and local providers on a loopback address need no
acknowledgment. An Ollama server can forward requests to cloud models, so Ollama is exempt only
while its local-only inference is on (the default; see providers in gptr_config()).
gptr contacts nothing else on its own. The model catalog is refreshed only by
gptr_models(refresh = TRUE), reachability checks run only with
gptr_providers(check = TRUE), and MCP servers, sub-agents and command-line tools are
contacted only when a session uses them. The claude and codex command-line routes send
the conversation through those vendors' tools under their own terms.
gptr_security, gptr_options, gptr_providers(), gptr_config().
Reads a .env file with gptr's own parser (a UTF-8 byte-order mark, CRLF line ends,
export prefixes, single and double quotes, multi-line quoted values, # comments and
hyphenated names such as jev-key are understood), maps aliases onto canonical variable
names (jev-key, JEV_KEY, JEV_API_KEY and TYPESAFE_KEY become TYPESAFE_API_KEY; a
line spelled exactly as the canonical name wins over an alias), registers secret values
in gptr's vault for redaction, and exports the canonical names with Sys.setenv(). Plain
configuration fields with suffixes such as _URL or _PATH are not registered as
secrets. It never prints, logs or returns a value.
gptr_env( path = ".env", aliases = NULL, set_env = getOption("gptr.env_export", TRUE), override = FALSE, quiet = FALSE )gptr_env( path = ".env", aliases = NULL, set_env = getOption("gptr.env_export", TRUE), override = FALSE, quiet = FALSE )
path |
Path of an existing |
aliases |
|
set_env |
If |
override |
If |
quiet |
If |
Invisibly, a gptr_env_report data frame with columns name (as spelled in the
file), variable (the canonical name), secret, fingerprint and action ("set",
"registered", "skipped" or "duplicate"), and the attribute bad_lines (the numbers
of malformed lines). It holds names and fingerprints, never values.
f = tempfile(fileext = ".env") writeLines("jev-key=example-not-a-real-key-123", f) gptr_env(f, set_env = FALSE)$variable unlink(f)f = tempfile(fileext = ".env") writeLines("jev-key=example-not-a-real-key-123", f) gptr_env(f, set_env = FALSE)$variable unlink(f)
Reads a synchronized .R history without executing it, asking a model or recovering
pending writes. In "r" format the original Peter statements become comments and their
recorded R stays executable. In "peter" format calls stay active and recorded R becomes
comments, so it is not executed a second time. User R and comments keep their source order.
gptr_export(file, to, format = c("r", "peter"))gptr_export(file, to, format = c("r", "peter"))
file |
An existing |
to |
A new |
format |
|
Only bare or symbol-assigned literal Peter calls and Peter-only native pipelines are admitted. Distinct statements sharing a line (including semicolon-separated statements), mixed pipelines, nested or computed calls, pending writes, missing or edited blocks, secret markers and interpolated-input hashes are refused. Raw exports also refuse ordinary code that uses a removed session handle. The Peter format retains such ordinary references, since its calls remain active. Feedback follows each pipeline operand when calls end on separate lines and only its pipe operator or a comment follows the closing call. Feedback follows the next operand's indentation (at most 74 characters); other layouts keep feedback after the complete statement. Peter calls already show their prompts, so only raw R adds prompt comments. Long raw prompt comments wrap at eighty characters. Strip the recorded-prompt prefix from the first line and the two-character comment prefix from continuations, then join without separators to recover the complete escaped R string literal. A Peter-only pipeline on one line keeps grouped feedback after the statement. Call source is never reformatted.
A completed-turn identity and matching source hashes establish a recorded snapshot, not
verified execution or a complete session. Ordinary console input and record = FALSE
effects cannot be reconstructed. External files, objects and package versions must still
be supplied. Remaining user code may use gptr or perform network and filesystem operations.
Captured #> output is limited to twelve lines per block and eighty characters per line;
outputs are comments. Encoding, line endings and the final newline follow the input file.
A UTF-8 byte order mark is preserved; source that exported file with
source(to, encoding = "UTF-8-BOM").
Invisibly, the normalized destination path.
gptr_doc(), gptr_source(), gptr_blocks()
input = tempfile(fileext = ".R") output = tempfile(fileext = ".R") writeLines(c("x = 1", "# Keep ordinary code and comments.", "y = x + 1"), input) gptr_export(input, output) readLines(output) unlink(c(input, output))input = tempfile(fileext = ".R") output = tempfile(fileext = ".R") writeLines(c("x = 1", "# Keep ordinary code and comments.", "y = x + 1"), input) gptr_export(input, output) readLines(output) unlink(c(input, output))
gptr_fake_provider() returns a provider spec that plays a script instead of calling a
model. It needs no network and no keys, so examples, tests and documents can run gptr end to
end offline. Use it as model = <spec> or register it with gptr_register().
gptr_fake_provider(script, name = "fake", type = c("chat", "classifier"))gptr_fake_provider(script, name = "fake", type = c("chat", "classifier"))
script |
A list of replies or a function (see Details). |
name |
Provider id: lower-case letters, digits and |
type |
|
A chat script is a list of replies (request i gets reply min(i, length(script)), so the
last reply repeats) or a function of the request returning one reply. The request is a list
with n, model, system, tools, messages, last_user, last_results and params. A
reply is a string (the answer text) or a list with any of: text; thinking and
signature; tool with input and id (one tool call); tools (a list of
list(name, input) for parallel calls); stop ("length", "refusal", "pause" or
"stop"); error with status and after (fail after after text deltas);
overflow = TRUE; hang = TRUE; json (a structured answer); and the modifiers delay,
gap, chunk and usage.
A classifier script (type = "classifier") answers System 1 questions: a list of answers
(recycled the same way, one answer per question asked) or function(state, question). An
answer is a probability for yes/no questions, a named probability vector for choices, a
vector of level probabilities for scores, or list(error =, status =). Classifier results
use the provider-neutral decision shape and report calibration as unknown (NA).
A provider spec: a list of class c("gptr_provider", "gptr_spec") with id = name,
api "fake" or "fake-classifier", one model ("<name>/<name>-1", or
"<name>/<name>-s1" for classifiers), offline = TRUE, the script, and log, an
environment whose requests element lists every request the provider received.
fake = gptr_fake_provider(list( list(tool = "r", input = list(code = "n = nrow(d)")), "There are 32 rows." )) fake$models[[1]]$ref fake$offline judge = gptr_fake_provider(list(0.93), name = "judge", type = "classifier") judge$models[[1]]$reffake = gptr_fake_provider(list( list(tool = "r", input = list(code = "n = nrow(d)")), "There are 32 rows." )) fake$models[[1]]$ref fake$offline judge = gptr_fake_provider(list(0.93), name = "judge", type = "classifier") judge$models[[1]]$ref
Creates a new idle session whose transcript is the source path up to a cut, with the same entry
ids. Nothing live is shared (listeners, queue, run, lock, usage); the fork's file is written
lazily at its first own message, with parentSession and gptr.forkOf in its header. The
fork's workspace is an overlay of the source's kept home: it reads every object of the source
at zero cost, and its writes stay in the overlay.
gptr_fork(s, at = NULL, envir = c("overlay", "shared"))gptr_fork(s, at = NULL, envir = c("overlay", "shared"))
s |
A |
at |
|
envir |
|
A new idle gptr_session.
fake = gptr_fake_provider(list("A", "B")) session = peter("first", model = fake) branch = gptr_fork(session) branch |> peter("branch") c(session$turns, branch$turns)fake = gptr_fake_provider(list("A", "B")) session = peter("first", model = fake) branch = gptr_fork(session) branch |> peter("branch") c(session$turns, branch$turns)
A hook runs handler(event, ctx) for one event of the catalog (see gptr_api()$features) or
for a plugin channel named "<plugin>:<topic>". What the handler may return depends on the
event: patches for tool_result, a decision for tool_call, nothing for notifications.
Handlers of tool_call, permission_request and document_write fail closed: an error blocks
or denies, and a tool_call answer with an unknown decision (anything but "block",
"modify" with an input list, or "allow"; for example "deny") blocks.
gptr_hook(event, handler, matcher = NULL)gptr_hook(event, handler, matcher = NULL)
event |
Event name. |
handler |
|
matcher |
|
A spec of class c("gptr_hook", "gptr_spec"), named after its event.
gptr_hook("tool_result", function(event, ctx) NULL, matcher = "r")gptr_hook("tool_result", function(event, ctx) NULL, matcher = "r")
.gptr/
Creates .gptr/ with settings.json, skills/, agents/, prompts/, and (by default) the
project-instructions file vignette.Rmd and .gitignore. Existing files are never
overwritten, so calling it again is safe. There is no default path: without path gptr asks
Create .gptr/ in <project>? [y/N] when you can answer, and signals an error otherwise.
Creating the workspace is consent to write there; it is not trust: gptr then asks separately
whether to trust the project (see gptr_trust()). In a package source it offers the
^\.gptr$ line for .Rbuildignore and never writes it silently.
gptr_init(path, instructions = TRUE, gitignore = TRUE)gptr_init(path, instructions = TRUE, gitignore = TRUE)
path |
The project directory (it must exist). |
instructions |
Write |
gitignore |
Write |
The absolute path of .gptr/, invisibly (NULL when you declined).
d = tempfile("proj") dir.create(d) gptr_init(d) list.files(file.path(d, ".gptr"), all.files = TRUE) unlink(d, recursive = TRUE)d = tempfile("proj") dir.create(d) gptr_init(d) list.files(file.path(d, ".gptr"), all.files = TRUE) unlink(d, recursive = TRUE)
Lists the job table of this R process: background sessions, peter$bg() jobs, Shiny
artifacts, the MCP server started by gptr_mcp_serve(), sub-agent workers and
subscription-CLI children. A finished job whose stop was requested reads stopped or
aborted, never error. Unavailable status information is shown as unknown.
gptr_jobs(kill = FALSE)gptr_jobs(kill = FALSE)
kill |
|
A gptr_jobs data frame with the columns id, kind (session, bg,
artifact, mcp_serve, worker, cli), name, pid, status and started.
Options of the transport and process layer (?gptr_options collects every option):
gptr.max_active (8): concurrent HTTP transfers (global).
gptr.connect_timeout (20), gptr.first_byte_timeout (120), gptr.idle_timeout (90):
seconds; there is no total timeout on streams.
gptr.max_retry_delay (60): seconds; a longer retry-after fails fast.
gptr.max_attempts (4): transport attempts per request.
gptr.wire_log (FALSE): TRUE writes one redacted JSON line per request start and end
to <workspace root>/cache/tmp/wire-<session id>.jsonl; a path must lie inside the
workspace root or tempdir().
gptr.supervise (NULL): processx supervision of children; NULL means on, except under
R CMD check.
gptr.stdin_timeout (60): seconds a child may take to accept pending stdin bytes.
gptr_jobs()gptr_jobs()
Stores a credential for a model provider (for example "openrouter") or for an MCP server
("mcp:<server>"). With method = "auto", providers and MCP servers that support OAuth
get the authorization-code flow with PKCE (S256): a page on 127.0.0.1 receives the redirect
when 'httpuv' and 'later' are installed; otherwise you paste the address your browser ends
on. Everything else gets masked key entry. Credentials go to the credential store
(auth.json, readable only by you, or a keyring reference); access tokens stay in memory.
A tool call never opens a browser: when an MCP server needs a sign-in, the call fails with
an error naming this function.
gptr_login(provider, method = c("auto", "oauth", "key")) gptr_logout(provider)gptr_login(provider, method = c("auto", "oauth", "key")) gptr_logout(provider)
provider |
A provider id such as |
method |
|
gptr_login() returns TRUE invisibly; gptr_logout() removes the stored
credential and forgets the access token held in memory, and returns TRUE invisibly when
it removed something, else FALSE.
if (interactive()) { gptr_login("openrouter") gptr_logout("openrouter") }if (interactive()) { gptr_login("openrouter") gptr_logout("openrouter") }
Without tools, lists gptr's servers (the user mcp.json and, in a trusted project,
.gptr/mcp.json) together with the servers configured for Claude Code, Claude Desktop,
Codex, Cursor, VS Code and Pi, which gptr reads but never edits. Nothing is started: the era
and the tool counts come from gptr's caches. With tools = TRUE, lists the tools of
server (or of every usable server) with their R signatures and catalog cost, from the
cache when it is fresh and otherwise by connecting (which starts stdio servers). Servers of
an untrusted project are listed but never started.
gptr_mcp(server = NULL, tools = FALSE, refresh = FALSE)gptr_mcp(server = NULL, tools = FALSE, refresh = FALSE)
server |
A server name, or |
tools |
|
refresh |
|
A gptr_mcp_servers data frame (name, source, transport, era, status,
tools, exposure, tokens, trusted) or, with tools = TRUE, a data frame with
server, tool, signature, exposure and tokens.
gptr_mcp_add, gptr_mcp_remove, gptr_login, gptr_mcp_serve;
vignette("mcp", package = "gptr") for setup, authentication and tool calls.
gptr_mcp()gptr_mcp()
gptr_mcp_add() writes a server into gptr's own mcp.json: the user file under
tools::R_user_dir("gptr", "config"), or .gptr/mcp.json of the project (used only when
you trust the project). It never edits another harness's files. Give exactly one of
command (a server started as a local process speaking stdio) and url (a Streamable HTTP
server). Secret values in env and headers must be ${VAR} placeholders: they are
expanded from the environment when gptr connects and never stored. Nothing connects until a
tool is used.
gptr_mcp_add( name, command = NULL, args = character(), url = NULL, env = NULL, headers = NULL, exposure = "r", timeout = 60, scope = c("user", "project") ) gptr_mcp_remove(name, scope = c("user", "project"))gptr_mcp_add( name, command = NULL, args = character(), url = NULL, env = NULL, headers = NULL, exposure = "r", timeout = 60, scope = c("user", "project") ) gptr_mcp_remove(name, scope = c("user", "project"))
name |
Server name: 1-64 letters, digits, |
command, args
|
The program and its arguments for a stdio server. |
url |
The endpoint of a Streamable HTTP server. |
env, headers
|
Named character vectors: environment variables of a stdio server, HTTP
headers of an HTTP server. Write secrets as |
exposure |
How the model reaches the tools: |
timeout |
Seconds per request; progress notifications from the server extend it. |
scope |
|
gptr_mcp_add() returns the server spec invisibly; gptr_mcp_remove() returns
TRUE invisibly when a server was removed, else FALSE.
proj = tempfile("proj") dir.create(proj) old = options(gptr.project_root = proj) gptr_init(proj) gptr_mcp_add("fs", command = "npx", args = c("-y", "@modelcontextprotocol/server-filesystem", "."), scope = "project") gptr_mcp_remove("fs", scope = "project") options(old) unlink(proj, recursive = TRUE)proj = tempfile("proj") dir.create(proj) old = options(gptr.project_root = proj) gptr_init(proj) gptr_mcp_add("fs", command = "npx", args = c("-y", "@modelcontextprotocol/server-filesystem", "."), scope = "project") gptr_mcp_remove("fs", scope = "project") options(old) unlink(proj, recursive = TRUE)
Starts an MCP server inside this R session that offers r, read, edit and write to
agents such as Codex, Claude Code, Claude Desktop or Cursor. It listens only on 127.0.0.1,
requires a 192-bit bearer token, rejects foreign browser origins, and runs every call through
your permission settings; R code evaluates in envir, where its objects persist. The calls
belong to a dedicated gptr session whose permission mode is the one in effect when the server
starts (stop and start the server to change it); like any new session, it becomes
gptr_last(). Requests are answered while R waits at the console or inside a gptr call; one
that needs your approval is refused with a note on how to allow it, because gptr never asks
from a background callback. The token appears only in the snippets of $config (printed
redacted; as.character() gives the text to paste; $config$codex holds the codex options
in $args and the environment to start Codex with in $env) and in the environment of
children gptr starts. One server runs per R process. Needs 'httpuv', 'later' and 'openssl'.
gptr_mcp_serve( tools = c("r", "read", "edit", "write"), envir = parent.frame(), port = NULL, stop = FALSE )gptr_mcp_serve( tools = c("r", "read", "edit", "write"), envir = parent.frame(), port = NULL, stop = FALSE )
tools |
The tools to serve: a subset of |
envir |
Where served R code evaluates and its objects persist. |
port |
A port, or |
stop |
|
If shutdown cannot be confirmed, access is revoked and the server is retained for retry.
Call gptr_mcp_serve(stop = TRUE) again; new requests are refused until shutdown completes.
A gptr_mcp_handle with $url, $port, $token_env, $config and $stop();
calling again returns the running handle; with stop = TRUE, invisible(NULL).
if (interactive() && rlang::is_installed(c("httpuv", "later", "openssl"))) { h = gptr_mcp_serve(envir = new.env()) h$config$codex gptr_mcp_serve(stop = TRUE) }if (interactive() && rlang::is_installed(c("httpuv", "later", "openssl"))) { h = gptr_mcp_serve(envir = new.env()) h$config$codex gptr_mcp_serve(stop = TRUE) }
Searches the merged model catalog: the shipped snapshot (models.dev plus gptr's reviewed
prices and capabilities), a refreshed copy in tools::R_user_dir("gptr", "cache"), models
declared by registered providers, user configuration and discovered local servers. Offline
by default: only refresh = TRUE touches the network.
gptr_models(query = NULL, provider = NULL, refresh = FALSE)gptr_models(query = NULL, provider = NULL, refresh = FALSE)
query |
|
provider |
|
refresh |
|
A catalog entry describes a route, not current account access. Copy its ref into the
model argument of peter() to choose that route. Ollama routes require current installed
model evidence before inference; discovery does not pull models. See
vignette("language-models", package = "gptr") for setup and gptr_providers() for
credentials and reachability.
A gptr_models data frame with columns ref, provider, name, context,
max_output, input_price, output_price (USD per million tokens, selected for today's
date from the available catalog; 0 for verified local inference, NA when unknown),
reasoning, aliases and status. Catalog prices can be stale and are not an account quote.
gptr_models("sonnet") gptr_models(provider = "anthropic")gptr_models("sonnet") gptr_models(provider = "anthropic")
Registers a session-scoped hook (rank 0) for one cataloged event (such as message_end,
tool_call, turn_end) or a plugin channel containing :. The handler is
function(event, ctx) and returns what the event allows. Forks never copy listeners.
gptr_on(s, event, handler, matcher = NULL)gptr_on(s, event, handler, matcher = NULL)
s |
A session. |
event |
An event name; Claude and Codex hook names are refused with the gptr name. |
handler |
|
matcher |
|
A function of no arguments that removes the hook, invisibly.
session = peter("hi", model = gptr_fake_provider(list("hello")), .run = FALSE) seen = new.env() seen$roles = character() off = gptr_on(session, "message_end", function(event, ctx) { seen$roles = c(seen$roles, event$message$role) NULL }) gptr_step(session) off() seen$rolessession = peter("hi", model = gptr_fake_provider(list("hello")), .run = FALSE) seen = new.env() seen$roles = character() off = gptr_on(session, "message_end", function(event, ctx) { seen$roles = c(seen$roles, event$message$role) NULL }) gptr_step(session) off() seen$roles
gptr reads each option with getOption() at the moment it needs it, so options set with
options() take effect at the next call. Options marked settings have no default of their
own: when unset, the value comes from the settings layers written by gptr_config()
(session, project .gptr/settings.json, user settings). The safety options (gptr.ui,
gptr.interactive, the guards, gptr.noninteractive_ask, gptr.protect_size, gptr.mode
and gptr.unsafe_no_permissions) are copied when a run starts, so code that the model runs
cannot change them for that run.
gptr.quiet (logical, FALSE): silence notices and progress messages.
gptr.interactive (logical or NULL, NULL): force the decision whether a person is
present to answer questions and permission prompts. This does not supply a UI or an answer
in an unattended process.
gptr.verbose (integer or NULL, NULL): 0 silent, 1 progress on stderr (stdout in an
ordinary IRkernel cell), 2 the streamed console, 3 debugging; NULL chooses by context
(0 in knitr and testthat, 1 under
Rscript, 2 at the console).
gptr.ui (character, UI spec or NULL, NULL): the user-interface backend; NULL means
the console when a person is present, else none.
gptr.history (logical, TRUE): add console inputs to the R history.
gptr.deprecations (character, "warn"): "warn" or "error" for deprecated calls.
gptr.model, gptr.mode, gptr.preset, gptr.system1, gptr.small_model (character or
NULL, settings): the option layer of the settings of the same names.
gptr.project_root (character or NULL, NULL): the project root; also the environment
variable GPTR_PROJECT_ROOT.
gptr.replay (character or NULL, settings, "auto"): how recorded document blocks are
used: "auto", "replay", "live" or "record"; the replay argument of peter() wins.
gptr.record (character or NULL, settings, "ask"): whether gptr may write into
documents: "auto", "ask" or "off".
gptr.interpolate (logical, TRUE): {identifier} interpolation in literal prompts.
gptr.max_turns (integer, 50): turns per programmatic run.
gptr.max_turns_console (integer, 200): turns per console prompt.
gptr.max_nested_calls (integer, 20): peter() calls per evaluation of model code.
gptr.value_copy_max (bytes, 1048576): designated result values below this size are
copied; larger ones are kept by name.
gptr.values_max_bytes (bytes, 67108864): value copies held per session.
gptr.background_tools (character, "idle"): "idle" or "wait" for experimental
background sessions.
gptr.out_keep (integer, 20): results kept per session for peter$out().
gptr.spill_days (number, 7): age in days after which spill files are pruned.
gptr.max_active (integer, 8): concurrent HTTP transfers.
gptr.subagents.max_active (integer, 8): concurrent inline sub-agents; the default of
gptr_parallel()'s max_active.
gptr.subagents.max_cli (integer, 4): concurrent command-line sub-agents.
gptr.subagents.max_workers (integer or NULL, NULL): worker processes; NULL means
min(4, cores - 1). Under R CMD check every pool of child processes is capped at 2.
gptr.subagents.max_tasks (integer, 8): children per team or fan-out started by model
code.
gptr.subagents.max_depth (integer, 1): nesting depth of child sessions (at most 2).
gptr.child_text_max (bytes, 51200): text returned per child task.
gptr.connect_timeout (seconds, 20), gptr.first_byte_timeout (seconds, 120) and
gptr.idle_timeout (seconds, 90): network timeouts.
gptr.max_retry_delay (seconds, 60): a longer retry-after from a provider fails at
once.
gptr.max_attempts (integer, 4): transport attempts per request.
gptr.wire_log (logical or path, FALSE): write a redacted log of every request and
response inside the workspace or the session temporary directory.
gptr.supervise (logical or NULL, NULL): supervise child processes; NULL means yes
except under R CMD check.
gptr.stdin_timeout (seconds, 60): time allowed to write pending input to a child.
gptr.cli_path (named list or NULL, NULL): explicit paths of the claude and codex
command-line tools.
gptr.cli_turn_timeout (seconds, 3600): wall-clock time per command-line turn.
gptr.r_timeout (seconds, 3600): time limit of the r tool when nobody is present.
gptr.r_output_tokens (integer, 4000): estimated tokens of one r result.
gptr.r_max_images (integer, 3): plot images attached to one r result.
gptr.helper_output_tokens (integer, 1500): printed size of peter$ helper results.
gptr.read_max_tokens (integer, 12000): size cap of the read tool.
gptr.plot_width, gptr.plot_height, gptr.plot_res (integers, 768, 512, 120):
plots sent to the model.
gptr.noninteractive_ask (character, "stop"): what a permission question does when
nobody can answer: "stop" ends the run with status blocked and a
gptr_error_permission condition; "deny" returns a denial to the model.
gptr.critical_guard (logical, TRUE): level-4 actions ask even in auto mode.
gptr.secret_guard (logical, TRUE): reads of registered secrets ask even in auto
mode.
gptr.protect_size (bytes, 1e8): overwriting a larger object is a level-3 action.
gptr.plan_handoff (logical, TRUE): hand a plan from plan mode to the next call.
gptr.unsafe_no_permissions (logical, FALSE): turns the permission gate off entirely;
honored only when set outside a run, for sandboxed continuous integration.
gptr.compact_at (tokens or NULL, 200000): the compaction soft cap; NULL disables
the cap.
gptr.compact_cold_min (tokens, 100000): the size above which a cold cache compacts.
gptr.cache_ttl (character, "gap"): prompt-cache lifetime policy: "gap", "5m" or
"1h".
gptr.cache_gap (seconds, 240): a pause between requests longer than this switches the
cache lifetime to one hour.
gptr.check_prefix (character, "event"): what a broken cache prefix does: "event",
"warn" or "error".
gptr.skills_budget (integer, 1500) and gptr.mcp_budget (integer, 1500): tokens of
the skill and MCP tool catalogs.
gptr.checkpoint (character, "on"): "on", "files" or "off".
gptr.undo_capture_max (bytes, 1e8): objects up to this size are captured by reference
before a change, even when the change was not predicted.
gptr.undo_max_bytes (bytes, 1e9): object images held in memory per session.
gptr.undo_spill_max (bytes, 2e9): the largest object image written to disk.
gptr.undo_turns (integer, 20): object images older than this many turns are dropped.
gptr.checkpoint_disk_bytes (bytes, 2e9), gptr.checkpoint_days (days, 30) and
gptr.checkpoint_turns (integer, 100): retention of the checkpoint store.
gptr.checkpoint_track_file_max (bytes, 1e6) and gptr.checkpoint_track_total (bytes,
1e8): the per-file and total size of tracked project files.
gptr.checkpoint_capture_max (bytes, 5e7): a larger changed file gets no stored copy.
gptr.checkpoint_scan_budget (seconds, 0.25): above this walk time the project is
scanned once per turn.
gptr.checkpoint_rng (logical, TRUE): report changes of the random-number state in the
rewind report (gptr never changes your random seed).
gptr.checkpoint_close_devices (logical, FALSE): close graphics devices opened by an
undone turn.
gptr.redact_min_chars (integer, 8): the shortest secret value that is redacted.
gptr.redact_patterns (logical, TRUE): also redact text that looks like a key; known
values are always redacted.
gptr.stream_hold_max (integer, 4096): characters held back while redacting a stream.
gptr.env_export (logical, TRUE): the default of gptr_env(set_env =).
gptr.prompt_secrets (character, "redact"): secret-looking text in prompts:
"redact" or "ask".
gptr.s1_max_active (integer, 8): concurrent System 1 requests.
gptr.s1_rounds (integer, 3): retry rounds for failed elements.
gptr.s1_state_max (integer, 2000): characters of a session's state sent to System 1.
gptr.s1_max_elements (integer, 10000): elements per System 1 call.
gptr.doc_output_lines (integer, 12): output lines recorded per execution.
gptr.doc_source_frames (logical, TRUE): let gptr find the calling line of a script run
with source().
gptr.mcp_timeout (seconds, 60) and gptr.mcp_probe_timeout (seconds, 5): MCP
request and protocol-probe time limits.
gptr.mcp_debug (logical, FALSE): keep redacted MCP server logs in the user cache.
gptr.artifact_max_bytes (bytes, 5e8): the largest artifact data snapshot.
GPTR_REPLAY: the replay mode below the gptr.replay option; GPTR_REPLAY=replay proves
that a script makes no model calls.
GPTR_PROJECT_ROOT: overrides the project root, like gptr.project_root.
ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, TYPESAFE_API_KEY and the other
provider keys: read at the first use of a provider; see gptr_env() for .env files.
GPTR_WORKER, GPTR_SUBAGENT_DEPTH and GPTR_MCP_TOKEN: set by gptr in its own child
processes only.
GPTR_LIVE_TESTS: "true" enables the package's live tests; not used at run time.
_R_CHECK_PACKAGE_NAME_: set by R CMD check; outside the package's own tests gptr then
replays recorded document blocks only and caps each child-process pool at two.
gptr_config() for settings stored in files, gptr_security and gptr_egress;
vignette("configuration", package = "gptr") for scope, precedence and grouped examples.
Each argument is a peter() call; it is evaluated with deferral on, so it builds its session
without running it, and all members then run together on one reactor, at most max_active at
a time. The result is a team session: team$text joins the members' answers under
### <name> (<model>) headings, team$value is the named list of their values, and
team$<name> (or team[[i]]) is a member's session. Piping the team into peter() continues
it.
gptr_parallel( ..., .list = NULL, max_active = NULL, on_error = c("return", "stop") )gptr_parallel( ..., .list = NULL, max_active = NULL, on_error = c("return", "stop") )
... |
Named |
.list |
A named list of sessions created with |
max_active |
The number of members that run at once; |
on_error |
|
Members evaluate R code in their own environment (envir =) with their own random-number
stream, and share one budget, as one peter() call does. A member's tools =, budget = and
the run options in its .opts (such as max_turns) are not applied.
Use peter(..., agents = list(...)) for named roles on one task, or parallel = for one
task per input element. Those routes start new foreground children and cannot be deferred
as members here. A team report is model-generated output; inspect child statuses and
workspace results before continuing the team with a synthesis prompt.
A team session (kind = "team").
fake = gptr_fake_provider(list("ok")) session = gptr_parallel(planner = peter("Plan it", model = fake), review = peter("Review it", model = fake)) names(session$children)fake = gptr_fake_provider(list("ok")) session = gptr_parallel(planner = peter("Plan it", model = fake), review = peter("Review it", model = fake)) names(session$children)
Lists the permission rules in effect, or adds and removes rules. A rule is tool or
tool(spec): a path glob for read, write, edit, grep, find and ls
(write(results/**), relative to the project root; ~/... for the home; //... for other
absolute paths); for r, level<=n, fn:name,... (every flagged function covered),
category:name,..., sh:<command glob> (r(sh:git status*)), sql:<keywords>
(r(sql:select)) and secret:NAME (the only rule that pre-approves a guarded secret read);
MCP tools by name (mcp__github__*). Deny rules win over ask rules, which win over allow
rules. Allow rules never loosen plan mode and never pre-approve level-4 (critical or control)
actions.
gptr_permissions( allow = NULL, ask = NULL, deny = NULL, remove = NULL, scope = c("session", "project", "user") )gptr_permissions( allow = NULL, ask = NULL, deny = NULL, remove = NULL, scope = c("session", "project", "user") )
allow, ask, deny
|
Character vectors of rules to add to that list, or |
remove |
Character vector of rules to remove from every list of |
scope |
One of |
Scopes: "session" is this R process; "project" is the user-level project file
tools::R_user_dir("gptr", "config")/projects/<hash>.json, personal and never inside the
project tree; "user" is the user settings file. The listing also shows the shared project
rules of .gptr/settings.json (an untrusted project contributes only deny and ask
rules) and the deny/ask rules of a legacy .gptr/settings.local.json in a trusted
project.
Called from model code during a run, adding or removing rules needs the user's approval of
that call; otherwise it signals gptr_error_permission.
A gptr_permissions data frame with columns rule, list, scope and source;
invisibly when rules were added or removed.
gptr_permissions(allow = "r(level<=1)") gptr_permissions() gptr_permissions(remove = "r(level<=1)")gptr_permissions(allow = "r(level<=1)") gptr_permissions() gptr_permissions(remove = "r(level<=1)")
Lists the plugins gptr can see: plugins enabled through peter(plugins = ) or the plugins
setting (a settings plugin not enabled yet shows as lazy), attached packages that ship
inst/gptr/, the project's .gptr/plugins/ directories and installed Claude Code plugins.
With installed = TRUE it also scans every installed package for inst/gptr/. Nothing is
loaded or run. A plugin enabled both for the process and for a live session is listed once.
gptr_plugins(installed = FALSE)gptr_plugins(installed = FALSE)
installed |
|
Enable a plugin with peter(plugins = "name") or the plugins configuration setting.
Packages put resources in inst/gptr/; directory plugins use a root plugin.json.
R factories activate lazily only when the manifest declares extension.provides and does
not request eager activation. Claude bundles contribute declarative resources; their hooks
and executable plugin behavior are not imported.
A gptr_plugins data frame with columns name, version, api, kind
(package, directory, claude-plugin), enabled, state (lazy, active,
disabled, failed), provides, tokens and path.
gptr_check, gptr_reload, gptr_registry;
vignette("skills-and-plugins", package = "gptr") for resource files and plugin manifests.
gptr_plugins(installed = TRUE)gptr_plugins(installed = TRUE)
check(call, ctx) sees every tool call before it runs and returns NULL (no opinion) or
list(decision = "allow" | "deny" | "ask" | "ask_human" | "modify", reason, input).
Decisions combine as deny > ask_human > ask > modify > allow; only a person answers an
ask_human, never a hook; a policy that errors denies. Keep checks under 10 ms.
gptr_policy(name, check, description = NULL)gptr_policy(name, check, description = NULL)
name |
Policy name. |
check |
|
description |
One line for listings. |
A spec of class c("gptr_policy", "gptr_spec").
gptr_policy("no_installs", check = function(call, ctx) { if (identical(call$name, "r") && grepl("install.packages", call$input$code, fixed = TRUE)) { list(decision = "deny", reason = "installs are not allowed here") } else { NULL } })gptr_policy("no_installs", check = function(call, ctx) { if (identical(call$name, "r") && grepl("install.packages", call$input$code, fixed = TRUE)) { list(decision = "deny", reason = "installs are not allowed here") } else { NULL } })
gptr_preimage() is the S3 generic the object checkpointer calls for a binding of the
workspace before a tool call that runs R code. It decides how the value the binding holds now
is kept, so that a rewind can put it back. Methods are leaf functions: they may read x but
must never store it anywhere.
gptr_preimage(x, name, ctx, ...) ## Default S3 method: gptr_preimage(x, name, ctx, ...) ## S3 method for class 'data.table' gptr_preimage(x, name, ctx, ...)gptr_preimage(x, name, ctx, ...) ## Default S3 method: gptr_preimage(x, name, ctx, ...) ## S3 method for class 'data.table' gptr_preimage(x, name, ctx, ...)
x |
The object bound to |
name |
The binding name (a string). |
ctx |
A list: |
... |
Unused; for methods. |
The default method keeps value-semantics objects by reference ("ref": nothing is copied
unless the agent edits the object in place) and reports environments (including R6 and
RefClass objects) and external pointers as not restorable ("none"). The data.table method
returns a deep copy made with data.table::copy() ("copy") when the agent's code is
predicted to modify the table by reference (:=, set*()) and the table fits the budget.
Packages add methods for their own classes with a delayed registration,
S3method(gptr::gptr_preimage, myclass); an R6 class can, for example, return
x$clone(deep = TRUE) as "copy". This generic is experimental.
A list with mode ("ref", "copy" or "none"), reason (a string explaining
"none", else NULL) and copy (the deep copy for "copy", else NULL).
gptr_preimage(1:3, "x", list(predicted = "assign", bytes = 64, budget = 1e9))$mode gptr_preimage(new.env(), "cfg", list(predicted = "modify", bytes = NA, budget = 1e9))$reasongptr_preimage(1:3, "x", list(predicted = "assign", bytes = 64, budget = 1e9))$mode gptr_preimage(new.env(), "cfg", list(predicted = "modify", bytes = NA, budget = 1e9))$reason
System 1 calls (peter(question, x, model = jev)) return typed vectors: a gptr_decision
(logical), a gptr_choice (character) or a gptr_score (double, the expected 0-based level).
They work in if(), while(), ifelse(), table(), sum() and comparisons like the bare
vectors, and carry the model's probabilities as attributes. gptr_prob() reads them.
gptr_prob(x, what = c("prob", "confidence", "probabilities"))gptr_prob(x, what = c("prob", "confidence", "probabilities"))
x |
A System 1 vector: a |
what |
|
Probabilities are the model's own; they are empirically calibrated only when the printed
footer says calibrated. Native decision models report calibration as unknown unless
calibration evidence was recorded, and emulated answers are always uncalibrated. Answers
combined from several calls (c(), [<-, vctrs::vec_c()) say calibrated only when every
part is calibrated and uncalibrated when any part is uncalibrated. For choices
and scores the confidence describes how concentrated the distribution is, not the probability
that the answer is correct.
A score can be fractional: with levels low, medium and high (0, 1 and 2), probabilities
0.85, 0.10 and 0.05 give the score 0.20. It is not rounded to the most likely level.
attr(x, "meta") records the model, engine, calibration state, cached elements, usage and
available execution provenance such as locality, model digest and server version.
A named numeric vector, or a matrix for what = "probabilities".
Atomic vectors and unnamed lists give one input state per element; data frames give one
per row. Fully named lists and I(x) give one structured state. These states can contain
the actual input values sent to the provider; see gptr_egress.
min_confidence makes low-confidence answers NA by default, including unknown
confidence when the minimum is positive. Use isTRUE() in scalar control flow when
abstention is possible, and handle uncertain inputs separately.
gptr.s1_max_active (8) concurrent requests, gptr.s1_rounds (3) bounded retry rounds,
gptr.s1_state_max (2000) characters of a piped session's state and gptr.s1_max_elements
(10000) elements per call.
judge = gptr_fake_provider(list(0.9, 0.2), name = "judge", type = "classifier") d = peter("Is this about dogs?", c(a = "A puppy.", b = "A car."), model = judge) gptr_prob(d)judge = gptr_fake_provider(list(0.9, 0.2), name = "judge", type = "classifier") d = peter("Is this about dogs?", c(a = "A puppy.", b = "A car."), model = judge) gptr_prob(d)
gptr_prompt() shows what gptr sends before the conversation: the two system blocks (T0,
the static sections; T1, the machine and project sections), the tool array and the first
user message, with an estimated token count per section. It makes no model call and writes
nothing: a preview never consumes a pending plan and queues no message for the model.
gptr_prompt(x = NULL, preset = NULL, tokens = TRUE) ## S3 method for class 'gptr_prompt_view' print(x, ...)gptr_prompt(x = NULL, preset = NULL, tokens = TRUE) ## S3 method for class 'gptr_prompt_view' print(x, ...)
x |
For |
preset |
|
tokens |
|
... |
Unused. |
For a session, the view shows its frozen blocks (restored from its gptr.frozen entry when
needed) and the text of its first user message, context blocks included. With preset, for a
session that has not frozen its prompt yet, or for one whose next run freezes a fresh prompt
(resumed from a file of another project or one that git tracks), it composes what would be
frozen now.
A gptr_prompt_view: a list with system (list(t0, t1)), tools_json (the tool
array as JSON text), first_message (text), sections (data frame name, tier,
tokens) and total_tokens; the attributes preset and tool_names name the preset and
the declared tools. print() shows each part with its token estimate and returns x
invisibly.
v = gptr_prompt(preset = "minimal") v$sectionsv = gptr_prompt(preset = "minimal") v$sections
A section of the frozen system prompt, rendered once per session in ascending order: T0
sections form the stable prefix, T1 sections follow. text may be a function of ctx;
parent makes the section a fragment of another section.
gptr_prompt_section( name, text, tier = c("T0", "T1"), order = 500L, budget = 300L, parent = NULL )gptr_prompt_section( name, text, tier = c("T0", "T1"), order = 500L, budget = 300L, parent = NULL )
name |
Section name (the tag it is wrapped in). |
text |
A string or |
tier |
|
order |
Position among sections. |
budget |
Token budget of the section. |
parent |
Name of the section this fragment belongs to, or |
A spec of class c("gptr_prompt_section", "gptr_spec").
gptr_prompt_section("house_rules", "Use SI units in every table.", tier = "T1", order = 780L)gptr_prompt_section("house_rules", "Use SI units in every table.", tier = "T1", order = 780L)
A provider is data: an id, the wire api its adapter implements, a base URL, how to find a
credential and its models. auth names environment variables (or is a function returning a
secret handle) and is resolved per request.
gptr_provider( id, api, base_url = NULL, auth = NULL, models = NULL, compat = list(), type = c("chat", "classifier", "cli"), headers = list(), discover = NULL, status = NULL, aliases = character(), local = FALSE, offline = FALSE, rate = NULL )gptr_provider( id, api, base_url = NULL, auth = NULL, models = NULL, compat = list(), type = c("chat", "classifier", "cli"), headers = list(), discover = NULL, status = NULL, aliases = character(), local = FALSE, offline = FALSE, rate = NULL )
id |
Provider id, |
api |
Wire api (the name of an adapter), for example |
base_url |
Endpoint base URL. |
auth |
Character vector of environment-variable names, a function, or |
models |
List of model records (each with at least |
compat |
Named list of compatibility switches for the adapter. |
type |
|
headers |
Named list of non-secret header strings. |
discover |
|
status |
|
aliases |
Alternative names of the provider. |
local |
Endpoint locality hint permitting unknown model ids. Resolved model locality is checked separately: a loopback server may route inference to a remote model. |
offline |
|
rate |
|
A spec of class c("gptr_provider", "gptr_spec").
gptr_provider("corp", api = "openai-completions", base_url = "https://llm.corp.example/v1", auth = "CORP_LLM_KEY", models = list(list(id = "corp-large", context = 128000)))gptr_provider("corp", api = "openai-completions", base_url = "https://llm.corp.example/v1", auth = "CORP_LLM_KEY", models = list(list(id = "corp-large", context = 128000)))
Shows every registered provider record: its wire api, where its credential comes from (as
NAME #fingerprint, never the value), the registry source of the record, its status, default
model, egress acknowledgment and, for subscription command-line tools, their version.
gptr_providers(check = FALSE, check_login = FALSE)gptr_providers(check = FALSE, check_login = FALSE)
check |
|
check_login |
Also check Codex and Claude Code's CLI-reported login status using
their supported status commands (3 s timeout per subprocess, no model request).
Adds a |
status is ready, no key, no base url or invalid base url (HTTP providers),
disabled (the settings say providers.<id>.enabled: false), error (the provider's
settings or its credential lookup failed) or what a command-line provider reports; with
check = TRUE the ready or no key of an HTTP provider becomes reachable (HTTP <code>)
for a reachable endpoint (a 401 without a key still proves reachability), otherwise
unreachable, or not checked under R CMD check. egress is ack when no
acknowledgment is needed (offline providers, local servers at a loopback address) or the
user has given it. Listing reads credentials only: it never registers an environment
variable or binds it to a provider.
ready means the required configuration is present; it does not validate the credential,
account quota or access to a specific model. check = TRUE tests reachability, not login.
See vignette("language-models", package = "gptr") for API, command-line and local setup.
A gptr_providers data frame with columns id, type, api, credential,
source, status, default_model, egress (ack or needed) and version, plus
login when check_login = TRUE.
gptr_providers()gptr_providers()
Replaces the values of registered secrets (and their URL-encoded, JSON-escaped and base64
forms) with markers such as [secret:TYPESAFE_API_KEY] and, except for the user_data
profile, applies the pattern layer (provider key shapes, bearer tokens, URL passwords,
private keys, NAME=value lines). gptr applies the same redactor at every sink; plugins
and users call it for their own logs. Redaction is idempotent and never fails on invalid
UTF-8 (it then matches bytewise). Opaque replay fields of messages (signatures, encrypted
reasoning) are never modified.
gptr_redact( x, profile = c("persist", "stream", "context", "code", "user_data") )gptr_redact( x, profile = c("persist", "stream", "context", "code", "user_data") )
x |
A character vector, or a list (redacted recursively). |
profile |
The sink profile: |
x with secrets replaced by markers; the same type and attributes as x.
gptr.redact_min_chars (8): shortest value that is value-redacted.
gptr.redact_patterns (TRUE): the pattern layer; values are always redacted.
gptr.stream_hold_max (4096): streaming hold-back cap in characters.
gptr.env_export (TRUE): default of gptr_env(set_env =).
gptr.prompt_secrets ("redact"): secret-looking text in prompts, "redact" or "ask".
gptr.secret_guard (TRUE): guarded secret reads ask even in auto mode.
gptr_redact("Authorization: Bearer abcdef0123456789abcdef") gptr_redact(list(note = "db at postgres://analyst:[email protected]/prod"))gptr_redact("Authorization: Bearer abcdef0123456789abcdef") gptr_redact(list(note = "db at postgres://analyst:[email protected]/prod"))
Registers a spec made by gptr_spec() or one of the spec constructors at top level: rank 3,
source "user", for the lifetime of the R process. Sessions frozen before the call are not
changed; the next session sees the record. A user record overrides a built-in record of the same
kind and name only (the built-in's other records keep working).
gptr_register(spec)gptr_register(spec)
spec |
A spec (class |
Called from model code while a run executes a tool, gptr_register() and the function it
returns signal gptr_error_permission unless the user approved that call.
A function that removes the record again, invisibly.
off = gptr_register(gptr_command("hello", function(args, ctx) "hi")) off()off = gptr_register(gptr_command("hello", function(args, ctx) "hi")) off()
One row per process-level record (session-scoped records are not listed): its kind, name,
source (builtin:<name>, plugin:<name>, user, project), rank, state (lazy, active,
overridden, disabled), the estimated tokens its declaration costs, and whether the kind is
experimental. With diagnostics = TRUE, the redacted diagnostics log instead.
gptr_registry(kind = NULL, diagnostics = FALSE)gptr_registry(kind = NULL, diagnostics = FALSE)
kind |
|
diagnostics |
|
A gptr_registry data frame (columns kind, name, source, rank, state,
tokens, experimental), or a gptr_diagnostics data frame (columns time, source,
event, class, message).
gptr_registry("tool") gptr_registry(diagnostics = TRUE)gptr_registry("tool") gptr_registry(diagnostics = TRUE)
Bumps the registry generation, so that extension API objects captured by old code signal
gptr_error_stale_api, and re-declares lazily activated plugins from their manifests (their
factories run again on first use). Discovery of declarative resources (skills, prompts, agents,
MCP configurations, plugin manifests) is keyed on the generation, so it runs again on next
use. Sessions whose prompt is already frozen are not changed. Refused from model code while a
run executes a tool, unless the user approved that call.
gptr_reload()gptr_reload()
The new registry generation (an integer), invisibly.
gptr_reload()gptr_reload()
Called by R code the agent runs (or by you inside a tool) to designate the run's result, which
the session then returns as $value. Objects bound in the session's workspace are kept by name
when large (no copy), copied when small; other values are boxed. Outside a run it returns its
argument invisibly and does nothing else, so recorded code that still contains the call runs
cleanly.
gptr_return(x)gptr_return(x)
x |
The value; a bare name is recorded by name. |
NULL invisibly during a run; x invisibly outside a run.
y = gptr_return(1:3) yy = gptr_return(1:3) y
gptr_rewind() is a branch-in-place on the one session object: it undoes the checkpoint
records of the turns being left (newest first), redoes the records of a target on another
branch (oldest first) and appends one gptr.rewind entry parented at the target (the session
file stays append-only and the rewind survives a reload). It hands back the undone prompt in
s$editor_text and returns s invisibly, so it pipes:
session |> gptr_rewind() |> peter("Try another way"). Use gptr_fork() for a second
session.
gptr_checkpoints() lists one row per turn of the active path (all = TRUE adds the turns of
abandoned branches): turn; id, the last entry of the turn (pass it as to to
gptr_rewind()); time, when the prompt was sent; prompt (its first 60 characters);
objects and files, "changed/restorable" counts; held_mb and disk_mb, megabytes of
object pre-images held in memory and on disk; and branch ("active" or "abandoned").
gptr_rewind( s, turn = -1L, to = NULL, restore = c("all", "conversation", "workspace"), force = FALSE, preview = FALSE ) gptr_checkpoints(s, all = FALSE)gptr_rewind( s, turn = -1L, to = NULL, restore = c("all", "conversation", "workspace"), force = FALSE, preview = FALSE ) gptr_checkpoints(s, all = FALSE)
s |
A |
turn |
Integer. Negative counts back from the last turn ( |
to |
An entry id from |
restore |
|
force |
Also restore items that changed after the checkpoint (3-way conflicts). |
preview |
Return the plan instead: a data frame with one row per item ( |
all |
Also list the turns of abandoned branches. |
Restores are 3-way: an object or file that changed after the turn (by you or another session)
is kept and reported, unless force = TRUE. Reference objects (environments, R6, external
pointers), objects over the undo budget, environment variables, loaded namespaces, the
random-number state and effects outside R (network, databases, processes) are not restored.
Items that were not restored are listed in s$last_rewind$report and raise the warning
gptr_warning_rewind_partial. Files outside the project and tempdir() are restored only
after you confirm each path. After a full restore the model is told nothing (the next
request's prefix is byte-identical to the earlier request at the target); after a partial one
the next prompt carries a short <rewind> block listing what was not restored. Model code may
rewind another session only when you approve that call.
gptr_rewind() returns s, invisibly (the plan when preview = TRUE);
s$last_rewind holds the report and s$editor_text the undone prompt.
gptr_checkpoints() returns a gptr_checkpoints data frame (it prints at most 20 rows).
Options of checkpoints and rewind (?gptr_options collects every option):
gptr.checkpoint ("on"): "files" checkpoints files only, "off" nothing (also the
settings key checkpoint).
gptr.undo_capture_max (1e8): bytes; objects up to this size are captured by reference.
gptr.undo_max_bytes (1e9): bytes of pre-images held in memory per session.
gptr.undo_spill_max (2e9): bytes; the largest object image written to disk.
gptr.undo_turns (20): object images older than this many turns are dropped.
gptr.checkpoint_disk_bytes (2e9): bytes of blobs and spilled images before a notice.
gptr.checkpoint_days (30): unreferenced blobs older than this many days are deleted.
gptr.checkpoint_turns (100): file checkpoints older than this many turns are not
restored.
gptr.checkpoint_track_file_max (1e6), gptr.checkpoint_track_total (1e8): bytes per
file and in all of the baseline taken at the first mutating call.
gptr.checkpoint_capture_max (5e7): bytes; a larger changed file gets no stored copy.
gptr.checkpoint_scan_budget (0.25): seconds; slower walks switch to one scan per turn.
gptr.checkpoint_rng (TRUE): report changes of the random-number state.
gptr.checkpoint_close_devices (FALSE): close graphics devices an undone turn opened.
d = tempfile("project") dir.create(d) op = options(gptr.project_root = d) fake = gptr_fake_provider(list( list(tool = "r", input = list(code = "x = 1")), "Made x.", list(tool = "r", input = list(code = "x = x + 1")), "Added one.")) work = new.env() session = peter("Make x", model = fake, mode = auto, envir = work) session |> peter("Add one to x") work$x session |> gptr_rewind() work$x session$editor_text gptr_checkpoints(session, all = TRUE) options(op)d = tempfile("project") dir.create(d) op = options(gptr.project_root = d) fake = gptr_fake_provider(list( list(tool = "r", input = list(code = "x = 1")), "Made x.", list(tool = "r", input = list(code = "x = x + 1")), "Added one.")) work = new.env() session = peter("Make x", model = fake, mode = auto, envir = work) session |> peter("Add one to x") work$x session |> gptr_rewind() work$x session$editor_text gptr_checkpoints(session, all = TRUE) options(op)
gptr_risk() is the advisory static classifier behind gptr's permission prompts. It reads
code without evaluating it and labels each effect it can see with a level from 0 (known
read-only) to 4 (critical) and a category (read, object_write, file_write,
file_delete, network, process, install, dynamic, session, secret,
interactive, critical, control, plus unlisted for functions the risk tables do not
list). Level 0 is only what the tables know to be read-only; code whose function is computed
at run time is level 3. It cannot see S4 methods, compiled code, package load hooks
or the files source() reads: it decides when gptr asks you, it is not a security boundary.
gptr_risk(code, envir = NULL, root = NULL)gptr_risk(code, envir = NULL, root = NULL)
code |
R code: a character vector, a call or an expression. |
envir |
|
root |
The project root used for path classes; |
Paths are classified relative to root (workspace, temp, outside, protected,
control, instructions, critical, url, wildcard, unknown). Calls of
peter$sh(), system(), system2() and processx::run() with literal commands are
classified with the command table (inst/extdata/risk-commands.csv), peter$sql() by its
statements and peter$py() by a token scan. Plugins and users extend both tables with
risk_rule records.
A gptr_risk object: a list with level (integer 0-4), label, categories,
flagged (a data frame with columns call, fn, level, category, path,
path_class), paths, secret, secret_guard, assigned, dynamic, and the additive
fields sizes (bytes of overwritten objects, by name), secrets (guarded secret names),
kind and parse_error.
gptr_risk("unlink('data', recursive = TRUE)")$level gptr_risk("summary(mtcars)") e = new.env() e$df = data.frame(a = 1:3) gptr_risk("df = head(df, 2)", envir = e)$flaggedgptr_risk("unlink('data', recursive = TRUE)")$level gptr_risk("summary(mtcars)") e = new.env() e$df = data.frame(a = 1:3) gptr_risk("df = head(df, 2)", envir = e)$flagged
A router is a virtual model: route(request, ctx) runs before every request of a session whose
model is the router's name and returns a model reference, or
list(model, thinking = NULL, state = NULL). A router that errors or exceeds timeout falls
back to the default model.
gptr_router(name, route, description = NULL, timeout = 2)gptr_router(name, route, description = NULL, timeout = 2)
name |
Router name, usable as |
route |
|
description |
One line for listings. |
timeout |
Seconds allowed per call. |
A spec of class c("gptr_router", "gptr_spec").
gptr_router("cheapest", route = function(request, ctx) "anthropic/claude-haiku-4-5")gptr_router("cheapest", route = function(request, ctx) "anthropic/claude-haiku-4-5")
Secrets are redacted when they enter a transcript, a cache or a document, but a value that
reached a file before it was registered (for example a key pasted into a prompt and only
later loaded with gptr_env()) stays there. gptr_scrub() scans persisted files for the
values of every registered secret and their derived forms and reports where they occur.
With dry_run = FALSE it rewrites those files, replacing each occurrence with a
[secret:NAME] marker; this is the only sanctioned rewrite of append-only session files,
each of which then gets a gptr.scrub entry. A key that reached a model or a commit must
still be rotated.
gptr_scrub(paths = NULL, dry_run = TRUE, error = FALSE)gptr_scrub(paths = NULL, dry_run = TRUE, error = FALSE)
paths |
|
dry_run |
If |
error |
If |
A data frame with columns file, secret (the variable name) and count; never
values. Returned visibly for a dry run, invisibly after a rewrite.
d = tempfile("proj") dir.create(d) writeLines("nothing secret here", file.path(d, "notes.txt")) gptr_scrub(d)d = tempfile("proj") dir.create(d) writeLines("nothing secret here", file.path(d, "notes.txt")) gptr_scrub(d)
gptr runs a language model agent inside your R session. The agent reads files, writes files, evaluates R code written by the model in the environment you give it and starts processes on your behalf. This page describes what gptr does to keep those actions under your control and where its protections end. gptr_egress describes what is sent to model providers.
Nothing runs when the package is loaded. A model is contacted only when you call peter() (or
a function that you give a prompt), and model-written code is evaluated only in the
environment you pass as envir (by default the frame that called peter()); gptr never
assigns into the global environment by itself. Files are written only inside a .gptr/
directory you created with gptr_init() or confirmed interactively, inside
tools::R_user_dir("gptr"), inside the session temporary directory, into documents you bound
with gptr_doc() or confirmed, and by tool calls that the permission mode allowed. In a
non-interactive run without such consent nothing is written outside the session temporary
directory.
Every tool call passes a permission gate. The default mode is manual: only actions that the
classifier knows to be read-only run without asking; every other action, including any change
to a file or an object, asks first with a one-line prompt. edits also allows file edits
inside the project and still asks before R code that is not known to be read-only; auto
asks only for level-4 actions (for example deleting the project directory, or changing gptr's
own configuration) and for reads of registered secrets; plan changes nothing. When nobody
can answer a question (Rscript, knitr, a scheduled job) the run stops with status blocked
and a gptr_error_permission condition that says how to allow the action, unless you set
options(gptr.noninteractive_ask = "deny"). Model code cannot switch the gate off or loosen
it during a run: the safety options are copied when the run starts. Only the option
gptr.unsafe_no_permissions, set by you outside a run, removes the gate, and it is meant for
disposable sandboxes.
The risk levels come from a static classifier (gptr_risk()). It is advisory and it is not a
security boundary: R code can compute function names, call compiled code or load packages
whose effects the classifier cannot see, and R has no sandbox for code that runs inside your
session. In auto mode a model can delete or overwrite files and objects. Use auto only
in projects you can restore (version control, backups, gptr_rewind() for recent turns),
and run untrusted prompts or untrusted projects in a disposable container or virtual machine.
Inline sub-agents run in your session and see its objects. The worker backend runs a
sub-agent in a separate R process that starts from gptr's reduced child environment (it does
not read your ~/.Renviron), but that process runs under your user account with your file
permissions: the worker backend is not an isolation boundary. Its permission requests are
sent to your session and classified again there. MCP servers, the claude and codex
command-line tools, shell commands started with peter$sh() and Shiny artifacts are ordinary
processes of your account as well; artifacts start without any registered secret and listen
on the loopback interface, and each launch gets an access token in its address (on Windows
only when 'openssl' is installed; otherwise gptr says that the artifact has no token).
Model replies, tool results, file contents, MCP results and project instruction files
(AGENTS.md, CLAUDE.md, .gptr/vignette.Rmd) are treated as data. Text from these sources
is never used as a formatting template, so braces in a reply cannot run R code. A project you
cloned is untrusted until you trust it with gptr_trust(trust = TRUE) (see gptr_trust()),
or answer yes when gptr_init() asks: until then its settings can only tighten
permissions, its extensions, plugins and MCP servers do not run, and its instruction files
are shown to the model as information rather than commands. When trusted files change after a
pull, gptr asks again.
Keys are held in a private vault and appear in sessions, logs and errors only as markers such
as [secret:ANTHROPIC_API_KEY]. Values are redacted before anything is written or sent: the
session files, documents, caches, spill files, wire logs and the output of child processes.
gptr never reads the credential files of other tools. Reading a registered secret from model
code asks even in auto mode. A key registered after it already appeared in a file (for
example pasted into a prompt) can be removed from the files with gptr_scrub(); run
gptr_scrub(error = TRUE) before committing to fail when any registered secret remains.
gptr keeps what it needs to resume and replay work. Review what you commit when the data are personal or clinical:
.gptr/sessions/ (full conversations, including printed results) is excluded from git by
the .gptr/.gitignore that gptr_init() writes.
.gptr/cache/s1/ holds System 1 answers and is committed by default so that a script
replays without model calls. It stores a salted hash of each input and a hash of each
question, never their text, but the answers themselves (a label and its probability)
remain, and the salt is committed with the cache, so anyone with the repository can test
guesses of short inputs. For PHI, stop committing it with
gptr_config(cache_commit = list(s1 = FALSE, s2 = FALSE), .scope = "project") (gptr then
keeps a .gitignore in cache/s1/), or clear it with gptr_cache("clear", "s1") before
committing.
.gptr/cache/s2/ (answer text for replay), .gptr/transcripts/ (console transcripts),
.gptr/checkpoints/ (pre-images of objects and files) and the data snapshots of artifacts
(.gptr/artifacts/<id>/v<n>/data/) are excluded from git by default.
.gptr/plans/ (plans proposed in plan mode) and the app.R of each artifact are
committed by default; they can quote data values the model saw.
Documents you record into keep the model's code and up to gptr.doc_output_lines lines of
printed output per step, which can contain data values. Review them before sharing.
gptr_mcp_serve() exposes the live session to other agents over HTTP on 127.0.0.1 only,
with a random bearer token and an Origin check, and every call passes the permission gate.
Any local process that learns the token can call the served tools while the server runs; stop
it with gptr_mcp_serve(stop = TRUE) when you are done.
gptr_egress, gptr_options, gptr_permissions(), gptr_trust(),
gptr_scrub(), gptr_risk().
gptr_sessions() lists the sessions of the workspace store (.gptr/sessions/, or
tempdir()/gptr/sessions/ without a workspace), newest first. It reads only the header and
the last lines of each file.
gptr_resume() returns the live object when one exists in this process; otherwise it rebuilds
the session from its JSONL file (leaf = the last entry; status idle when the tail is a final
answer, else interrupted) with home envir. A rebuilt fork always gets a fresh overlay of
envir. A detached copy (from saveRDS(), a knitr cache or callr) is attached under the
split-brain rules. block = returns the session that a document replay bound to that block.
Resuming restores conversation state, not a complete analysis workspace, and does not
rerun the R tool code. Make required objects available in envir; use document replay
when the intention is to execute the recorded analysis again.
gptr_last() returns the most recently active session of this R process. It is held strongly
(it survives gc()), so a session whose call was interrupted before its result was assigned
is not lost.
gptr_sessions(project = TRUE) gptr_resume(x = NULL, envir = parent.frame(), block = NULL, child = NULL) gptr_last()gptr_sessions(project = TRUE) gptr_resume(x = NULL, envir = parent.frame(), block = NULL, child = NULL) gptr_last()
project |
|
x |
|
envir |
The home of a rebuilt session. |
block, child
|
A document block id (and a team member name): the session replay bound to
that block in this process, or |
gptr_sessions() returns a gptr_sessions data frame: id, file, created,
updated, turns, model, status, title (the first prompt, 60 characters), live.
gptr_resume() returns a gptr_session: the live object when one exists in this process,
otherwise one rebuilt from its session file. gptr_last() returns the most recently active
session of this process, or NULL when no session was created in this process.
session = peter("hi", model = gptr_fake_provider(list("hello"))) identical(gptr_last(), session) gptr_sessions() identical(gptr_resume(session$id), session)session = peter("hi", model = gptr_fake_provider(list("hello"))) identical(gptr_last(), session) gptr_sessions() identical(gptr_resume(session$id), session)
gptr_skills() lists the Agent Skills gptr can see: the project's .gptr/skills,
.agents/skills and .claude/skills, the user's skill directories, the skills of gptr and of
attached packages, and those of enabled plugins. Project skills are listed even when the
project is not trusted (their source reads project (untrusted)), but only trusted skills
enter the catalog the model sees. gptr_agents() lists agent definition files the same way.
Both only read files.
gptr_skills(scope = c("all", "project", "user", "packages")) gptr_agents(scope = c("all", "project", "user", "packages"))gptr_skills(scope = c("all", "project", "user", "packages")) gptr_agents(scope = c("all", "project", "user", "packages"))
scope |
One of |
A skill is a directory containing SKILL.md with a YAML description and optional name.
Its body is read on demand, or preloaded with peter(skills = "name").
disable-model-invocation: true hides it from automatic catalog selection, while explicit
preloading remains available. allowed-tools is metadata, not a permission rule.
gptr_skills(): a gptr_skills data frame with columns name, description,
source, path, tokens (catalog cost) and visible. gptr_agents(): a gptr_agents
data frame with columns name, description, model, backend, source and path.
gptr_agent, gptr_plugins, gptr_trust;
vignette("skills-and-plugins", package = "gptr") for skills, templates and agent files.
gptr_skills("packages") gptr_agents()gptr_skills("packages") gptr_agents()
Evaluates file top-level expression by expression in envir, like source() with
keep.source = TRUE. A peter() call whose block is fresh replays without calling a model
and the block's code then runs as ordinary R. A call whose block is stale (its prompt or the
values interpolated into it changed), or every call under replay = "live", asks the model
again and rewrites its block in place, and the old block is skipped, which base source()
cannot do.
gptr_source( file, replay = getOption("gptr.replay", "auto"), envir = parent.frame(), echo = FALSE )gptr_source( file, replay = getOption("gptr.replay", "auto"), envir = parent.frame(), echo = FALSE )
file |
Path of an |
replay |
Replay mode for the calls in the file: |
envir |
Environment in which the expressions are evaluated. |
echo |
|
Replay executes the recorded R code, including its ordinary side effects. It does not
freeze package versions, supply external inputs or validate the analysis. This function
accepts .R scripts; render .Rmd and .qmd with their report tools, and execute
.ipynb through its R kernel. Use gptr_blocks() to inspect any supported format.
Invisibly, the gptr_blocks listing of the file after the run with an extra column
action: replayed, regenerated, ran, skipped, or NA for blocks no call touched.
A stale block whose call ran but could not be rewritten (for example without write consent)
is ran and keeps its status.
f = tempfile(fileext = ".R") writeLines(c("x = 1", "y = x + 1"), f) gptr_source(f, replay = "replay", envir = new.env())f = tempfile(fileext = ".R") writeLines(c("x = 1", "y = x + 1"), f) gptr_source(f, replay = "replay", envir = new.env())
The general constructor behind the eleven spec constructors: it builds a spec of kind from its
fields and validates it with the kind's validator. Use it for kinds without a constructor
(env_alias, setting, service, preset, ...) and for kinds defined by plugins. Unknown
fields are kept (forward compatibility); a wrong type of a known field is an error naming the
field.
gptr_spec(kind, name, ...)gptr_spec(kind, name, ...)
kind |
The kind name, one of the |
name |
The record name within the kind. |
... |
The kind's fields, named. |
A spec: a list of class c("gptr_<kind>", "gptr_spec").
gptr_spec("env_alias", "SLACK_BOT_TOKEN", aliases = "slack-token") gptr_spec("setting", "panel.size", default = 3L, description = "Reviewers per panel")gptr_spec("env_alias", "SLACK_BOT_TOKEN", aliases = "slack-token") gptr_spec("setting", "panel.size", default = 3L, description = "Reviewers per panel")
The one enqueue function behind the pipe into a running session, the pause menu and
ctx$send(). A steer reaches the model after the current tool results, as "The user sent this
message while you were working: ..."; a follow-up when the agent would otherwise stop. On an
idle session the item is taken when the next run starts.
gptr_steer(s, text, as = c("steer", "follow_up"))gptr_steer(s, text, as = c("steer", "follow_up"))
s |
A session. |
text |
The message (secrets are redacted before it is queued). |
as |
|
s, invisibly, at once.
session = peter("Summarize mtcars", model = gptr_fake_provider(list("ok")), .run = FALSE) gptr_steer(session, "Use only the mpg column", as = "follow_up")session = peter("Summarize mtcars", model = gptr_fake_provider(list("ok")), .run = FALSE) gptr_steer(session, "Use only the mpg column", as = "follow_up")
Starts the queued input of an idle session (built with .run = FALSE, or given a follow-up
with gptr_steer()) and pumps it until turns model turns have ended or the run settles. A
running session is advanced the same way.
gptr_step(s, turns = 1L)gptr_step(s, turns = 1L)
s |
A session. |
turns |
The number of turns to advance ( |
.run = FALSE builds a session without making its model request; gptr_step() or
gptr_wait() starts it. Supply an explicit workspace with envir = when results must
remain available outside the function that creates the session.
s, invisibly. A run that settles in status error, blocked, budget or
max_turns signals the condition documented in peter().
session = peter("Plan the analysis", model = gptr_fake_provider(list("Plan: ...")), .run = FALSE) gptr_step(session) session$turnssession = peter("Plan the analysis", model = gptr_fake_provider(list("Plan: ...")), .run = FALSE) gptr_step(session) session$turns
A tool is one capability the model can use: declared directly in the request's tool array
(exposure = "direct"), callable from R code as peter$<namespace>$<name>() ("r", one
signature line in the prompt), found through peter$search() ("deferred") or callable only by
gptr code ("hidden"). Give execute (function(input, ctx), the direct-tool form), fun (an
R function whose formals match the schema properties, the member form), or both. A direct tool
with only fun gets a generated execute that prints the value within output_tokens; an r
member with only execute gets a generated fun.
gptr_tool( name, description, parameters = NULL, execute = NULL, fun = NULL, exposure = c("direct", "r", "deferred", "hidden"), namespace = NULL, execution = c("sequential", "concurrent"), risk = NULL, snippet = NULL, guidelines = NULL, signature = NULL, output_tokens = NULL, record = TRUE, available = NULL, annotations = list() )gptr_tool( name, description, parameters = NULL, execute = NULL, fun = NULL, exposure = c("direct", "r", "deferred", "hidden"), namespace = NULL, execution = c("sequential", "concurrent"), risk = NULL, snippet = NULL, guidelines = NULL, signature = NULL, output_tokens = NULL, record = TRUE, available = NULL, annotations = list() )
name |
Tool name, |
description |
Model-facing description; direct tools stay under 400 estimated tokens. |
parameters |
A JSON Schema list with |
execute |
|
fun |
The R-callable form of the tool. |
exposure |
One of |
namespace |
Namespace of an |
execution |
|
risk |
|
snippet |
One line shown in the prompt's tool list (direct tools). |
guidelines |
Bullet lines added to the prompt's rules (direct tools). |
signature |
Catalog line for |
output_tokens |
Budget for printed results; |
record |
Keep calls of this member in recorded code. |
available |
|
annotations |
Named list: |
A spec of class c("gptr_tool", "gptr_spec").
gptr_register, gptr_check;
vignette("extending-gptr", package = "gptr") for complete tool and policy examples.
gptr_tool("nrow_of", "Number of rows of a data frame in the session", fun = function(name) nrow(get(name, envir = globalenv())), exposure = "r", namespace = "demo")gptr_tool("nrow_of", "Number of rows of a data frame in the session", fun = function(name) nrow(get(name, envir = globalenv())), exposure = "r", namespace = "demo")
What a tool's execute() returns: text and images for the model, details kept in the
transcript but never sent to a model, and value, the R object handed to R callers of the
member (kept in memory only, never persisted).
gptr_tool_result( text = NULL, images = NULL, details = NULL, is_error = FALSE, value = NULL )gptr_tool_result( text = NULL, images = NULL, details = NULL, is_error = FALSE, value = NULL )
text |
Character vector, joined with newlines into one text block, or |
images |
List of image blocks, PNG file paths or raw PNG vectors, or |
details |
Named list of details, or |
is_error |
|
value |
Any R value returned to R callers. |
A gptr_tool_result list with content, details, is_error, value, spill,
out_id, truncated and terminate.
gptr_tool_result("3 rows", details = list(n = 3L), value = 3L)gptr_tool_result("3 rows", details = list(n = 3L), value = 3L)
Trust decides whether gptr applies or runs what a project directory contains: project
settings beyond tightening, .gptr/extensions/ and project plugins, project MCP servers,
SYSTEM.md and APPEND_SYSTEM.md, project .env discovery, provider base-URL overrides, the
tool and model fields of project agent files, and the authority of project instructions. The
decision is kept in tools::R_user_dir("gptr", "config")/trust.json with a fingerprint of the
trust-gated files; when they change, the project counts as untrusted again until you confirm.
Called from model code during a run, recording a decision is refused.
gptr_trust(path = ".", trust = NULL)gptr_trust(path = ".", trust = NULL)
path |
A directory inside the project; its project root is used. |
trust |
|
With trust = NULL, the recorded decision: TRUE, FALSE or NA (undecided).
Otherwise the previous decision, invisibly.
d = tempfile("proj") dir.create(d) gptr_trust(d) unlink(d, recursive = TRUE)d = tempfile("proj") dir.create(d) gptr_trust(d) unlink(d, recursive = TRUE)
Aggregates the usage rows of sessions (children included, each request counted once) and, for
x = NULL, of every live session of this process plus the process System 1 log. Reads only.
gptr_usage( x = NULL, by = c("session", "agent", "model", "route"), detail = FALSE )gptr_usage( x = NULL, by = c("session", "agent", "model", "route"), detail = FALSE )
x |
A |
by |
Grouping of the summary: |
detail |
|
Unknown usage stays unknown: a token count or cost that a provider did not report is NA,
never zero, so a group or total that includes it is NA and the footer prints it as
unknown. A known zero, such as the metered charge of a local model, stays zero. Rows without
a session, agent, model or route (process-level System 1 calls) form the NA group.
The detailed component ledger contains estimates; its sum can differ from provider-reported usage. A run's token budget checks estimated next-input tokens and recorded usage before requests; cost limits check recorded cost. The next output or an unknown final charge can exceed a remaining allowance, so these stopping policies are not billing reservations. Teams and fan-outs count child requests against their shared root budget.
A gptr_usage or gptr_ledger data frame.
gptr_usage() session = peter("hi", model = gptr_fake_provider(list("hello"))) gptr_usage(session)gptr_usage() session = peter("hi", model = gptr_fake_provider(list("hello"))) gptr_usage(session)
Starts idle sessions that have queued input, then pumps until no session is running or
waiting, or timeout seconds have passed. Every session's egress and replay checks pass before
any is started, so a refusal starts none. On timeout the sessions keep their running status
and no condition is raised.
gptr_wait(x, timeout = Inf)gptr_wait(x, timeout = Inf)
x |
A session or a list of sessions (a team or fan-out session counts as one). |
timeout |
Seconds to wait. |
timeout limits reactor polling; it does not interrupt R code. Request preparation
and synchronous callbacks finish their current step before the deadline is checked
again, so a call can return after the specified time.
A timeout is not cancellation. Inspect $status and use gptr_cancel() if you want to
abort active work. In Rscript and rendered reports, a blocking call such as this is how
experimental background sessions progress when there is no idle console.
x, invisibly. For a single session, a terminal status signals its condition.
fake = gptr_fake_provider(list("a")) runs = list(a = peter("one", model = fake, .run = FALSE), b = peter("two", model = fake, .run = FALSE)) gptr_wait(runs, timeout = 10) vapply(runs, function(x) x$status, "")fake = gptr_fake_provider(list("a")) runs = list(a = peter("one", model = fake, .run = FALSE), b = peter("two", model = fake, .run = FALSE)) gptr_wait(runs, timeout = 10) vapply(runs, function(x) x$status, "")
peter(..., background = TRUE) returns the session at once while its run keeps going.
A timer from the later package advances the run every 50 ms while the R console is
idle, so you can keep working. Piping into the running session,
session |> peter("..."), queues a steer that the agent receives after its current
tool result; gptr_wait() waits for the session, gptr_cancel()
aborts its run and gptr_jobs() lists it. Background sessions are
experimental: they need the later package, and they are never used in
examples or in CRAN tests.
Background work is not an independent R execution thread: an inline R tool occupies the
process while it runs. Returning a session does not establish idle progress in an
unverified front end; inspect its status and use a blocking wait when needed.
Streams progress at every idle tick. While a blocking gptr call runs
(peter(), gptr_wait(), gptr_step() or a console turn), that call
advances the background runs as well and the background timer does nothing.
R tools of a background run execute at an idle tick when
options(gptr.background_tools = "idle") (the default). The console is busy
while such a tool runs; Ctrl-C then opens the pause menu. With "wait" they run
only inside a blocking gptr call such as gptr_wait().
A background run never asks a question at the idle console. When it needs an
approval or an answer at an idle tick, the action is not performed: the agent is told
that the user will be asked, its run stops, and the session moves to status
"waiting" with a notice. At your next gptr_wait(), peter() call or
console turn the session continues with one more model request, the agent repeats the
call, and you are asked as usual. A message piped into a waiting session is delivered
when it continues.
gptr_cancel() stops a running background session. A waiting session has no
run to cancel: gptr_jobs(kill = TRUE) stops it (together with every other job).
When an R tool changed objects in your workspace at an idle tick, one notice names them.
Under Rscript, knitr and Quarto there is no idle console: background runs progress only inside blocking gptr calls.
| Front end | Status |
| Terminal R on macOS | verified: idle ticks, pause menu, pipe steering |
| Terminal R on Linux | unverified (the same later event loop as macOS) |
| Rscript, knitr, Quarto | no idle ticks by design; progress inside blocking gptr calls |
| RStudio | unverified (later is expected to run callbacks at its idle console) |
| Positron, Jupyter (IRkernel), Rgui | unverified |
| Windows consoles | unverified; a timer polls the reactor, so child pipes are served |
gptr.background_tools"idle" (default) or "wait": whether
R tools of background runs execute at idle ticks or wait for the next blocking gptr
call.
peter, gptr_wait, gptr_cancel,
gptr_steer, gptr_jobs
peter() is the single entry point. Give it a quoted prompt and, optionally, the objects the
agent should work on; it returns the agent session, which you can print, query ($text,
$value, $usage) and continue with the pipe. Models, modes, skills, plugins, extensions and
tools may be written as bare names.
peter(..., model = NULL, mode = NULL, skills = NULL, plugins = NULL, extensions = NULL, tools = NULL, agents = NULL, parallel = NULL, choices = NULL, levels = NULL, threshold = 0.5, min_confidence = NULL, uncertain = NULL, prompt = NULL, envir = parent.frame(), background = FALSE, budget = NULL, replay = NULL, .opts = list(), .run = TRUE, .stdin = FALSE)peter(..., model = NULL, mode = NULL, skills = NULL, plugins = NULL, extensions = NULL, tools = NULL, agents = NULL, parallel = NULL, choices = NULL, levels = NULL, threshold = 0.5, min_confidence = NULL, uncertain = NULL, prompt = NULL, envir = parent.frame(), background = FALSE, budget = NULL, replay = NULL, .opts = list(), .run = TRUE, .stdin = FALSE)
... |
A session to continue, the prompt, and context objects. |
model |
A model name ( |
mode |
One of |
skills, plugins, extensions
|
Names (bare or quoted) of skills to preload, plugins and
extensions to enable for this session; |
tools |
Tool names, |
agents |
A named list of agent definitions for a team ( |
parallel |
Fan one list-like context object out over this many concurrent sub-agents. |
choices, levels, threshold, min_confidence, uncertain
|
System 1 answer shape and abstention. |
prompt |
An explicit prompt; wins over positional selection. |
envir |
Where the agent evaluates R code and creates objects. |
background |
Experimental: return the running session at once (needs later). |
budget |
|
replay |
Document replay mode: |
.opts |
Rare switches such as |
.run |
|
.stdin |
Drive the console from piped standard input. |
Conversational agents compute in memory: their R tools use the objects already loaded in
envir, and later turns can reuse fitted models and intermediate results without saving and
reloading the dataset. Model context contains bounded descriptions and requested results;
R computes on the full local object. Ordinary R allocations, file-backed inputs, checkpoints
and worker transfers still have their usual costs. See
vignette("execution-model", package = "gptr") for these boundaries.
The dots take, in order: at most one leading session to continue, the prompt (the first unnamed string literal, else the first unnamed length-1 character value), and context objects (unnamed ones are labeled by their expression, named ones by name). Conversational context bindings refer to objects where they live; descriptions are budgeted separately from in-memory R computation. Every other argument is matched by its exact name only.
A literal prompt gets {name} interpolation from envir (atomic vectors of 1 to 50 values;
{{ and }} are literal braces); .opts = list(interpolate = FALSE) switches it off.
Terminal statuses become conditions carrying the session as $session: error signals
gptr_error_provider, blocked gptr_error_permission, budget gptr_error_budget_<kind>
and max_turns gptr_error_max_turns. peter() with no prompt opens the console when someone
can answer, and signals gptr_error_noninteractive otherwise.
A new interactive console without an explicit or configured model first offers CLI selection
or manual API/Ollama instructions. Selecting an available CLI saves its default at user scope;
cancellation or manual setup returns without starting a session. Existing sessions, explicit
or configured models and .stdin = TRUE skip setup. CLI-reported login is not proof of online
access or subscription billing. See vignette("interactive-console", package = "gptr").
The name honors Peter Cathcart Wason, whose research with Jonathan Evans distinguished
processes underlying reasoning and introspection, and Peter Naur of the Backus-Naur form,
in the spirit of
recording sessions as readable, replayable documents. A user object named peter hides the
gateway; call gptr::peter() then.
A gptr_session for agent work (invisibly when its answer was streamed to the
console), or a typed System 1 vector for classifier models.
peter() without a prompt opens a console when someone can answer (interactive R or
IRkernel); peter(.stdin = TRUE) reads its input from standard input, and
session |> peter() opens it on session. With no explicit or configured model, the
interactive console first offers Codex CLI, Claude Code CLI or API configuration
instructions. Choosing an available CLI saves its default model at user scope; cancelling
returns to R. Piped input skips this setup.
Each input is one of:
a prompt, sent as session |> peter("...") with {name} interpolation; @file adds
the head of a file (at most 40 lines) and @object attaches an object by name;
!code: R code run in the session's environment; the code and its output go with the next
prompt (at most 300 estimated tokens). !!code omits that note. Both execute your own R
immediately, without the model's permission gate or a model request. Workspace changes
remain visible to later calls, and enabled transcripts can record the code; !! is not a
privacy boundary. A fenced R block works like !code, a """ block is a multi-line prompt,
and a trailing backslash continues a line;
a slash command such as /model, /mode, /cost or /exit; /help lists them all.
Ctrl-C while an answer runs opens a pause menu in supported terminal front ends:
[s]teer (delivered after the current tool results), [f]ollow-up, [c]ontinue, [a]bort
and, for a foreground call (including a chat turn) when available, [b]ackground;
a second Ctrl-C aborts. Backgrounding returns to the chat prompt; use
!!gptr::gptr_wait(gptr::gptr_last()) there to wait for completion. Returning to the prompt
does not guarantee progress while the chat waits for input. Under Rscript, background runs
advance only inside blocking gptr calls.
Front ends that cannot resume use an abort fallback. /exit, two consecutive interrupts at
the prompt or the end of piped input return the session invisibly, so session = peter()
keeps the conversation. Use Ctrl-C in a terminal; RStudio, R.app, RGui and Positron use Esc.
Options: gptr.verbose (0 silent, 1 progress, 2 streamed console, 3 debug; default 0 in
knitr and testthat, 1 under Rscript, 2 at the console), gptr.max_turns_console
(turns per console prompt, default 200) and gptr.history (console inputs to R's history,
default TRUE). Ordinary progress uses normal output; actual errors use stderr.
vignette("interactive-console", package = "gptr") gives input examples and the complete
built-in command table.
A pipe such as session |> peter("Explain the result.") adds work to the same session
and kept workspace. Use gptr_fork() to branch explicitly. The final answer is
session$text; session$value is the R value selected by gptr_return() during a tool
call. Agent-created objects remain in envir.
gptr_security, gptr_egress and gptr_options;
vignette("language-models", package = "gptr") for connecting models and scripted calls.
fake = gptr_fake_provider(list("The data has 32 rows.", "The data has 11 columns.")) session = peter("How many rows does the data have?", mtcars, model = fake) session$text session |> peter("And how many columns?") identical(gptr_last(), session)fake = gptr_fake_provider(list("The data has 32 rows.", "The data has 11 columns.")) session = peter("How many rows does the data have?", mtcars, model = fake) session$text session |> peter("And how many columns?") identical(gptr_last(), session)
The footer is status . model . turns . tokens . cost . id. A token count or cost that a
provider did not report is printed as unknown, never as zero.
## S3 method for class 'gptr_session' print(x, ...)## S3 method for class 'gptr_session' print(x, ...)
x |
A |
... |
Unused. |
x, invisibly.
Display the latest recorded messages at the current console width. This changes neither the complete history table nor the session, and makes no model request. Unknown token counts remain unknown. Previews are single lines; the underlying table retains its text.
## S3 method for class 'gptr_session_summary' print(x, n = 8L, ...)## S3 method for class 'gptr_session_summary' print(x, n = 8L, ...)
x |
A |
n |
Maximum number of recent messages to display; |
... |
Unused. |
x, invisibly.
Show a session's structure
## S3 method for class 'gptr_session' str(object, ...)## S3 method for class 'gptr_session' str(object, ...)
object |
A |
... |
Unused. |
NULL, invisibly.
Reads a table of recorded turns without a model request. It does not generate a narrative
workflow summary or export an executable script. To request prose, continue the session
with peter() and verify the model-generated answer against the recorded work.
Both summary(session) and session$history retain every recorded message. Printing shows
the latest eight messages and a snapshot of session metadata. Notebook, R Markdown and
Quarto displays use the same compact preview by default. Use print(x, n = Inf) to display
every row, or as.data.frame(x) for an ordinary data frame without the display metadata.
## S3 method for class 'gptr_session' summary(object, ...)## S3 method for class 'gptr_session' summary(object, ...)
object |
A |
... |
Unused. |
A gptr_session_summary data frame (turn, role, preview, tools, tokens).