Elyra VM Tools
Elyra VM Tools is a small agent that runs in a guest, as root, and does what the VM's own process on the Mac asks of it. With it, a VM
- runs commands for you, a script or an AI agent:
elyravm exec <vm> -- <command> - gives you a shell in this terminal, with no network or SSH:
elyravm shell <vm> - copies files and folders in and out:
elyravm cp <file> <vm>:<path> - takes files dropped on the VM's window into the guest's Downloads (
elyravm send), and, in macOS guests, lets files be dragged out of the guest into Finder - shares the clipboard with macOS guests, which Apple's framework doesn't (Linux has it through the SPICE agent)
- reports who it is: the system's name and version, its host name and its addresses, in
the library, the VM's settings and
elyravm status --json - keeps its clock right after it was paused or suspended
- mounts the shared folders at
/mnt/mac(Linux; macOS mounts them by itself) - shuts down cleanly when you choose Shut Down, also where the power button is ignored
- keeps itself up to date: a VM gets the agent of the Elyra VM that runs it
The agent talks to the Mac over a virtio socket (vsock), a channel between the VM and its own process only: nothing on the network, and no other VM, can reach it.
Getting it
Systems ready to use from the catalog
A VM made from a system ready to use (Ubuntu Server 26.04, Fedora Cloud 44, Debian 13, or one of their desktops) has it from the first boot, with nothing to install (Linux guests).
Other Linux guests
Every VM sees Elyra VM Tools as a read-only folder in its shared folders. Mount them and run the installer as root:
sudo mkdir -p /mnt/mac
sudo mount -t virtiofs elyravm /mnt/mac
sudo sh "/mnt/mac/Elyra VM Tools/Linux/install.sh"
It copies the agent to /usr/local/sbin/elyravm-tools and runs it as a service: a systemd unit
(elyravm-tools.service), or an OpenRC service on Alpine and others without systemd. The agent
is one static program, so it runs on any ARM64 Linux, with no packages to install. The kernel
needs vsock for virtio (vmw_vsock_virtio_transport), which current distributions have.
Within a few seconds the VM's settings say Elyra VM Tools: Running.
macOS guests
Once macOS is set up and you are logged in, open Terminal in the guest and run:
sudo sh "/Volumes/My Shared Files/Elyra VM Tools/macOS/install.sh"
It installs the agent in /usr/local/libexec/elyravm-tools and runs it twice:
- as a launch daemon, as root, for
exec,shell,cp, the clock and shutting down, as in Linux; - as a launch agent in each user's session (
elyravm-tools --session), as that user, for what only a session reaches: the clipboard, and files dropped on the VM's window.
macOS says a background item was added; that is it. Elyra VM Tools.pkg, in the same folder
in builds that carry it, installs the same; unsigned, Gatekeeper asks you to allow it in
System Settings ▸ Privacy & Security first. The script needs no such step.
With it, what you copy on the Mac and in the guest follows to the other both ways, within a second (as long as the VM's settings share the clipboard): plain text, formatted text (RTF and HTML, from TextEdit, Pages, Safari, Mail) and pictures (PNG and TIFF, such as a screenshot), up to 32 MB a copy. Each copy goes with every kind it has, so the app you paste into picks the best one, as on one Mac.
Files copied in Finder go across too, up to 1 GB a copy: their contents are sent to the
other side (the window's subtitle says Copying 2 items to the VM's clipboard…) into a folder
of their own, with their metadata, and that side's clipboard holds them there, so pasting in
Finder copies them in. Only the last copy's files are kept: in the guest in its temporary
folder, on the Mac in ~/Library/Caches/Elyra VM/Clipboard. A copy of more than 1 GB stays on
its side, as runner.log says; drop such files on the window instead. and files dropped on the window land in the
logged-in user's Downloads. The first time something reads Downloads through the session
agent, macOS asks in the guest whether elyravm-tools may use it: allow it (until then, such a
command waits for the answer). elyravm exec --session <vm> -- <command> runs a command as that user,
in their session, as the session agent: open -a Safari, osascript, pbpaste.
The daemon runs as root, but macOS keeps the folders it protects (Desktop, Documents,
Downloads and others) from it; reach those with --session, or give elyravm-tools Full Disk
Access in the guest's settings.
Running commands
elyravm exec <vm> [--user <name>] [--timeout <seconds>] [--json] -- <command> [<argument>…]
The command runs in the guest as root, or as --user, with that user's groups, in that
user's home, with its HOME. It is run directly, not through a shell; for pipes and &&, run
a shell:
$ elyravm exec "web server" -- uname -r
7.0.0-34-generic
$ elyravm exec "web server" --user kh -- sh -c 'cd ~/app && git pull'
$ echo "hello" | elyravm exec "web server" -- tr a-z A-Z
HELLO
- Output comes as the command writes it: its standard output on stdout, its standard error on stderr, binary or text, of any size.
- Standard input from a pipe or a file goes to the command as it comes; from a terminal, the command gets none.
- The exit code is the command's own;
128 + nfor one killed by signaln. --timeoutstops the command, and everything it started, after that many seconds (an hour when not given), and the exit code is124, as withtimeout(1).- Stopping
exec(⌃C, or killing it) stops the command in the guest too. --jsonprints{"exit": 0, "stdout": "…", "stderr": "…", "timed_out": false}when the command has ended, instead of the output as it comes.- Several commands may run at once, each on a connection of its own.
- What a command leaves running in the background, such as a server started with
&, goes on running afterexecreturns.
If the agent isn't running in the VM, exec says so and exits with 1.
A terminal
elyravm shell <vm> [--user <name>]
elyravm exec -t <vm> [--user <name>] [--timeout <seconds>] -- <command> [<argument>…]
shell opens a login shell in the VM, root's or the --user's, in the terminal you type it
in: a terminal of its own in the guest (/dev/pts/…), the size of your window and following
it, with your TERM. Every key goes to the guest, ⌃C, ⌃Z and ⌃D too; colours and full-screen
programs (top, vim, less) work. exit ends it, and elyravm exits with the shell's
code. It needs no network, no SSH and no password.
$ elyravm shell "web server" --user kh
kh@web-server:~$
exec -t runs a command in such a terminal, for one that wants one (htop, apt with its
progress bars). Without -t, a command has no terminal, and its stdout and stderr stay apart.
With -t they are one, as on any terminal, --json can't be used, and there is no time limit
unless --timeout is given.
Closing the terminal, or killing elyravm, ends the shell or command in the guest. A terminal
needs Elyra VM Tools 0.12.0 or later in the VM, which guests get by themselves when they
start.
Copying files
elyravm cp [--user <name>] <from> <to>
One side is in the VM, written <vm>:<path>; the other is on the Mac. A path in the VM that
isn't absolute is in root's home (/root), or the user's with --user.
$ elyravm cp report.pdf "web server:/tmp/" # a file into a folder
$ elyravm cp app.conf "web server:/etc/app.conf" # a file to a name
$ elyravm cp --user kh ~/Projects/site "web server:" # a folder into kh's home
$ elyravm cp "web server:/var/log/syslog" . # a file out
$ elyravm cp "web server:/srv/data" ./data-copy # a folder out, as a new name
Like cp -r: when <to> is a folder that is there, the file or folder goes into it;
otherwise it becomes <to>. A file keeps its permissions and the time it was last changed; a
folder comes with what is in it, symbolic links as links, times kept. On a terminal, a copy
that takes more than a second shows how far it has come: Copying “big.iso” · 40 % · 1.2 GB of
3 GB. What is copied into the VM belongs to root, or to --user. What
comes out belongs to you.
cp works through exec, with cat and tar in the guest, which every Linux has.
Dropping files
Drag files and folders from Finder onto a VM's window: they are copied into the Downloads
folder of the guest's user, as they are, and belong to that user. The window's
subtitle says Copying “report.pdf” · 40 %, then Copied “report.pdf” to ~/Downloads. A name
that is taken there gets a number, as in Finder: report 2.pdf.
In Linux, the guest's user is the one the VM was set up with (a system ready to
use), or else the first ordinary user in the guest (an id from
1000 with a login shell), or else root (/root/Downloads). In macOS, it is the user logged
in, through the session agent.
The window takes files once the VM runs with Elyra VM Tools (in macOS, with a user logged in); otherwise its subtitle says why not while you drag.
Dragging files out
In a macOS guest with Elyra VM Tools and a user logged in, drag files or folders in the guest's Finder out over the edge of the VM's window, and on to Finder on your Mac, or any app that takes files: as the pointer leaves the window, the drag becomes the Mac's, and where you drop it, the files are copied out of the guest, as they are (a name taken there gets a number, as Finder does). In the guest, the drag is called off, and nothing moves.
Linux guests can't do this yet: their desktops (Wayland) don't let Elyra VM Tools see a drag
that begins in another program. Use elyravm cp or a shared folder.
elyravm send does the same from the command line, and prints where each went:
$ elyravm send "web server" report.pdf ~/Projects/site
/home/kh/Downloads/report.pdf
/home/kh/Downloads/site
$ elyravm send "web server" --json report.pdf
{"user":"kh","paths":["/home/kh/Downloads/report 2.pdf"]}
--user sends to another user's Downloads.
Updating it
It updates itself. When a VM starts, or its agent connects, and the agent is older than
the Elyra VM running the VM, Elyra VM sends it the new one (in macOS, the session agents
start again as the new one within half a minute). The agent checks that the new
one runs, puts it in its own place and starts again as it, in a few seconds, with nothing to
restart. runner.log in the VM's folder says so:
Elyra VM Tools in the guest was updated from 0.10.0 to 0.10.1.
An agent of 0.9.0 came before this, and can neither update itself nor run exec and cp as
they are now; they say it is too old. Install it again once, in the guest (over SSH, or at
the console):
sudo sh "/mnt/mac/Elyra VM Tools/Linux/install.sh"
A VM sees the Elyra VM Tools of the Elyra VM that started it; after an update of Elyra VM, restart the VM before installing by hand.
Taking it out
sudo systemctl disable --now elyravm-tools
sudo rm /etc/systemd/system/elyravm-tools.service /usr/local/sbin/elyravm-tools