For VMs which can only make outbound connections you can still dial out to a WebSocket (eg. for the Claude mobile app).
Running server.py on your machine (it's the WS endpoint taking in input) and agent.py on the VM allows you to get a shell into the VM.
Your laptop:
TOKEN=$(openssl rand -hex 16); echo "$TOKEN"
uv run server.py --port 8765 --token "$TOKEN"
ngrok http 8765On the VM:
uv run agent.py wss://XXXX.ngrok-free.app --token <TOKEN>The moment it connects, your server.py terminal is a shell on the VM.
Quit locally with Ctrl-C.