Companion Transport
Forge uses its own Iroh and QUIC path for iPhone pairing.
The quickstart stays one command. This page is the deeper view:
what starts on the desktop, what the QR contains, how the phone
finds the machine, where relays fit, how Forge frames API
requests, and why the protocol is called
forge-companion/1.
npx forge-memory
npx forge-memory pair-ios
Quick Path
The base install does not ask users to understand transport
internals.
Default user flow
Users run npx forge-memory. Forge installs the
local runtime, discovers host adapters, keeps one data folder
explicit, and offers iPhone pairing from the same guided flow.
npx forge-memory
Later pairing
If Forge is already installed, pairing can be reopened without
repeating setup. This prints the default Iroh QR and transport
diagnostics.
npx forge-memory pair-ios
Network Model
The phone dials a desktop identity, not a changing IP address.
What starts on the desktop
Forge starts the repo-owned Rust host
forge-companion-iroh. The host creates or reloads
an Iroh secret key under the Forge data root, derives a stable
node id, registers ALPN forge-companion/1, and
proxies authenticated stream requests into the local Fastify
runtime.
What the iPhone dials
The QR gives the iPhone a node id, token, optional relay hint,
and forge-iroh:// URLs. The Swift app links the
same Rust transport core as a native static library, dials that
node id through Iroh, and sends Forge request envelopes over
QUIC streams.
Relay reality
Iroh still uses public rendezvous and relay infrastructure. That
replaces the need for the user to install Tailscale, open a
router port, or maintain a public Forge URL. It does not remove
the need for a public meeting point.
Direct path when possible
Iroh can use relay-assisted NAT traversal to attempt direct
encrypted QUIC. If the network blocks that path, encrypted QUIC
traffic can stay relayed. The relay is not the Forge app server
and does not need Forge's database.
Pairing Payload
The QR is a connection recipe, not just a URL.
{
"apiBaseUrl": "forge-iroh://<node-id>/api/v1",
"uiBaseUrl": "forge-iroh://<node-id>/forge/",
"transportMode": "iroh",
"transport": {
"protocol": "iroh",
"provider": "forge-companion-iroh",
"status": "ready",
"nodeId": "<node-id>",
"relay": "https://relay.example",
"alpn": "forge-companion/1",
"agent": "forge",
"pairPayload": {
"v": 1,
"node_id": "<node-id>",
"token": "<pairing-token>",
"host_name": "desktop-name",
"relay": "https://relay.example"
}
}
}
Node id
The stable public-key identity of the desktop Iroh endpoint. It
remains the durable target even when the current IP changes.
Pairing token
The app-level secret. The first stream frame must prove the
phone scanned the current QR before Forge accepts requests.
ALPN
The QUIC protocol selector. Forge uses
forge-companion/1 so this is clearly Forge's
protocol, not KittyLitter or Alleycat.
Wire Protocol
Forge carries existing API requests over authenticated QUIC
streams.
| Step |
Message |
Responsibility |
| 1 |
connect frame |
First JSON frame includes version, pairing token, and agent
forge.
|
| 2 |
ok frame |
Desktop host validates the token and accepts or rejects the
stream.
|
| 3 |
HTTP request envelope |
iPhone sends method, path, headers, and base64 body for a
Forge API route.
|
| 4 |
HTTP response envelope |
Rust host proxies to Fastify and returns status, headers, and
base64 body.
|
Fallbacks
Manual HTTP remains available, but it is no longer the default.
Use Iroh first
The default QR path should be Iroh. It avoids forcing users to
install a VPN app, configure port forwarding, or copy a LAN
address that breaks when the network changes.
Use HTTP deliberately
Direct HTTP/TCP is still useful for known LAN hosts, Tailscale
operator setups, and debugging. It is an explicit mode.
npx forge-memory pair-ios --manual-http
License Boundary
Forge owns this protocol and keeps the code permissive.
Forge license
Forge-owned public code is Apache-2.0. That keeps the open
source project permissive, patent-explicit, and compatible with
future closed-source commercial Forge forks.
Upstream boundary
Alleycat and KittyLitter were studied for the Iroh pairing
pattern. Forge does not vendor, link, copy, or name its protocol
after Alleycat. The protocol label is
forge-companion/1.
Verification
Transport changes should be checked at Rust, TypeScript, server,
and iOS layers.
cargo fmt --manifest-path companion-iroh/Cargo.toml --check
cargo test --manifest-path companion-iroh/Cargo.toml
cargo build --release --manifest-path companion-iroh/Cargo.toml --bin forge-companion-iroh
npx tsc --noEmit
npm run check:server
npm run test:forge-memory
iOS bridge changes should also build and test
ios-companion/ForgeCompanion.xcodeproj. Dependency
installs should stay deliberate; most local checks can use the
already installed toolchains and packages.