ifURI examples
← all examples

32 — drive a NAT'd node from natural language, through the relay

The capstone of the mesh story: a host turns natural language into a URI flow and runs it on a node that has no inbound port — entirely through the mesh.urirun.com relay.

urirun host ask "<NL>"
   │  discover    GET /routes on the proxy  ── auto from the relay (bridge published them)
   │  plan        NL -> URI flow            ── heuristic (--no-llm) or an LLM
   │  execute     each step: serviceMap -> proxy /run -> relay -> node
   ▼
node (behind NAT)  runs it under its own --allow, returns the envelope

Both sides only make outbound HTTP to the relay; the host never reaches the node directly — discovery *and* execution ride the relay.

Run

./run.sh

With a real model (key + LLM_MODEL from examples/.env):

USE_LLM=1 ./run.sh     # plan with the LLM instead of the heuristic
== 4) ... [plan: LLM (openrouter/google/gemini-3.1-flash-image-preview)] ==
  planner:    {"fallback":false,"provider":"litellm"}
  flow steps: ["env://office/runtime/query/health","shell://office/command/date"]
  timeline:   [{...,"ok":true},{...,"ok":true}]
PASS

(litellm 1.89.x segfaults in an atexit cleanup *after* returning the result, so the LLM run sets PYTHONUNBUFFERED=1 to flush host ask's JSON before that crash and strips litellm's Provider List stdout banner — the plan is still produced.)

run.sh stands up the whole chain on localhost (the relay/proxy stand in for the internet) and drives it with urirun host ask --no-llm by default, so it is deterministic and needs no API key:

== 4) NL -> urirun host ask -> plan -> execute, all over the relay ==
  flow steps: ["env://office/runtime/query/health","shell://office/command/date"]
  timeline:   [{"uri":"env://office/runtime/query/health","ok":true},
               {"uri":"shell://office/command/date","ok":true}]
PASS: drove a NAT'd node from natural language end-to-end through the relay

The real-world version

On the node (e.g. 192.168.188.201, SSH closed, behind NAT) — bridge it once:

MESH_RELAY=https://mesh.urirun.com MESH_NODE=lenovo MESH_TOKEN=$SECRET \
  LOCAL_NODE=http://127.0.0.1:8765 ../../mesh-urirun-com/clients/mesh-node.sh

On your host — proxy + a mesh config that points the node at the proxy:

MESH_RELAY=https://mesh.urirun.com MESH_TOKEN=$SECRET \
  python3 ../../mesh-urirun-com/clients/mesh-proxy.py --node lenovo --port 8090 &   # routes auto-discovered
cat > .urirun/mesh.json <<'JSON'
{"name":"relay-host","nodes":[{"name":"lenovo","url":"http://127.0.0.1:8090"}]}
JSON

urirun host ask --node lenovo "list the top processes and read the screen" --execute
# or with a real model: drop --no-llm and set LLM_MODEL / OPENROUTER_API_KEY (see examples/.env)

Why it works (and the pieces)

relay at registration; the proxy serves them as its own /routes, so urirun host builds the action space without touching the node.

serviceMap; with the node's URL pointed at the proxy, every step's /run enqueues on the relay, the node's bridge runs it locally (its --allow still gates), and the result comes back.

Token-free, port-free, RDP-free remote control — driven by natural language.

See also

Example 33 builds the richer half: six office tasks (email, browser, files, calendar, windows…) as ≥10-step flows an LLM plans over an MCP tool surface, each verified against the resulting system state. Those same office URIs run on a remote NAT'd node through this relay.

Files

.gitignoreMakefileREADME.mdrun.sh

View on GitHub →