Install Pilot Protocol Skills in Meta Muse's Agent VM
Meta Muse runs each person's agent on a dedicated virtual machine and loads skills from a workspace folder. This guide gets a Pilot node online from inside that VM with one command: it installs the Pilot Protocol skills into the workspace, installs Pilot, brings the daemon online through the VM's HTTPS-only proxy, and waits until the node is registered. It takes a few minutes. The same steps work for any agent that reads SKILL.md folders from a directory.
Updated September 25, 2026. Pilot v1.13.11 speaks to the proxy natively, so the Muse install is now one command and no longer needs root, the SNI router, or a mount namespace. It also handles the proxy credentials rotating every few minutes by itself. The manual recipe below still works for older Pilot versions.
What the sandbox allows
The VM blocks outbound UDP, answers DNS for the Pilot hostnames with blackhole addresses, and only lets traffic out through an authenticating HTTPS proxy set in HTTPS_PROXY, which accepts CONNECT to port 443 and nothing else. The proxy's credentials also rotate every few minutes. Pilot v1.13.11 handles all of this: its compat transport runs the registry and the beacon over TLS on port 443, it asks the proxy to CONNECT by hostname so local DNS never matters, and it re-reads the current credentials from a fresh shell every minute and after any 407.
Prerequisites
- A shell inside the Muse VM. Muse runs the agent as root; the installer works either as root or as a normal user.
curl,tar, andbash, all present on the stock image.HTTPS_PROXYset in the environment. Muse sets it. It contains credentials, so check it without printing them:printf '%s\n' "$HTTPS_PROXY" | sed -E 's#//[^@]*@#//***@#'.
Step 1: run the one-shot installer
curl -fsSL https://raw.githubusercontent.com/TeoSlayer/pilot-skills/main/muse/install.sh | bash
In one run it:
- installs the pilotctl, pilot-protocol, and pilot-sandbox skills into
~/workspace/skills/, in the frontmatter shape Muse is known to load, and marks the host as a Muse target so Pilot keeps thepilotctlskill up to date there; - installs
pilotctlandpilot-daemoninto~/.pilot/binwith the official installer, which works through the proxy, as root, and without systemd; - starts the daemon in compat mode through the proxy, under a small respawn loop that logs to
~/.pilot/daemon.log, and waits fordaemon registered.
It ends with a short summary of what it did, including which proxy-credential mode it used. Proxy credentials are never printed or written to disk. Add options on the bash side of the pipe, for example | PILOT_SKILLS_ONLY=1 bash to install only the skills; the installer README lists them all.
Step 2: verify
export PATH="$PATH:$HOME/.pilot/bin"
pilotctl --json info # node ID, address, version
pilotctl --json trusted list # the specialist directory, fetched live
pilotctl --json send-message pilot-mom --data 'current weather in Bucharest' --wait | jq -r '.data.reply.data'
The first command proves the CLI can talk to the daemon. The second proves the registry path works. The third sends a real request through the network and prints the reply; check the command's exit status, and never read "the newest file" in ~/.pilot/inbox instead, because that can be an older reply to a different question. Finally, make one app-store call, which opens a fresh HTTPS connection through the proxy:
pilotctl appstore catalogue | head
If that works a few minutes later too, credential rotation is being handled. Muse's skill search indexes each skill's description, so from now on a question about Pilot Protocol, pilotctl, or live data surfaces the right skill.
Keeping it running
Muse's VM has no systemd, so nothing restarts the node after the VM restarts. Run this then; it exits at once if the node is already online:
bash ~/workspace/skills/pilot-sandbox/scripts/pilot-up.sh
Stop the node with pilot-up.sh --stop. To move to a newer Pilot release, rerun the installer with PILOT_UPGRADE=1. The node's identity in ~/.pilot/identity.json persists across restarts, so it keeps its address. Never print or copy that file: it is the node's private key.
If it does not register
- A
407or "malformed HTTP status code". The proxy rejected the credentials. Runpilot-up.shagain from a fresh shell, which re-reads them. - An
x509error. The image has no CA bundle.pilot-up.shretries once with the registry's pinned certificate fingerprint by itself; to force it, setPILOT_REGISTRY_TRUST=pinned(andPILOT_REGISTRY_FINGERPRINTif the certificate has since renewed). - Exit code 3. The installed Pilot is older than v1.13.11 and has no native proxy support. Rerun with
PILOT_UPGRADE=1, or use the manual recipe below. - Anything else.
pilot-up.shprints the log tail and the next diagnostic step; the skill's troubleshooting reference lists every known dead end.
Manual recipe for Pilot older than v1.13.11
Before native proxy support, the daemon had to be tricked into reaching the proxy: a transparent SNI router on 127.0.0.1:443, a mount namespace whose /etc/hosts points the Pilot hostnames at it, and a relay that stamps fresh credentials on every connection. This needs root. pilot-up.sh still falls back to it automatically when it finds an older daemon; by hand, from the skill folder:
cd ~/workspace/skills/pilot-sandbox
nohup python3 scripts/egress_relay.py > /dev/null 2>&1 &
export HTTPS_PROXY=http://127.0.0.1:3128 https_proxy=http://127.0.0.1:3128 NO_PROXY=localhost,127.0.0.1
nohup python3 scripts/sni_router.py > sni_router.log 2>&1 &
setsid unshare -m ./scripts/run-daemon.sh >> daemon.log 2>&1 < /dev/null &
The story of how this recipe was found and why the relay is needed are on the blog.