The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Teams and background work

gptr logo

Use a team for several roles working on one task, a fan-out for the same task over several inputs, or gptr_parallel() for independently specified calls. Each returns a session whose children can be inspected. Model requests run concurrently; ordinary inline R code still executes in the one R process.

The examples below need a configured model and are shown without running them.

A team of named roles

library(gptr)
session = peter("Review the analysis workflow.", agents = list(
  statistics = gptr_agent(system = "Check the statistical assumptions."),
  code = gptr_agent(system = "Check the code and input/output handling.")
))
session$statistics$text
session$code$status

The member names identify roles. gptr_agent() can specify each role’s model, system text, tools, skills, backend and exported object names. A multi-member inline team uses child workspace overlays: reads can use the parent’s already-loaded objects, while ordinary assignments stay in each child until requested exports are collected. That is not a security boundary or protection against arbitrary code mutating an external resource. Worker backends use separate R processes and serialize selected inputs, with their own memory and temporary file costs; CLI backends need their external CLI and authentication. See Execution model for copy-on-modify and backend boundaries. Role definitions do not waive the usual tool permission checks.

session$text joins member reports under headings, where a member that failed says (ended with status error), and session$value is their named list of values, until the team is continued; session$statistics is the member session. A report is model-generated output, not verification. Inspect each child’s status and the actual results before relying on it.

Continuing a team without agents = asks the container’s model to synthesize those reports. Afterwards session$text and printing show the synthesis, session$value is a value it returns, and session$statistics$text is still that member’s report:

session |> peter("Reconcile the reviews into one prioritized list of fixes.")

This adds a model request. agents = starts new children; it cannot be used to continue a piped session. Teams and fan-outs run in the foreground and cannot be combined with background = TRUE, .run = FALSE, or nested as gptr_parallel() members.

A fan-out over input elements

cohorts = list(A = 1:3, B = 4:6, C = 7:9)
session = peter("Summarize this cohort.", cohorts, parallel = 2)
session$A$text

parallel = 2 limits active children, not the number of inputs processed: every element is queued. Exactly one attached context object must supply the batch, as a list, atomic vector or data-frame rows. Each child receives its own element. Unique nonempty element names become child names; otherwise positions are used. Inspect a child with session$A or session[[1]]. session$text is the named vector of the children’s answers, and printing the session shows each answer under its child’s name.

For object-producing work, keep each child’s results separate and specify exports only when needed. Export-name collisions are reported and results are collected in task order; this is not an automatic merge of competing analyses. Keep exports and returned values self-contained: a fan-out child that succeeds keeps only the values it returned with gptr_return(), and a worker sends back only its exports, so an exported function or plot finds the caller’s objects but none of the child’s other objects.

At the console each child of a foreground call prints one line when it starts, sub-agent A (<model>) started, and one when it ends, sub-agent A done (1/3) with its turns and seconds, or sub-agent A failed (1/3): <reason>. A child’s approval prompts and questions name it (? sub-agent A: allow r?; a nested peter() call by its prompt and number, 'Summarise ...' #2), and its printed output stays in its own result. A peter() call that the agent’s own R code makes without envir = reads your objects and keeps the ones it creates in res$envir. R code that wraps such calls in capture.output() or sink() also captures their prompts.

Independent calls with gptr_parallel()

session = gptr_parallel(
  planner = peter("Plan the analysis.", envir = new.env()),
  review = peter("Review the inputs.", envir = new.env()),
  max_active = 2
)
session$planner$text
session$review$text

The calls are deferred while the members are constructed, then scheduled together. You can also pass .list = a named list of sessions created with .run = FALSE. Member names must not collide with session accessors such as text or status. A member must be idle with queued input, rather than an already completed call passed by variable.

Each member retains its own model. A member without envir = evaluates in the caller’s environment, which it shares with the other members, so give each one envir = new.env() to keep their objects apart. Member tools =, budget = and per-run .opts (including max_turns) are not applied. Members share the call’s budget. Set applicable defaults before launch or run under an enclosing budget; see Token efficiency. on_error = "return" keeps failed members for inspection; "stop" signals the first failed member’s condition after all members settle. A team, fan-out or gptr_parallel() result whose members did not all finish takes the first such member’s status, and $reason names each one; agents = and parallel = signal that member’s condition, with the team as $session, when no member finished.

Coaching runs many sessions

gptr_coach() also runs many sessions, but to improve a harness rather than to answer a question. With the defaults it runs your task 4 times and starts 3 coach sessions, and it says how many before it starts. Each session runs unattended in its own R process, with copies of your objects and an empty folder of its own, so it cannot change your objects. A step that needs your approval ends that run, so most tasks need mode = "auto". On a Claude Code or Codex plan, at most two sessions run at once. The result is a harness, a function you call like peter(), not the work of the runs. See Harnesses and coaching.

Deferred sessions and SDK control

.run = FALSE constructs an idle session with queued input without requesting a model yet. gptr_step() advances it by model turns; gptr_wait() runs queued work until it finishes or times out. Returned sessions can be inspected at each stage.

session = peter("Prepare a plan.", .run = FALSE)
session$status
gptr_step(session, turns = 1)
session$text

gptr_steer(session, "Include an input validation step.", as = "follow_up")
gptr_wait(session, timeout = 10)
session$text

A steer reaches a running agent after its current tool results; a follow-up is delivered when it would otherwise stop. On an idle session, either remains queued until the next run. Piping a prompt into a running session uses the same steering mechanism. gptr_wait() timing out leaves the run running; it does not cancel it. gptr_cancel() aborts active runs, keeps partial history and leaves idle sessions alone.

gptr_on(session, event, function(event, ctx) ...) subscribes to cataloged session events and returns a function that removes the listener. Keep reporting state outside the agent’s workspace and remove listeners when finished:

seen = new.env()
seen$roles = character()
off = gptr_on(session, "message_end", function(event, ctx) {
  seen$roles = c(seen$roles, event$message$role)
  NULL
})
session |> peter("Check the plan's assumptions.")
off()
seen$roles

Experimental background work

A background session runs through idle-console callbacks from the optional later package. It is not an independent R execution thread. Given an existing fitted model fit, start with a short task and an explicit workspace:

work = new.env()
work$fit = fit
session = peter("Inspect fit and propose follow-up checks.", fit = work$fit,
                envir = work, background = TRUE)
session$status
gptr_jobs()
session |> peter("Prioritize residual diagnostics.")
gptr_wait(session, timeout = 30)
# Cancel only if the run is still active and you want to stop it.
gptr_cancel(session)

With gptr.background_tools = "idle" (default), an R tool can run at an idle tick and occupy the R console until it finishes. "wait" defers those tools to a blocking gptr call. Rscript, knitr and Quarto have no idle-console progress: use gptr_wait() or another blocking call. Other front ends have the support limits documented in help("gptr-background", package = "gptr"); do not infer support from the mere return of a session object.

An approval or question at an idle tick parks the session as waiting, without performing the action. gptr_wait() on the session resumes it with a message saying that you are at the console, and the model repeats its request before the usual prompt; other calls leave it waiting. That extra request can use tokens. A waiting session has no active run for gptr_cancel() to abort; inspect its status before choosing how to resume or stop jobs.

Checkpoints, usage and durable history

After a modifying run, inspect checkpoints and preview a rewind before restoring state:

gptr_checkpoints(session)
gptr_rewind(session, preview = TRUE)
gptr_rewind(session)
gptr_usage(session, by = "agent")

restore = "conversation" changes the conversation; "workspace" restores captured workspace state; "all" requests both. Restoration covers captured objects/files and registered checkpointers, with conflicts and unsupported changes reported. It does not undo arbitrary external services or uncaptured side effects. Check the report and restored data. Assigning a session to another name keeps the same object; use gptr_fork() for a branch.

For a top-level team (agents =) or fan-out (parallel =) call in a designated history document, the code of each child that exports objects or returns a value with gptr_return() is recorded under that statement. Replay reconstructs the children and reruns that code, so the exported objects and each child’s $value (f$value of a fan-out) come back without a model call. gptr_parallel() records nothing, since its members are nested calls: use agents = or parallel = for a team a document should replay. Recording, answer caches and usable blocks must be present; a narrative team report alone is not a replayable workflow. See Record, replay and export for recording and summary recipes, and Token efficiency for shared budgets and usage.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.