mirai
Help users write correct R code for async, parallel, and distributed computing using mirai. Use when users need to run R code asynchronously or in parallel, write mirai code with correct dependency passing, set up parallel workers, convert from future or parallel, use mirai_map, integrate with Shiny or promises, or configure cluster/HPC computing.
What this skill does
mirai is a minimalist R framework for async, parallel, and distributed evaluation, built on nanonext.
## Core Principle: Explicit Dependency Passing
mirai evaluates expressions in a **clean environment** on a daemon process. Nothing from the calling environment is available unless passed explicitly — this is the #1 source of mistakes.
```r
# WRONG: my_data and my_func are not available on the daemon
m <- mirai(my_func(my_data))
```
There are two ways to pass objects, and the names used **must match** the names referenced in the expression.
### `.args` (recommended)
Objects in `.args` populate the expression's **local evaluation environment** — available directly by name inside the expression.
```r
m <- mirai(my_func(my_data), .args = list(my_func = my_func, my_data = my_data))
```
### `...` (dot-dot-dot)
Objects passed via `...` are assigned to the **daemon's global environment**. Use this when objects need to be found by R's standard scoping rules (e.g., helper functions called by other functions).
```r
m <- mirai(my_func(my_data), my_func = my_func, my_data = my_data)
```
### Shortcut: pass the whole calling environment
```r
# .args form — populates local eval env
process <- function(x, y) mirai(x + y, .args = environment())
# ... form — single unnamed environment, populates daemon global env
df_matrix <- function(x, y) mirai(as.matrix(rbind(x, y)), environment())
```
### When to use which
| Scenario | Use |
|----------|-----|
| Data and simple functions | `.args` |
| Helper functions called by other functions that need lexical scoping | `...` |
| Pass entire local scope to local eval env | `.args = environment()` |
| Pass entire local scope to daemon global env | `mirai(expr, environment())` |
| Large objects shared across many tasks | `everywhere()` first, then reference by name |
## Common Mistakes
### Unqualified package functions
Daemons start with no user packages loaded. Same applies inside `mirai_map()` callbacks.
```r
# WRONG: dplyr is not loaded on the daemon
m <- mirai(filter(df, x > 5), .args = list(df = my_df))
# CORRECT: namespace-qualify
m <- mirai(dplyr::filter(df, x > 5), .args = list(df = my_df))
# CORRECT: load inside the expression
m <- mirai({
library(dplyr)
filter(df, x > 5)
}, .args = list(df = my_df))
# CORRECT: pre-load on all daemons
everywhere(library(dplyr))
m <- mirai(filter(df, x > 5), .args = list(df = my_df))
```
### Expecting results immediately
`m$data` accesses the value but may still be unresolved. Use `m[]` (or `collect_mirai(m)`) to block until done; use `unresolved(m)` for a non-blocking check.
```r
m <- mirai(slow_computation())
result <- m[] # blocks until resolved
if (!unresolved(m)) result <- m$data # non-blocking
```
## Setting Up Daemons
### No daemons required
`mirai()` works without calling `daemons()` first — it launches a transient background process per call. Setting up daemons is only needed for persistent pools of workers.
### Local daemons
```r
# Start 4 local daemon processes (with dispatcher, the default)
daemons(4)
# Direct connection (no dispatcher) — lower overhead, round-robin scheduling
daemons(4, dispatcher = FALSE)
# Concise programmatic statistics (vs. the richer status())
info()
# Reset (daemons otherwise persist for the session)
daemons(0)
```
### Scoped daemons (auto-cleanup)
`with(daemons(...), {...})` **creates** daemons and automatically cleans them up when the block exits.
```r
with(daemons(4), {
m <- mirai(expensive_task())
m[]
})
```
### Scoped compute profile switching
`local_daemons()` and `with_daemons()` **switch** the active compute profile to one that already exists — they do not create daemons.
```r
daemons(4, .compute = "workers")
# Switch active profile for the duration of the calling function
my_func <- function() {
local_daemons("workers")
mirai(task())[] # uses "workers" profile
}
# Switch active profile for a block
with_daemons("workers", {
m <- mirai(task())
m[]
})
```
### Compute profiles (multiple independent pools)
```r
daemons(4, .compute = "cpu")
daemons(2, .compute = "gpu")
m1 <- mirai(cpu_work(), .compute = "cpu")
m2 <- mirai(gpu_work(), .compute = "gpu")
```
## Memory Backpressure (`memory` + `try_mirai()`)
For high-throughput producers (Shiny, promises, ingest pipelines), use the `memory` argument to `daemons()` to cap the queued task payload at dispatcher (MB, metric). Pair it with `try_mirai()` so the host R thread never blocks on submission.
```r
# 100 MB queue cap. mirai() blocks on submission once the queue is full.
daemons(4, memory = 100)
# try_mirai() returns NULL (invisibly) instead of blocking when the cap is hit.
m <- try_mirai(work(x), .args = list(x = x))
if (is.null(m)) {
# backpressure: drop, retry later, or signal upstream
} else {
# m is a regular mirai
}
# Inspect current and peak queue usage
status()$memory
```
`memory` requires dispatcher. Without dispatcher (or with `memory = NULL`), `try_mirai()` always returns a mirai.
## mirai_map: Parallel Map
Requires daemons to be set. Maps `.x` element-wise over a function, distributing across daemons. Namespace-qualify any package functions used inside the callback (see Mistake 2).
```r
daemons(4)
# Basic map — collect with []
results <- mirai_map(1:10, function(x) x^2)[]
# Constants via .args, helpers via ... (same passing rules as mirai())
results <- mirai_map(
data_list,
function(x, power) helper(x, power),
.args = list(power = 3),
helper = my_helper_func
)[]
# Flatten results to a vector
results <- mirai_map(1:10, sqrt)[.flat]
# Progress bar (requires cli package)
results <- mirai_map(1:100, slow_task)[.progress]
# Early stopping on error
results <- mirai_map(1:100, risky_task)[.stop]
# Combine options
results <- mirai_map(1:100, task)[.stop, .progress]
```
### Mapping over multiple arguments (data frame rows)
```r
# Each row becomes arguments to the function
params <- data.frame(mean = 1:5, sd = c(0.1, 0.5, 1, 2, 5))
results <- mirai_map(params, function(mean, sd) rnorm(100, mean, sd))[]
```
### Process as completed (`race_mirai`)
`race_mirai()` returns the integer index of the first resolved mirai in a list (or `0L` if empty). Useful when you want to handle results in completion order rather than submission order.
```r
remaining <- mirai_map(jobs, run)
while (length(remaining) > 0) {
idx <- race_mirai(remaining)
process(remaining[[idx]]$data)
remaining <- remaining[-idx]
}
```
## everywhere: Pre-load State on All Daemons
```r
daemons(4)
# Load packages on all daemons
everywhere(library(DBI))
# Set up persistent connections
everywhere(con <<- dbConnect(RSQLite::SQLite(), db_path), db_path = tempfile())
# Export objects to daemon global environment via ...
# The empty {} expression is intentional — the point is to export objects via ...
everywhere({}, api_key = my_key, config = my_config)
# .min = N forces a synchronization point: the call must complete on at least
# N daemons before subsequent mirai evaluations proceed. Useful when launching
# remote daemons that connect over time.
everywhere(library(arrow), .min = 4)
```
## Error Handling
```r
m <- mirai(stop("something went wrong"))
m[]
is_mirai_error(m$data) # TRUE for execution errors
is_mirai_interrupt(m$data) # TRUE for cancelled tasks
is_error_value(m$data) # TRUE for any error/interrupt/timeout
m$data$message # Error message
m$data$stack.trace # Full stack trace
m$data$condition.class # Original error classes
# Timeouts (requires dispatcher)
m <- mirai(Sys.sleep(60), .timeout = 5000) # 5-second timeout
# Cancellation (requires dispatcher)
m <- mirai(long_running_task())
stop_mirai(m)
```
## Shiny / Promises Integration
### ExtendedTask pattern
```r
library(shiny)
library(bslib)
library(mirai)
daemons(4)
onStop(function() daemons(0))
ui <- page_fluid(
input_task_button("run", "Run Analysis"),
plotOutput("result")
)
server <- function(inputRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.