{ "name": "requester", "description": "Request compute on the socialweb.computer market: sign and publish an RFP, collect bids, accept one, release the VM.", "session": "requester", "actions": [ { "entry": "contract", "label": "Run a contract", "description": "One run: create the vm and a signed rfp, submitRfp to each bidder, accept the first free bid, wait for the receipt and the guest's reports, optionally run a command over iroh or webrtc, hold, release, delete its records. release: false keeps the VM; the result names its MCP servers (mcp).", "fields": [ { "key": "bidders", "label": "Bidder DIDs", "type": "array", "required": true, "description": "Bidder DIDs to submit the rfp to (at most 10)." }, { "key": "user_data", "label": "cloud-init user data", "type": "string", "description": "cloud-init for the VM. Omitted: the userData hook builds it from shell, webrtc_ssh, iroh and ssh_key (default: a guest agent serving the MCP shell); a JSON #cloud-config's tunnels.json tags are read for webrtc reports." }, { "key": "shell", "label": "MCP shell", "type": "boolean", "description": "Without user_data: the guest agent's MCP shell service and its \"shell\" webrtc tunnel (default true)." }, { "key": "webrtc_ssh", "label": "ssh over webrtc", "type": "boolean", "description": "Without user_data: an \"ssh\" webrtc tunnel to sshd (needs ssh_key; default false)." }, { "key": "iroh", "label": "ssh over iroh", "type": "boolean", "description": "Without user_data: dumbpipe in front of sshd, its ticket the guest's onNetwork report (needs ssh_key; default false)." }, { "key": "ssh_key", "label": "SSH public key", "type": "string", "description": "Without user_data: the OpenSSH public key for root, with webrtc_ssh or iroh." }, { "key": "tunnels", "label": "More tunnels", "type": "array", "description": "Without user_data: datachannel tunnels to local TCP ports on the VM, [{tag, port, transport: \"webrtc\"}] (the user-data module's)." }, { "key": "kind", "label": "Compute kind", "type": "string", "values": { "default": "vm", "enum": ["vm", "deno"] }, "description": "What the bidder runs: vm, a firecracker VM (default), or deno, a sandbox running user_data as its program. Always written to the vm record." }, { "key": "role", "label": "Role", "type": "string", "description": "RBAC role the compute runs under (default compute)." }, { "key": "cpus", "label": "vCPUs", "type": "integer", "description": "Number of vCPUs." }, { "key": "mem", "label": "Memory", "type": "string", "description": "Memory request, e.g. 4G; a number is GiB." }, { "key": "disk", "label": "Disk", "type": "string", "description": "Disk request (default 50G)." }, { "key": "network", "label": "Network quota", "type": "string", "description": "Network throughput or quota, e.g. 500G." }, { "key": "expires_at", "label": "Expires at", "type": "string", "description": "When the bidder ends the VM, an RFC 3339 datetime (compute.vm expiresAt; without it a bidder ends it a day after the accept)." }, { "key": "policies", "label": "Policy strong refs", "type": "array", "description": "Strong refs {uri, cid} to policies the rfp names." }, { "key": "via", "label": "iroh or webrtc", "type": "string", "description": "Wait for what this transport needs (iroh: ticket and host keys; webrtc: the tag's fingerprint) and run command over it." }, { "key": "tag", "label": "webrtc tag", "type": "string", "description": "The webrtc tag to wait for and run command on (default ssh; shell for the MCP shell channel, without command)." }, { "key": "tags", "label": "webrtc tags", "type": "array", "description": "Tags whose onNetwork reports to read (default ssh, shell), besides user_data's tunnels and tag." }, { "key": "command", "label": "Command", "type": "string", "description": "Run on the guest once ready (needs via)." }, { "key": "stdin", "label": "Command stdin", "type": "string", "description": "The command's stdin (secrets go here, not in command); at most 65536 bytes." }, { "key": "hold_ms", "label": "Hold (ms)", "type": "integer", "description": "Keep the VM this long before releasing (max 3600000)." }, { "key": "release", "label": "Release", "type": "boolean", "description": "false keeps the VM: the result has mcp servers and records for a later release (default true)." }, { "key": "cleanup", "label": "Clean up", "type": "boolean", "description": "Delete the records the run created after release (default true)." }, { "key": "reason", "label": "Release reason", "type": "string", "description": "vm.delete reason (default session_ended)." }, { "key": "accept_paid", "label": "Accept paid bids", "type": "boolean", "description": "Accept a bid that is not free (default false)." }, { "key": "poll_ms", "label": "Poll interval (ms)", "type": "integer", "description": "Re-read interval while waiting (default 3000, max 60000)." }, { "key": "max_polls", "label": "Poll budget", "type": "integer", "description": "Reads per wait before giving up (default 40, max 200)." } ] }, { "entry": "bind_key", "label": "Bind attestation key", "description": "Publish the badgeBlueKeys record binding the host's attestation did:key to you, so bidders accept your signed RFPs.", "fields": [] }, { "entry": "associate", "label": "Associate", "description": "Confirm an association with a requester or bidder DID (associateConfirm through its #_associate service).", "fields": [ { "key": "peer", "label": "Peer DID", "type": "string", "required": true, "description": "The requester or bidder DID." }, { "key": "role", "label": "Role (requester or bidder)", "type": "string", "description": "The peer's role (default requester)." } ] }, { "entry": "offerings", "label": "Find bidders", "description": "Each bidder DID's compute offering as { did, endpoints } (pass them as request's bidders: the host picks iroh, then https).", "readOnly": true, "fields": [ { "key": "bidders", "label": "Bidder DIDs", "type": "array", "required": true, "description": "Bidder DIDs (at most 10)." } ] }, { "entry": "request", "label": "Request compute", "description": "Create a compute.vm and a signed market.rfp, then submitRfp to each bidder endpoint.", "fields": [ { "key": "user_data", "label": "cloud-init user data", "type": "string", "description": "cloud-init for the VM. Omitted: the userData hook builds it from shell, webrtc_ssh, iroh and ssh_key (default: a guest agent serving the MCP shell)." }, { "key": "shell", "label": "MCP shell", "type": "boolean", "description": "Without user_data: the guest agent's MCP shell service and its \"shell\" webrtc tunnel (default true)." }, { "key": "webrtc_ssh", "label": "ssh over webrtc", "type": "boolean", "description": "Without user_data: an \"ssh\" webrtc tunnel to sshd (needs ssh_key; default false)." }, { "key": "iroh", "label": "ssh over iroh", "type": "boolean", "description": "Without user_data: dumbpipe in front of sshd, its ticket the guest's onNetwork report (needs ssh_key; default false)." }, { "key": "ssh_key", "label": "SSH public key", "type": "string", "description": "Without user_data: the OpenSSH public key for root, with webrtc_ssh or iroh." }, { "key": "tunnels", "label": "More tunnels", "type": "array", "description": "Without user_data: datachannel tunnels to local TCP ports on the VM, [{tag, port, transport: \"webrtc\"}] (the user-data module's)." }, { "key": "bidders", "label": "Bidder endpoints", "type": "array", "description": "https origins or DIDs to submitRfp to; none just creates the records." }, { "key": "kind", "label": "Compute kind", "type": "string", "values": { "default": "vm", "enum": ["vm", "deno"] }, "description": "What the bidder runs: vm, a firecracker VM (default), or deno, a sandbox running user_data as its program. Always written to the vm record." }, { "key": "role", "label": "Role", "type": "string", "description": "RBAC role the compute runs under (default compute)." }, { "key": "cpus", "label": "vCPUs", "type": "integer", "description": "Number of vCPUs." }, { "key": "mem", "label": "Memory", "type": "string", "description": "Memory request, e.g. 4G; a number is GiB." }, { "key": "disk", "label": "Disk", "type": "string", "description": "Disk request (default 50G)." }, { "key": "network", "label": "Network quota", "type": "string", "description": "Network throughput or quota, e.g. 500G." }, { "key": "expires_at", "label": "Expires at", "type": "string", "description": "When the bidder ends the VM, an RFC 3339 datetime (compute.vm expiresAt; without it a bidder ends it a day after the accept)." }, { "key": "policies", "label": "Policy strong refs", "type": "array", "description": "Strong refs {uri, cid} to policies the rfp names." }, { "key": "onBehalfOf", "label": "On behalf of", "type": "object", "description": "Strong ref {uri, cid} the rfp names as its principal." } ] }, { "entry": "bids", "label": "Collect bids", "description": "Bids on an RFP from these bidder DIDs, and the winner (first free, else lowest cost).", "readOnly": true, "fields": [ { "key": "rfp", "label": "RFP strong ref", "type": "object", "required": true, "description": "{uri, cid} of the rfp." }, { "key": "bidders", "label": "Bidder DIDs", "type": "array", "description": "Bidders whose bid on this rfp to read (at the key a bidder gives it)." }, { "key": "bids", "label": "Bid URIs", "type": "array", "description": "Bid at:// URIs to read exactly." } ] }, { "entry": "accept", "label": "Accept bid", "description": "Create a signed market.accept and submitAccept to the bid's submitAccept, returning the receipt.", "fields": [ { "key": "rfp", "label": "RFP strong ref", "type": "object", "required": true, "description": "{uri, cid} of the rfp." }, { "key": "bid", "label": "Bid strong ref", "type": "object", "required": true, "description": "{uri, cid} of the bid." }, { "key": "submitAccept", "label": "Bid submitAccept", "type": "string", "description": "The bid's submitAccept (https origin or did#service)." } ] }, { "entry": "receipt", "label": "Find receipt", "description": "The winner's receipt for an accept, read at the key the winner gives it.", "readOnly": true, "fields": [ { "key": "bidder", "label": "Bidder DID", "type": "string", "required": true }, { "key": "accept", "label": "Accept strong ref", "type": "object", "required": true, "description": "{uri, cid} of the accept." } ] }, { "entry": "guest", "label": "Guest", "description": "What the bidder reports about the VM for a receipt: iroh ticket, webrtc fingerprints, host keys, signals, termination.", "readOnly": true, "fields": [ { "key": "bidder", "label": "Bidder DID", "type": "string", "required": true }, { "key": "receipt", "label": "Receipt URI", "type": "string", "required": true, "description": "The receipt's at:// URI." }, { "key": "tags", "label": "webrtc tags", "type": "array", "description": "Tags whose onNetwork reports to read (default ssh, shell)." } ] }, { "entry": "watch", "label": "Watch guest", "description": "Re-read the guest's reports and event streams for a receipt until what `via` needs (or `until`: terminated, answer) is there.", "readOnly": true, "fields": [ { "key": "bidder", "label": "Bidder DID", "type": "string", "required": true }, { "key": "receipt", "label": "Receipt URI", "type": "string", "required": true, "description": "The receipt's at:// URI." }, { "key": "via", "label": "iroh or webrtc", "type": "string", "description": "Ready when this transport's reports are there." }, { "key": "tag", "label": "webrtc tag", "type": "string", "description": "Tag for via webrtc and until answer (default ssh)." }, { "key": "tags", "label": "webrtc tags", "type": "array", "description": "Tags whose onNetwork reports to read (default ssh, shell)." }, { "key": "until", "label": "until", "type": "string", "description": "terminated or answer instead of via's readiness." }, { "key": "poll_ms", "label": "Poll interval (ms)", "type": "integer", "description": "Re-read interval while waiting (default 3000, max 60000)." }, { "key": "max_polls", "label": "Poll budget", "type": "integer", "description": "Reads per wait before giving up (default 40, max 200)." } ] }, { "entry": "release", "label": "Release VM", "description": "Sign vm.delete and market.event for a receipt and submitEvent them, wait for vm.terminated, then delete the kept records (records, else found from the receipt: accept, rfp, vm in your repo), its own and the signal records.", "fields": [ { "key": "receipt", "label": "Receipt strong ref", "type": "object", "required": true, "description": "{uri, cid, submitEvent?}: the contract result's receipt." }, { "key": "records", "label": "Kept records", "type": "array", "description": "A kept contract's records to delete; without it they are found from the receipt." }, { "key": "submitEvent", "label": "Receipt submitEvent", "type": "string", "description": "https origin or did#service (default: the receipt's)." }, { "key": "reason", "label": "Reason", "type": "string", "description": "vm.delete reason (default session_ended)." }, { "key": "cleanup", "label": "Clean up", "type": "boolean", "description": "false keeps every record (default true)." }, { "key": "poll_ms", "label": "Poll interval (ms)", "type": "integer", "description": "Re-read interval while waiting (default 3000, max 60000)." }, { "key": "max_polls", "label": "Poll budget", "type": "integer", "description": "Reads per wait before giving up (default 40, max 200)." } ] }, { "entry": "signal", "label": "Signal guest", "description": "Send the VM's guest agent a sealed webrtc offer (or an age publicKey) as signed guest.* and market.event records.", "fields": [ { "key": "receipt", "label": "Receipt strong ref", "type": "object", "required": true, "description": "{uri, cid}" }, { "key": "tag", "label": "Tunnel tag", "type": "string", "required": true }, { "key": "offer", "label": "Sealed offer (age armored)", "type": "string" }, { "key": "key", "label": "age publicKey", "type": "string" }, { "key": "submitEvent", "label": "Receipt submitEvent", "type": "string" } ] }, { "entry": "shell", "label": "Shell on guest", "description": "Run a command on the VM over a host transport: webrtc (the host signals and opens the datachannel; tag ssh; no command just opens it) or iroh (ssh over the guest's iroh ticket, host keys pinned).", "fields": [ { "key": "receipt", "label": "Receipt strong ref", "type": "object", "required": true, "description": "{uri, cid}" }, { "key": "command", "label": "Command", "type": "string", "description": "Required over iroh; none over webrtc just opens the channel." }, { "key": "stdin", "label": "Command stdin", "type": "string", "description": "At most 65536 bytes." }, { "key": "via", "label": "Transport (webrtc or iroh)", "type": "string", "description": "Default webrtc." }, { "key": "tag", "label": "Tunnel tag (webrtc, default ssh)", "type": "string" } ] } ], "config": [ {"key": "bidders", "label": "Bidder DIDs", "type": "array", "description": "The bidders to ask, by DID (at most 10)."}, {"key": "kind", "label": "Compute kind", "description": "vm (a firecracker VM, the default) or deno."}, {"key": "cpus", "label": "vCPUs", "type": "integer", "description": "vCPUs a contract asks for."}, {"key": "mem", "label": "Memory (GiB)", "type": "integer", "description": "Memory a contract asks for, in GiB."}, {"key": "ssh_key", "label": "SSH public key", "description": "Without user_data: root's OpenSSH public key."}, {"key": "shell", "label": "MCP shell", "type": "boolean", "description": "Without user_data: the guest agent's MCP shell."}, {"key": "iroh", "label": "ssh over iroh", "type": "boolean", "description": "Without user_data: dumbpipe in front of sshd."}, {"key": "tunnels", "label": "More tunnels", "type": "array", "description": "Without user_data: datachannel tunnels to local TCP ports, [{tag, port, transport: \"webrtc\"}]."}, {"key": "via", "label": "iroh or webrtc", "description": "The transport a contract waits for."}, {"key": "release", "label": "Release", "type": "boolean", "description": "false keeps the VM after a contract."}, {"key": "poll_ms", "label": "Poll interval (ms)", "type": "integer", "description": "Re-read interval while waiting."}, {"key": "max_polls", "label": "Poll budget", "type": "integer", "description": "Reads per wait before giving up."}, {"key": "reason", "label": "Release reason", "description": "vm.delete reason."} ], "calls": [ "com.atproto.repo.createRecord", "com.atproto.repo.deleteRecord", "com.atproto.repo.getRecord", "com.fedfork.exec.attest", "com.fedfork.exec.webrtc.connect", "com.fedfork.exec.iroh.connect", "com.publicdomainrelay.temp.requester.associateConfirm", "com.publicdomainrelay.temp.market.submitRfp", "com.publicdomainrelay.temp.market.submitAccept", "com.publicdomainrelay.temp.market.submitEvent" ], "hooks": [ { "nsid": "com.publicdomainrelay.temp.market.evaluatePolicy", "required": true, "combine": "all-allow", "default": "policy-requester-tangled-vouch", "reason": "kcp: each bid's bidder in scope mode, then the chosen winner in full mode with the rfp and bid refs, before the accept; every routed policy must allow" }, { "nsid": "com.fedfork.exec.iroh.connect", "reason": "shell and contract with via iroh (the default): the host's iroh transport; a host without it fails that call" }, { "nsid": "com.fedfork.exec.webrtc.connect", "reason": "shell and contract with via webrtc: a host with a webrtc transport (the pages); a host without it fails that call" }, { "nsid": "computer.socialweb.vm.userData", "default": "user-data", "entries": [ "request", "contract" ], "reason": "request and contract without user_data: cloud-init from shell, webrtc_ssh, iroh and ssh_key (the user-data module)" } ], "implements": [ { "nsid": "computer.socialweb.vm.provision", "entry": "contract" }, { "nsid": "computer.socialweb.vm.release", "entry": "release" }, { "nsid": "com.fedfork.market.contract", "entry": "contract" }, { "nsid": "com.fedfork.market.release", "entry": "release" }, { "nsid": "com.fedfork.market.watch", "entry": "watch" } ] }