Capability Trees: A proposal for an ATProto native capabilities system

I have two leaflets to present here.

The proposal itself: Capability Trees: A Protocol-Level Extension of Object Capabilities, Draft 2

Why capabilities are better than ACLs: Authority as Possession: Permissioned Spaces Deserve Better Than ACLs

1 Like

@ngerakines.me I think I solved your revocation problem

Me and @meri.garden were talking yesterday about a design built on the permissioned data diary leaflet, and we actually ended up with something that shares similarities to what you’re describing @holobrine.bsky.social.

In the permissioned data proposal, access to a space is controlled by the membership list that is owned by the space creator.

The membership list allows you to map user IDs to read or write access and significantly, the proposal allows you to use any means you would like to produce that membership list.

Our idea is to have a service we call the “Arbiter” that is meant to be the space host, i.e. it creates the space and maintains the member list.

But to produce the final membership list, we wanted to layer on the concept of roles. Roles are very similar to spaces, in that they have a membership list, and they can in fact have the membership list queried identically to the way you query the membership list of a space.

The difference is that we add additional APIs so that you can say, “this role/space contains all the members of another role/space”.

There might not be any real distinction between a role and a space on the Arbiter, other than the fact that the feature of adding a role as a member to another role is something that our Arbiter adds as an extra feature and can’t be expected to exist in every permissioned space host.

Often times when you say, “this space can be accessed by anyone in this role” you will be referring to a role that is hosted on the same arbiter, but it is also possible that you say, “this space can be accessed by anyone in this role on another arbiter”.

This acts as a delegation of sorts, allowing another arbiter to add members to your role, which you may then add as a member of a permissioned space.

That aspect of delegating, allowing some other service to contribute to your role’s member list, is where things are similar to what you are talking about with your delegation chain.


There are differences of course. Because any role may delegate it’s members to another arbiter’s role, it may result in a chain of HTTP requests between arbiters to resolve the member list. These requests will most-likely need to be cached with a TTL or something like that, very similar to DNS. So updates to the member lists in 3rd party arbiters may not propagate instantly.

We could potentially supplement this system with a mechanism for realtime notification of member list changes.

Also there needs to be a way to break / detect cycles. A simple depth limit + tracking the chain might be enough.


I read through this and I undestand to some extent what you’re saying, but I’m also not understanding exactly makes the capability scheme you’re outlining much different.

The community space ID has to come from somewhere, and even in a capability model, your root of trust has to lie somewhere. If this is enforced cryptographically, there has to be some place to “capture” that authority’s private key. Unless you use something like FROST which is still a cryptographic measure that cannot encode a community charter.

I think maybe what you’re getting at is an inversion of “me giving you access to this data” instead of the space owner creating the place for you to put data that the group has access to?

It sounds like maybe you’re saying that a user stores all their private data repos, and then selectively delegates those to others?

The main difference then with the current proposal would be that it’s possible to delegate the same permissioned data of yours to multiple different spaces?

I think I need some more consice, concrete examples of scenarios to understand what you’re saying.


This is also somewhat related to what @meri.garden wrote here:

One of the concerns with the permissioned data proposal is that it’s a little hard to move data from one space to another.

It sounds like what you’re saying is something like, “you don’t have to move the data to a new space, you just create a new delegation”, and that does seem like it might have advantages if you want your data to be able to live in multiple spaces.

But we are also dealing with content-addressed storage, so maybe that is not all that different than copying your records from one space to another space so that the copy exists in both? The data isn’t actually duplicated, you’re just copying the hashes.

Migrating from one compromised space to another by copying the set of hashes may not be much different than what you’re describing of creating a new delegation to a new circle identity.


Putting data in a permissioned space is a delegation you are maing to the space owner: “I’m delegating read access to the permissioned space owner and allowing them to further delegate that access to any other member of this space”.

The design me and @meri.garden were discussing yesterday extends that by allowing the space owner to further delegate access to other member lists on other arbiters, or potentially any other service that implements the member list XRPC endpoint.


Sorry for the long post. I may be misunderstanding your proposal or getting some things wrong. I do think it’s an interesting direction, but it seems like maybe the permissioned data proposal isn’t actually structurally flawed, and maybe what you want to accomplish can be done essentially as easily within the bounds of the permissioned space proposal.

Maybe it would be good to define some specific scenarios you’re concerned about as a “test case” to see concretely how that would look differently in your system and permissioned spaces.

1 Like