holm

Rust API

The holm crate drives a box from Rust with no server. This page gives the main types and methods. For every item, build the API docs:

cargo doc -p holm --no-deps --open

To add the dependency, see the Rust quick start.

Main types

Type Purpose
Computer One box. Owns the box and its screens.
Builder Configures a box before launch. From Computer::builder().
Screen One screen of a box. computer.primary() is screen 0.
Devtools The box's browser, through Chrome DevTools. From computer.browser().
Page One browser tab.
Takeover A takeover by a person. From hand_over() or share().
Error, Result The error type for all operations.

Computer has the same input, screenshot, clipboard, widget, and takeover methods as Screen. They act on the primary screen.

Create and remove a box

Method Effect
Computer::launch() Launch a box with the defaults: one 1280x800 screen on Docker.
Computer::builder()…launch() Launch a box with options. See Builder.
Computer::attach(name) Attach to a running box by name.
computer.shutdown() Stop and remove the box.
computer.pause(), resume() Pause and resume.
computer.stop(), start(within) Stop the box and keep its files, then start a new desktop. start returns a new Computer.

When a Computer is dropped, its box is removed, unless the builder set keep_on_drop(true).

Builder

let computer = Computer::builder()
    .size(1920, 1080)
    .audio()
    .network(false)
    .memory("2g")
    .expires_after(Duration::from_secs(3600))
    .launch()
    .await?;
Method Effect
size(w, h) Screen size.
packages([…]) Apt packages to install.
wide_fonts(), video(), dock(), accessibility(), audio(), x11_apps() Add a feature. The built-in image has wide fonts, video, the dock, and accessibility by default, and XWayland on Wayland. See Boxes.
minimal(), without(feature), features([…]) The bare desktop, one feature left out, or the whole list.
profile(Arc::new(WaylandProfile)) Use Wayland instead of X11.
network(false) Block network access.
memory(limit), cpus(n) Resource limits.
runtime(program) docker (default), podman, or nerdctl.
machine(Arc<dyn Machine>) Another runtime, such as a microVM, E2B, Vercel, Daytona, or Modal.
name(name) The box name, for attach.
image(tag) Use an image that is already built.
profiles(volume) Keep the browser profile in a named volume.
expires_after(duration) Remove the box after a fixed time.
expires_when_idle(duration) Remove the box after a time with no use. Call touch() when work reaches the box by another path.
keep_on_drop(true) Keep the box when the Computer is dropped.
auth(Auth), publish_on(Bind), advertise(host) Viewer access. See Human control.
config() Return the resolved configuration and do not launch.
Builder::from_spec(&spec) Start a builder from a box spec. Use it for settings with no builder method, such as the number of screens and catalog applications.

Screen input

Coordinates are device pixels. (0, 0) is the top-left corner. A point is Point::new(x, y) or (x, y).

Method Effect
screenshot() Return a PNG of the screen.
capture(&Shot) Capture a window or a rectangle.
move_to(at) Move the pointer.
click(at, button), double_click(at, button) Click.
click_with(…), drag_with(…) Click or drag with modifier keys held, or with motion.
drag(from, to, button) Drag.
scroll(at, Delta::down(3)) Turn the wheel, in notches.
type_text(text) Type into the focused element. Add .every(duration) to slow it down.
press("ctrl+l") Press a key or combination.
cursor() Get the pointer position.
wait_until_still(settle, within) Wait until the screen stops changing.

Windows and applications

On Screen (computer.primary()):

Method Effect
windows() List windows.
active_window() Get the window that receives keyboard input.
wait_for_window(class, within) Wait for a window to appear.
focus(window), close_window(window) Bring to the front, or close.
arrange(window, Arrange) Move, resize, maximize, minimize, or restore.
launch(&Launch) Open an application.

Browser

let browser = computer.browser().ok_or("no DevTools port")?;
let mut page = browser
    .open_page("https://example.com", Duration::from_secs(30))
    .await?;

page.fill("Email", "[email protected]").await?;
page.click_on("Sign in", Button::Left).await?;
page.wait_for("Dashboard", false, Duration::from_secs(10)).await?;
let text = page.read(Reading::Markdown, None, None).await?;

browser() returns None when the box has no DevTools port. On E2B, Vercel, Daytona, and Modal, see Browser mode on remote runtimes.

Devtools:

Method Effect
open_page(url, within) Open a tab and return its Page.
pages() List tabs.
visible_page() The tab that the screen shows.
cookies(url), set_cookies(…), clear_cookies(url) Cookies.
export_session(origins, carry), import_session(&session) Move a login between boxes.
create_group() An isolated browser session.

Page:

Method Effect
read(format, limit, max_links) The page as Markdown, text, or HTML.
snapshot(scope, limit), snapshot_delta(…) List the controls, each with a reference such as @e12.
find(query, limit, scroll, exact) Find elements.
click_on(query, button), double_click_on(…), hover(query), drag_on(…) Pointer actions on an element.
fill(query, text), focus(query), check(query, on) Field actions.
options(query), choose(query, options, drop) Dropdowns.
upload(query, paths) File inputs. Paths are in the box.
wait_for(query, gone, within), wait_for_any(…), wait_until_true(js, within), wait_for_load(within) Waits.
evaluate(js) Run JavaScript.
navigate(url), back(), forward(), reload() Navigation.
bring_to_front(), visible() Make this tab the one the screen shows.
screenshot(), capture(&PageShot), pdf(landscape, background) Captures.
console(clear) The console log.
call(method, params) Send any CDP command.

Native widgets

Needs accessibility() on the builder. See Control modes.

Method Effect
nodes(app, depth) The widget tree.
find_nodes(&NodeQuery, limit) Find widgets.
focus_node(&NodeQuery) Give a widget the keyboard focus.
set_node(&NodeQuery, value) Set a field.
invoke_node(&NodeQuery, action) Run a widget action.

Files, commands, and clipboard

Method Effect
exec(argv), exec_within(argv, within) Run a command. Returns the exit code, stdout, and stderr.
read_file(path), write_file(path, bytes) Read or write a file in the box.
upload(from, to), download(from, to) Copy a file between the host and the box.
list_dir(path), grep(&Search), glob(…) Search the box.
clipboard(), set_clipboard(text) The clipboard.
selection(Selection::Primary), set_selection(…) The primary selection.

Human control

See Human control.

Method Effect
viewer_url() The watch URL.
hand_over() Start an exclusive takeover. The Takeover has the control URL.
share() Start a shared takeover.
wait_until_free(within) Wait until no person has the control viewer open.
takeover.end() End the takeover.
person_driving(), reclaim() Check for and end a takeover that has no owner.
start_recording(fps), stop_recording() Record the screen. Needs video().

Errors

All methods return holm::Result<T>. The variants of holm::Error:

Variant Meaning
Unavailable The runtime or a program is not available.
Unsupported The box cannot do this. gaps names what is missing.
Invalid The request is not valid.
Gone The box is gone.
Denied Refused. Usually a person has control of the screen.
Failed A command ran and did not succeed.
Timeout An operation did not finish in time.
ScreenUnavailable The screen cannot be used now.
Transport The box could not be reached.

error.retryable() tells you if the same call can succeed later.

Extension points

Trait Implement it to
Machine Run boxes on a different platform.
Profile Use a different desktop image or display stack.
Engine Use a different container CLI.
MicroVmApi Add a hypervisor.
RemoteApi Add a cloud sandbox vendor.

See examples/custom_image.rs and examples/custom_sandbox.rs.

Examples

Run each with cargo run --example <name>.

Example Shows
quickstart Launch, open a page, click, type, screenshot
serve Launch a box that stays after the program exits, and print its viewer and DevTools URLs
tour Open a box, drive it, and keep it
attach Attach to a running box by name and type into it
browser Page operations through DevTools
elements Find, fill, dropdowns, and file inputs on an attached box
waiting Page waits instead of sleeps
capture Screenshots of the screen, a rectangle, and a window
recording A GIF made from frames
takeover Handing control to a person
from_spec Launching from a box spec (box.json)
custom_image A custom image
custom_sandbox A custom remote vendor
microvm A microVM through microsandbox
e2b, e2b_takeover E2B, with and without a takeover. Need --features e2b and E2B_API_KEY.
vercel Vercel Sandbox. Needs --features vercel and the VERCEL_* variables.
daytona Daytona. Needs --features daytona and DAYTONA_API_KEY.
modal Modal. Needs --features modal, MODAL_TOKEN_ID, and MODAL_TOKEN_SECRET.