Radish alpha
r
rad:z3trNYnLWS11cJWC6BbxDs5niGo82
Radicle Improvement Proposals (RIPs)
Radicle
Git
RIP 5: Agent Repository
Draft fintohaps opened 1 year ago
1 file changed +726 -0 329dee9a 9973e232
added 0005-agent-repository.md
@@ -0,0 +1,726 @@
+
---
+
RIP: 5
+
Title: Agent Repository
+
Author: '@fintohaps <fintan.halpenny@gmail.com>, @lorenz <lorenz@leutgeb.xyz>'
+
Status: Draft
+
Created: 2024-10-23
+
License: CC0-1.0
+
---
+

+
RIP #5: Agent Repository
+
========================
+
This RIP introduces the concept of an agent repository, a specialized kind of
+
repository, into the Heartwood protocol. The aim is to define a repository that
+
can represent agents in the network, holding any required metadata that helps
+
define this agent.
+

+
An *agent* is any entity that we want to identify uniquely, interacting
+
with others on the Radicle network. Human users are considered agents, but we
+
also consider computers as agents, e.g. CI/CD systems, security bots, etc.
+

+
Overview
+
--------
+
In the main section, [Agent Repository](#agent-repository), we define what agent
+
repositories are, comparing and contrasting them to the existing project
+
repositories. In particular:
+
 1. How [Repository Identity](#repository-identity) differs from project
+
    repositories, introducing the new `xyz.radicle.agent` payload.
+
 2. Which special [References](#references) agent repositories contain, how they
+
    relate to DIDs and the Heartwood protocol.
+
 3. How agent repositories interact with
+
    [Signing and Verification](#signing-and-verification).
+

+
In [Referencing Agent Repositories](#referencing-agent-repositories) we discuss
+
methods of cross-referencing agent repositories from other repositories. Two
+
alternative method are suggested: [Git References](#git-references) and [Gossip
+
Protocol](#gossip-protocol).
+

+
Finally, we hint at [Future Work](#future-work). In particular how agent
+
repositories could be extended to support KERI and how they will enable support
+
for associating multiple devices with one agent.
+

+
Table of Contents
+
-----------------
+
1. [Overview](#overview)
+
2. [Motivation](#motivation)
+
3. [Agent Repository](#agent-repository)
+
   - [Repository Identity](#repository-identity)
+
     - [Agent Payload](#agent-payload)
+
       - [Controller](#controller)
+
       - [Profile Information](#profile-information)
+
     - [Lifecycle](#lifecycle)
+
       - [Create](#create)
+
       - [Update](#update)
+
       - [Delete](#delete)
+
     - [Verification](#verification)
+
     - [Historical Verification](#historical-verification)
+
   - [References](#references)
+
     - [DID Namespace](#did-namespace)
+
       - [DID Methods](#did-methods)
+
         - [DID Document](#did-document)
+
         - [Example: `did:key`](#example-didkey)
+
         - [Example: `did:keri`](#example-didkeri)
+
     - [Radicle Namespace](#radicle-namespace)
+
       - [Example: Multi-Device](#example-multi-device)
+
   - [Signing and Verification](#signing-and-verification)
+
4. [Referencing Agent Repositories](#referencing-agent-repositories)
+
   - [Git References](#git-references)
+
     - [Lifecycle](#lifecycle)
+
       - [Create](#create-1)
+
       - [Read](#read)
+
       - [Update](#update-1)
+
       - [Delete](#delete-1)
+
   - [Gossip Protocol](#gossip-protocol)
+
     - [Lifecycle](#lifecycle-1)
+
       - [Create](#create-2)
+
       - [Read](#read-1)
+
       - [Update](#update-2)
+
       - [Delete](#delete-2)
+
5. [Future Work](#future-work)
+
   - [did:key Agent Repository](#didkey-agent-repository)
+
   - [KERI Agent Repository](#keri-agent-repository)
+
   - [Multi-Device](#multi-device)
+
6. [Appendix](#appendix)
+
   - [JSON Schema](#json-schema)
+
7. [Copyright](#copyright)
+
8. [References](#references)
+

+
Motivation
+
----------
+
The motivation for this RIP is to define the foundational element of the agent
+
repository, to enable us to further work on more refined approaches to user
+
identity and multi-device support – this RIP aims to set the stage for these
+
future RIPs.
+

+
The initial approach was exploring how to approach multi-device support, and
+
after some thought and discussions, we decided that it would be best to define
+
multiple RIPs in order to achieve our end goals.
+

+
The agent repository came from the idea that we have a generic component that
+
only needs minimal definition, specified here, and leaves room for extension
+
points for later RIPs – including KERI and multi-device support.
+

+
Furthermore, the agent repository as defined here may be used without
+
these new, future components, i.e. it integrates with our
+
existing `did:key` mechanisms.
+

+
Agent Repository
+
----------------
+
An Agent Repository is a Radicle repository as specificied in RIP-2[^rip-2].
+
This implies that it is stored the same way as per RIP-3[^storage-layout], and
+
contains an identity document. The identity document is extended with a new
+
payload (see [Agent Payload](#agent-payload)).
+

+
The purpose of an agent repository is to store and replicate the relationship
+
between the agent and a DID[^did] it is using to identify itself, along with any
+
metadata that is useful to the protocol and tooling built on top of Heartwood.
+

+
In this RIP, we establish a new kind of repository in the Heartwood protocol,
+
which specifically aims to represent agents within the Heartwood protocol. An
+
agent can be any entity that we want to identify uniquely, and which takes
+
actions within the protocol. The most common use case of an agent repository
+
will be for the concept of a user or user persona, e.g. I can identify myself as
+
`alice` for this project, but I may want to establish and use a different
+
persona – by creating a separate agent repository – for some other projects.
+
Other use cases we may want to consider are CI/CD agents that will have
+
permission to merge patches into projects. We leave the potential up to your
+
imagination, and only define the necessary foundations here.
+

+
At a high level, the relation between DIDs of agents to RIDs of agent repository
+
*at a given point in time* is a partial function. By changing the DID associated
+
with an agent (discussed below), the function may change over time. However, it
+
is:
+
 * *surjective*: When creating an agent repository, it must be created *for a
+
   particular DID*. While it is possible to change the associated DID to a
+
   different one, i.e. the RID mapped to by a DID may change over time, it is
+
   not possible to completely dissociate an agent repository from a DID.
+
 * *injective*: A DID is in relation with *at most one* RID (note partiality).
+
   Creating two or more agent repositories for the same DID is not supported.
+

+
Note that there's no hope for totality here: for backwards-compatibility, we
+
cannot require DIDs with the DID method `did:key` to map to an RID. Also,
+
Radicle will likely only support a very small number of DID methods.
+

+
In [Referencing Agent Repositories](#referencing-agent-repositories), a refined
+
version of this relation is established, clarifying changes over time.
+

+
### Repository Identity
+
As mentioned, the agent repository is still a Heartwood repository, which means
+
it has an RID and an identity document. In its current state (as of
+
RIP-4[^canonical-refs] Canonical References), the identity document requires a
+
`delegates` field and a set of values. Previously, this would be expected to be
+
filled with `did:key` DIDs. However, with the advent of the agent repository –
+
and attempting to support multiple DID methods – the underlying DID method can
+
and should be used in this field. It is recommended to set `delegates` to a
+
singleton, containing only the DID of the agent, but it is not forbidden to add
+
other DIDs to the set.
+

+
Note that it is not sufficient to add DIDs to the set of delegates in order to
+
link them to the agent repository – we discuss the association of the DID to the
+
agent repository in the [Controller](#controller) section.
+

+
#### Agent Payload
+
Similarly to the `xyz.radicle.project` payload for defining metadata about the
+
project, we define an `agent` payload, under `xyz.radicle.agent`, which can
+
hold metadata about the agent. We define this payload as follows (with the [JSON
+
Schema](#json-schema) provided):
+

+
```json
+
    {
+
      "xyz.radicle.agent": {
+
        "controller": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
+
        "alias": "alice"
+
      }
+
    }
+
```
+

+
The fields and their values are described as follows:
+

+
- The `controller` field specifies the current, controlling DID of the agent
+
  repository, explained further in the [Controller](#controller) section below.
+
- The `alias` field is a name or nickname for the agent, represented by a
+
  string, which can be no longer than 32 characters. We also restrict the string
+
  to reject any whitespace or control characters – a regular expression is
+
  provided in [JSON Schema](#json-schema).
+

+
##### Controller
+
The controller DID, i.e. the contents of the `controller` field, is the DID of
+
the agent controlling the repository. By ensuring it holds exactly one DID, we
+
achieve injection of the (time-dependent) partial function from DIDs to RIDs of
+
agent repositories.
+

+
The `controller` for the repository may be updated to a new DID by updating the
+
payload – given the update adheres to the verification of the repository
+
identity. We mandate that when the `controller` is updated, the `delegates` of
+
the repository are also updated to include the new `controller` – either by
+
adding the new DID to the set or replacing the old DID with the new one.
+

+
As well as this, the DID of the `controller` must be defined in the agent
+
repository as a [DID Namespace](#did-namespace).
+

+
##### Profile Information
+
As this RIP is concerned with the foundational definition of the agent
+
repository, it avoids discussing any social metadata as part of the
+
specification. Instead, we encourage the specification of another RIP to define
+
something like a `xyz.radicle.profile` payload that can be used across different
+
user facing tools. This could include metadata such as avatars and website URLs
+
to other social sites. We also note that the DID specification also allows for
+
this kind of metadata using the [`alsoKnownAs`][^also-known-as] property of the
+
DID document.
+

+
#### Lifecycle
+
In this section we briefly specify the lifecycle of an agent repository, in
+
particular its association with a DID.
+

+
##### Create
+
Creation of an agent repository requires the same steps as creation of a project
+
repository[^identity-storage]. In addition, the identity document must contain
+
the controlling DID under both the `delegates` field and the `controller` field,
+
within the agent payload. The agent payload also defines an `alias` for this
+
agent.
+

+
##### Update
+
Updating the repository is also subject to the requirements for updating a
+
Heartwood repository identity, such that it passes verification. As mentioned in
+
[Controller](#controller), we also require that when changing the DID of the
+
`controller` field, it must also be inserted into the `delegates` field of the
+
repository identity – whether it replaces the old DID or is added alongside the
+
old DID.
+

+
##### Delete
+
As of writing, there is no mechanism to delete repositories in Radicle.
+
Therefore we do not specify any deletion mechanism. When such a mechanism is
+
introduced in the future, we expect this deletion mechanism to apply to agent
+
repositories too. The deletion of a an agent repository should cause removal
+
of references to the agent repository, see corresponding sections within
+
[Referencing Agent Repositories](#referencing-agent-repositories).
+

+
#### Verification
+
The verification of an agent repository follows the verification of any
+
Heartwood repository[^identity-verification]. Furthermore, it must also verify
+
that:
+
 * the DID is the controller of the agent repository, i.e. the repository
+
   contains an [agent payload](#agent-payload), and the contents of the
+
   `controller` field of the payload match the given DID.
+
 * the DID is an element of the set of `delegates`.
+

+
#### Historical Verification
+
To verify that a given DID was the controller of a given agent repository
+
for a given commit, ensure that the commit is an ancestor of `rad/id`, and
+
carry out the verification procedure above for the repository identity *at
+
that revision*.
+

+
If the commit is omitted, then the verifier must assume the latest commit of the
+
`rad/id`. This is necessary to avoid any attacks from compromised DIDs.
+

+
### References
+
We have established that an agent repository is similar to that of a project
+
repository. In the upcoming sections, we will discuss the reference layout
+
required for an agent repository and what is expected to exist within its
+
namespaces.
+

+
The existing layout[^layout-section] will still apply, copied below:
+

+
    <storage>
+
    └─ <rid>                    # The "physical" Git repository
+
       └─ refs
+
          └─ namespaces         # All forks are stored under this namespace
+
             ├─ <nid>           # One peer's fork is stored here
+
             │  └─ refs
+
             ├─ <nid>           # Another peer's fork is stored here
+
             │  └─ refs
+
             └─ <nid>           # Etc.
+
                └─ refs
+

+
We introduce a new reference namespace `did`, and extend the `rad` namespace, in
+
[DID Namespace](#did-namespace) and [Radicle Namespace](#radicle-namespace). It
+
is expected that canonical reference rules are defined to allow the promotion of
+
these namespaces to the top-level `refs`.
+

+
#### DID Namespace
+
According to the specification of Decentralized Identifiers (DIDs)[^did], a DID
+
is separated into three parts, separated by colons:
+
`did:<method-name>:<method-specific-id>`.
+

+
The namespace we introduce here resembles this structure:
+
`refs/did/<method-name>/<method-specific-id>`. It is specific to a particular
+
DID method[^did] and its required metadata. The `<method-name>` defines the
+
placeholder name for the kind of DID method that this agent is using and the
+
`<method-specific-id>` refers to the the DID method's specific ID. The contents
+
of this namespace are discussed in the next section.
+

+
Below is an example of what the storage layout looks like given the new DID
+
namespace[^git-ref-format]:
+

+
    <storage>
+
    └─ <rid>                                       # The "physical" Git repository
+
       └─ refs
+
          ├─ rad
+
          │   └─ id                                # Canonical identity reference
+
          ├─ namespaces                            # All forks are stored under this namespace
+
          │  └─ <nid>                              # Another peer's fork is stored here
+
          │     └─ refs
+
          │        └─ did                          # All DID relevant material
+
          │           └─ <method-name>             # The DID method name
+
          │              └─ <method-specific-id>   # The unique identifier for this DID method
+
          │                 └─ ...                 # Any references required for the DID method
+
          └─ did                                   # The canonical reference namespace for the DID
+
             └─ <method-name>
+
                └─ <method-specific-id>
+
                   └─ ...
+

+
##### DID Methods
+
The agent repository is not prescriptive about the references inside the `did`
+
namespace. The namespace is simply reserved so that methods can effectively use
+
them for storing metadata and helping to resolve to a DID document, or providing
+
other data for cryptographic operations.
+

+
When a `method` for an agent repository is proposed it must define the
+
references that are stored under this namespace, and what the contents of those
+
references are, i.e. Git tags, commits, trees, and blobs.
+

+
###### DID Document
+
Since the DID specification specifies that methods are associated with DID
+
documents[^did-architecture], it is recommended that a well-known reference is
+
defined to store the document. This reference is recommended to be named
+
`refs/did/<method-name>/<method-specific-id>/document`.
+

+
###### Example: `did:key`
+
The simplest example of a DID method as an agent repository is `did:key`.
+
DIDs take the shape `did:key:<mb-value>`[^did-key].
+
The reference scheme could be proposed as:
+

+
    <storage>
+
    └─ <rid>
+
       └─ refs
+
          └─ did
+
             └─ key
+
                └─ <mb-value>
+

+
The `<mb-value>` is the latter portion of `did:key:<mb-value>`, and this is
+
already enough information for obtaining the corresponding public key.
+
Optionally the DID document could be pointed to by that reference, otherwise it
+
could be an empty Git commit.
+

+
###### Example: `did:keri`
+
To give a taste for a more complex DID method, an agent repository could be
+
instantiated as a `did:keri` repository. The reference scheme may be proposed
+
as:
+

+
    <storage>
+
    └─ <rid>
+
       └─ refs
+
          └─ did
+
             └─ keri
+
                └─ EXq5YqaL6L48pf0fu7IUhL0JRaU2_RxFP0AL43wYn148
+
                   └─ kel
+

+
The `kel` is the KERI Event Log (KEL), which can be used to check the state of
+
the KERI entity.
+

+
The signing and verification of data is completed via the specified approach in
+
the KERI spec[^keri-spec], via the KEL.
+

+
#### Radicle Namespace
+
A second Git namespace is also reserved for any Heartwood specific extensions to
+
the agent repository. This namespace is reserved under the existing `rad`
+
hierarchy as `rad/<module>`, and looks like the following:
+

+
Below is an example of what the storage layout looks like given the new
+
`rad/<module>` namespace:
+

+
    <storage>
+
    └─ <rid>                        # The "physical" Git repository
+
       └─ refs
+
          ├─ rad
+
          │   ├─ id                 # Canonical identity reference
+
          │   └─ <module>           # Canonical module namespace
+
          │      └─ ...
+
          └─ namespaces             # All forks are stored under this namespace
+
             └─ <nid>               # Another peer's fork is stored here
+
                └─ refs
+
                   └─ rad
+
                      └─ <module>   # The name of the Heartwood protocol module
+
                         └─ ...     # Any references required for the method
+

+
This RIP does not propose any material to go under this namespace – it merely
+
sets it up for further use. We will propose an example, in the next section,
+
which will be further developed in a future RIP.
+

+
###### Example: Multi-Device
+
We plan to use the `rad/multidevice` hierarchy to propose a multi-device
+
approach. That is, we plan to use references to associate nodes to an agent so
+
that when an agent works on different devices, their device keys can be unified
+
under their agent identity. The current thoughts on the reference hierarchy is
+
to have something like the following, but is subject to change:
+

+
    <storage>
+
    └─ <rid>
+
       └─ refs
+
          ├─ rad
+
          │   ├─ id
+
          │   └─ multidevice
+
          │      ├─ nodes              # All nodes currently associated with the agent
+
          │      │  ├─ <nid>           # A node associated with the agent
+
          │      │  └─ <nid>           # A second node
+
          │      └─ revoked            # Revoked nodes
+
          │         └─ <nid>           # A revoked node
+
          └─ namespaces                # All forks are stored under this namespace
+
             └─ <nid>                  # Another peer's fork is stored here
+
                └─ refs
+
                   └─ rad              # All DID relevant material
+
                      └─ multidevice   # The method name for categorisation
+
                         ├─ nodes      # All nodes currently associated with the agent
+
                         │  ├─ <nid>   # A node associated with the agent
+
                         │  └─ <nid>   # A second node
+
                         └─ revoked    # Revoked nodes
+
                            └─ <nid>   # A revoked node
+

+
### Signing and Verification
+
It is required that the DID method defines the way in which it signs data
+
payloads and verifies signatures. For example, if the method resolves to a DID
+
document, and that document contains verification methods, then one of these can
+
be used to perform verification.
+

+
This means that the signing and verification are a black box, when it comes to
+
the protocol using an agent repository for signing and verification. The
+
standard API for this signing and verification is inspired by the
+
`signature`[^signature-crate] crate, from the Rust ecosystem. The crate provides
+
two traits, `Signer`[^signature-signer] and `Verifier`[^signature-verifier]. The
+
former defines a method `try_sign`, which attempts to sign the bytes provided,
+
noting that it can fail. The latter defines a method `verify` which attempts to
+
verify the bytes and signature provided, and only returning `Ok(())` if it
+
succeeded. It is important to note that the signature here is kept generic. DID
+
methods will differ in their signature outputs, and in fact, they may have
+
complex signature schemes, for example, multi-signature schemes.
+

+
We want to avoid arbitrarily executing signing and verification operations of
+
DID methods within clients of the protocol. This means that new DID methods for
+
agent repositories must be first proposed as their own RIP, so that the signing
+
and verification methods can be audited, and implemented as part of the
+
protocol.
+

+
The Heartwood protocol already makes heavy use of `ssh-agent`, so new DID
+
methods may easily use this approach when it comes to signing data.
+

+
Referencing Agent Repositories
+
------------------------------
+
Agent repositories will become an important part of the Heartwood protocol.
+
For one, it will be a way to unify the view of a single user across multiple
+
devices. This means that it will be important to be able to look up an agent
+
repository from other repositories. In this section we will present a
+
standardized way of achieving this, which repository implementations must use.
+

+
In the following sections we will explore two approaches to being able to
+
reference agent repositories from other repositories, discussing the pros and
+
cons of each. However, we decided that [Gossip Protocol](#gossip-protocol) is
+
the approach we will take, and leave the other options for posterity.
+

+
The high level relation between DIDs and RIDs mentioned in
+
[Agent Repository](#agent-repository) is not precise with regards to changes
+
over time. However, we have mentioned in
+
[Historical Verification](#historical-verification) how to verify the relation
+
between DID and RID across time. In order to capture change over time, when
+
referencing agent repositories, we not only include the RID, but also the hash
+
of a commit in the agent repository – where the commit is either the tip of the
+
`rad/id` reference, or is an ancestor of this tip.
+

+
### Git References
+
A first approach to this problem is by further utilizing the underlying Git
+
storage of the Radicle storage[^storage-layout]. When a node is using an agent
+
to perform an action, e.g. creating a new COB, it will create an entry in its
+
namespace hierarchy that records the DID, RID of the agent repository, and the
+
commit of the `rad/id` reference at the given time.
+

+
The name of the reference will follow the pattern
+
`did-<method-name>-<method-specific-id>`, e.g.
+
`did-keri-EXq5YqaL6L48pf0fu7IUhL0JRaU2_RxFP0AL43wYn148`,
+
`did-key-z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM`,
+
`did-dns-danubetech.com`, etc.
+

+
This means that the reference layout in a repository that is referencing the
+
agent looks like the following:
+

+
    <storage>
+
    └─ <rid>                           # The "physical" Git repository
+
       └─ refs
+
          └─ namespaces                # All forks are stored under this namespace
+
             ├─ <nid>                  # One peer's fork is stored here
+
             │  └─ refs
+
             │     ├─ did-key-<suffix> # A did:key repository agent
+
             │     └─ ...
+
             └─ <nid>                  # Another peer's fork is stored here
+
                └─ refs
+
                   ├─ did-key-<suffix>
+
                   └─ ...
+

+
The reference points to a Git commit that contains a Git tree, and that tree
+
points to a single Git blob, `rid`. The `rid` blob contains the RID in
+
plain-text, as well as the commit of the `rad/id` reference, e.g.:
+

+
    rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji 0ca42d376bd566631083c8913cf86bec722da392
+

+
#### Lifecycle
+

+
##### Create
+
When someone wants to advertise their DID in another repository, for example
+
when creating a patch for a project, a reference is created in the repository:
+

+
    refs/namespaces/<nid>/refs/did-<method-name>-<method-specific-id>
+

+
This reference must point to a commit, which is initialized with a single tree
+
that points to a single blob, named `rid`. The contents of which are defined
+
above.
+

+
Note that this reference should not be updated to point to a new RID. This would
+
invalidate the fact that a DID and RID have a one-to-one relationship.
+

+
When another node wants to verify the DID, it will perform the lookup of this
+
reference, resolve the RID to the repository, and perform the
+
[Verification](#verification) of the DID in the agent repository. If the
+
verification fails, it may decide to not create the reference instead.
+

+
Note that multiple entries for the DID reference may be created under different
+
node namespaces, i.e. `refs/namespaces/<nid>`. It is expected that these should
+
all point to the same RID.
+

+
##### Read
+
To read a mapping from DID `did:example:id` to RID ("lookup"), iterate over all
+
references of the form `refs/namespaces/<nid>/refs/did-example-id`. From these
+
references extract the respective RIDs. Validate all RIDs according to the
+
conditions mentioned in [Validation](#validation) below, removing all RIDs that
+
fail validation. If there are multiple candidate RIDs left, the program should
+
fail and report the discrepancy.
+

+
Note that implementations may choose to penalize nodes that have announced
+
mappings that failed validation.
+

+
##### Update
+
Updating a DID for a given agent repository means that when the user wants
+
advertise the new DID in another repository, they create a new
+
`did-<method-name>-<method-specific-id>` reference that points to the same RID
+
as the previous DID, but with the updated commit of the `rad/id` – which must
+
contain the new controller.
+

+
The old reference should be kept, in order for it to be used in lookups, since
+
it may be included historical data.
+

+
The same verification principles apply, as in the previous section.
+

+
We also allow updating the entry to maintain the same RID and DID pair, but
+
changing the commit SHA of `rad/id`, when this reference is updated.
+

+
##### Delete
+
Deletion of the DID is strongly discouraged, since it may be referenced in data
+
that is being circulated, and will also prevent any chance of verification from
+
that DID.
+

+
However, to remove the DID from the repository, the references under each
+
`refs/namespaces/<nid>` that match that DID can be removed.
+

+
### Gossip Protocol
+
One approach to finding out which RIDs identify which agents is through the
+
gossip protocol. A new gossip message is introduced that advertises which RID is
+
associated with a particular DID. We can think of this as another kind of
+
address book. The message has the following shape:
+

+
    AgentAnnouncement = (
+
        Did,
+
        RepoId,
+
        Commit,
+
    )
+

+
It contains the DID which is controlling the agent repository, which is
+
identified by the `RepoId` (RID), and the commit that is the tip of the `rad/id`
+
reference at the time.
+

+
Nodes broadcast this message when they are made aware of this pairing. In the
+
case of the node that created the agent repository, it can be broadcasted to the
+
network immediately. This message is relayed and propagated to the rest of the
+
network. If a node comes across a DID they are not aware of, then they would
+
send a request to the network to find out the RID and DID pair.
+

+
This information would be stored alongside the rest of the other network
+
information that is recorded, e.g. in an SQLite database.
+

+
We also add a second message, for querying other nodes about a DID:
+

+
    AgentQuery = (
+
        Did,
+
    )
+

+
#### Lifecycle
+

+
##### Create
+

+
###### Initial Announcement
+
In the first case, a node will want to create an entry for an RID and DID pair
+
when the node itself is creating the agent repository for the given DID. The
+
node can then construct the gossip message, defined above, and broadcast it to
+
the network.
+

+
Any node must not advertise an RID and DID pair where the same DID points to two
+
different RIDs. This violates our one-to-one relationship, stated in
+
[Agent Repository](#agent-repository).
+

+
###### Forwarding
+
The other case is when a node receives a gossip message about the RID and DID.
+
The node may record this entry and should verify that the association is correct
+
– by fetching the repository and performing the verification (see
+
[Verification](#verification)) of the agent repository. This prevents nodes
+
attempting to spoof DID and RID pairings – the DID controller of the agent
+
repository can sign changes, and thus can also be verified via the same DID.
+

+
If a node receives multiple messages for the same DID but different RIDs,
+
then it must accept, at most, one of them.
+

+
##### Read
+
When a node wants to find out which agent repository is represented by a given
+
DID, it will first lookup the entry in the storage mechanism it is using for
+
keeping track of gossip data. If there is an entry, it must be the RID for the
+
agent repository that this DID is associated with – the node should only persist
+
these pairs if the DID verifies with the given RID.
+

+
Otherwise, if there is no such entry, the node may gossip to the network, asking
+
for this information – verifying any responses it may receive.
+

+
##### Update
+
To update an RID with a new DID, the advertising node should update their
+
storage with the new entry – given that it is verifiable – and may relay the new
+
pair via the gossip message.
+

+
The same verification criteria applies to updating as it does for creation.
+

+
We also allow updating the commit of the entry, when the `rad/id` reference changes.
+

+
##### Delete
+
Deletion of the DID is strongly discouraged, since it may be referenced in data
+
that is being circulated, and will also prevent any chance of verification from
+
that DID.
+

+
If it is necessary, then the entry in the storage may be deleted. This may be
+
useful if the controller of the DID has created two separate RIDs and wants to
+
converge on using only one – however, there are better methods for this, like
+
updating the original agent repository instead.
+

+
The message for this is to send the `AgentAnnouncement` message with a zeroed
+
commit. The node may decide to accept the message and delete the entry, however,
+
it must originate from the DID controller.
+

+
Future Work
+
-----------
+

+
### `did:key` Agent Repository
+
We will use this RIP and define an agent repository specification for the
+
`did:key` method, ensuring that we can use agent repositories in our current
+
state – keeping compatibility with the existing architecture.
+

+
### KERI Agent Repository
+
This RIP only goes as far as specifying the agent repository, however, it will
+
be important for the protocol to have its first instance of an agent repository
+
and integrate one into the protocol. Riding on the coat tails of this RIP, will
+
be a RIP that defines an implementation that is based on the KERI
+
specification[^storage-layout].
+

+
### Multi-Device
+
As well as this in [Radicle Namespace](#radicle-namespace), we mentioned the
+
concept of being able to manage multiple devices under the same persona. This
+
RIP carved out the reference space for associating keys within an agent
+
repository, and the details of this approach will be specified in a future RIP.
+

+
Appendix
+
--------
+

+
### JSON Schema
+

+
```json
+
    {
+
      "$schema": "http://json-schema.org/draft/2020-12/schema",
+
      "type": "object",
+
      "properties": {
+
        "xyz.radicle.agent": {
+
          "type": "object",
+
          "properties": {
+
            "alias": {
+
              "type": "string",
+
              "maxLength": 32,
+
              "pattern": "^[^\s\p{Cc}]+$"
+
            },
+
            "controller": {
+
              "type": "string",
+
              "pattern": "^did:([a-z0-9]+):((([A-Za-z0-9._%-][A-Za-z0-9._%-]*:)*[A-Za-z0-9._%-]+))$"
+
            }
+
          },
+
          "required": ["alias", "controller"],
+
          "additionalProperties": false
+
        }
+
      },
+
      "required": ["xyz.radicle.agent"],
+
      "additionalProperties": false
+
    }
+
```
+

+
Copyright
+
---------
+
This document is licensed under the Creative Commons CC0 1.0 Universal license.
+

+
References
+
----------
+
[^rip-2]: https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/0002-identity.md
+
[^storage-layout]: https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/0003-storage-layout.md
+
[^layout-section]: https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/0003-storage-layout.md#layout
+
[^did]: https://www.w3.org/TR/did-core/
+
[^signature-crate]: https://docs.rs/signature/latest/signature/
+
[^signature-signer]: https://docs.rs/signature/latest/signature/trait.Signer.html
+
[^signature-verifier]: https://docs.rs/signature/latest/signature/trait.Verifier.html
+
[^keri-spec]: https://trustoverip.github.io/tswg-keri-specification
+
<!-- TODO: update to latest version when it is merged -->
+
[^canonical-refs]: https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/df1bc0f914e4e5592d9f04a73a5c916f2e94bfcd/0004-canonical-references.md
+
[^check-ref-format]: https://git-scm.com/docs/git-check-ref-format
+
[^did-key]: https://w3c-ccg.github.io/did-method-key
+
[^did-keri]: https://weboftrust.github.io/did-keri/
+
[^git-ref-format]: The `<method-name>` and `<method-specific-id>` must be valid Git reference components, which can be checked via `git-check-ref-format`[^check-ref-format]. If they are not valid path components, then the RIP proposing them must standardize how those characters are escaped or replaced.
+
[^identity-verification]: https://app.radicle.xyz/nodes/seed.radicle.xyz/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/4d7bef6e2cfdba76fb781d4ba008c22ca41a8c24/0002-identity.md#verification
+
[^also-known-as]: https://www.w3.org/TR/did-core/#also-known-as
+
[^identity-storage]: https://app.radicle.xyz/nodes/seed.radicle.xyz/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/0002-identity.md#identity-storage
+
[^did-architecture]: https://www.w3.org/TR/did-core/#architecture-overview