The easy path

One gateway in front of the whole market

You don't have to run your own PDS, watch the firehose, or write a scorer. The Compute Contract Gateway is a single Hono service that speaks XRPC on one side and the decentralized market on the other — request a VM or a worker with one call, get a receipt and a terminal back.

Two kinds of compute, one endpoint

compute.vm

Full VM

A real machine — SSH in over a websocat relay tunnel (ProxyCommand → dispatcher → tunnel-subscriber on guest → sshd) once the receipt clears. Good for anything that needs a whole OS.

gateway.requestComputeVM

deno worker

Deno Worker

Ship source + a deno.json instead of provisioning a full VM. Both ephemeral and persistent workers are provisioned through the same VM contract flow (runComputeContract) — they differ only in bidder discovery scope. Tunnel URLs are not returned for workers.

gateway.requestComputeWorkerEphemeral / …Persistent

Pair your gateway with a bidder

Before requesting compute, a gateway and a bidder confirm each other with a small bidirectional attestation.

1

Gateway writes a badgeBlueKeys record — a challenge naming the bidder's DID, signed and published on the gateway's own repo.

2

Bidder acknowledges automatically — the bidder software writes a market.bidderAssociation record pointing back. No manual step on the bidder's side.

Request a VM

One call, given a service-auth token and an SSH public key.

goat xrpc procedure "$GATEWAY_URL" com.publicdomainrelay.temp.gateway.requestComputeVM \
  Authorization:"Bearer $SVC_TOKEN" \
  sshPublicKey="$(cat my-vm-key.pub)" \
  tokens:='{"submitRfp":"...","submitAccept":"...","createRecord":"..."}' \
  skipSsh:=false \
  bidWindowSec:=30 \
  computeVm:='{"cpus":1,"mem":"512M","disk":"10G","network":"500G","role":"my-vm"}' \
  extraBidderDids:='["'"$BIDDER_DID"'"]'

The gateway returns a receipt plus everything you need to get a shell:

{
  "receiptOk": true,
  "receiptUri": "at://did:plc:gateway/market.receipt/3abc...",
  "receiptCid": "bafyrei...receipt",
  "websocatUrl": "wss://my-vm--did-plc-abc123.fedproxy.com",
  "vmFqdn": "my-vm--did-plc-abc123.fedproxy.com",
  "winnerDid": "did:plc:bob",
  "sshReady": true
}
ssh -o ProxyCommand='websocat --binary wss://my-vm--did-plc-abc123.fedproxy.com' \
    -o IdentityFile=./my-vm-key \
    root@my-vm--did-plc-abc123.fedproxy.com

Gateway CLI options

FlagEnvDescription
--portPORTTCP port
--hostnameHOSTNAMEPublic hostname (default: localhost)
--private-key-hexPRIVATE_KEY_HEXSecp256k1 private key hex (takes priority over --private-key-hex-path)
--private-key-hex-pathREPO_PRIVATE_KEY_HEX_PATHPath to load/save private key hex for stable DID
--pds-state-pathPDS_STATE_PATHPersistent PDS state (Deno.Kv SQLite)
--storage-pathSTORAGE_PATHFallback storage path (aliases --pds-state-path)
--plc-directory-urlPLC_DIRECTORY_URLPLC directory (default: https://plc.directory)
--ingress-proxy-hostINGRESS_PROXY_HOSTXRPC relay dispatcher host (default: xrpc.fedproxy.com)
--fedproxy-hostFEDPROXY_HOSTFedProxy SSH ingress host (default: fedproxy.com)
--relay-urlsRELAY_URLSComma-separated relay URLs for bidder discovery

Current limitations

Prefer to run it yourself?

Every record the gateway writes is one you could write by hand — see the raw protocol.