R-native interaction and secure storage

Rho keeps scheduling, presentation, and storage as separate protocols. nanonext owns asynchronous I/O, mirai owns worker evaluation, and S7 generics connect optional interactive or storage implementations. A graphics window, terminal renderer, or credential cipher must not become an implicit event loop.

Several packages by Mike Cheng provide useful implementations and, equally importantly, sharp examples of how those responsibilities should be separated.

Component decisions

Project Useful capability Place in Rho
nara Fast, in-place drawing and image operations on nativeRaster values Optional in-memory graphics surface. Ownership must be explicit because drawing mutates the raster. Durable output remains a declared RhoGraphicArtifact.
tigerfb Cross-platform framebuffer window with keyboard, mouse, capture, and update operations Optional graphics-preview presenter. It presents pixels and emits input state; it does not schedule provider or agent work.
eventloop Typed mouse, keyboard, frame, and device state around R graphics event handlers Design reference only. Its X11 graphics-device loop is blocking and platform-specific, so it is not Rho’s event substrate.
devoutansi and miniansi ANSI graphics-device output Optional terminal graphic renderer. ANSI image output is distinct from terminal input, layout, focus, and accessibility; these packages do not constitute a TUI.
tickle Tcl/Tk widgets, event bindings, canvas operations, and scheduled idle callbacks Possible downstream desktop UI extension. Tcl/Tk lifecycle remains inside that extension.
rmonocypher XChaCha20-Poly1305 authenticated encryption and Argon2id Implements Rho’s encrypted CredentialStore envelope through raw AEAD operations, not arbitrary R-object encryption.
cryptorng Operating-system cryptographic random bytes No core dependency. nanonext::random(convert = FALSE) already supplies cryptographic bytes from its bundled Mbed TLS implementation.
cryogenic Capture, inspect, modify, and later evaluate R calls No dependency required. Rho model and compute specifications already use language objects directly and attach contracts with S7 classes.
zstdlite Zstandard compression for raw data and R serialization Possible artifact compression adapter. Compression and its parameters must be part of artifact metadata.
serializer and zap C-level R serialization and compact R-specific encodings Useful implementation references, not durable interchange formats. CAS identities and credential envelopes must not depend on an opaque R serialization layout.
rconnection Custom R connections and composable connection filters Design reference while the relevant R connection API remains experimental. Rho streams stay typed async streams rather than masquerading as blocking connections.
priorityqueue and governor Priority ordering and frame-rate control No scheduler dependency. Agent ordering is semantic, and waiting belongs to nanonext condition variables or an owning UI loop.

No package is imported merely because its implementation is attractive. Each adapter first needs a typed Rho contract, supported-platform checks, cancellation semantics, and an executable integration example.

Interactive safe points

The opt-in rho.async task-callback bridge uses base::taskCallbackManager() to drain work that is already ready in the later loop after a top-level R expression.

nanonext Aio completion ──> RhoTask / RhoStream ──> promises/later notification
                                                        │
top-level R expression completed ──> non-blocking pump ─┘

The bridge has deliberately narrow semantics:

This improves interactive progress without creating a second scheduler beside nanonext and mirai.

Graphics presentation

rho.graphics continues to render archival PNG, SVG, and PDF artifacts on declared devices. Interactive presentation is a separate operation. A future presenter generic can dispatch on both artifact or raster type and presentation target:

RhoGraphicSpec ──render──> RhoGraphicArtifact
                              │
                              ├── present in a tigerfb window
                              ├── encode with an ANSI graphics device
                              └── attach to a desktop or web UI

nara is suitable for fast transient raster work before presentation. tigerfb is suitable for a cross-platform preview window. Neither changes the artifact’s content identity or provenance. Window captures become new artifacts rather than mutations of the original artifact record.

Terminal UI work needs a separate terminal capability contract covering raw input, resize, cursor control, color depth, focus, and cleanup. ANSI graphics alone does not satisfy that contract.

Encrypted credential storage

rho.ai preserves the existing CredentialStore interface for encrypted storage and keeps key acquisition explicit. Its on-disk envelope has a versioned schema containing:

The payload is JSON for the typed credential fields, not serialize(..., xdr = FALSE) output. Encryption and decryption failures resolve to typed values, and filesystem reads, writes, and replacement remain asynchronous effects.

Rho uses rmonocypher::encrypt_raw() and decrypt_raw(), generates salts with nanonext::random(convert = FALSE), and supplies explicit additional authenticated data. A passphrase uses Argon2id with the stored random salt; an automated caller can instead supply an explicit 32-byte key. Secret keys should cross as little R code as possible; measured key-handling or envelope work can move to C without moving the public S7 protocol out of R.

rho_keychain_credential_store() is the alternative for systems with a native credential service. It deliberately rejects keyring’s environment and file backends, so a caller cannot silently exchange OS-backed storage for a process variable or another unencrypted file.

Compression, when useful, happens before encryption and is declared in the envelope. It is not required for the small credential documents expected here.