Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Kwebbel

Vex is a lightweight host-to-guest VM communication tool over vsock. It provides a CLI ( vex ), an HTTP daemon ( vexd ), a golang embedable HTTP client ( api/client) and a cross-platform guest agent ( vex-agent ) for reliable command execution inside VMs

Why Vex?

We need to run end-to-end automation tests against ephemeral VMs spawned from Proxmox templates: installing software, running commands, and verifying integrations across different operating systems. QEMU Guest Agent worked initially, but as we scaled up (more VMs, more concurrent commands) we kept hitting timeout errors that no amount of tuning could fix.

Research led us to vsock as a faster, more stable transport. However, qemu-ga doesn't support binding to vsock on Windows guests, which was a dealbreaker for our multi-OS test matrix. Rather than maintaining a fork of qemu-ga or relying on another opaque tool where failures are hard to diagnose, we built Vex: a minimal, purpose-built tool that does one thing well: reliable host↔guest communication over vsock.

The HTTP daemon ( vexd ) exists so our test orchestrator can run on a separate machine and drive everything through a simple REST API.

Install

Quick install (Linux host)

Install or update vex , vexd , and the systemd service in one command:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash

Pin a specific version:

curl -sSfL https://raw.githubusercontent.com/JimberSoftware/vex/main/scripts/install.sh | sudo bash -s -- -v v1.2.3

Manual install

Download binaries directly from the GitHub Releases page.

# vex CLI client
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex_linux_amd64.tar.gz | tar xz
sudo mv vex /usr/local/bin/
# vexd HTTP daemon
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vexd_linux_amd64.tar.gz | tar xz
sudo mv vexd /usr/local/bin/
# vex-agent (Linux guest)
curl -fsSL https://github.com/JimberSoftware/vex/releases/latest/download/vex-agent_linux_amd64.tar.gz | tar xz
sudo mv vex-agent /usr/local/bin/

Windows (guest VM)

Download the appropriate archive for your architecture:

Extract and place vex-agent.exe somewhere on your PATH .

macOS (guest VM)

Install the package matching the guest architecture:

VERSION=1.2.3
curl -fLO "https://github.com/JimberSoftware/vex/releases/download/v${VERSION}/vex-agent_${VERSION}_amd64.pkg"
sudo installer -pkg "vex-agent_${VERSION}_amd64.pkg" -target /

The package installs /usr/local/bin/vex-agent and the io.jimber.vex-agent system LaunchDaemon. The daemon starts during boot, before the login screen, and is kept running by launchd.

Verify the service without logging in to the desktop:

sudo launchctl print system/io.jimber.vex-agent

Verify

vex --version
vex-agent --version
vexd --version

Proxmox VE setup

Proxmox VMs need a vsock device before vex can communicate with the guest agent.

  1. Stop the VM (or template).
  2. SSH into the Proxmox node and edit the VM config:
nano /etc/pve/qemu-server/<VMID>.conf
  1. Add the following line:
args: -device vhost-vsock-pci,guest-cid=<CID>

Replace <CID> with a unique number ≥ 3 for each VM (e.g. use VMID ).

  1. Start the VM.

If the VM already has an args: line, append the vsock device to it:

args: <existing args> -device vhost-vsock-pci,guest-cid=<CID>

VMs cloned from a template inherit the vsock device, but each clone must have a unique CID so make sure to update the args: line for each clone.

vex-agent

Guest-side agent that listens for incoming vsock connections.

Build

go build ./cmd/vex-agent/

Run

vex-agent [--cid <uint32>] [--port <uint32>]
FlagDefaultDescription
--port1024vsock port to listen on
--cid4294967295Context ID to bind ( 4294967295 = VMADDR_CID_ANY , binds all CIDs)

Local loopback testing (Linux)

sudo modprobe vsock_loopback
vex-agent --cid 1 --port 1024

In a second terminal:

socat - VSOCK-CONNECT:1:1024

Shut down with Ctrl+C .

About

Execute commands in guest VMs over vsock

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages