From 154479eb31b13e3b7180e67c13b39d733191cbc1 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 16:53:57 +0200 Subject: [PATCH 01/17] docs: propose Iroh Gateway transport RFC --- rfcs/0009-iroh-gateway-transport.md | 175 ++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 rfcs/0009-iroh-gateway-transport.md diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md new file mode 100644 index 00000000..6f8d419f --- /dev/null +++ b/rfcs/0009-iroh-gateway-transport.md @@ -0,0 +1,175 @@ +--- +title: Iroh Gateway transport +authors: + - Benjamin Jesuiter +created: 2026-06-20 +last_updated: 2026-06-20 +status: draft +issue: +rfc_pr: +--- + +# Proposal: Iroh Gateway transport + +## Summary + +Add Iroh as an optional OpenClaw Gateway transport so clients can discover and +connect to a Gateway without requiring a VPN such as Tailscale. The first version +should coexist with the existing Gateway connection options and use Iroh endpoint +identity, address lookup, NAT traversal, and relay fallback while preserving +OpenClaw's existing Gateway authorization model. + +## Motivation + +OpenClaw currently relies on existing reachable Gateway URLs, remote URLs, +Tailscale Serve/Funnel, or LAN/custom bind addresses during pairing. Tailscale is +a strong option for desktop and trusted-network workflows, but it is a high-friction +dependency for mobile clients because users need to install and configure a VPN. + +One concrete example is mobile app testing against a local Gateway. A developer +may have an OpenClaw Gateway bound to localhost only. To test from an iPhone, +they would need to open the Gateway port and then either forward it through a VPN +such as NetBird or expose it through a reverse proxy. That feels more complex and +less secure than directly pairing the phone with the Gateway over an +application-level Iroh connection. + +Iroh v1 provides a stable wire protocol and supported APIs for Rust, Python, +Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and native +mobile bindings for Swift and Kotlin. This makes it a plausible transport layer +for OpenClaw clients that need to connect to a user-owned Gateway through NATs +without asking users to set up a VPN. + +## Goals + +- Provide an optional Gateway transport that works without requiring Tailscale or + another VPN. +- Let clients pair with a Gateway using an Iroh ticket or endpoint identity. +- Support reconnecting through a stable Iroh `EndpointId` rather than relying on + stale direct-address tickets. +- Preserve OpenClaw Gateway authentication, authorization, and device-pairing + semantics. +- Make the user-facing configuration describe product behavior, such as + `relay: "public"`, instead of exposing Iroh implementation terms such as `n0`. +- Keep Tailscale and existing Gateway URL discovery paths available. +- Make the first implementation small enough to validate with mobile clients + first before committing to Iroh as a default transport. +- Leave room for a browser-based frontend to connect to the Iroh endpoint if the + Iroh WASM implementation proves suitable, so contributors do not need the full + OpenClaw app development environment to try the flow. + +## Non-Goals + +- Replacing Tailscale as a supported Gateway connection path. +- Treating Iroh endpoint identity as sufficient application authorization. +- Requiring all clients to implement Iroh before existing Gateway transports keep + working. +- Designing a fully self-hosted relay service as part of the first version. +- Exposing public unauthenticated Gateway access. + +## Proposal + +Add an experimental Iroh Gateway transport behind explicit configuration: + +```jsonc +{ + "gateway": { + "iroh": { + "mode": "on", + "relay": "public", + "secretKeyPath": "~/.openclaw/iroh-gateway.key" + } + } +} +``` + +`gateway.iroh.mode` controls whether the Gateway starts an Iroh endpoint. The +initial allowed values should be `"off"` and `"on"`. + +`gateway.iroh.relay` controls relay behavior. The first supported value should be +`"public"`, which maps to Iroh's default n0 public relay and address-discovery +infrastructure. Future values may include `"disabled"` or a custom relay map for +self-hosted deployments. + +`gateway.iroh.secretKeyPath` points to a persisted Iroh secret key for the +Gateway. The Gateway should create this key on first use and reuse it so the +Gateway keeps a stable Iroh `EndpointId` across restarts. + +When enabled, the Gateway should bind an Iroh endpoint with an OpenClaw-specific +ALPN such as `openclaw-gateway-v1`. The Gateway should publish Iroh pairing data +alongside the existing setup-code payload. The pairing payload may include: + +- the Gateway Iroh `EndpointId` +- an `EndpointTicket` for QR/bootstrap pairing +- relay mode metadata suitable for UI display + +Long-term reconnect should store the Gateway `EndpointId` and rely on Iroh +address lookup. Tickets are useful for bootstrap pairing, but they may contain +direct IP address information and can become stale. + +The RFC process should decide between two transport designs before +implementation: + +1. Native Gateway protocol over Iroh QUIC bidirectional streams. + - This is the preferred long-term design. + - It avoids exposing a local HTTP/WebSocket server through a bridge. + - It requires clients to implement an Iroh transport for the Gateway protocol. +2. Iroh-to-localhost bridge inside the Gateway process. + - This may be faster to prototype. + - Incoming Iroh streams proxy to `127.0.0.1:`. + - It carries more proxy, WebSocket, and security complexity. + +The initial release should be experimental and optimized for mobile pairing and +connectivity validation. A browser-based frontend may also be part of the +experiment if Iroh's WASM implementation can connect to the same Gateway endpoint +with acceptable packaging, browser compatibility, and security constraints. This +would make the prototype easier for reviewers and contributors who are not set +up to build the native OpenClaw app. + +Iroh support must be audited as public/remote Gateway exposure. The Gateway must +not allow Iroh transport with unauthenticated Gateway mode. Pairing should keep +using OpenClaw authorization, tokens, passwords, device records, or equivalent +application-level controls. After pairing, OpenClaw should consider binding +client records to Iroh peer `EndpointId`s or requiring a bootstrap token before a +new peer is accepted. + +The Gateway should avoid logging full Iroh tickets because tickets may include +direct IP addresses. Configuration audit warnings should explain that public +relay mode uses public n0 infrastructure for relay and discovery fallback while +traffic remains encrypted end-to-end by Iroh. + +## Rationale + +Iroh is a good fit for the Gateway problem because it gives OpenClaw stable +public-key endpoint identities, QUIC streams, NAT traversal, and relay fallback +without asking users to configure a VPN. The v1 release and official Node, +Swift, and Kotlin APIs make it realistic for the Gateway and mobile clients. + +Keeping Iroh optional reduces risk. Tailscale remains mature, user-controlled, +and already integrated into OpenClaw's connection flow. Iroh introduces new +operational questions around public relay dependency, address discovery, +packaging native bindings, browser/WASM viability, and mobile client +implementation. Treating it as an experimental transport lets OpenClaw learn from +real pairing and reconnect flows without disrupting existing users. + +The user-facing `relay: "public"` wording is preferred over `relayMode: "n0"` +because users care that OpenClaw is using public relay infrastructure, not the +internal provider name. The implementation can still map this to Iroh's n0 +preset or equivalent API. + +Native Gateway protocol over Iroh streams is cleaner than a localhost bridge, +but the bridge may be useful for a short spike. This RFC intentionally leaves the +native-streams-versus-bridge decision unresolved so maintainers can decide it +during review with more implementation evidence. + +## Unresolved questions + +- Should the first implementation use native Gateway protocol framing over Iroh + streams, or an Iroh-to-localhost bridge? +- What exact fields should the setup-code payload expose for Iroh pairing? +- Should paired client records store and enforce client Iroh `EndpointId`s? +- What should the final relay configuration shape be for disabled relay or + self-hosted relay deployments? +- Should the first supported client be native mobile only, or should the RFC also + require a browser frontend using Iroh WASM for easier review and contribution? +- How should OpenClaw present public relay dependency and metadata implications + in setup UI and security audits? From 2c98e365dac544d0e86b05997fd6bd699b1cd49b Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 20:56:52 +0200 Subject: [PATCH 02/17] docs: clarify Iroh transport RFC --- rfcs/0009-iroh-gateway-transport.md | 38 ++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 6f8d419f..36894fba 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -24,28 +24,32 @@ OpenClaw's existing Gateway authorization model. OpenClaw currently relies on existing reachable Gateway URLs, remote URLs, Tailscale Serve/Funnel, or LAN/custom bind addresses during pairing. Tailscale is a strong option for desktop and trusted-network workflows, but it is a high-friction -dependency for mobile clients because users need to install and configure a VPN. +dependency for mobile clients because users need to install and configure a VPN and, most importantly, keep it running to be able to reach the gateway from the phone. This might increase battery draw and greatly reduces friction for low-bandwith, high-latency networks -One concrete example is mobile app testing against a local Gateway. A developer -may have an OpenClaw Gateway bound to localhost only. To test from an iPhone, -they would need to open the Gateway port and then either forward it through a VPN -such as NetBird or expose it through a reverse proxy. That feels more complex and -less secure than directly pairing the phone with the Gateway over an +One concrete example is mobile app testing (or production usage, too) against a local Gateway. A developer may have an OpenClaw Gateway bound to localhost only. To test from an iPhone, +they would need to open the Gateway port and then either forward it through a VPN such as NetBird or expose it through a reverse proxy. That feels more complex and less secure than directly pairing the phone with the Gateway over an application-level Iroh connection. Iroh v1 provides a stable wire protocol and supported APIs for Rust, Python, -Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and native -mobile bindings for Swift and Kotlin. This makes it a plausible transport layer -for OpenClaw clients that need to connect to a user-owned Gateway through NATs -without asking users to set up a VPN. +Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and native mobile bindings for Swift and Kotlin. This makes it a plausible transport layer for OpenClaw clients that need to connect to a user-owned Gateway through NATs without asking users to set up a VPN. Also, this might be more performant than tunneling https trafic over a VPN, since it sets up on the transport protocol layer (QUIC) directly, including encrypting the connection + +## Glossary + +- **Iroh ticket**: A shareable connection bootstrap value. For OpenClaw, it is + similar to a pairing code, but it can carry more network data, such as the + Gateway's Iroh endpoint identity, relay hints, and direct IP/port addresses + when they are available. +- **Iroh `EndpointId`**: The stable public identity of an Iroh endpoint. It is + derived from the endpoint's secret key. If the Gateway persists that secret key + across restarts, clients can remember the Gateway's `EndpointId` and use Iroh + discovery to find its current address instead of depending on old ticket data. ## Goals -- Provide an optional Gateway transport that works without requiring Tailscale or - another VPN. +- Provide an optional Gateway transport that works without requiring Tailscale or another VPN. - Let clients pair with a Gateway using an Iroh ticket or endpoint identity. -- Support reconnecting through a stable Iroh `EndpointId` rather than relying on - stale direct-address tickets. +- Allow paired clients to reconnect after Gateway network changes without + requiring a new QR code or setup flow. - Preserve OpenClaw Gateway authentication, authorization, and device-pairing semantics. - Make the user-facing configuration describe product behavior, such as @@ -161,6 +165,12 @@ but the bridge may be useful for a short spike. This RFC intentionally leaves th native-streams-versus-bridge decision unresolved so maintainers can decide it during review with more implementation evidence. +## Future questions + +- Do we want to run OpenClaw relay servers to make this easier for users? The + suggested answer for now is to decide after measuring the impact on the user + flow when using Iroh's existing relay and discovery infrastructure. + ## Unresolved questions - Should the first implementation use native Gateway protocol framing over Iroh From 0603959d42fd3d13bea43c1077a4fb8cba0738ce Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:09:05 +0200 Subject: [PATCH 03/17] docs: model Iroh as gateway bind option --- rfcs/0009-iroh-gateway-transport.md | 85 ++++++++++++++++++----------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 36894fba..7f77787b 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -52,8 +52,9 @@ Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and nati requiring a new QR code or setup flow. - Preserve OpenClaw Gateway authentication, authorization, and device-pairing semantics. -- Make the user-facing configuration describe product behavior, such as - `relay: "public"`, instead of exposing Iroh implementation terms such as `n0`. +- Add Iroh as a Gateway bind option because it provides a client connection + entrypoint, while keeping Iroh-specific endpoint configuration aligned with + normal Iroh configuration. - Keep Tailscale and existing Gateway URL discovery paths available. - Make the first implementation small enough to validate with mobile clients first before committing to Iroh as a default transport. @@ -77,26 +78,45 @@ Add an experimental Iroh Gateway transport behind explicit configuration: ```jsonc { "gateway": { + "bind": "iroh", "iroh": { - "mode": "on", - "relay": "public", - "secretKeyPath": "~/.openclaw/iroh-gateway.key" + "secretKeyPath": "~/.openclaw/iroh-gateway.key", + "endpoint": { + "relayMode": "default" + } } } } ``` -`gateway.iroh.mode` controls whether the Gateway starts an Iroh endpoint. The -initial allowed values should be `"off"` and `"on"`. - -`gateway.iroh.relay` controls relay behavior. The first supported value should be -`"public"`, which maps to Iroh's default n0 public relay and address-discovery -infrastructure. Future values may include `"disabled"` or a custom relay map for -self-hosted deployments. - -`gateway.iroh.secretKeyPath` points to a persisted Iroh secret key for the -Gateway. The Gateway should create this key on first use and reuse it so the -Gateway keeps a stable Iroh `EndpointId` across restarts. +`gateway.bind` should gain an `"iroh"` option because Iroh provides a Gateway +entrypoint in the same broad family as the existing bind policies. Today +`gateway.bind` describes how clients can reach the local Gateway: `"loopback"` +for localhost-only, `"lan"` for local-network exposure, `"tailnet"` for a +Tailscale address, and `"custom"` for an explicit host. `"iroh"` would mean the +Gateway remains locally owned but publishes an Iroh endpoint for client +connections. + +The shape under `gateway.iroh.endpoint` should be a 1:1 representation of normal +Iroh endpoint configuration wherever possible. OpenClaw should not invent +product-level config names that map onto Iroh concepts. If OpenClaw needs +additional values for Gateway lifecycle, persistence, or UI, those values should +live next to `endpoint` under `gateway.iroh` and be merged with the Iroh endpoint +config when constructing the endpoint. + +`gateway.iroh.endpoint.relayMode` is an example of this approach if that is the +native Iroh configuration name. The first supported relay mode should represent +Iroh's default public relay and address-discovery infrastructure. OpenClaw UI and +help text should describe this as public relay infrastructure rather than hiding +or renaming the native Iroh field in configuration. Future values may include a custom relay map for self-hosted or OpenClaw-operated +relay deployments if those match Iroh's configuration surface. + +`gateway.iroh.secretKeyPath` is an OpenClaw-specific value for persisted Gateway +identity unless Iroh provides an equivalent config field. Its name follows the +existing Gateway config style for filesystem-backed credentials such as +`gateway.tls.certPath` and `gateway.tls.keyPath`. The Gateway should create this +key on first use and reuse it so the Gateway keeps a stable Iroh `EndpointId` +across restarts. When enabled, the Gateway should bind an Iroh endpoint with an OpenClaw-specific ALPN such as `openclaw-gateway-v1`. The Gateway should publish Iroh pairing data @@ -124,17 +144,13 @@ implementation: The initial release should be experimental and optimized for mobile pairing and connectivity validation. A browser-based frontend may also be part of the -experiment if Iroh's WASM implementation can connect to the same Gateway endpoint -with acceptable packaging, browser compatibility, and security constraints. This -would make the prototype easier for reviewers and contributors who are not set -up to build the native OpenClaw app. +experiment if Iroh's WASM implementation can connect to the same Gateway endpoint with acceptable packaging, browser compatibility, and security constraints. This would make the prototype easier for reviewers and contributors who are not set up to build the native OpenClaw app. Iroh support must be audited as public/remote Gateway exposure. The Gateway must not allow Iroh transport with unauthenticated Gateway mode. Pairing should keep using OpenClaw authorization, tokens, passwords, device records, or equivalent application-level controls. After pairing, OpenClaw should consider binding -client records to Iroh peer `EndpointId`s or requiring a bootstrap token before a -new peer is accepted. +client records to Iroh peer `EndpointId`s or requiring a bootstrap token before a new peer is accepted. The Gateway should avoid logging full Iroh tickets because tickets may include direct IP addresses. Configuration audit warnings should explain that public @@ -152,13 +168,19 @@ Keeping Iroh optional reduces risk. Tailscale remains mature, user-controlled, and already integrated into OpenClaw's connection flow. Iroh introduces new operational questions around public relay dependency, address discovery, packaging native bindings, browser/WASM viability, and mobile client -implementation. Treating it as an experimental transport lets OpenClaw learn from -real pairing and reconnect flows without disrupting existing users. - -The user-facing `relay: "public"` wording is preferred over `relayMode: "n0"` -because users care that OpenClaw is using public relay infrastructure, not the -internal provider name. The implementation can still map this to Iroh's n0 -preset or equivalent API. +implementation. Treating it as an experimental transport lets OpenClaw learn from real pairing and reconnect flows without disrupting existing users. + +Modeling Iroh as `gateway.bind: "iroh"` fits the existing Gateway mental model +better than adding a separate `gateway.iroh.enabled` or `gateway.iroh.mode` flag: +it selects the entrypoint clients use to reach the local Gateway. The low-level +endpoint configuration should still mirror Iroh's native configuration surface so +OpenClaw does not introduce a product-level mapping layer that must be maintained +separately from Iroh. OpenClaw-specific fields should follow existing Gateway +config conventions, such as `*Path` for filesystem-backed material and nested +objects for transport-owned config. When OpenClaw needs extra Gateway-specific +values, it can merge those values with the Iroh config at endpoint construction +time. UI and help text can still explain that the default relay mode uses public +relay and discovery infrastructure. Native Gateway protocol over Iroh streams is cleaner than a localhost bridge, but the bridge may be useful for a short spike. This RFC intentionally leaves the @@ -177,8 +199,9 @@ during review with more implementation evidence. streams, or an Iroh-to-localhost bridge? - What exact fields should the setup-code payload expose for Iroh pairing? - Should paired client records store and enforce client Iroh `EndpointId`s? -- What should the final relay configuration shape be for disabled relay or - self-hosted relay deployments? +- What exact Iroh endpoint configuration fields should OpenClaw expose 1:1 under + `gateway.iroh.endpoint` for self-hosted or OpenClaw-operated relay + deployments? - Should the first supported client be native mobile only, or should the RFC also require a browser frontend using Iroh WASM for easier review and contribution? - How should OpenClaw present public relay dependency and metadata implications From c3eecd915622c40670585e2413211ab7b9544180 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:13:21 +0200 Subject: [PATCH 04/17] docs: tighten Iroh Gateway proposal --- rfcs/0009-iroh-gateway-transport.md | 143 ++++++++++++---------------- 1 file changed, 61 insertions(+), 82 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 7f77787b..d0f5a23d 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -14,24 +14,17 @@ rfc_pr: ## Summary Add Iroh as an optional OpenClaw Gateway transport so clients can discover and -connect to a Gateway without requiring a VPN such as Tailscale. The first version -should coexist with the existing Gateway connection options and use Iroh endpoint -identity, address lookup, NAT traversal, and relay fallback while preserving -OpenClaw's existing Gateway authorization model. +connect to a Gateway without requiring a VPN such as Tailscale. The first version should coexist with the existing Gateway connection options and use Iroh endpoint identity, address lookup, NAT traversal, and relay fallback while preserving OpenClaw's existing Gateway authorization model. ## Motivation OpenClaw currently relies on existing reachable Gateway URLs, remote URLs, -Tailscale Serve/Funnel, or LAN/custom bind addresses during pairing. Tailscale is -a strong option for desktop and trusted-network workflows, but it is a high-friction -dependency for mobile clients because users need to install and configure a VPN and, most importantly, keep it running to be able to reach the gateway from the phone. This might increase battery draw and greatly reduces friction for low-bandwith, high-latency networks +Tailscale Serve/Funnel, or LAN/custom bind addresses during pairing. Tailscale is a strong option for desktop and trusted-network workflows, but it is a high-friction dependency for mobile clients because users need to install and configure a VPN and, most importantly, keep it running to be able to reach the gateway from the phone. This might increase battery draw and greatly reduces friction for low-bandwith or high-latency networks. -One concrete example is mobile app testing (or production usage, too) against a local Gateway. A developer may have an OpenClaw Gateway bound to localhost only. To test from an iPhone, -they would need to open the Gateway port and then either forward it through a VPN such as NetBird or expose it through a reverse proxy. That feels more complex and less secure than directly pairing the phone with the Gateway over an -application-level Iroh connection. +One concrete example is mobile app testing (or production usage, too) against a local Gateway. A user may have an OpenClaw Gateway bound to localhost only, especially when only using Telegram as a transport iwth message polling mode. To test from an iPhone, they would need to open the Gateway port and then either forward it through a VPN such as NetBird or expose it through a reverse proxy. That feels more complex and less secure than directly pairing the phone with the Gateway over an application-level Iroh connection. Iroh v1 provides a stable wire protocol and supported APIs for Rust, Python, -Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and native mobile bindings for Swift and Kotlin. This makes it a plausible transport layer for OpenClaw clients that need to connect to a user-owned Gateway through NATs without asking users to set up a VPN. Also, this might be more performant than tunneling https trafic over a VPN, since it sets up on the transport protocol layer (QUIC) directly, including encrypting the connection +Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and native mobile bindings for Swift and Kotlin. This makes it a plausible transport layer for OpenClaw clients that need to connect to a user-owned Gateway through NATs without asking users to set up a VPN. Also, this might be more performant than tunneling https trafic over a VPN, since it sets up on the transport protocol layer (QUIC) directly, including encrypting the connection. ## Glossary @@ -73,7 +66,7 @@ Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and nati ## Proposal -Add an experimental Iroh Gateway transport behind explicit configuration: +Add Iroh as an experimental Gateway bind target: ```jsonc { @@ -81,81 +74,67 @@ Add an experimental Iroh Gateway transport behind explicit configuration: "bind": "iroh", "iroh": { "secretKeyPath": "~/.openclaw/iroh-gateway.key", - "endpoint": { - "relayMode": "default" - } + "endpoint": {} } } } ``` -`gateway.bind` should gain an `"iroh"` option because Iroh provides a Gateway -entrypoint in the same broad family as the existing bind policies. Today -`gateway.bind` describes how clients can reach the local Gateway: `"loopback"` -for localhost-only, `"lan"` for local-network exposure, `"tailnet"` for a -Tailscale address, and `"custom"` for an explicit host. `"iroh"` would mean the -Gateway remains locally owned but publishes an Iroh endpoint for client -connections. - -The shape under `gateway.iroh.endpoint` should be a 1:1 representation of normal -Iroh endpoint configuration wherever possible. OpenClaw should not invent -product-level config names that map onto Iroh concepts. If OpenClaw needs -additional values for Gateway lifecycle, persistence, or UI, those values should -live next to `endpoint` under `gateway.iroh` and be merged with the Iroh endpoint -config when constructing the endpoint. - -`gateway.iroh.endpoint.relayMode` is an example of this approach if that is the -native Iroh configuration name. The first supported relay mode should represent -Iroh's default public relay and address-discovery infrastructure. OpenClaw UI and -help text should describe this as public relay infrastructure rather than hiding -or renaming the native Iroh field in configuration. Future values may include a custom relay map for self-hosted or OpenClaw-operated -relay deployments if those match Iroh's configuration surface. - -`gateway.iroh.secretKeyPath` is an OpenClaw-specific value for persisted Gateway -identity unless Iroh provides an equivalent config field. Its name follows the -existing Gateway config style for filesystem-backed credentials such as -`gateway.tls.certPath` and `gateway.tls.keyPath`. The Gateway should create this -key on first use and reuse it so the Gateway keeps a stable Iroh `EndpointId` -across restarts. - -When enabled, the Gateway should bind an Iroh endpoint with an OpenClaw-specific -ALPN such as `openclaw-gateway-v1`. The Gateway should publish Iroh pairing data -alongside the existing setup-code payload. The pairing payload may include: - -- the Gateway Iroh `EndpointId` -- an `EndpointTicket` for QR/bootstrap pairing -- relay mode metadata suitable for UI display - -Long-term reconnect should store the Gateway `EndpointId` and rely on Iroh -address lookup. Tickets are useful for bootstrap pairing, but they may contain -direct IP address information and can become stale. - -The RFC process should decide between two transport designs before -implementation: - -1. Native Gateway protocol over Iroh QUIC bidirectional streams. - - This is the preferred long-term design. - - It avoids exposing a local HTTP/WebSocket server through a bridge. - - It requires clients to implement an Iroh transport for the Gateway protocol. -2. Iroh-to-localhost bridge inside the Gateway process. - - This may be faster to prototype. - - Incoming Iroh streams proxy to `127.0.0.1:`. - - It carries more proxy, WebSocket, and security complexity. - -The initial release should be experimental and optimized for mobile pairing and -connectivity validation. A browser-based frontend may also be part of the -experiment if Iroh's WASM implementation can connect to the same Gateway endpoint with acceptable packaging, browser compatibility, and security constraints. This would make the prototype easier for reviewers and contributors who are not set up to build the native OpenClaw app. - -Iroh support must be audited as public/remote Gateway exposure. The Gateway must -not allow Iroh transport with unauthenticated Gateway mode. Pairing should keep -using OpenClaw authorization, tokens, passwords, device records, or equivalent -application-level controls. After pairing, OpenClaw should consider binding -client records to Iroh peer `EndpointId`s or requiring a bootstrap token before a new peer is accepted. - -The Gateway should avoid logging full Iroh tickets because tickets may include -direct IP addresses. Configuration audit warnings should explain that public -relay mode uses public n0 infrastructure for relay and discovery fallback while -traffic remains encrypted end-to-end by Iroh. +`gateway.bind: "iroh"` means the local Gateway publishes an Iroh endpoint as its +client connection entrypoint. It belongs with the existing bind policies because +`gateway.bind` already describes how clients reach the local Gateway: +`"loopback"` for localhost-only, `"lan"` for local-network exposure, +`"tailnet"` for a Tailscale address, and `"custom"` for an explicit host. + +`gateway.iroh.endpoint` is the Iroh-owned endpoint configuration. Its shape should +mirror normal Iroh configuration instead of translating through OpenClaw-specific +names. An empty object uses Iroh's default endpoint behavior, including the +default public relay and discovery infrastructure. If the RFC or implementation +needs custom relay maps, relay presets, or other Iroh endpoint options, those +fields should be exposed under `gateway.iroh.endpoint` using Iroh's native names. +OpenClaw UI and help text can explain those native fields in product language. + +`gateway.iroh.secretKeyPath` is an OpenClaw-owned Gateway lifecycle field. The +Gateway should create the secret key on first use and reuse it across restarts so +it keeps a stable Iroh `EndpointId`. Other OpenClaw-owned fields, if needed, +should live beside `endpoint` under `gateway.iroh` and be merged with the Iroh +endpoint config when constructing the endpoint. + +When `gateway.bind` is `"iroh"`, Gateway startup should: + +1. Load or create the persisted Iroh secret key. +2. Construct an Iroh endpoint from `gateway.iroh.endpoint` plus OpenClaw-owned + runtime values such as the secret key and ALPN. +3. Bring the endpoint online with an OpenClaw-specific ALPN such as + `openclaw-gateway-v1`. +4. Publish Iroh pairing data alongside the existing setup-code payload. + +The setup-code payload should include enough Iroh data for bootstrap pairing, +such as the Gateway `EndpointId`, an `EndpointTicket`, and relay/discovery +metadata suitable for UI display. Clients should use tickets for bootstrap +pairing, then store the Gateway `EndpointId` for reconnects. This lets paired +clients reconnect after network changes without requiring a new QR code or setup +flow. + +The initial release should be experimental and mobile-first. A browser-based +frontend may also be part of the experiment if Iroh's WASM implementation can +connect to the same Gateway endpoint with acceptable packaging, browser +compatibility, and security constraints. Existing Tailscale, remote URL, LAN, and +loopback Gateway paths should continue to work. + +The RFC intentionally leaves the Gateway protocol mapping unresolved. The first +implementation must choose between native Gateway protocol framing over Iroh QUIC +bidirectional streams and an Iroh-to-localhost bridge inside the Gateway process. +Native streams are the preferred long-term shape, while a localhost bridge may be +a lower-risk spike if it preserves existing Gateway behavior. + +Iroh support must be treated as public/remote Gateway exposure. The Gateway must +not allow `gateway.bind: "iroh"` with unauthenticated Gateway mode. Pairing must +continue to use OpenClaw authorization, tokens, passwords, device records, or an +equivalent application-level control. After pairing, OpenClaw should consider +binding client records to Iroh peer `EndpointId`s or requiring a bootstrap token +before accepting a new peer. Logs and diagnostics should avoid full Iroh tickets +because tickets may include direct IP addresses. ## Rationale From 5e4128e43ceed95866d9d96d85bf918d458c4abd Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:15:17 +0200 Subject: [PATCH 05/17] docs: clarify Iroh Gateway usability goal --- rfcs/0009-iroh-gateway-transport.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index d0f5a23d..1d1084ec 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -39,6 +39,9 @@ Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and nati ## Goals +- Provide an optional Gateway connection path that is as simple to use as + starting the localhost Gateway and using it with the Telegram provider. + - Provide an optional Gateway transport that works without requiring Tailscale or another VPN. - Let clients pair with a Gateway using an Iroh ticket or endpoint identity. - Allow paired clients to reconnect after Gateway network changes without From 0789e7311b62a5157d323deec2e12b1db1666887 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:15:55 +0200 Subject: [PATCH 06/17] docs: align Iroh RFC with docs validation --- rfcs/0009-iroh-gateway-transport.md | 35 +++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 1d1084ec..ff8794d8 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -19,12 +19,28 @@ connect to a Gateway without requiring a VPN such as Tailscale. The first versio ## Motivation OpenClaw currently relies on existing reachable Gateway URLs, remote URLs, -Tailscale Serve/Funnel, or LAN/custom bind addresses during pairing. Tailscale is a strong option for desktop and trusted-network workflows, but it is a high-friction dependency for mobile clients because users need to install and configure a VPN and, most importantly, keep it running to be able to reach the gateway from the phone. This might increase battery draw and greatly reduces friction for low-bandwith or high-latency networks. - -One concrete example is mobile app testing (or production usage, too) against a local Gateway. A user may have an OpenClaw Gateway bound to localhost only, especially when only using Telegram as a transport iwth message polling mode. To test from an iPhone, they would need to open the Gateway port and then either forward it through a VPN such as NetBird or expose it through a reverse proxy. That feels more complex and less secure than directly pairing the phone with the Gateway over an application-level Iroh connection. +Tailscale Serve/Funnel, or LAN/custom bind addresses during pairing. Tailscale is +a strong option for desktop and trusted-network workflows, but it is a +high-friction dependency for mobile clients because users need to install and +configure a VPN and, most importantly, keep it running to reach the Gateway from +the phone. This may increase battery draw and add friction on low-bandwidth or +high-latency networks. + +One concrete example is mobile app testing, or production usage, against a local +Gateway. A user may have an OpenClaw Gateway bound to localhost only, especially +when using Telegram as a polling transport. To test from an iPhone, they would +need to open the Gateway port and then either forward it through a VPN such as +NetBird or expose it through a reverse proxy. That feels more complex and less +secure than directly pairing the phone with the Gateway over an application-level +Iroh connection. Iroh v1 provides a stable wire protocol and supported APIs for Rust, Python, -Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and native mobile bindings for Swift and Kotlin. This makes it a plausible transport layer for OpenClaw clients that need to connect to a user-owned Gateway through NATs without asking users to set up a VPN. Also, this might be more performant than tunneling https trafic over a VPN, since it sets up on the transport protocol layer (QUIC) directly, including encrypting the connection. +Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and +native mobile bindings for Swift and Kotlin. This makes it a plausible transport +layer for OpenClaw clients that need to connect to a user-owned Gateway through +NATs without asking users to set up a VPN. It may also avoid the overhead of +routing Gateway traffic through a VPN by using encrypted QUIC connections +directly. ## Glossary @@ -122,8 +138,12 @@ flow. The initial release should be experimental and mobile-first. A browser-based frontend may also be part of the experiment if Iroh's WASM implementation can connect to the same Gateway endpoint with acceptable packaging, browser -compatibility, and security constraints. Existing Tailscale, remote URL, LAN, and -loopback Gateway paths should continue to work. +compatibility, and security constraints. The browser path is not required for the +first mobile-first experiment; if included, it must account for Iroh's current +browser limitations, including relay-only browser traffic and the need for an +application-specific WASM wrapper rather than an official browser npm package. +Existing Tailscale, remote URL, LAN, and loopback Gateway paths should continue +to work. The RFC intentionally leaves the Gateway protocol mapping unresolved. The first implementation must choose between native Gateway protocol framing over Iroh QUIC @@ -150,7 +170,8 @@ Keeping Iroh optional reduces risk. Tailscale remains mature, user-controlled, and already integrated into OpenClaw's connection flow. Iroh introduces new operational questions around public relay dependency, address discovery, packaging native bindings, browser/WASM viability, and mobile client -implementation. Treating it as an experimental transport lets OpenClaw learn from real pairing and reconnect flows without disrupting existing users. +implementation. Treating it as an experimental transport lets OpenClaw learn from +real pairing and reconnect flows without disrupting existing users. Modeling Iroh as `gateway.bind: "iroh"` fits the existing Gateway mental model better than adding a separate `gateway.iroh.enabled` or `gateway.iroh.mode` flag: From fdfccca49795b0868a20736d027d3d686e68c656 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:23:19 +0200 Subject: [PATCH 07/17] docs: refine Iroh Gateway RFC goals --- rfcs/0009-iroh-gateway-transport.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index ff8794d8..af005d61 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -55,10 +55,12 @@ directly. ## Goals -- Provide an optional Gateway connection path that is as simple to use as - starting the localhost Gateway and using it with the Telegram provider. - -- Provide an optional Gateway transport that works without requiring Tailscale or another VPN. +- Provide an optional Gateway connection path that is: + - as simple to use as the localhost Gateway with the Telegram channel + - built on open protocols such as QUIC and Iroh's open-source stack + - avoids requiring users to depend on a single VPN provider or closed network + - directly integrated into OpenClaw without requiring the user to set up extra + infrastructure, such as VPNs - Let clients pair with a Gateway using an Iroh ticket or endpoint identity. - Allow paired clients to reconnect after Gateway network changes without requiring a new QR code or setup flow. @@ -68,8 +70,8 @@ directly. entrypoint, while keeping Iroh-specific endpoint configuration aligned with normal Iroh configuration. - Keep Tailscale and existing Gateway URL discovery paths available. -- Make the first implementation small enough to validate with mobile clients - first before committing to Iroh as a default transport. +- Make the first implementation small enough to validate the benefits first + before committing to Iroh as one permanent transport option. - Leave room for a browser-based frontend to connect to the Iroh endpoint if the Iroh WASM implementation proves suitable, so contributors do not need the full OpenClaw app development environment to try the flow. From 22783c3b71216d7732e3b709dd2afa641f88b511 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:34:08 +0200 Subject: [PATCH 08/17] docs: clarify Iroh pairing and secrets --- rfcs/0009-iroh-gateway-transport.md | 32 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index af005d61..2240d2a0 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -61,7 +61,8 @@ directly. - avoids requiring users to depend on a single VPN provider or closed network - directly integrated into OpenClaw without requiring the user to set up extra infrastructure, such as VPNs -- Let clients pair with a Gateway using an Iroh ticket or endpoint identity. +- Let clients bootstrap pairing with a Gateway using an Iroh ticket, then use + the remembered Gateway endpoint identity for reconnects and address lookup. - Allow paired clients to reconnect after Gateway network changes without requiring a new QR code or setup flow. - Preserve OpenClaw Gateway authentication, authorization, and device-pairing @@ -117,9 +118,15 @@ OpenClaw UI and help text can explain those native fields in product language. `gateway.iroh.secretKeyPath` is an OpenClaw-owned Gateway lifecycle field. The Gateway should create the secret key on first use and reuse it across restarts so -it keeps a stable Iroh `EndpointId`. Other OpenClaw-owned fields, if needed, -should live beside `endpoint` under `gateway.iroh` and be merged with the Iroh -endpoint config when constructing the endpoint. +it keeps a stable Iroh `EndpointId`. The default path should live under the +OpenClaw state directory and use the same local-secret file hardening OpenClaw +uses elsewhere: create parent directories with owner-only permissions, write the +key atomically with owner-only file permissions, reject symlink-based key paths, +and fail startup rather than silently regenerating or weakening a key when an +existing key file is unreadable or has unsafe filesystem state. Other +OpenClaw-owned fields, if needed, should live beside `endpoint` under +`gateway.iroh` and be merged with the Iroh endpoint config when constructing the +endpoint. When `gateway.bind` is `"iroh"`, Gateway startup should: @@ -147,11 +154,13 @@ application-specific WASM wrapper rather than an official browser npm package. Existing Tailscale, remote URL, LAN, and loopback Gateway paths should continue to work. -The RFC intentionally leaves the Gateway protocol mapping unresolved. The first -implementation must choose between native Gateway protocol framing over Iroh QUIC -bidirectional streams and an Iroh-to-localhost bridge inside the Gateway process. -Native streams are the preferred long-term shape, while a localhost bridge may be -a lower-risk spike if it preserves existing Gateway behavior. +The RFC intentionally leaves the Gateway protocol mapping for maintainer review. +The maintainers should decide whether the first implementation should use native +Gateway protocol framing over Iroh QUIC bidirectional streams, or an +Iroh-to-localhost bridge inside the Gateway process. Native streams are the +preferred long-term architecture, while a localhost bridge may be the right +lower-effort validation spike if it preserves existing Gateway behavior and is +clearly documented as experimental. Iroh support must be treated as public/remote Gateway exposure. The Gateway must not allow `gateway.bind: "iroh"` with unauthenticated Gateway mode. Pairing must @@ -189,8 +198,9 @@ relay and discovery infrastructure. Native Gateway protocol over Iroh streams is cleaner than a localhost bridge, but the bridge may be useful for a short spike. This RFC intentionally leaves the -native-streams-versus-bridge decision unresolved so maintainers can decide it -during review with more implementation evidence. +native-streams-versus-bridge decision unresolved so maintainers can decide, +during review, whether the project wants the lowest-effort experiment first or a +more direct implementation of the desired long-term architecture. ## Future questions From 0cf0ec51c071b487532ffd204fb844af5efbbb07 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:57:43 +0200 Subject: [PATCH 09/17] docs: concise iroh gateway transport RFC --- rfcs/0009-iroh-gateway-transport.md | 243 ++++++++-------------------- 1 file changed, 68 insertions(+), 175 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 2240d2a0..c8e0dd2e 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -13,82 +13,43 @@ rfc_pr: ## Summary -Add Iroh as an optional OpenClaw Gateway transport so clients can discover and -connect to a Gateway without requiring a VPN such as Tailscale. The first version should coexist with the existing Gateway connection options and use Iroh endpoint identity, address lookup, NAT traversal, and relay fallback while preserving OpenClaw's existing Gateway authorization model. +Add Iroh as an experimental OpenClaw Gateway transport. + +Clients should be able to pair with and reconnect to a Gateway through Iroh endpoint identity, discovery, NAT traversal, and relay fallback, without requiring Tailscale or another VPN. OpenClaw Gateway authorization remains the source of trust. ## Motivation -OpenClaw currently relies on existing reachable Gateway URLs, remote URLs, -Tailscale Serve/Funnel, or LAN/custom bind addresses during pairing. Tailscale is -a strong option for desktop and trusted-network workflows, but it is a -high-friction dependency for mobile clients because users need to install and -configure a VPN and, most importantly, keep it running to reach the Gateway from -the phone. This may increase battery draw and add friction on low-bandwidth or -high-latency networks. - -One concrete example is mobile app testing, or production usage, against a local -Gateway. A user may have an OpenClaw Gateway bound to localhost only, especially -when using Telegram as a polling transport. To test from an iPhone, they would -need to open the Gateway port and then either forward it through a VPN such as -NetBird or expose it through a reverse proxy. That feels more complex and less -secure than directly pairing the phone with the Gateway over an application-level -Iroh connection. - -Iroh v1 provides a stable wire protocol and supported APIs for Rust, Python, -Node.js, Swift, and Kotlin. It exposes a Node package, `@number0/iroh`, and -native mobile bindings for Swift and Kotlin. This makes it a plausible transport -layer for OpenClaw clients that need to connect to a user-owned Gateway through -NATs without asking users to set up a VPN. It may also avoid the overhead of -routing Gateway traffic through a VPN by using encrypted QUIC connections -directly. - -## Glossary - -- **Iroh ticket**: A shareable connection bootstrap value. For OpenClaw, it is - similar to a pairing code, but it can carry more network data, such as the - Gateway's Iroh endpoint identity, relay hints, and direct IP/port addresses - when they are available. -- **Iroh `EndpointId`**: The stable public identity of an Iroh endpoint. It is - derived from the endpoint's secret key. If the Gateway persists that secret key - across restarts, clients can remember the Gateway's `EndpointId` and use Iroh - discovery to find its current address instead of depending on old ticket data. +OpenClaw Nodes currently depend on reachable Gateway URLs, Tailscale Serve/Funnel, or LAN access if the Node is not on localhost. These work, but they add friction. A phone user may need to install a VPN, configure it, and keep it running just to reach a Gateway. Users behind carrier-grade NAT (CGNAT) need complicated DDNS and reverse-proxy setups to publish their OpenClaw Gateway so external OpenClaw Nodes can connect to their home instance. Iroh solves this by exposing the Gateway as an application-level encrypted connection instead. + +Iroh v1 provides a stable wire protocol plus APIs for Node.js, Rust, Python, Swift, and Kotlin. The `@number0/iroh` package and native mobile bindings make it a plausible transport for OpenClaw Gateway access through NATs. + +## Terms + +- Iroh ticket: A shareable bootstrap value with endpoint identity, relay hints, and direct addresses when available. +- Iroh `EndpointId`: A stable public endpoint identity derived from the endpoint secret key. If the Gateway persists that key, clients can remember the `EndpointId` and rediscover the Gateway after network changes. ## Goals -- Provide an optional Gateway connection path that is: - - as simple to use as the localhost Gateway with the Telegram channel - - built on open protocols such as QUIC and Iroh's open-source stack - - avoids requiring users to depend on a single VPN provider or closed network - - directly integrated into OpenClaw without requiring the user to set up extra - infrastructure, such as VPNs -- Let clients bootstrap pairing with a Gateway using an Iroh ticket, then use - the remembered Gateway endpoint identity for reconnects and address lookup. -- Allow paired clients to reconnect after Gateway network changes without - requiring a new QR code or setup flow. -- Preserve OpenClaw Gateway authentication, authorization, and device-pairing - semantics. -- Add Iroh as a Gateway bind option because it provides a client connection - entrypoint, while keeping Iroh-specific endpoint configuration aligned with - normal Iroh configuration. -- Keep Tailscale and existing Gateway URL discovery paths available. -- Make the first implementation small enough to validate the benefits first - before committing to Iroh as one permanent transport option. -- Leave room for a browser-based frontend to connect to the Iroh endpoint if the - Iroh WASM implementation proves suitable, so contributors do not need the full - OpenClaw app development environment to try the flow. - -## Non-Goals - -- Replacing Tailscale as a supported Gateway connection path. -- Treating Iroh endpoint identity as sufficient application authorization. -- Requiring all clients to implement Iroh before existing Gateway transports keep - working. -- Designing a fully self-hosted relay service as part of the first version. -- Exposing public unauthenticated Gateway access. +- Add an optional Gateway connection path, not a replacement for existing paths. +- Let clients pair with an Iroh ticket, then reconnect using the stored Gateway `EndpointId`. +- Preserve OpenClaw authentication, authorization, and device-pairing semantics. +- Add `"iroh"` as a `gateway.bind` option. +- Keep Iroh endpoint configuration under `gateway.iroh.endpoint` using Iroh-native field names. +- Keep the first implementation small and experimental. +- Keep Tailscale, remote URL, LAN, loopback, and custom bind paths working. +- Leave room for browser/WASM support if it proves practical. + +## Non-goals + +- Not replacing Tailscale. +- Not treating Iroh endpoint identity as application authorization. +- Not requiring all clients to support Iroh. +- Not designing self-hosted relays in the first version. +- Not exposing unauthenticated public Gateway access. ## Proposal -Add Iroh as an experimental Gateway bind target: +Add an experimental bind target: ```jsonc { @@ -102,122 +63,54 @@ Add Iroh as an experimental Gateway bind target: } ``` -`gateway.bind: "iroh"` means the local Gateway publishes an Iroh endpoint as its -client connection entrypoint. It belongs with the existing bind policies because -`gateway.bind` already describes how clients reach the local Gateway: -`"loopback"` for localhost-only, `"lan"` for local-network exposure, -`"tailnet"` for a Tailscale address, and `"custom"` for an explicit host. - -`gateway.iroh.endpoint` is the Iroh-owned endpoint configuration. Its shape should -mirror normal Iroh configuration instead of translating through OpenClaw-specific -names. An empty object uses Iroh's default endpoint behavior, including the -default public relay and discovery infrastructure. If the RFC or implementation -needs custom relay maps, relay presets, or other Iroh endpoint options, those -fields should be exposed under `gateway.iroh.endpoint` using Iroh's native names. -OpenClaw UI and help text can explain those native fields in product language. - -`gateway.iroh.secretKeyPath` is an OpenClaw-owned Gateway lifecycle field. The -Gateway should create the secret key on first use and reuse it across restarts so -it keeps a stable Iroh `EndpointId`. The default path should live under the -OpenClaw state directory and use the same local-secret file hardening OpenClaw -uses elsewhere: create parent directories with owner-only permissions, write the -key atomically with owner-only file permissions, reject symlink-based key paths, -and fail startup rather than silently regenerating or weakening a key when an -existing key file is unreadable or has unsafe filesystem state. Other -OpenClaw-owned fields, if needed, should live beside `endpoint` under -`gateway.iroh` and be merged with the Iroh endpoint config when constructing the -endpoint. +`gateway.bind: "iroh"` selects the entrypoint clients use to reach the local Gateway. This matches the existing bind model: `"loopback"`, `"lan"`, `"tailnet"`, and `"custom"`. + +`gateway.iroh.endpoint` should mirror Iroh’s native endpoint configuration. An empty object uses Iroh defaults, including default public relay and discovery infrastructure. Custom relay maps, relay presets, and related Iroh options should live under this object with Iroh’s own field names. + +`gateway.iroh.secretKeyPath` is OpenClaw-owned. The Gateway should create the key on first use and reuse it so the Gateway keeps a stable `EndpointId`. The default path should live under the OpenClaw state directory. Key handling must: + +- create parent directories with owner-only permissions +- write the key atomically with owner-only file permissions +- reject symlink paths +- fail startup if an existing key is unreadable or unsafe When `gateway.bind` is `"iroh"`, Gateway startup should: 1. Load or create the persisted Iroh secret key. -2. Construct an Iroh endpoint from `gateway.iroh.endpoint` plus OpenClaw-owned - runtime values such as the secret key and ALPN. -3. Bring the endpoint online with an OpenClaw-specific ALPN such as - `openclaw-gateway-v1`. -4. Publish Iroh pairing data alongside the existing setup-code payload. - -The setup-code payload should include enough Iroh data for bootstrap pairing, -such as the Gateway `EndpointId`, an `EndpointTicket`, and relay/discovery -metadata suitable for UI display. Clients should use tickets for bootstrap -pairing, then store the Gateway `EndpointId` for reconnects. This lets paired -clients reconnect after network changes without requiring a new QR code or setup -flow. - -The initial release should be experimental and mobile-first. A browser-based -frontend may also be part of the experiment if Iroh's WASM implementation can -connect to the same Gateway endpoint with acceptable packaging, browser -compatibility, and security constraints. The browser path is not required for the -first mobile-first experiment; if included, it must account for Iroh's current -browser limitations, including relay-only browser traffic and the need for an -application-specific WASM wrapper rather than an official browser npm package. -Existing Tailscale, remote URL, LAN, and loopback Gateway paths should continue -to work. - -The RFC intentionally leaves the Gateway protocol mapping for maintainer review. -The maintainers should decide whether the first implementation should use native -Gateway protocol framing over Iroh QUIC bidirectional streams, or an -Iroh-to-localhost bridge inside the Gateway process. Native streams are the -preferred long-term architecture, while a localhost bridge may be the right -lower-effort validation spike if it preserves existing Gateway behavior and is -clearly documented as experimental. - -Iroh support must be treated as public/remote Gateway exposure. The Gateway must -not allow `gateway.bind: "iroh"` with unauthenticated Gateway mode. Pairing must -continue to use OpenClaw authorization, tokens, passwords, device records, or an -equivalent application-level control. After pairing, OpenClaw should consider -binding client records to Iroh peer `EndpointId`s or requiring a bootstrap token -before accepting a new peer. Logs and diagnostics should avoid full Iroh tickets -because tickets may include direct IP addresses. +2. Build an Iroh endpoint from `gateway.iroh.endpoint` plus OpenClaw runtime values, including the secret key and ALPN. +3. Bring the endpoint online with an OpenClaw ALPN, for example `openclaw-gateway-v1`. +4. Add Iroh pairing data to the existing setup-code payload. + +The setup-code payload should include the Gateway `EndpointId`, an `EndpointTicket`, and relay/discovery metadata useful for setup UI. Clients should use the ticket for first pairing, then store the Gateway `EndpointId` for reconnects. This should let paired clients survive Gateway network changes without requiring a new QR code or setup flow. + +The first release should focus on native mobile clients. A browser frontend can be part of the experiment only if Iroh WASM is practical. Browser support must account for current limits, including relay-only traffic and the need for an application-specific WASM wrapper. + +The Gateway protocol mapping remains open for maintainer review: + +- Preferred long term: native Gateway protocol framing over Iroh QUIC bidirectional streams. +- Lower-effort spike: an Iroh-to-localhost bridge inside the Gateway process, documented as experimental. + +Iroh support must be treated as public remote Gateway exposure. OpenClaw must reject `gateway.bind: "iroh"` with unauthenticated Gateway mode. Pairing must continue to use OpenClaw authorization, tokens, passwords, device records, or an equivalent application-level control. + +After pairing, OpenClaw should consider binding client records to Iroh peer `EndpointId`s or requiring a bootstrap token before accepting a new peer. Logs and diagnostics should avoid full Iroh tickets because tickets may include direct IP addresses. ## Rationale -Iroh is a good fit for the Gateway problem because it gives OpenClaw stable -public-key endpoint identities, QUIC streams, NAT traversal, and relay fallback -without asking users to configure a VPN. The v1 release and official Node, -Swift, and Kotlin APIs make it realistic for the Gateway and mobile clients. - -Keeping Iroh optional reduces risk. Tailscale remains mature, user-controlled, -and already integrated into OpenClaw's connection flow. Iroh introduces new -operational questions around public relay dependency, address discovery, -packaging native bindings, browser/WASM viability, and mobile client -implementation. Treating it as an experimental transport lets OpenClaw learn from -real pairing and reconnect flows without disrupting existing users. - -Modeling Iroh as `gateway.bind: "iroh"` fits the existing Gateway mental model -better than adding a separate `gateway.iroh.enabled` or `gateway.iroh.mode` flag: -it selects the entrypoint clients use to reach the local Gateway. The low-level -endpoint configuration should still mirror Iroh's native configuration surface so -OpenClaw does not introduce a product-level mapping layer that must be maintained -separately from Iroh. OpenClaw-specific fields should follow existing Gateway -config conventions, such as `*Path` for filesystem-backed material and nested -objects for transport-owned config. When OpenClaw needs extra Gateway-specific -values, it can merge those values with the Iroh config at endpoint construction -time. UI and help text can still explain that the default relay mode uses public -relay and discovery infrastructure. - -Native Gateway protocol over Iroh streams is cleaner than a localhost bridge, -but the bridge may be useful for a short spike. This RFC intentionally leaves the -native-streams-versus-bridge decision unresolved so maintainers can decide, -during review, whether the project wants the lowest-effort experiment first or a -more direct implementation of the desired long-term architecture. - -## Future questions - -- Do we want to run OpenClaw relay servers to make this easier for users? The - suggested answer for now is to decide after measuring the impact on the user - flow when using Iroh's existing relay and discovery infrastructure. +Iroh fits the Gateway problem: stable public-key endpoint identity, QUIC streams, NAT traversal, and relay fallback without VPN setup. Its v1 protocol and Node, Swift, and Kotlin APIs make Gateway plus mobile support realistic. + +Keeping Iroh optional limits risk. Tailscale remains mature and already works. Iroh adds new questions around public relays, address discovery, native bindings, browser packaging, and mobile integration. An experimental transport lets OpenClaw test pairing and reconnect flows before committing to Iroh as a permanent option. + +`gateway.bind: "iroh"` fits the current Gateway model because it selects how clients reach the Gateway. Low-level endpoint configuration should stay close to Iroh’s native config so OpenClaw does not need to maintain a parallel naming layer. + +## Future question + +- Should OpenClaw run its own relay servers? Decide after measuring the user flow with Iroh’s existing relay and discovery infrastructure. ## Unresolved questions -- Should the first implementation use native Gateway protocol framing over Iroh - streams, or an Iroh-to-localhost bridge? -- What exact fields should the setup-code payload expose for Iroh pairing? +- Should v1 use native Gateway protocol streams or a localhost bridge? +- What exact Iroh fields should the setup-code payload include? - Should paired client records store and enforce client Iroh `EndpointId`s? -- What exact Iroh endpoint configuration fields should OpenClaw expose 1:1 under - `gateway.iroh.endpoint` for self-hosted or OpenClaw-operated relay - deployments? -- Should the first supported client be native mobile only, or should the RFC also - require a browser frontend using Iroh WASM for easier review and contribution? -- How should OpenClaw present public relay dependency and metadata implications - in setup UI and security audits? +- Which Iroh endpoint fields should OpenClaw expose 1:1? +- Should v1 support native mobile only, or require browser/WASM support too? +- How should setup UI explain public relay dependency and metadata exposure? From 6f58b79973aceffc99114e23aae7e531dd6741a7 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 21:59:33 +0200 Subject: [PATCH 10/17] docs: add product fit to Iroh RFC --- rfcs/0009-iroh-gateway-transport.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index c8e0dd2e..6d5720f1 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -23,6 +23,10 @@ OpenClaw Nodes currently depend on reachable Gateway URLs, Tailscale Serve/Funne Iroh v1 provides a stable wire protocol plus APIs for Node.js, Rust, Python, Swift, and Kotlin. The `@number0/iroh` package and native mobile bindings make it a plausible transport for OpenClaw Gateway access through NATs. +## Product fit + +This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, and safe defaults by making phone-to-Gateway access simpler without replacing Gateway auth. + ## Terms - Iroh ticket: A shareable bootstrap value with endpoint identity, relay hints, and direct addresses when available. From 670a497965b40c7f10e21e4775d7738f899d8bf0 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 22:30:13 +0200 Subject: [PATCH 11/17] docs: refine Iroh Gateway RFC --- rfcs/0009-iroh-gateway-transport.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 6d5720f1..ffb8ae3a 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -37,8 +37,9 @@ This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, - Add an optional Gateway connection path, not a replacement for existing paths. - Let clients pair with an Iroh ticket, then reconnect using the stored Gateway `EndpointId`. - Preserve OpenClaw authentication, authorization, and device-pairing semantics. -- Add `"iroh"` as a `gateway.bind` option. +- Add `gateway.iroh.enabled` as the experiment switch while keeping `gateway.bind` as the local HTTP/WebSocket bind policy. - Keep Iroh endpoint configuration under `gateway.iroh.endpoint` using Iroh-native field names. +- Treat Iroh as remote Gateway exposure in setup, logs, diagnostics, and security audit. - Keep the first implementation small and experimental. - Keep Tailscale, remote URL, LAN, loopback, and custom bind paths working. - Leave room for browser/WASM support if it proves practical. @@ -53,13 +54,14 @@ This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, ## Proposal -Add an experimental bind target: +Add an experimental Iroh exposure flag: ```jsonc { "gateway": { - "bind": "iroh", + "bind": "loopback", "iroh": { + "enabled": true, "secretKeyPath": "~/.openclaw/iroh-gateway.key", "endpoint": {} } @@ -67,7 +69,7 @@ Add an experimental bind target: } ``` -`gateway.bind: "iroh"` selects the entrypoint clients use to reach the local Gateway. This matches the existing bind model: `"loopback"`, `"lan"`, `"tailnet"`, and `"custom"`. +`gateway.iroh.enabled` publishes an Iroh endpoint in addition to the normal Gateway listener. `gateway.bind` should keep its existing meaning: the local TCP bind policy for Gateway HTTP/WebSocket, Control UI, existing clients, and any localhost bridge. Keeping Iroh separate avoids overloading `bind` with a non-IP transport and lets the normal listener stay loopback-only while Iroh is treated as remote exposure. `gateway.iroh.endpoint` should mirror Iroh’s native endpoint configuration. An empty object uses Iroh defaults, including default public relay and discovery infrastructure. Custom relay maps, relay presets, and related Iroh options should live under this object with Iroh’s own field names. @@ -78,14 +80,16 @@ Add an experimental bind target: - reject symlink paths - fail startup if an existing key is unreadable or unsafe -When `gateway.bind` is `"iroh"`, Gateway startup should: +When `gateway.iroh.enabled` is `true`, Gateway startup should: 1. Load or create the persisted Iroh secret key. 2. Build an Iroh endpoint from `gateway.iroh.endpoint` plus OpenClaw runtime values, including the secret key and ALPN. 3. Bring the endpoint online with an OpenClaw ALPN, for example `openclaw-gateway-v1`. 4. Add Iroh pairing data to the existing setup-code payload. -The setup-code payload should include the Gateway `EndpointId`, an `EndpointTicket`, and relay/discovery metadata useful for setup UI. Clients should use the ticket for first pairing, then store the Gateway `EndpointId` for reconnects. This should let paired clients survive Gateway network changes without requiring a new QR code or setup flow. +The setup-code payload should include the Gateway `EndpointId`, an `EndpointTicket`, and relay/discovery metadata useful for setup UI. The exact additive or versioned payload shape should be defined during the spike or implementation and must preserve existing setup-code clients. Clients should use the ticket for first pairing, then store the Gateway `EndpointId` for reconnects. This should let paired clients survive Gateway network changes without requiring a new QR code or setup flow. + +Bootstrap token persistence over Iroh should require transport pinning: the connected Gateway `EndpointId` must match the setup-code or stored Gateway `EndpointId`, and the connection must use the expected OpenClaw ALPN. Iroh endpoint identity is still not application authorization, but it can decide whether the transport is trusted enough to persist bootstrap-issued device/operator tokens. On mismatch or missing pinning, clients should refuse token persistence and require re-pairing or explicit user confirmation. The first release should focus on native mobile clients. A browser frontend can be part of the experiment only if Iroh WASM is practical. Browser support must account for current limits, including relay-only traffic and the need for an application-specific WASM wrapper. @@ -94,7 +98,9 @@ The Gateway protocol mapping remains open for maintainer review: - Preferred long term: native Gateway protocol framing over Iroh QUIC bidirectional streams. - Lower-effort spike: an Iroh-to-localhost bridge inside the Gateway process, documented as experimental. -Iroh support must be treated as public remote Gateway exposure. OpenClaw must reject `gateway.bind: "iroh"` with unauthenticated Gateway mode. Pairing must continue to use OpenClaw authorization, tokens, passwords, device records, or an equivalent application-level control. +Iroh support must be treated as public remote Gateway exposure. OpenClaw must reject `gateway.iroh.enabled: true` with unauthenticated Gateway mode. Pairing must continue to use OpenClaw authorization, tokens, passwords, device records, or an equivalent application-level control. + +Security and audit integration is part of v1. Doctor/security audit should surface Iroh exposure, weak or missing Gateway auth, unsafe Iroh key files, relay dependency and metadata implications, and ticket logging hazards. After pairing, OpenClaw should consider binding client records to Iroh peer `EndpointId`s or requiring a bootstrap token before accepting a new peer. Logs and diagnostics should avoid full Iroh tickets because tickets may include direct IP addresses. @@ -104,7 +110,7 @@ Iroh fits the Gateway problem: stable public-key endpoint identity, QUIC streams Keeping Iroh optional limits risk. Tailscale remains mature and already works. Iroh adds new questions around public relays, address discovery, native bindings, browser packaging, and mobile integration. An experimental transport lets OpenClaw test pairing and reconnect flows before committing to Iroh as a permanent option. -`gateway.bind: "iroh"` fits the current Gateway model because it selects how clients reach the Gateway. Low-level endpoint configuration should stay close to Iroh’s native config so OpenClaw does not need to maintain a parallel naming layer. +`gateway.iroh.enabled` is intentionally separate from `gateway.bind`: `bind` remains the local HTTP/WebSocket listener policy, while Iroh is an additional non-TCP exposure path. This keeps existing Gateway semantics, security checks, and Control UI behavior clear while still allowing either native Iroh streams or a localhost bridge during the experiment. Low-level endpoint configuration should stay close to Iroh’s native config so OpenClaw does not need to maintain a parallel naming layer. ## Future question @@ -113,7 +119,6 @@ Keeping Iroh optional limits risk. Tailscale remains mature and already works. I ## Unresolved questions - Should v1 use native Gateway protocol streams or a localhost bridge? -- What exact Iroh fields should the setup-code payload include? - Should paired client records store and enforce client Iroh `EndpointId`s? - Which Iroh endpoint fields should OpenClaw expose 1:1? - Should v1 support native mobile only, or require browser/WASM support too? From eb22754b2af1287ce2ea3d97b52dd8f28b547a44 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 22:37:40 +0200 Subject: [PATCH 12/17] docs: clarify Iroh Gateway RFC scope --- rfcs/0009-iroh-gateway-transport.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index ffb8ae3a..12283de3 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -42,7 +42,7 @@ This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, - Treat Iroh as remote Gateway exposure in setup, logs, diagnostics, and security audit. - Keep the first implementation small and experimental. - Keep Tailscale, remote URL, LAN, loopback, and custom bind paths working. -- Leave room for browser/WASM support if it proves practical. +- Leave room for browser/WASM support if needed for development. ## Non-goals @@ -71,7 +71,7 @@ Add an experimental Iroh exposure flag: `gateway.iroh.enabled` publishes an Iroh endpoint in addition to the normal Gateway listener. `gateway.bind` should keep its existing meaning: the local TCP bind policy for Gateway HTTP/WebSocket, Control UI, existing clients, and any localhost bridge. Keeping Iroh separate avoids overloading `bind` with a non-IP transport and lets the normal listener stay loopback-only while Iroh is treated as remote exposure. -`gateway.iroh.endpoint` should mirror Iroh’s native endpoint configuration. An empty object uses Iroh defaults, including default public relay and discovery infrastructure. Custom relay maps, relay presets, and related Iroh options should live under this object with Iroh’s own field names. +`gateway.iroh.endpoint` should mirror Iroh’s native endpoint configuration. An empty object uses Iroh defaults, including default public relay and discovery infrastructure. OpenClaw should either pass this object through to Iroh or validate only the minimal subset needed for safety and diagnostics; it should not maintain a parallel full schema. Custom relay maps, relay presets, and related Iroh options should live under this object with Iroh’s own field names. `gateway.iroh.secretKeyPath` is OpenClaw-owned. The Gateway should create the key on first use and reuse it so the Gateway keeps a stable `EndpointId`. The default path should live under the OpenClaw state directory. Key handling must: @@ -91,7 +91,7 @@ The setup-code payload should include the Gateway `EndpointId`, an `EndpointTick Bootstrap token persistence over Iroh should require transport pinning: the connected Gateway `EndpointId` must match the setup-code or stored Gateway `EndpointId`, and the connection must use the expected OpenClaw ALPN. Iroh endpoint identity is still not application authorization, but it can decide whether the transport is trusted enough to persist bootstrap-issued device/operator tokens. On mismatch or missing pinning, clients should refuse token persistence and require re-pairing or explicit user confirmation. -The first release should focus on native mobile clients. A browser frontend can be part of the experiment only if Iroh WASM is practical. Browser support must account for current limits, including relay-only traffic and the need for an application-specific WASM wrapper. +V1 should add Gateway-side Iroh support. Native mobile is the main intended validation path, but Gateway support should not depend on requiring a specific first client. Browser/WASM support is not a product requirement for v1; include it only if it is needed to make development, review, or testing of the Gateway flow practical. Browser support must account for current limits, including relay-only traffic and the need for an application-specific WASM wrapper. The Gateway protocol mapping remains open for maintainer review: @@ -102,7 +102,7 @@ Iroh support must be treated as public remote Gateway exposure. OpenClaw must re Security and audit integration is part of v1. Doctor/security audit should surface Iroh exposure, weak or missing Gateway auth, unsafe Iroh key files, relay dependency and metadata implications, and ticket logging hazards. -After pairing, OpenClaw should consider binding client records to Iroh peer `EndpointId`s or requiring a bootstrap token before accepting a new peer. Logs and diagnostics should avoid full Iroh tickets because tickets may include direct IP addresses. +For v1, clients should pin the Gateway `EndpointId`; Gateway-side enforcement of client Iroh `EndpointId`s is left for later. Existing OpenClaw device identity, device tokens, and pairing records remain the client authorization boundary. Logs and diagnostics should avoid full Iroh tickets because tickets may include direct IP addresses. ## Rationale @@ -112,14 +112,12 @@ Keeping Iroh optional limits risk. Tailscale remains mature and already works. I `gateway.iroh.enabled` is intentionally separate from `gateway.bind`: `bind` remains the local HTTP/WebSocket listener policy, while Iroh is an additional non-TCP exposure path. This keeps existing Gateway semantics, security checks, and Control UI behavior clear while still allowing either native Iroh streams or a localhost bridge during the experiment. Low-level endpoint configuration should stay close to Iroh’s native config so OpenClaw does not need to maintain a parallel naming layer. -## Future question +## Future questions - Should OpenClaw run its own relay servers? Decide after measuring the user flow with Iroh’s existing relay and discovery infrastructure. +- Should a later version store and enforce each paired client’s stable Iroh `EndpointId` as additional defense in depth? This depends on mobile clients persisting Iroh secret keys reliably and having clear recovery for reinstalls or key rotation. -## Unresolved questions +## Unresolved question +__must be resolved before accepting this RFC__ - Should v1 use native Gateway protocol streams or a localhost bridge? -- Should paired client records store and enforce client Iroh `EndpointId`s? -- Which Iroh endpoint fields should OpenClaw expose 1:1? -- Should v1 support native mobile only, or require browser/WASM support too? -- How should setup UI explain public relay dependency and metadata exposure? From 4aa27d09877bdb25c2f73d27c6bd5d160f334b5d Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 22:45:34 +0200 Subject: [PATCH 13/17] docs: tighten Iroh gateway transport RFC --- rfcs/0009-iroh-gateway-transport.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 12283de3..c0323034 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -1,5 +1,5 @@ --- -title: Iroh Gateway transport +title: Iroh Gateway transport as alternative to Tailscale or reverse proxy authors: - Benjamin Jesuiter created: 2026-06-20 @@ -25,7 +25,7 @@ Iroh v1 provides a stable wire protocol plus APIs for Node.js, Rust, Python, Swi ## Product fit -This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, and safe defaults by making phone-to-Gateway access simpler without replacing Gateway auth. +This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, and safe defaults by making phone-to-Gateway access simpler. ## Terms @@ -36,21 +36,18 @@ This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, - Add an optional Gateway connection path, not a replacement for existing paths. - Let clients pair with an Iroh ticket, then reconnect using the stored Gateway `EndpointId`. -- Preserve OpenClaw authentication, authorization, and device-pairing semantics. -- Add `gateway.iroh.enabled` as the experiment switch while keeping `gateway.bind` as the local HTTP/WebSocket bind policy. +- Add `gateway.iroh.enabled` as the experiment switch without changing `gateway.bind` semantics. - Keep Iroh endpoint configuration under `gateway.iroh.endpoint` using Iroh-native field names. - Treat Iroh as remote Gateway exposure in setup, logs, diagnostics, and security audit. - Keep the first implementation small and experimental. - Keep Tailscale, remote URL, LAN, loopback, and custom bind paths working. -- Leave room for browser/WASM support if needed for development. ## Non-goals - Not replacing Tailscale. -- Not treating Iroh endpoint identity as application authorization. +- Not using Iroh endpoint identity as application authorization or exposing unauthenticated public Gateway access. - Not requiring all clients to support Iroh. - Not designing self-hosted relays in the first version. -- Not exposing unauthenticated public Gateway access. ## Proposal @@ -87,22 +84,22 @@ When `gateway.iroh.enabled` is `true`, Gateway startup should: 3. Bring the endpoint online with an OpenClaw ALPN, for example `openclaw-gateway-v1`. 4. Add Iroh pairing data to the existing setup-code payload. -The setup-code payload should include the Gateway `EndpointId`, an `EndpointTicket`, and relay/discovery metadata useful for setup UI. The exact additive or versioned payload shape should be defined during the spike or implementation and must preserve existing setup-code clients. Clients should use the ticket for first pairing, then store the Gateway `EndpointId` for reconnects. This should let paired clients survive Gateway network changes without requiring a new QR code or setup flow. +The setup-code payload should include the Gateway `EndpointId`, an `EndpointTicket`, and setup UI relay/discovery metadata. The exact additive or versioned payload shape should be defined during the spike or implementation and must preserve existing setup-code clients. Clients should use the ticket for first pairing and store the Gateway `EndpointId` for reconnects after network changes. -Bootstrap token persistence over Iroh should require transport pinning: the connected Gateway `EndpointId` must match the setup-code or stored Gateway `EndpointId`, and the connection must use the expected OpenClaw ALPN. Iroh endpoint identity is still not application authorization, but it can decide whether the transport is trusted enough to persist bootstrap-issued device/operator tokens. On mismatch or missing pinning, clients should refuse token persistence and require re-pairing or explicit user confirmation. +Bootstrap token persistence over Iroh should require transport pinning: clients may persist bootstrap-issued device/operator tokens only when the connected Gateway `EndpointId` matches the setup-code or stored Gateway `EndpointId` and the connection uses the expected OpenClaw ALPN. On mismatch or missing pinning, clients should refuse token persistence and require re-pairing or explicit user confirmation. -V1 should add Gateway-side Iroh support. Native mobile is the main intended validation path, but Gateway support should not depend on requiring a specific first client. Browser/WASM support is not a product requirement for v1; include it only if it is needed to make development, review, or testing of the Gateway flow practical. Browser support must account for current limits, including relay-only traffic and the need for an application-specific WASM wrapper. +V1 should add Gateway-side Iroh support. Native mobile is the intended validation path, but Gateway support should not depend on a specific first client. Browser/WASM support is not a v1 product requirement; include it only if needed for development, review, or testing. Browser support must account for current limits, including relay-only traffic and the need for an application-specific WASM wrapper. The Gateway protocol mapping remains open for maintainer review: - Preferred long term: native Gateway protocol framing over Iroh QUIC bidirectional streams. - Lower-effort spike: an Iroh-to-localhost bridge inside the Gateway process, documented as experimental. -Iroh support must be treated as public remote Gateway exposure. OpenClaw must reject `gateway.iroh.enabled: true` with unauthenticated Gateway mode. Pairing must continue to use OpenClaw authorization, tokens, passwords, device records, or an equivalent application-level control. +Iroh support must be treated as public remote Gateway exposure. OpenClaw must reject `gateway.iroh.enabled: true` with unauthenticated Gateway mode. Security and audit integration is part of v1. Doctor/security audit should surface Iroh exposure, weak or missing Gateway auth, unsafe Iroh key files, relay dependency and metadata implications, and ticket logging hazards. -For v1, clients should pin the Gateway `EndpointId`; Gateway-side enforcement of client Iroh `EndpointId`s is left for later. Existing OpenClaw device identity, device tokens, and pairing records remain the client authorization boundary. Logs and diagnostics should avoid full Iroh tickets because tickets may include direct IP addresses. +For v1, Gateway-side enforcement of client Iroh `EndpointId`s is left for later. Existing device tokens and pairing records remain the client authorization boundary. Logs and diagnostics should avoid full Iroh tickets because tickets may include direct IP addresses. ## Rationale @@ -110,7 +107,7 @@ Iroh fits the Gateway problem: stable public-key endpoint identity, QUIC streams Keeping Iroh optional limits risk. Tailscale remains mature and already works. Iroh adds new questions around public relays, address discovery, native bindings, browser packaging, and mobile integration. An experimental transport lets OpenClaw test pairing and reconnect flows before committing to Iroh as a permanent option. -`gateway.iroh.enabled` is intentionally separate from `gateway.bind`: `bind` remains the local HTTP/WebSocket listener policy, while Iroh is an additional non-TCP exposure path. This keeps existing Gateway semantics, security checks, and Control UI behavior clear while still allowing either native Iroh streams or a localhost bridge during the experiment. Low-level endpoint configuration should stay close to Iroh’s native config so OpenClaw does not need to maintain a parallel naming layer. +Keeping low-level endpoint configuration close to Iroh’s native config avoids a parallel naming layer while still allowing custom relay maps and other Iroh options to pass through cleanly. ## Future questions From 610c503e77b01ef259a16f3b09447672d939fc1b Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 22:47:08 +0200 Subject: [PATCH 14/17] docs: link Iroh Gateway RFC PR --- rfcs/0009-iroh-gateway-transport.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index c0323034..01930148 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -6,7 +6,7 @@ created: 2026-06-20 last_updated: 2026-06-20 status: draft issue: -rfc_pr: +rfc_pr: https://github.com/openclaw/rfcs/pull/23 --- # Proposal: Iroh Gateway transport From 8f53000b35f9fb4b2b42ee5860d2db2f11d4409d Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 22:47:50 +0200 Subject: [PATCH 15/17] docs: link Iroh v1 announcement --- rfcs/0009-iroh-gateway-transport.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 01930148..70854a03 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -21,7 +21,7 @@ Clients should be able to pair with and reconnect to a Gateway through Iroh endp OpenClaw Nodes currently depend on reachable Gateway URLs, Tailscale Serve/Funnel, or LAN access if the Node is not on localhost. These work, but they add friction. A phone user may need to install a VPN, configure it, and keep it running just to reach a Gateway. Users behind carrier-grade NAT (CGNAT) need complicated DDNS and reverse-proxy setups to publish their OpenClaw Gateway so external OpenClaw Nodes can connect to their home instance. Iroh solves this by exposing the Gateway as an application-level encrypted connection instead. -Iroh v1 provides a stable wire protocol plus APIs for Node.js, Rust, Python, Swift, and Kotlin. The `@number0/iroh` package and native mobile bindings make it a plausible transport for OpenClaw Gateway access through NATs. +[Iroh v1](https://www.iroh.computer/blog/v1) provides a stable wire protocol plus APIs for Node.js, Rust, Python, Swift, and Kotlin. The `@number0/iroh` package and native mobile bindings make it a plausible transport for OpenClaw Gateway access through NATs. ## Product fit From cd68e0e42c36f610d5deaf22dd1873b704d4c7c2 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 23:05:11 +0200 Subject: [PATCH 16/17] docs: resolve iroh gateway transport choice --- rfcs/0009-iroh-gateway-transport.md | 34 +++++++++++------------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 70854a03..18b1f6ce 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -13,9 +13,7 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/23 ## Summary -Add Iroh as an experimental OpenClaw Gateway transport. - -Clients should be able to pair with and reconnect to a Gateway through Iroh endpoint identity, discovery, NAT traversal, and relay fallback, without requiring Tailscale or another VPN. OpenClaw Gateway authorization remains the source of trust. +Add Iroh as an experimental OpenClaw Gateway transport so clients can pair with and reconnect to a Gateway through Iroh endpoint identity, discovery, NAT traversal, and relay fallback, without requiring Tailscale or another VPN. OpenClaw Gateway authorization remains the source of trust. ## Motivation @@ -23,15 +21,8 @@ OpenClaw Nodes currently depend on reachable Gateway URLs, Tailscale Serve/Funne [Iroh v1](https://www.iroh.computer/blog/v1) provides a stable wire protocol plus APIs for Node.js, Rust, Python, Swift, and Kotlin. The `@number0/iroh` package and native mobile bindings make it a plausible transport for OpenClaw Gateway access through NATs. -## Product fit - This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, and safe defaults by making phone-to-Gateway access simpler. -## Terms - -- Iroh ticket: A shareable bootstrap value with endpoint identity, relay hints, and direct addresses when available. -- Iroh `EndpointId`: A stable public endpoint identity derived from the endpoint secret key. If the Gateway persists that key, clients can remember the `EndpointId` and rediscover the Gateway after network changes. - ## Goals - Add an optional Gateway connection path, not a replacement for existing paths. @@ -42,7 +33,7 @@ This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, - Keep the first implementation small and experimental. - Keep Tailscale, remote URL, LAN, loopback, and custom bind paths working. -## Non-goals +## Non-Goals - Not replacing Tailscale. - Not using Iroh endpoint identity as application authorization or exposing unauthenticated public Gateway access. @@ -51,6 +42,9 @@ This fits OpenClaw’s focus on setup reliability, first-run UX, companion apps, ## Proposal +- Iroh ticket: A shareable bootstrap value with endpoint identity, relay hints, and direct addresses when available. +- Iroh `EndpointId`: A stable public endpoint identity derived from the endpoint secret key. If the Gateway persists that key, clients can remember the `EndpointId` and rediscover the Gateway after network changes. + Add an experimental Iroh exposure flag: ```jsonc @@ -66,7 +60,7 @@ Add an experimental Iroh exposure flag: } ``` -`gateway.iroh.enabled` publishes an Iroh endpoint in addition to the normal Gateway listener. `gateway.bind` should keep its existing meaning: the local TCP bind policy for Gateway HTTP/WebSocket, Control UI, existing clients, and any localhost bridge. Keeping Iroh separate avoids overloading `bind` with a non-IP transport and lets the normal listener stay loopback-only while Iroh is treated as remote exposure. +`gateway.iroh.enabled` publishes an Iroh endpoint in addition to the normal Gateway listener. `gateway.bind` should keep its existing meaning: the local TCP bind policy for Gateway HTTP/WebSocket, Control UI, existing clients, and any validation-only Iroh-to-localhost bridge spike. Keeping Iroh separate avoids overloading `bind` with a non-IP transport and lets the normal listener stay loopback-only while Iroh is treated as remote exposure. `gateway.iroh.endpoint` should mirror Iroh’s native endpoint configuration. An empty object uses Iroh defaults, including default public relay and discovery infrastructure. OpenClaw should either pass this object through to Iroh or validate only the minimal subset needed for safety and diagnostics; it should not maintain a parallel full schema. Custom relay maps, relay presets, and related Iroh options should live under this object with Iroh’s own field names. @@ -90,10 +84,9 @@ Bootstrap token persistence over Iroh should require transport pinning: clients V1 should add Gateway-side Iroh support. Native mobile is the intended validation path, but Gateway support should not depend on a specific first client. Browser/WASM support is not a v1 product requirement; include it only if needed for development, review, or testing. Browser support must account for current limits, including relay-only traffic and the need for an application-specific WASM wrapper. -The Gateway protocol mapping remains open for maintainer review: +V1 should use a full native Iroh Gateway transport: native Gateway protocol framing over Iroh QUIC bidirectional streams using the OpenClaw ALPN. The Iroh path should be modeled, tested, diagnosed, and secured as a first-class Gateway transport rather than as a proxy into the local HTTP/WebSocket listener. -- Preferred long term: native Gateway protocol framing over Iroh QUIC bidirectional streams. -- Lower-effort spike: an Iroh-to-localhost bridge inside the Gateway process, documented as experimental. +An Iroh-to-localhost HTTP bridge inside the Gateway process may be used only as a validation spike. It can de-risk endpoint persistence, pairing, relay behavior, and mobile connectivity before the native transport is complete, but it should not be accepted as the v1 architecture. Iroh support must be treated as public remote Gateway exposure. OpenClaw must reject `gateway.iroh.enabled: true` with unauthenticated Gateway mode. @@ -105,16 +98,15 @@ For v1, Gateway-side enforcement of client Iroh `EndpointId`s is left for later. Iroh fits the Gateway problem: stable public-key endpoint identity, QUIC streams, NAT traversal, and relay fallback without VPN setup. Its v1 protocol and Node, Swift, and Kotlin APIs make Gateway plus mobile support realistic. +Choosing the full native Iroh Gateway path costs more than an Iroh-to-localhost HTTP bridge because OpenClaw must define Gateway protocol framing over QUIC streams and test auth, reconnects, diagnostics, and failure modes on a second transport. That extra implementation work is preferable to shipping a proxy architecture. A bridge has lower initial implementation cost because it reuses the existing HTTP Gateway, but it also adds proxying behavior, duplicates exposure/security decisions around the local listener, and can hide transport-specific failure modes that production Iroh support needs to handle directly. + Keeping Iroh optional limits risk. Tailscale remains mature and already works. Iroh adds new questions around public relays, address discovery, native bindings, browser packaging, and mobile integration. An experimental transport lets OpenClaw test pairing and reconnect flows before committing to Iroh as a permanent option. Keeping low-level endpoint configuration close to Iroh’s native config avoids a parallel naming layer while still allowing custom relay maps and other Iroh options to pass through cleanly. -## Future questions +## Unresolved questions + +Relevant follow-up questions that do not block accepting this RFC: - Should OpenClaw run its own relay servers? Decide after measuring the user flow with Iroh’s existing relay and discovery infrastructure. - Should a later version store and enforce each paired client’s stable Iroh `EndpointId` as additional defense in depth? This depends on mobile clients persisting Iroh secret keys reliably and having clear recovery for reinstalls or key rotation. - -## Unresolved question -__must be resolved before accepting this RFC__ - -- Should v1 use native Gateway protocol streams or a localhost bridge? From 4d19511ad372e4392066464425847ae0bd3ec803 Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Sat, 20 Jun 2026 23:08:51 +0200 Subject: [PATCH 17/17] docs: shorten RFC 0009 title --- rfcs/0009-iroh-gateway-transport.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0009-iroh-gateway-transport.md b/rfcs/0009-iroh-gateway-transport.md index 18b1f6ce..702751ac 100644 --- a/rfcs/0009-iroh-gateway-transport.md +++ b/rfcs/0009-iroh-gateway-transport.md @@ -1,5 +1,5 @@ --- -title: Iroh Gateway transport as alternative to Tailscale or reverse proxy +title: Iroh Gateway transport authors: - Benjamin Jesuiter created: 2026-06-20