Skip to contents

Use this reference to discover settings, inspect and edit configuration objects, and launch configured sessions. Examples are displayed without execution. For a complete analysis task, see Giving an agent an R session.

Session configuration

The development interface uses S7 from RConsortium/S7, pinned in DESCRIPTION. Install the declared GitHub dependency with pak/remotes before building the package; R CMD INSTALL alone does not process Remotes. During development, use path= to select the current checkout’s Console binary. Use a matching Console executable for these configuration operations.

ConsoleConfig() combines runtime selection, package preparation, permissions, and tool presentation. It reads no configuration files. The class constructors have explicit named arguments matching the application schema.

config <- ConsoleConfig(
  r = RConfig(
    executable = "/opt/R/bin/R",
    packages = c("dplyr", "ggplot2"),
    resolution = "fixed"
  ),
  python = ManagedPython(
    version = "3.13",
    packages = "pandas",
    resolution = "explicit"
  ),
  sandbox = SandboxPolicy(
    filesystem = SandboxFilesystem(read_write = "./output", deny = "./secrets"),
    network = SandboxNetwork(
      proxy = SandboxProxy(domains = SandboxDomains(allow = "api.example.com"))
    )
  ),
  resolver = ResolverConfig(
    environment = c(UV_INDEX_URL = "https://pypi.org/simple")
  )
)

tool <- console_tool(config = config, project = "/path/to/project")

project sets the child’s working directory without changing the caller’s directory. Relative paths use that launch directory. ExistingPython(".venv") selects a preinstalled interpreter or standard virtual environment; it accepts no preparation options. ManagedPython() prepares a uv-managed environment. R and managed Python independently support implicit, explicit, and fixed resolution. R defaults to implicit; managed Python defaults to explicit. R also supports disabled for preinstalled packages. Worker restart retains the captured runtime and configuration. See ?RConfig, ?ExistingPython, and ?ResolverConfig.

The launch choices make file discovery explicit:

console_tool() # Discover global and project files, materialize, then launch
console_tool(config = ConsoleConfig()) # Built-in defaults, no config files
console_tool(config = ConsoleConfig(sandbox = FALSE)) # Host execution

console_tool() discovers configuration files by default. Pass config = ConsoleConfig() to use built-in defaults without reading files. Discovery trusts the whole application configuration, including executable selection, environments, and permissions.

Discover configuration once

Read the global and project files into an R object before inspecting or modifying them:

config <- discover_console_config(project = "/path/to/project")
print(prune_console_config(config, project = "/path/to/project"))
tool <- console_tool(config = config, project = "/path/to/project")

Discovery reads config.yaml in MCP_CONSOLE_HOME (otherwise ~/.agents/console/config.yaml), then .agents/console/config.yaml in the launch directory. It does not search ancestors. Both paths are optional: a missing file is skipped, but a malformed or unreadable file fails. The result is an ordinary, fully materialized S7 ConsoleConfig with file discovery disabled. Changing the source files afterward does not change this object or its launch.

Choose the sources directly, or set either to NULL:

config <- discover_console_config(
  global_file = NULL,
  project_file = "settings/report.yaml",
  config = ConsoleConfig(inherit_environment = FALSE),
  project = "/path/to/project"
)

# Require one selected file. JSON and YAML use the same configuration schema.
config <- read_console_config("report.json", project = "/path/to/project")

read_console_config() fails if its file is missing and reads no other files. Relative paths, including paths inside configuration files, use project. In either reader, config overrides the files: mappings merge recursively, package lists replace inherited lists, and explicit Python selections and sandbox policies replace their entire nodes. An empty package vector means no optional startup packages. sandbox = FALSE clears worker and resolver permissions and disables enforcement; it cannot be combined with an explicit resolver policy.

Inspect and edit configuration

Materialization and pruning are two views of the same class:

Operation Result
ConsoleConfig(...) Only the settings supplied in R; no file reads
materialize_console_config(config) Settings plus native defaults, complete tool prose, and signature metadata
prune_console_config(config) Settings that differ from native defaults, retaining meaningful empty values
discover_console_config(...) Optional file layers captured and materialized once
read_console_config(file) One required JSON or YAML file, materialized without discovery

Omitting config from materialization or pruning starts with ConsoleConfig() and reads no files. The selected executable supplies the defaults and validates the result without starting interpreters or installing packages. Pruning is useful for reviewing changes; omissions follow the defaults of the binary used on the next launch. Use the same path or version and project when comparing, editing, and launching configurations.

config <- materialize_console_config(ConsoleConfig(languages = "r"))
print(config) # Full contents, including untruncated descriptions
config@tool@description <- "Run one R cell in a persistent workbench."
config@tool@parameters$timeout_ms@enabled <- FALSE
config@tool@parameters$r@description <- "Evaluate a complete R expression."
print(prune_console_config(config))
tool <- console_tool(config = config)

Use @ for S7 properties and $ for entries in the named parameters list. The parameter schema contains read-only types and constraints; native validation rejects schema edits. Use enabled = FALSE to hide a field; assigning NULL removes an override and restores its default. Materialized descriptions are literal overrides: changing visibility, languages, or permissions does not regenerate saved prose. Clear the affected description with NULL before materializing again to regenerate it.

Compare or save the application settings with ordinary R tools:

edited_config <- config
edited_config@tool@parameters$timeout_ms@enabled <- TRUE
before <- prune_console_config(config)
after <- prune_console_config(edited_config)
all.equal(as.list(before), as.list(after))

writeLines(
  as.character(jsonlite::toJSON(
    as.list(after),
    auto_unbox = TRUE,
    pretty = TRUE
  )),
  "report.json"
)
restored <- read_console_config("report.json")

as.list() excludes launch-only controls: discovery and sandbox = FALSE. For host execution, retain the S7 object (for example with saveRDS()) or pass config = ConsoleConfig(sandbox = FALSE) when reading JSON. Runtime-dependent interpreter selection, automatic package lists, and runtime-owned cache paths remain policies. Materialization does not lock dependencies or copy inherited environment variables.

config@tool@instructions is server guidance returned during MCP initialization, which some clients use for deferred tool discovery. config@tool@description and parameter descriptions arrive through tools/list. The ellmer adapter uses the latter tool definition and does not automatically insert server instructions into the chat prompt. See tool presentation and lifecycle.

Launch a configured session

resolve_console_config() is an alias for full materialization. Configuration objects use S7 properties, and executable/project choices are explicit arguments:

config <- materialize_console_config(path = binary, project = project)
config@tool@description <- "Run a report cell."
tool <- console_tool(config = config, path = binary, project = project)

ConsoleConfig(discovery = ConfigDiscovery(...)) requests discovery at launch. Use discover_console_config(global_file = ..., project_file = ...) to read the files before launch. Explicit config = NULL is equivalent to ConsoleConfig(); omitting config uses discovery. Constructed, discovered, materialized, and pruned objects share validation and temporary-file transport, so long descriptions and startup programs do not consume command-line space.

Python fallback policies and SQL startup source use the same typed constructors when supplied directly or returned by materialization:

ConsoleConfig(
  python = FirstAvailablePython(list(
    ExistingPython(".venv"),
    "active_venv",
    ManagedPython(packages = character())
  )),
  startup = StartupConfig(
    language = "python",
    code = "import sqlite3; _console.sql_connection(sqlite3.connect(':memory:'))"
  )
)

Sandbox policies

A SandboxPolicy() can configure worker or resolver permissions. Its nested classes are SandboxFilesystem, SandboxNetwork, SandboxProxy, SandboxDomains, and SandboxSockets. An empty worker policy grants no workspace writes or networking. Use SandboxPolicy(profile = "workspace") to allow project writes with the native workspace metadata protections; network access remains independent. For configuration shared by Codex and Claude, or another client without sandbox metadata, configure that client’s default permissions with a fallback:

SandboxPolicy(
  profile = InheritCodexSandboxProfile(fallback = "workspace"),
  filesystem = SandboxFilesystem(read_write = "./output")
)

The first MCP send selects the translated client profile when usable metadata is present, or the workspace profile otherwise. Explicit permission settings compose with that selected base; fallback workspace grants are not added to the client profile. Use profile = "inherit_codex" for the default "read_only" fallback, or set InheritCodexSandboxProfile(fallback = "read_only") explicitly. Missing metadata selects the configured fallback silently; malformed metadata emits a warning on server stderr and selects the same fallback. tempdir selects "managed", "read_write", or "read_only" as described in temporary storage. This is a host-read/private-write baseline, not filesystem secrecy: sensitive readable locations need explicit denial. Create required output directories on the host before granting them; R does not create or normalize configured paths.

policy <- SandboxPolicy(filesystem = SandboxFilesystem(read_write = "./output"))
tool <- console_tool(config = ConsoleConfig(sandbox = policy))

NULL policy properties are omitted, SandboxFilesystem() is an explicit empty mapping, and read_write = character() is an explicit empty sequence. Serialization preserves these distinctions. Worker and resolver policies are independent; an omitted resolver filesystem retains its native cache grants, while an explicit mapping replaces them. Explicit resolver sandbox policies are unsupported on Windows, where preparation runs with host permissions.

See ?ConsoleConfig and ?SandboxPolicy.

Use ToolConfig() to replace descriptions or hide parameters for evaluations:

console_tool(
  config = ConsoleConfig(
    tool = ToolConfig(
      description = "Run R code in a persistent session.",
      parameters = list(
        r = ToolParameterConfig(description = "Execute one complete R cell."),
        timeout_ms = ToolParameterConfig(enabled = FALSE),
        requirements = ToolParameterConfig(
          parameters = list(
            r = ToolParameterConfig(description = "R package requirements.")
          )
        )
      )
    )
  )
)

Descriptions replace the complete selected text, including empty strings. instructions independently replaces MCP initialization instructions. Hidden parameters are removed from the signature and rejected if supplied; omission retains their runtime defaults. Hiding timeout_ms retains the 60,000 ms wait budget. See ?ToolConfig and the tool configuration contract.