For a TL;DR; just read the bold text in each section.
Table of Contents
Trust
Trust is an interesting thing. Every day we make many decisions which rely consciously or subconsciously on trust relationships. We outsource fulfillment of various things we need based on these trust relationships.
Let's look at a quick list of some Portland (OR) grocery related examples to make things a little more concrete:
We trust WinCo for produce, but maybe not for meat.
We trust People's for local sourcing, but maybe also not for meat (since they don't carry it).
We trust Costco for meat, but probably not for locally sourcing things.
Now that we've eaten, let's return our focus to compute. Compute Contracts operate within a trust heavy space. Both the requester and the provider have different criteria for trust. We also have different scopes or rings within which we mentally place a provider similar to our food related example above. From the requesters point of view where we land our compute, that is, which provider we choose, can be thought of in a similar way to a privilege ring:
While this isn't a perfect mapping to privilege rings, the concept of concentric rings of trust does apply here. For the sake of example (please do not consider this the final mapping) let's define a few rings:
Self-hosting something falls into Ring 0, since trusting yourself is our baseline for this example.
Our existing Cloud Service Providers (CSPs) fall into Ring 1 from the requester point of view, as we already trust them to run our workloads.
From here on out we enter uncharted territory, we're used to the above, but what else could there be? What should we consider when placing an actor within a trust ring?
Personally knowing someone would place them in a lower ring.
Someone who is morally, legally, fiscally, or otherwise motivated to be trustworthy would place them in a lower ring.
People within your network, for example people you see at your local ATproto meetup, would be in a lower ring.
Random unassociated (anonymous) decentralized identifiers (DID) would be in the highest ring.
The could potentially have a network history corroborated via Transparency Services (RFC9943) which may place them in a higher ring. Think of this as a "review system".
Given these considerations, let's sketch out our rings again:
Ring 0: Self
Ring 1: Known good actors with collective responsibility
CSPs (DigitalOcean, OVH, etc.)
Groups you belong to (pdx.atproto.camp, pdxhf.org)
Ring 2: Known good actors with single points of failure
Your friends
Ring 3: Known good network actors
Other groups you may not belong to but which you know to be reputable.
Ring 4: Unknown good network actors
Watchers/oracles scour the market network and determine trust rankings for anonymous DIDs. Those who have continuously fulfilled their contract obligations get good ratings, those that do not get bad ratings. - This is a dramatic oversimplification of what will be many more blog posts and a lot of continuous work-streams.
Ring 5: Unknown network actors
Shot in the dark, anonymous DID showed up and wants to provide compute, no history of previous contract fulfillment.
Ring N+1:
Your enemies, should have have any (I pray not)
Of course depending on your threat model, you may switch these up a bit as you see fit. But what is your threat model? Well that depends doesn't it! It's highly context dependent. Are you running:
Production web services your business relies on?
Ring 1
Your personal finance application that sees your bank account login info?
Ring 0
Video game server
Rings 0 through 3
AI agents doing software development on:
Proprietary code
Rings 0 through 3
Open source
Rings 0 through N+1 (you'll review the pull request)
The list of course goes on infinitely, since different workloads have different trust requirements for their provider depending on their threat model.
The key here is that because different workloads have different threat models, we have many potential options for providers! We can leverage our social graph help us find the right option for the right job!
Through the looking glass the provider looks back at the requester. What workloads do they want running on their hardware? Different operators are okay with different things. Will your friends let you mine crypto on their spare cycles? Maybe. Will a CSP? Probably not. Workload analysis is a topic we'll cover in the future, as that requires in-depth discussion and deals heavily with supply chain security concepts.
Collectives
Most of our most trusted rings share the property of being collectives. What makes a collective? At the most base level: association. All the machines your favorite CSP runs (mine is DigitalOcean) are associated with that operator. They are a big ol' pool of hardware and the CSP decides which node in their big ol' pool is going to run your Droplet (VM).
An individual actor/entity may also have multiple nodes in a pool and want to associate them with their primary identity, the identity which acts as the Operator of that pool.
We'll cover more on the code involved later in this post, but here's an example of how association can work, it's as simple as one DID owned by the process which will operate as a compute providing node requesting that another DID owned by the operator of the pool create an association record:
We can associate the workloads we run that request compute and the workloads we run that provider compute with our primary account which serves as the Operator.
When we request compute or bid on contracts to provide compute we can operate in any number of policy modes:
For our pre-Alpha release we've implemented only the above modes for now. Since those can help us operates within the core rings we defined above for a minimal Proof of Concept (PoC).
An organization wishing to distribute compute to it's members can leverage the tangled-vouch or mutuals policy modes today. The org needs only follow the person back on BlueSky or vouch for them on Tangled and any contract bidders the organization runs will know that that they should bid to provide on contracts their org members request.
Market Flow
The Market Flow makes all this possible. It's a bit different from your traditional "listing of things people can by" because compute capacity inherently involves a liveness check.
The flow is:
Request For Proposal (RFP)
Bid
Accept
Receipt
These are all ATproto records with published lexicons. They currently live under com.publicdomainrelay.temp.market.* but they probably belong in some more market specific NSID long term, but for now that's where they are.
Each record references the previous records, they also have badge.blue attestations over them to help us know which DID associated with which operator minted them (since some bidders and requesters are ephemeral and their PDS won't be around post-flow).
When we watch the flow over the firehose we can make a nice graph of how the nodes are connected, since they're just some data with a lot of strongRefs:
Workload Identity
One thing you might be wondering is: what about secrets? If we createRecord everything and put it on-protocol, then where does that leave secrets? Why my dear friend I'm so glad you asked!
Workload identity has the cure for us! Within the market flow is buried the hidden treasure of bidConfig, it's a strongReference to an object which describes how, if accepted, the bidder will configure workload identity. This allows the requester to pre-configure services which they want their workload to have access to prior to issuance of the accept or requesting provisioning and receipt.
In an earlier iteration of the networking setup, we were using this along with a Personal Data Server (PDS) OIDC reverse proxy to enable the workload to directly call createRecord with only a specific payload (as validated by JSON schema over POST body):
There's probably some fun to be had tying atproto and https://openid.net/specs/openid-federation-1_0.html together into something fun...
Networking
Right now there are three options for networking:
Public internet
Reverse proxy relay
Firehose/jetstream/atproto-relays
Obviously if you put everything on the public internet with real FDDNs that's cleanest. Of course we're talking about hosting custom compute here so that's mostly out the window, unless you're using the DigitalOcean provider that's currently implemented.
For all self-hosted options, we have two primary ways of communicating right now. The first of which will be replaced with iroh.computer which is better and serves the same purpose, the second of which is basically just watching the firehose.
If we run a bidder or requester on the public internet or accessible via relay/reverse-proxy, we add submitBid, submitAccept, submitEvent to respective records, and can call the bidder or requester service directly via XRPC or service proxied XRPC calls.
Finally, one can just call createRecord and as long as your PDS is being crawled by a relay which will forward the market collection NSIDs, you'll see the records over the firehose. BlueSky accounts on BlueSky PDSs with the --atproto-oauth-qr code will work this way.
Code
Uh, so, the code... ya the code has gone through several iterations. Would I say I love it? Absolutely not. Would I say it gets the job done. Sure ya I guess.
The code needs to be significantly more ergonomic than it is today. But we'll get there. Having a PoC codebase that's been abstracted enough allows for in incremental re-write.
After all, the whole thing is loosely coupled! The protocol is what matters, the code is whatever.
If you'd like to see insomniac commits, go nuts, here's the repo: https://github.com/publicdomainrelay/org-root-dispatcher-typescript
If you want to wait until things get ironed out a bit - that's what I'd recommend. But please do play with it! Just don't expect any ergonomic non-HTTP/CLI interfaces to play with at the moment. HTTP and CLI interfaces are pretty solid right now I'd say, although undoubtedly will be subject to shape changes.
Further Applications
One could imagine a world where more than just compute could be automatically distributed. At a glance, applications which lend themselves well to the market flow include:
In such a world, when you need sugar for a recipe you're cooking up with pantryhost.app, your neighbor could be operating a bidder which says "Hey, I have that!".
Say you needed a bookshelf, you could submit a Request For Proposal (RFP) and the gifthood.community bidder could come back with one for bids.free. The openmkt.app might come back with several options for bids.cash or bids.x402.
The possibilities here are exciting! Transparency in supply chains combined with automated fulfillment could create a network effect of mutual aid!
What's Next
Needless to say, there is plenty of work cut out of us. Here are a few high value targets:
Networking
Replace our custom xrpc.fedproxy.com key dialing with iroh.computer based approach.
Virtualization Ease of Use and Hardening
Container hosting is the easiest thing to run right now
VM hosting requires building a squashfs which is finicky but I think working right now
Deno Workers but ATproto native
A lot of work on this has been sketched out, and the bidder itself will happily run as a Deno worker deployed via the compute contract flow of a bidder (bidception)
Ephemeral Deno workers will REALLY open up what we can do here, as they cost nothing to host when they're not running.
Of key importance here is where their state is stored, if anywhere, when they're not running
Policy Modes
Dynamic policies and policy engines
Focus on how we carry the policy through chains of RFPs
What if we requested a
compute.database? Could a bidder RFP a subsequentcompute.vmto host that database? Would the requester be able to ensure the RFP chain adheres to it's values/policies?
Refactor for code-level-API ergonomics
This will enable building market flows for arbitrary NSIDs super easy. It's already abstracted a bit it's just a little disgusting looking still and needs to be cleaner before we should recommend anyone go playing with it.
The future looks bright. And it's exciting watching the ATmosphere grow. A future where resource sharing is easy and auto-optimized is ahead of us, and as we all know sharing is caring! We'll cross this bridge together, and on other side will be a whole lot of caring for one another.