VM0 Computer Connector
Access the user's local filesystem from a VM0 sandbox over a secure WebDAV tunnel established by the VM0 Computer Connector.
When to Use
Use this skill when you need to:
- List files and directories on the user's local machine
- Read files from the user's computer into the sandbox
- Write or update files on the user's local machine
- Transfer outputs back to the user's local filesystem
How to Use
Setup
Note on Proxy Persistence: VM0 sandboxes are stateless environments. The proxy process and
/tmp/proxy.mjsfile will be cleared between sessions. This is expected behavior - you'll need to reinstallwsand recreate the proxy each time you start a new sandbox session.
Write the proxy script to /tmp/proxy.mjs:
import { WebSocket, WebSocketServer } from "ws";
import http from "http";
import https from "https";
const TOKEN = process.env.COMPUTER_CONNECTOR_BRIDGE_TOKEN;
const DOMAIN = process.env.COMPUTER_CONNECTOR_DOMAIN;
// Chrome CDP WebSocket proxy: ws://127.0.0.1:9222 → wss://chrome.{DOMAIN}
const wss = new WebSocketServer({ host: "127.0.0.1", port: 9222 });
wss.on("connection", (local) => {
const remote = new WebSocket(`wss://chrome.${DOMAIN}`, {
headers: { "x-vm0-token": TOKEN },
});
local.on("message", (msg) => remote.send(msg));
remote.on("message", (msg) => local.send(msg));
local.on("close", () => remote.close());
remote.on("close", () => local.close());
});
// WebDAV HTTP proxy: http://127.0.0.1:8080 → https://webdav.{DOMAIN}
http.createServer((req, res) => {
const upstream = https.request(
`https://webdav.${DOMAIN}${req.url}`,
{ method: req.method, headers: { ...req.headers, "x-vm0-token": TOKEN, host: `webdav.${DOMAIN}` } },
(proxyRes) => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res); }
);
req.pipe(upstream);
}).listen(8080, "127.0.0.1");
console.log("WebDAV proxy: http://127.0.0.1:8080");
console.log("CDP proxy: ws://127.0.0.1:9222");
Run
cd /tmp && npm install ws && node /tmp/proxy.mjs &
The proxy runs in the background. Tools can now connect to http://127.0.0.1:8080 (WebDAV) and ws://127.0.0.1:9222 (Chrome CDP) without any additional headers.
1. List Files in a Directory
Use PROPFIND to list the contents of a directory (depth 1):
curl -s -X PROPFIND "http://127.0.0.1:8080"
List a subdirectory:
curl -s -X PROPFIND "http://127.0.0.1:8080/reports/" --header "Depth: 1"
2. Download a File from the Local Machine
curl -s -o /tmp/myfile.pdf "http://127.0.0.1:8080/myfile.pdf"
Read a text file directly:
curl -s "http://127.0.0.1:8080/notes.txt"
3. Upload a File to the Local Machine
Write a local sandbox file to remote:
curl -s -X PUT "http://127.0.0.1:8080/output-report.txt" --header "Content-Type: text/plain" --data-binary @/home/user/output-report.txt
Upload from stdin (inline content):
curl -s -X PUT "http://127.0.0.1:8080/result.json" --header "Content-Type: application/json" -d '{"status": "done"}'
4. Delete a File
curl -s -X DELETE "http://127.0.0.1:8080/old-file.txt"
5. Create a Directory
curl -s -X MKCOL "http://127.0.0.1:8080/new-folder/"
6. Move (Rename) a File
curl -s -X MOVE "http://127.0.0.1:8080/old-name.txt" --header "Destination: http://127.0.0.1:8080/new-name.txt"
Move to a subdirectory:
curl -s -X MOVE "http://127.0.0.1:8080/report.pdf" --header "Destination: http://127.0.0.1:8080/archive/report.pdf"
7. Search File Contents
WebDAV does not support full-text search natively. Use PROPFIND with Depth: infinity to list all files recursively, then download and search:
# List all files recursively
curl -s -X PROPFIND "http://127.0.0.1:8080/" --header "Depth: infinity" | grep -o '<D:href>[^<]*</D:href>' | sed 's/<[^>]*>//g'
Search for a keyword across all text files:
for f in $(curl -s -X PROPFIND "http://127.0.0.1:8080/" --header "Depth: infinity" | grep -o '<D:href>[^<]*</D:href>' | sed 's/<[^>]*>//g' | grep '\.txt$'); do
content=$(curl -s "http://127.0.0.1:8080${f}")
echo "$content" | grep -q "keyword" && echo "Found in: $f"
done
Troubleshooting
SSL Certificate Error (ERR_TLS_CERT_ALTNAME_INVALID)
Issue: The first connection attempt may fail with ERR_TLS_CERT_ALTNAME_INVALID or similar SSL certificate errors.
Cause: The ngrok tunnel needs a few minutes to provision and propagate SSL certificates after the Computer Connector starts.
Solution:
- Wait 2-3 minutes after starting the Computer Connector for SSL certificates to be fully provisioned
- The proxy will automatically work once certificates are ready - no code changes needed
- Test with a simple curl command:
curl -s "http://127.0.0.1:8080/"
Note: Do NOT add rejectUnauthorized: false to the proxy code as a workaround. This weakens security and is unnecessary - simply wait for proper certificate provisioning.