sess is an R package for connecting your R sessions to an editor (client). The
VS Code R extension is our primary
target client and sess powers many of the extension's core features:
workspace, data and plot viewers, help panel, hover and completion, RStudio API
emulation, etc.
Under the hood, sess talks to the client over a local socket (Unix domain
socket on macOS/Linux, named pipe on Windows) using
JSON-RPC 2.0 messages.
Note
Users of the VS Code R extension (>=v3.0.0) do not need to install sess
manually. The extension bundles its own copy of sess and will install it
for you (along with any missing CRAN dependencies) if it is missing or
outdated. Managed R terminals ask first; attaching an existing session
installs without prompting.
sess is not yet on CRAN. But you can install the development version from R-universe:
install.packages(
"sess",
repos = c("https://reditorsupport.r-universe.dev", getOption("repos"))
)When you start an R terminal from VS Code, the extension's R profile calls
sess::connect() for you. To connect a session yourself:
sess::connect(
endpoint = NULL, # socket/pipe endpoint; see below
use_rstudioapi = TRUE, # emulate rstudioapi functions
use_httpgd = TRUE, # allow httpgd as the plot device
use_jgd = FALSE # allow jgd as the plot device
)If endpoint is omitted, connect() resolves it in this order:
- The
SESS_ENDPOINTenvironment variable. - The
endpointfield of the JSON file named bySESS_DISCOVERY_FILE.
The discovery file must have integer schema version 1 and a nonempty endpoint.
When discovery is needed, a missing, invalid, or unsupported file prevents connection.
An explicit endpoint or SESS_ENDPOINT takes precedence over discovery.
If the discovery file describes the connected endpoint, unexpected disconnection
starts a retry loop. It waits for a different endpoint and reconnects with the same
runtime options and process-lifetime session_id. A manual connect() cancels
pending retries. Each managed terminal has its own discovery file in extension
storage; VS Code refreshes it after reload, using extension-private terminal PID
metadata even when a wrapper's PID differs from R's. Unknown fields are ignored.
{"version":1,"endpoint":"/path/to/sess.sock","jgdSocket":"/path/to/jgd.sock"}Only version and endpoint are required. Consumers must ignore unknown fields.
New backends may add optional fields under version 1: adding a field does not
require a schema version bump. Removing or changing the meaning/type of existing
fields, or making additional fields mandatory, is a breaking change and requires
a new schema version. This discovery schema version is separate from the IPC
protocol_version.
The optional jgdSocket string describes the JGD renderer belonging to that
endpoint. When use_jgd = TRUE, sess applies it before runtime initialization,
including automatic reconnect: a nonempty string sets JGD_SOCKET, an empty
string unsets it (renderer unavailable), and an omitted field leaves it untouched.
A present value of another type is invalid. It does not enable JGD or override
use_jgd; no arbitrary environment variables or R code are accepted. VS Code
publishes endpoint and renderer together in one atomic file replacement, with
an empty jgdSocket when its current backend does not provide JGD.
Fields belonging to other backends remain optional and are interpreted only by
implementations that support them. terminalPid is VS Code-private metadata for
finding managed terminal discovery files; sess does not use it as identity.
Once connected, sess registers hooks (via register_hooks()) that redirect
R's interactive features to the client:
| R feature | Behavior |
|---|---|
View() |
Data frames, matrices, Arrow tables and polars data frames open in a paged, sortable, filterable data viewer. Lists open as JSON; other objects as R code. |
browseURL(), viewer, page_viewer |
URLs and local HTML files (e.g. htmlwidgets) open in the editor. |
?topic, help.search() |
Help pages open in the editor's help panel, in the column configured by r.session.viewers.viewColumn.helpPanel. |
| Graphics device | Plots appear in the editor's plot viewer (see below). |
rstudioapi |
Editor functions such as getActiveDocumentContext() and insertText() are emulated when use_rstudioapi = TRUE. |
| Top-level task callback | The client is notified after each command so it can refresh the workspace view. |
These changes are undone when the connection closes. sess removes its task
callbacks, closes its graphics devices, and restores any options, bindings, S3
methods and plot hooks it replaced (unless other code has since changed them).
A plot held only by a jgd device may not survive a disconnect or window reload.
Calling register_hooks() again replaces the previous installation rather than
stacking hooks.
For displaying R plots, sess chooses a graphics device in this order:
- jgd, if
use_jgd = TRUE, theJGD_SOCKETenvironment variable is set, and the jgd package is installed. - httpgd, if
use_httpgd = TRUEand the httpgd package is installed. - Standard: plots are recorded on a null device and re-rendered by the client on demand at the viewer's size (as SVG via svglite if installed, otherwise PNG).
In VS Code, this is controlled by the r.plot.backend setting.
| Name | Type | Purpose |
|---|---|---|
SESS_ENDPOINT |
env var | Socket/pipe path used by connect(). |
SESS_RSTUDIOAPI |
env var | TRUE/FALSE; passed as use_rstudioapi by the extension's R profile. |
SESS_PLOT_BACKEND |
env var | auto, standard, httpgd or jgd; sets use_httpgd/use_jgd in the extension's R profile. |
JGD_SOCKET |
env var | Socket used by the jgd device; set by the extension. |
This section is for developers writing or debugging a client.
- Transport: Unix domain socket (macOS/Linux) or named pipe (Windows).
sessis the connecting side; the client listens. - Framing: JSON Lines. Each message is one
JSON-RPC 2.0 object followed by
\n. Receivers buffer incoming data and dispatch complete lines only. - Messages: standard JSON-RPC 2.0 notifications (no
id), requests (withid) and responses (resultorerror). Unknown request methods receive error-32601(Method not found). - Coordinates: row and column positions in
rstudioapi/*messages are 1-indexed, as in R.
On connecting, sess sends an attach notification:
{
"jsonrpc": "2.0",
"method": "attach",
"params": {
"protocol_version": 1,
"sess_version": "3.0.0",
"session_id": "sess-session-...",
"host": "compute42",
"version": "4.5.0",
"pid": 12345,
"tempdir": "/tmp/Rtmp.../sess",
"wd": "/path/to/project",
"info": {
"command": "/usr/bin/R",
"version": "R version 4.5.0 (...)",
"start_time": "2026-05-05 06:00:00"
}
}
}protocol_version versions the message contract independently of the R package
version. The extension rejects unsupported versions. session_id identifies an
R process across reconnects; PID and host are metadata, not connection identity.
The attached socket's lifetime controls cleanup. A replacement socket with the
same identity supersedes the old one; a late close cannot remove its replacement.
A fork child receives its own identity. Terminal PID association is local-only.
Sent with notify_client().
| Method | Params | Sent when |
|---|---|---|
attach |
see above | Connection is established. |
workspace_updated |
none | A top-level command completes. |
dataview |
title, source, type, and view_id (tables) or file (other objects) |
View() is called. |
plot_updated |
none | The standard device records a new or changed plot. |
httpgd |
url |
An httpgd device is opened. |
help |
requestPath |
A help page or help search is printed. |
browser / webview / page_viewer |
url |
The corresponding R viewer option is invoked. |
restart_r |
command, clean |
rstudioapi::restartSession() is called. |
rstudioapi/send_to_console |
code, execute, focus, animate |
rstudioapi::sendToConsole() is called. |
Sent with request_client(), which blocks until the matching response
arrives. All are used by rstudioapi emulation:
rstudioapi/active_editor_context, rstudioapi/document_context,
rstudioapi/insert_or_modify_text,
rstudioapi/replace_text_in_current_selection,
rstudioapi/set_selection_ranges, rstudioapi/navigate_to_file,
rstudioapi/document_new, rstudioapi/document_save,
rstudioapi/document_save_all, rstudioapi/document_close,
rstudioapi/get_project_path, rstudioapi/show_dialog,
rstudioapi/ask_for_password.
| Method | Params | Result |
|---|---|---|
workspace |
none | globalenv (objects with class, type, length, ...), search, loaded_namespaces |
workspace_children |
name, path, start |
children, next_start (paged expansion of lists, environments, S4/R6 objects) |
hover |
expr |
str: the str() output of the evaluated expression |
completion |
expr, trigger ($ or @) |
Array of {name, type, str}, where str is the element's class |
plot_latest |
width, height, format (svglite or png), devArgs |
format, data (base64) |
dataview_init |
view_id |
columns, totalRows |
dataview_page |
view_id, startRow, endRow, sortModel, filterModel |
rows, totalRows, totalUnfiltered, lastRow |
dataview_dispose |
view_id |
true |
Example exchange:
{"jsonrpc":"2.0","id":4,"method":"completion","params":{"expr":"mtcars","trigger":"$"}}
{"jsonrpc":"2.0","id":4,"result":[{"name":"mpg","type":"double","str":"numeric"},{"name":"cyl","type":"double","str":"numeric"}]}