<?xml version="1.0" encoding="utf-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="exp"
     docName="draft-phelan-dtl-00"
     ipr="trust200902"
     submissionType="IETF"
     consensus="false"
     tocInclude="true"
     tocDepth="3"
     sortRefs="true"
     symRefs="true"
     version="3">

  <front>
    <title abbrev="DTL">DTL: Dyadic Typed Layer</title>
    <seriesInfo name="Internet-Draft" value="draft-phelan-dtl-00"/>
    <author fullname="Evan Phelan" initials="E." surname="Phelan">
      <organization>Minuet Labs</organization>
      <address>
        <email>evan@minuet.ai</email>
        <uri>https://opendtl.org/</uri>
      </address>
    </author>
    <date year="2026" month="July"/>
    <area>General</area>
    <keyword>agents</keyword>
    <keyword>relationship</keyword>
    <keyword>delegation</keyword>
    <keyword>ERC-8004</keyword>

    <abstract>
      <t>DTL (Dyadic Typed Layer) defines a single, minimal primitive: a
      typed, directed relationship between two agents that the controller of
      each agent has confirmed, together with the lifecycle of that
      relationship. The name describes the primitive: Dyadic (it concerns one
      pair of parties), Typed (the relationship carries exactly one kind), and
      Layer (it sits above an identity substrate, not inside it).</t>

      <t>Agent ecosystems have built out several coordination layers: identity
      (who an agent is), reputation and attestation (what is asserted about an
      agent), and discovery and messaging (how agents find and talk to each
      other). One primitive is comparatively underserved, the relationship: a
      standing, acknowledged, directed connection between two specific agents,
      recording that they are related and in what capacity. No existing
      standard, to the author's knowledge, provides exactly this primitive in
      this form. DTL specifies it and nothing more. It is normative about the
      mechanism (a typed, directed, two-party, controller-confirmed edge and
      its lifecycle) and deliberately silent about substrate, transport,
      storage, and the open vocabulary of relationship types. An informative
      binding to ERC-8004 is provided as the first anchoring substrate.</t>
    </abstract>
  </front>

  <middle>

    <section anchor="motivation" numbered="true">
      <name>Motivation</name>
      <t>Autonomous software agents increasingly act on behalf of different
      principals and across organizational boundaries. Several coordination
      layers are now actively addressed:</t>
      <dl>
        <dt>Identity</dt>
        <dd>stable, verifiable identifiers for agents (registries, DIDs,
        on-chain agent records).</dd>
        <dt>Reputation / attestation</dt>
        <dd>assertions about an agent: scores, reviews, verifiable
        credentials, trust signals.</dd>
        <dt>Discovery and messaging</dt>
        <dd>how agents are found and how they exchange messages (e.g.
        agent-interaction protocols).</dd>
      </dl>
      <t>Identity and attestation are one-way: one party makes a claim about,
      or an identifier for, another. Discovery and messaging concern
      communication, not a standing bond. None captures a relationship: a
      connection between two specific agents that both sides acknowledge, in a
      specific capacity, with a direction: "agent A delegates to agent B,"
      "agent A may message agent B," "agent A depends on agent B."</t>
      <t>The constructs closest to this are either one-way (attestations,
      reputation, and recent verifiable-delegation schemes) or
      relationship-shaped but not typed for the standing relationship (peer
      connections that record that two parties are connected, where any type
      present describes the connecting handshake rather than the kind of
      standing relationship that results). The gap is a connection that is at
      once acknowledged by both parties, directed, typed, and
      lifecycle-bearing.</t>
      <t>This is a small but load-bearing unit of coordination. Google
      DeepMind's June 2026 multi-agent-safety funding call highlighted
      identity, reputation, and commitment among the priorities for secure
      cross-platform agent interactions, the same problem space DTL addresses.
      "Commitment" is used here in the broad sense of a standing, acknowledged
      relationship, not the narrower game-theoretic sense of a commitment
      device that binds an agent's future choices (as studied in the
      cooperative-AI literature on decentralized commitment devices). DTL
      specifies the smallest useful version of a standing relationship: one
      confirmed, typed, directed relationship between two agents.</t>

      <section anchor="scope" numbered="true">
        <name>Scope and Non-Goals</name>
        <t>In scope. The single pairwise relationship: its record, its one
        type, its lifecycle, and the semantics of confirmation. This is the
        dyad: exactly two parties.</t>
        <t>Out of scope.</t>
        <dl>
          <dt>The network or graph</dt>
          <dd>that emerges from many relationships. DTL defines the edge; it
          specifies no global query, ranking, traversal, or discovery
          semantics over a collection of edges.</dd>
          <dt>Transport and storage.</dt>
          <dd>Where records live and how they are exchanged is a deployment
          concern.</dd>
          <dt>Identity issuance.</dt>
          <dd>DTL assumes each agent already has a stable identifier on some
          substrate; minting that identifier is the substrate's job.</dd>
          <dt>Reputation, scoring, and capability enforcement.</dt>
          <dd>A relationship records consent to a relationship, not
          trustworthiness, and it grants or constrains no capability (see
          <xref target="security"/>).</dd>
          <dt>Proof mechanics and conflict resolution.</dt>
          <dd>The canonical serialization of a record, the exact signing input
          and verification procedure for the <tt>signed</tt> profile, and the
          resolution of conflicting or concurrent actions (e.g. a total order
          across replicas) are binding- and deployment-defined, not specified
          here, and are a known area for a future version. A binding
          (<xref target="binding"/>) supplies the concrete, interoperable
          profile against which independent implementations interoperate.</dd>
        </dl>
        <t>General in mechanism, specific in framing. The mechanism is defined
        over generic parties that have a controller; this specification frames
        and motivates it around AI agents as the primary case. A DTL agent may
        be software or embodied (e.g. robotics); DTL operates above the agent's
        internal cognitive architecture and embodiment, and makes no assumption
        about how an agent is built. The following are deliberately left as
        non-goals for v1, noted only for forward compatibility (the mechanism
        admits them, but they are not specified here):</t>
        <dl>
          <dt>(a) Non-agent parties.</dt>
          <dd>The same edge admits human-agent (an agent and its principal) and
          agent-service relationships. Agents are the primary case; these are
          not specified.</dd>
          <dt>(b) Cross-substrate relationships.</dt>
          <dd>Because confirmation is performed independently by each party's
          controller (<xref target="confirmation"/>), two agents anchored on
          different substrates could in principle confirm one relationship.
          This interoperability case is enabled in principle but not
          specified.</dd>
        </dl>
      </section>
    </section>

    <section anchor="terminology" numbered="true">
      <name>Terminology</name>
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
      "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
      "OPTIONAL" in this document are to be interpreted as described in BCP 14
      <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when,
      they appear in all capitals, as shown here.</t>
      <dl>
        <dt>Agent</dt>
        <dd>an autonomous actor with a stable identity on some substrate. An
        agent may be software or embodied (<xref target="scope"/>); DTL makes
        no assumption about its internal construction. Agents are the endpoints
        of a relationship.</dd>
        <dt>Controller</dt>
        <dd>the authority recognized by an agent's identity substrate as able
        to authorize actions on the agent's behalf. A controller MAY be a human
        owner, a delegated organization, or the agent itself. (The term echoes
        controller in W3C Decentralized Identifiers <xref target="DID-CORE"/>;
        in DTL it denotes the authorization authority for an agent, which MAY
        but need not coincide with the controller of any DID document.)</dd>
        <dt>Party</dt>
        <dd>one of the two agents in a relationship. Each party has a
        controller.</dd>
        <dt>Relationship</dt>
        <dd>a typed, directed connection from a source agent to a target agent,
        as defined by this specification.</dd>
        <dt>Relationship record</dt>
        <dd>the data structure representing a relationship and its current
        state.</dd>
        <dt>Proof of authorization</dt>
        <dd>evidence that a party's controller authorized a relationship action
        (proposal, confirmation, decline, withdrawal, or revocation). Its
        concrete form is determined by the confirmation profile.</dd>
        <dt>Confirmation profile</dt>
        <dd>a named scheme that defines how a proof of authorization is
        produced and verified, and the degree of trust it conveys.</dd>
      </dl>
    </section>

    <section anchor="record" numbered="true">
      <name>The Relationship Record</name>
      <t>A relationship is represented by a relationship record, a JSON
      <xref target="RFC8259"/> object. A record MUST contain:</t>
      <dl>
        <dt><tt>source</tt></dt>
        <dd>the identifier of the source agent (substrate-defined).</dd>
        <dt><tt>target</tt></dt>
        <dd>the identifier of the target agent (substrate-defined).
        <tt>target</tt> MUST NOT equal <tt>source</tt> (no
        self-relationship).</dd>
        <dt><tt>type</tt></dt>
        <dd>exactly one relationship type, a non-empty string drawn from an
        open vocabulary (<xref target="types"/>).</dd>
        <dt><tt>status</tt></dt>
        <dd>the lifecycle state (<xref target="lifecycle"/>): one of
        <tt>proposed</tt>, <tt>established</tt>, <tt>declined</tt>,
        <tt>withdrawn</tt>, <tt>revoked</tt>.</dd>
        <dt><tt>proofs</tt></dt>
        <dd>the proofs of authorization for the lifecycle actions taken so far,
        in the form defined by the profile. A record MUST carry one proof for
        each action that brought it to its current <tt>status</tt>
        (<xref target="confirmation"/>); <xref target="schema"/> specifies the
        required entries per state.</dd>
        <dt><tt>profile</tt></dt>
        <dd>the confirmation profile (<xref target="confirmation"/>) under
        which its proofs were produced.</dd>
      </dl>
      <t>A record MAY carry an <tt>id</tt>, timestamps (<tt>created_at</tt>,
      <tt>updated_at</tt>), a free-form human-readable <tt>description</tt>, and
      an <tt>ext</tt> object holding deployment- or substrate-specific
      extension fields. The record's top-level fields are otherwise closed
      (<xref target="schema"/>); <tt>ext</tt> is the single designated place for
      fields this specification does not define, and its contents are
      unconstrained.</t>
      <t>A relationship is directed: source -> target is significant and is not
      symmetric. "A <tt>delegates_to</tt> B" is a different relationship from "B
      <tt>delegates_to</tt> A." A verifier MUST NOT treat a relationship as
      symmetric.</t>
      <t>The constraint that <tt>source</tt> and <tt>target</tt> MUST differ (no
      self-relationship) is normative but is not expressible in JSON Schema:
      Draft 2020-12 cannot compare two instance values to each other.
      Implementations MUST enforce it outside the schema.</t>
      <t>A normative JSON Schema for the record is given in
      <xref target="schema"/>.</t>
    </section>

    <section anchor="types" numbered="true">
      <name>Types</name>
      <t>A relationship MUST carry exactly one <tt>type</tt>.</t>
      <t>The <tt>type</tt> vocabulary is open: <tt>type</tt> is a free-form
      string, and implementations MAY define their own types. This
      specification is normative about typed-ness (a relationship carries
      exactly one type) but NOT about the set of legal type values. A
      <tt>type</tt> is a descriptive label on the record: it names what the
      relationship asserts and is not prescriptive; this specification attaches
      no behavioral semantics to any type, and a type by itself grants no
      capability and triggers no enforcement (<xref target="security"/>). It is
      a label, not a directive.</t>
      <t>Recommended vocabulary (informative). Implementations are encouraged,
      for interoperability, to use the following bare identifiers where they
      apply:</t>
      <dl>
        <dt><tt>delegates_to</tt></dt>
        <dd>the source may request the target to perform work on its
        behalf.</dd>
        <dt><tt>can_send_message_to</tt></dt>
        <dd>the source may send messages to the target.</dd>
        <dt><tt>depends_on</tt></dt>
        <dd>the source depends on the target (e.g. for sequencing or a required
        input).</dd>
      </dl>
      <t>Namespacing (SHOULD). To avoid collisions in the open vocabulary: bare
      identifiers are reserved for types defined by this specification (the
      recommended vocabulary above). Any other type SHOULD be namespaced as a
      URI, for example <tt>https://example.com/dtl/audits</tt>, following the
      convention <xref target="RFC8288"/> (Web Linking) uses for extension
      relation types, which are themselves URIs.</t>
    </section>

    <section anchor="lifecycle" numbered="true">
      <name>Lifecycle</name>
      <t>A relationship moves through the following states:</t>
      <figure>
        <name>Relationship lifecycle</name>
        <artwork type="ascii-art"><![CDATA[
                        confirm
    proposed  -------------------------->  established
       |  |                                    |
       |  | withdraw                           | revoke
       |  | (source)                           | (either party)
       |  v                                    v
       |  withdrawn (terminal)              revoked (terminal)
       |
       | decline (target)
       v
    declined (terminal)
]]></artwork>
      </figure>
      <ul>
        <li>A relationship is created by the source's controller in state
        <tt>proposed</tt>.</li>
        <li>While the relationship is <tt>proposed</tt>, the target's
        controller either confirms it (-> <tt>established</tt>) or declines it
        (-> <tt>declined</tt>); independently, the source's controller MAY
        withdraw its own still-unconfirmed proposal (->
        <tt>withdrawn</tt>).</li>
        <li>An <tt>established</tt> relationship MAY be revoked (->
        <tt>revoked</tt>) by either party's controller.</li>
        <li><tt>withdrawn</tt>, <tt>declined</tt>, and <tt>revoked</tt> are
        terminal. A new relationship between the same parties MAY be proposed
        afresh.</li>
      </ul>
      <t>A single principle governs every exit: a controller may unilaterally
      retract its own authorization at any nonterminal stage in which it still
      holds that authorization; the change takes effect immediately and is
      attributable to that controller. Before confirmation only the source has
      authorized, so only the source can unwind the proposal (withdraw), while
      the target unwinds simply by declining rather than confirming. After
      confirmation both parties have authorized, so either may unwind (revoke).
      Forming a relationship requires both sides; exiting one never does:
      requiring mutual consent to end a relationship would let one party trap
      the other in a stale edge.</t>
      <t>Multiplicity (deployment-defined). This specification defines the
      lifecycle of a single relationship record. Whether two parties may
      simultaneously hold several relationships of the same <tt>type</tt>, and
      whether proposing afresh supersedes a terminal prior record or coexists
      with it, are deployment-defined and out of scope.</t>
    </section>

    <section anchor="confirmation" numbered="true">
      <name>Confirmation Semantics</name>
      <t>The defining property of DTL is confirmation by both parties: a
      relationship reaches <tt>established</tt> only when the controller of each
      party has authorized it, the source by proposing, the target by
      confirming. This two-party authorization is exactly what distinguishes a
      relationship from a one-way attestation. These are two endpoint-role
      authorizations, one for the source role, one for the target. DTL does not
      require the two controllers to be distinct; where a single controller
      holds both agents it authorizes both roles. The structural distinction
      DTL draws is two endpoint-role authorizations, not necessarily two
      independent parties.</t>
      <t>Each authorization is a proof of authorization. What counts as a valid
      proof, and who can verify it, is set by the confirmation profile in force
      for the record. This specification defines two profiles and permits
      others.</t>
      <t>The <tt>proofs</tt> of a record form an append-only set of
      authorizations, at most one per action, accrued as the record advances
      and never rewritten: a record MUST carry a proof of authorization for
      every lifecycle action (<xref target="lifecycle"/>) that has brought it to
      its current <tt>status</tt>. A <tt>proposed</tt> record carries a
      <tt>proposal</tt> proof; an <tt>established</tt> record carries
      <tt>proposal</tt> and <tt>confirmation</tt>; a <tt>declined</tt> record
      carries <tt>proposal</tt> and <tt>decline</tt>; a <tt>withdrawn</tt>
      record carries <tt>proposal</tt> and <tt>withdrawal</tt>; and a
      <tt>revoked</tt> record carries <tt>proposal</tt>, <tt>confirmation</tt>,
      and <tt>revocation</tt>. <xref target="schema"/> encodes these per-status
      requirements normatively, but constrains only which proofs are present,
      not their contents: the internal structure of each proof is
      profile-defined, so schema-validity does NOT imply proof-satisfaction. As
      with the requirement that <tt>source</tt> and <tt>target</tt> differ
      (<xref target="record"/>), proof attribution (that a proof was genuinely
      produced by the named controller) is not expressible in JSON Schema and
      is the responsibility of the profile and the verifier.</t>
      <dl>
        <dt><tt>attested</tt> profile.</dt>
        <dd>A trusted third party (an attesting service) records that each
        controller authorized the relevant action. Verifiers trust the
        attesting service's record. This profile is convenient and requires no
        controller-held verification material, but a proof is not independently
        verifiable by a party that does not trust the attesting service, and
        typically not offline. Where an attested proof carries a
        <tt>method</tt> field (e.g. <tt>siwe</tt>, as in
        <xref target="examples"/>), that field describes the attester's
        authentication process only; it confers no independent verifiability,
        and only the <tt>signed</tt> profile yields proofs a third party can
        check without trusting the attesting service. (Example: each controller
        authenticates to a platform, and the platform records the
        authorization.)</dd>
        <dt><tt>signed</tt> profile.</dt>
        <dd>Each controller produces a proof that any party can verify without
        relying on a trusted attesting service, for example a digital signature
        over the record, verifiable against the controller's own published
        verification material. Verification still depends on obtaining that
        verification material (which may itself involve a resolver, DNS, or a
        ledger, a trust anchor of its own) but not on a third party's
        attestation of the authorization. Whether verification can also be done
        offline depends on how the material is obtained: immediate for
        self-describing identifiers (e.g. <tt>did:key</tt>), but requiring a
        lookup for methods that resolve material over the network or a ledger
        (e.g. <tt>did:web</tt>, on-chain keys). Its integrity rests on the
        controller's verification material rather than on a trusted
        service.</dd>
      </dl>
      <t>A record MUST declare which profile produced its proofs. Profiles are
      extensible: a deployment MAY define additional profiles, provided each
      specifies how proofs are produced and verified and what trust they
      convey.</t>
      <t>Profiles vs bindings. The two profiles defined here are trust
      categories, not wire-complete schemes: they classify the trust a proof
      conveys but do not by themselves fix a proof's contents, its canonical
      signing input, or a verification procedure. A concrete, interoperable
      profile (one against which two independent implementations can produce
      and check the same proofs) is supplied by a binding to a specific
      substrate (the ERC-8004 binding of <xref target="binding"/> is the
      first). Canonicalization, signing input, and the verification procedure
      are therefore binding- and deployment-defined (a non-goal for v0; see
      <xref target="scope"/>).</t>
      <t>Field casing (informative). Fields defined by this specification
      (record-level fields and the fields of the <tt>attested</tt> profile's
      proofs) use snake_case (e.g. <tt>created_at</tt>, <tt>attested_by</tt>).
      Fields adopted from an external standard inside a <tt>proofs</tt> object
      retain that standard's convention, for example
      <tt>verificationMethod</tt> keeps the camelCase form specified by W3C
      DID.</t>
      <blockquote>
        <t>Autonomy (informative). In the <tt>signed</tt> profile the
        controller that produces a proof MAY be the agent itself, when the
        agent holds its own verification material. This is the path by which a
        relationship can be formed with no human in the loop: the mechanism is
        neutral as to whether a controller is a human, an organization, or the
        agent itself.</t>
      </blockquote>
    </section>

    <section anchor="binding" numbered="true">
      <name>Binding: ERC-8004 (Informative)</name>
      <t>This binding describes how DTL maps onto ERC-8004
      <xref target="ERC-8004"/> ("Trustless Agents"), the first substrate on
      which it is anchored. It is informative; nothing here is normative for
      DTL.</t>
      <dl>
        <dt>Identity / agents.</dt>
        <dd>ERC-8004 provides on-chain agent identity on EVM chains. An agent's
        DTL identifier is its ERC-8004 agent identity, expressed as
        <tt>chainId:agentId</tt> (e.g. <tt>11155111:123</tt>) for unambiguous
        cross-chain reference.</dd>
        <dt>Controller.</dt>
        <dd>A party's controller is the agent's on-chain owner, the address
        recorded as the agent's owner on ERC-8004.</dd>
        <dt>Confirmation (profile).</dt>
        <dd>The reference deployment implements the <tt>attested</tt> profile:
        each controller authenticates with Sign-In with Ethereum (SIWE)
        <xref target="EIP-4361"/>, the target confirms through a single-use
        confirmation link, and the service records both authorizations. A
        <tt>signed</tt> profile (direct signatures by each owner over the
        record) is the natural trustless extension and is not yet
        implemented.</dd>
        <dt>Records are off-chain.</dt>
        <dd>DTL relationship records are held off-chain, keyed to on-chain
        ERC-8004 identities; ERC-8004 supplies identity, DTL supplies the
        relationship layer above it.</dd>
        <dt>Lifecycle mapping.</dt>
        <dd>The reference implementation's statuses map to DTL states as
        follows: <tt>verified</tt> -> <tt>established</tt>; <tt>rejected</tt> ->
        <tt>declined</tt>; <tt>proposed</tt> and <tt>pending</tt> (proposal
        initiated, awaiting the target) -> <tt>proposed</tt>. The implementation
        additionally has an <tt>inferred</tt> seeding state for candidate
        relationships that carry no controller authorization; these fall
        outside the DTL lifecycle and are not DTL relationships until proposed
        and confirmed. DTL's <tt>withdrawn</tt> and <tt>revoked</tt> states are
        defined by this specification but are not yet implemented in the
        reference deployment.</dd>
        <dt>Type provenance.</dt>
        <dd>The reference deployment uses five types: the recommended trio
        (<tt>delegates_to</tt>, <tt>can_send_message_to</tt>,
        <tt>depends_on</tt>) plus <tt>supervises</tt> and <tt>complements</tt>.
        The latter two are lower-confidence (<tt>supervises</tt> is awkward
        across organizational boundaries; <tt>complements</tt> is the least
        precisely observable) and are NOT part of the recommended vocabulary in
        <xref target="types"/>. Note also that <tt>complements</tt> reads as
        symmetric, whereas DTL records are directed (<xref target="record"/>); a
        mutual "complements" relationship is therefore represented as two
        explicit directed records, not one.</dd>
      </dl>
    </section>

    <section anchor="security" numbered="true">
      <name>Security Considerations</name>
      <dl>
        <dt>Trust follows the profile.</dt>
        <dd>The trust conveyed by an <tt>established</tt> relationship depends
        entirely on its confirmation profile. An <tt>attested</tt> relationship
        is only as trustworthy as its attesting service and is not portable to
        parties that do not trust that service; a <tt>signed</tt> relationship
        can be verified without trusting an attesting service, though still
        contingent on obtaining and trusting the controllers' verification
        material (and the resolver, DNS, or ledger through which it is
        published).</dd>
        <dt>Controller compromise.</dt>
        <dd>Whoever can act as a controller can authorize relationships for that
        agent. Compromise of a controller's credentials or keys permits forged
        proposals, confirmations, withdrawals, or revocations. Revocation
        limits the lifetime of a standing relationship but does not undo actions
        taken while it was <tt>established</tt>, and it constrains that lifetime
        only to the extent a verifier can observe current state: a stale or
        cached record may not yet reflect a revocation that has occurred.</dd>
        <dt>Consent, not capability.</dt>
        <dd>A relationship records that two controllers consented to a typed,
        directed connection. It does NOT by itself grant, constrain, or enforce
        any capability. A <tt>delegates_to</tt> relationship does not confer
        permission; enforcement is the responsibility of the systems that act
        on the relationship and is out of scope.</dd>
        <dt>Replay and binding.</dt>
        <dd>A proof of authorization SHOULD be bound to the specific
        relationship instance it authorizes, at minimum the fields that
        constitute the authorized proposition (<tt>source</tt>,
        <tt>target</tt>, <tt>type</tt>) and, where a deployment permits more
        than one record for the same <tt>source</tt>/<tt>target</tt>/<tt>type</tt>
        over time (<xref target="lifecycle"/>), a value that distinguishes the
        specific record instance (such as its <tt>id</tt> or a per-proof nonce).
        Where such multiplicity is permitted, binding to the instance is
        REQUIRED, so that an old proof from a since-terminated relationship
        cannot be replayed onto a fresh proposal of the same triple; otherwise
        it SHOULD be present.</dd>
        <dt>Direction integrity.</dt>
        <dd>Because relationships are directed and asymmetric, verifiers MUST
        preserve <tt>source</tt>/<tt>target</tt> ordering and MUST NOT infer the
        reverse relationship from a record.</dd>
        <dt>Proposal is not assent.</dt>
        <dd>A <tt>proposed</tt> record carries only the source's authorization;
        a verifier MUST NOT read it as the target's agreement. Until
        confirmation it is an unaccepted offer, and a deployment SHOULD guard
        against unsolicited-proposal ("proposal spam") abuse.</dd>
        <dt>Acknowledged, not solved (v0).</dt>
        <dd>Several hardening concerns are deliberately deferred to bindings and
        future versions (see <xref target="scope"/>): the canonical signing
        input and verification procedure for the <tt>signed</tt> profile;
        controller rotation (a relationship authorized under a key or owner that
        later changes); domain separation (ensuring a proof minted for one
        purpose, type, or deployment cannot be reinterpreted in another); and
        freshness / stale state (a verifier acting on an out-of-date record).
        DTL specifies the relationship and its lifecycle; closing these is
        binding- and deployment-specific work.</dd>
      </dl>
    </section>

    <section anchor="related" numbered="true">
      <name>Related Work (Informative)</name>
      <t>No existing standard, to the author's knowledge, provides exactly
      DTL's primitive: a relationship that is at once typed on the standing
      relationship, directed, two-party (controller-confirmed), and
      lifecycle-bearing. The claim is combinational: each property below exists
      in prior art, but no single neighbor combines all four for an
      open-vocabulary standing relationship. The table summarizes where the
      closest neighbors sit; the notes give the detail.</t>
      <table anchor="capability-matrix">
        <name>Capability comparison with the closest neighbors</name>
        <thead>
          <tr>
            <th>Prior art</th>
            <th>Typed (on standing relationship)</th>
            <th>Directed</th>
            <th>Two-party confirmed</th>
            <th>Lifecycle</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>DIDComm / DID Exchange connections</td>
            <td>no (types the handshake)</td>
            <td>yes</td><td>yes</td><td>yes</td>
          </tr>
          <tr>
            <td>Verifiable delegation (AIP, LDP)</td>
            <td>partial (delegation only)</td>
            <td>yes</td>
            <td>no (one-way grant)</td>
            <td>no (no standing-relationship lifecycle)</td>
          </tr>
          <tr>
            <td>One-way attestation (ERC-8240)</td>
            <td>yes</td><td>yes</td><td>no</td><td>no</td>
          </tr>
          <tr>
            <td>Labeled-edge models (RDF, FOAF, schema.org, XFN)</td>
            <td>yes</td><td>yes</td><td>no</td><td>no</td>
          </tr>
          <tr>
            <td>FIPA Contract Net</td>
            <td>no (types the task)</td>
            <td>yes</td>
            <td>per task</td>
            <td>per interaction</td>
          </tr>
          <tr>
            <td>Commitment machines (Yolum &amp; Singh)</td>
            <td>partial (types the obligation)</td>
            <td>yes</td><td>yes</td><td>yes</td>
          </tr>
          <tr>
            <td>ActivityPub (Follow / Accept / Undo)</td>
            <td>no (single fixed kind)</td>
            <td>yes</td><td>yes</td><td>partial</td>
          </tr>
          <tr>
            <td>XMPP presence subscriptions (RFC 6121)</td>
            <td>no (single fixed kind)</td>
            <td>yes</td><td>yes</td><td>yes</td>
          </tr>
          <tr>
            <td>Social friend-graphs (proprietary)</td>
            <td>no (single fixed kind)</td>
            <td>varies</td><td>yes</td><td>partial</td>
          </tr>
          <tr>
            <td>WS-Agreement (Open Grid Forum)</td>
            <td>partial (agreement terms)</td>
            <td>yes</td><td>yes</td><td>yes</td>
          </tr>
          <tr>
            <td>DTL</td>
            <td>yes (open vocabulary)</td>
            <td>yes</td><td>yes</td><td>yes</td>
          </tr>
        </tbody>
      </table>
      <dl>
        <dt>DIDComm / DID Exchange connections (DID/SSI ecosystem)</dt>
        <dd>
          <t>the closest relationship-shaped prior art: a connection is
          mutually acknowledged, directed at setup, persistent, and
          lifecycle-bearing. A connection can carry a type (DID Exchange
          Protocol 1.0, Aries RFC 0023 <xref target="ARIES-0023"/>, and Goal
          Codes, Aries RFC 0519, express a <tt>goal</tt> / <tt>goal_code</tt>)
          but that type describes the purpose of the connecting handshake, not
          the kind of the standing relationship it produces. DTL's contribution
          relative to this is a type on the standing relationship itself.</t>
          <t>Worked example. Suppose A and B establish one DID Exchange
          connection (a single handshake, <tt>goal_code: "establish-connection"</tt>).
          Over that one identity pair, their controllers then confirm three
          independently-lifecycled DTL relationships (<tt>A delegates_to B</tt>,
          <tt>A depends_on B</tt>, and <tt>B can_send_message_to A</tt>) each
          separately revocable (B may revoke <tt>delegates_to</tt> while
          <tt>depends_on</tt> still stands). The connection's <tt>goal_code</tt>
          types one handshake's purpose; it cannot represent N
          independently-confirmed, independently-revocable typed standing facts
          over the same identity pair. That gap, between typing the handshake
          and typing the standing relationship, is the daylight DTL
          occupies.</t>
        </dd>
        <dt>Verifiable agent delegation (recent, 2026)</dt>
        <dd>the Agent Identity Protocol (AIP <xref target="AIP"/>, with IETF
        draft draft-prakash-aip-00) defines Invocation-Bound Capability Tokens
        that fuse identity, attenuated authorization, and provenance for
        agent-to-agent delegation across MCP and A2A; LDP
        <xref target="LDP"/> ("LDP: An Identity-Aware Protocol for Multi-Agent
        LLM Systems") similarly scopes delegated authority for multi-agent
        routing. These are the nearest current neighbors to the
        <tt>delegates_to</tt> type, but authorization flows one way (an issuer
        grants to a delegatee; the second party does not confirm a standing
        relationship), there is no DTL standing-relationship lifecycle, and
        there is no open relationship-type vocabulary. DTL differs on all
        three.</dd>
        <dt>One-way attestation / reputation</dt>
        <dd>e.g. the draft ERC-8240 <xref target="ERC-8240"/> (Trust
        Infrastructure for Agents and Assets, a one-way trust layer in which
        evaluators submit signed, contestable attestations about agents and
        assets): one party asserts about another (scores, attestations). There
        is no confirmation by the second party and no standing, directed, typed
        edge. DTL differs in requiring two-party confirmation.</dd>
        <dt>Generic labeled-edge models</dt>
        <dd>RDF and RDF-star triples, FOAF (<tt>foaf:knows</tt>), schema.org
        relations, and HTML XFN <tt>rel</tt> values express a typed, directed
        edge between two identified subjects, and are the broad precedent for an
        open vocabulary of labeled relations. But such a statement does not
        standardize DTL's bilateral authorization and lifecycle: it is published
        by one party, the second subject does not confirm it, and there is no
        lifecycle. DTL adds two-party confirmation and a lifecycle to the
        labeled edge.</dd>
        <dt>The propose/accept and commitment lineage</dt>
        <dd>the FIPA Contract Net Interaction Protocol
        <xref target="FIPA-CONTRACTNET"/> is an early standardized proposal ->
        accept/reject handshake, but it types the task being bid and its
        lifecycle is per-interaction rather than a standing relationship. The
        commitment-machine line in multi-agent systems (Singh; Yolum &amp;
        Singh, "Commitment Machines," ATAL 2001 <xref target="COMMITMENT-MACHINES"/>)
        is the closer ancestor of a lifecycle-bearing social relationship (a
        social commitment that is created and then discharged, cancelled, or
        released) though commitment machines model the obligation's semantics,
        whereas DTL types are deliberately non-behavioral
        (<xref target="types"/>). DTL's proposal -> establishment ->
        revocation/withdrawal lifecycle is a small, two-party specialization in
        the spirit of that line. This social-commitment sense is distinct from
        the game-theoretic commitment device of the cooperative-AI literature
        (<xref target="motivation"/>).</dd>
        <dt>Social and presence graphs</dt>
        <dd>ActivityPub <xref target="ACTIVITYPUB"/> (with ActivityStreams
        <tt>Follow</tt> / <tt>Accept</tt> / <tt>Reject</tt> / <tt>Undo</tt>, and
        the <tt>Relationship</tt> object) and XMPP presence subscriptions
        <xref target="RFC6121"/>, as well as proprietary social friend-graphs,
        do implement a confirmed, directed, lifecycle-bearing relationship, but
        each ships a single fixed relationship kind (a follow, a presence
        subscription, a friendship), not an open typed vocabulary of standing
        relationships. They occupy the confirmed/directed/lifecycle cell for one
        hard-coded type; DTL generalizes it to an open type vocabulary over
        arbitrary agent pairs.</dd>
        <dt>WS-Agreement (Open Grid Forum)</dt>
        <dd>a two-party offer/accept agreement format with state
        <xref target="WS-AGREEMENT"/>, but a heavyweight SLA document for
        service-level guarantees rather than a minimal typed standing
        relationship between agent identities; it does not fill the cell.</dd>
        <dt>Open agent-relationship and identity efforts (2025-2026)</dt>
        <dd>the W3C AI Agent Protocol Community Group (proposed 2025) names,
        among its goals, letting agents "dynamically establish or dissolve
        collaborations," but has not shipped a relationship primitive. Broader
        identity, discovery, and interoperability efforts (Microsoft Entra Agent
        ID (GA 2026), AGNTCY, ANP, ACP, NANDA, and NIST's agent-identity work)
        address agent identity, discovery, or messaging, not a confirmed
        standing relationship between two specific agents.</dd>
        <dt>Agent interaction protocols (A2A, MCP)</dt>
        <dd>define how agents communicate, not a standing, confirmed
        relationship between two specific agents. DTL is complementary: a
        relationship record such protocols could reference.</dd>
      </dl>
    </section>

    <section anchor="iana" numbered="true">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>

  </middle>

  <back>
    <references>
      <name>Normative References</name>
      <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author initials="S." surname="Bradner" fullname="Scott Bradner"/>
          <date year="1997" month="March"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
      </reference>
      <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author initials="B." surname="Leiba" fullname="Barry Leiba"/>
          <date year="2017" month="May"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
      </reference>
      <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259">
        <front>
          <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
          <author initials="T." surname="Bray" fullname="Tim Bray" role="editor"/>
          <date year="2017" month="December"/>
        </front>
        <seriesInfo name="STD" value="90"/>
        <seriesInfo name="RFC" value="8259"/>
      </reference>
      <reference anchor="JSON-SCHEMA" target="https://json-schema.org/draft/2020-12/schema">
        <front>
          <title>JSON Schema: A Media Type for Describing JSON Documents</title>
          <author initials="A." surname="Wright" role="editor"/>
          <author initials="H." surname="Andrews" role="editor"/>
          <author initials="B." surname="Hutton" role="editor"/>
          <author initials="G." surname="Dennis"/>
          <date year="2022" month="June"/>
        </front>
        <refcontent>Internet-Draft draft-bhutton-json-schema-01, Draft 2020-12</refcontent>
      </reference>
    </references>

    <references>
      <name>Informative References</name>
      <reference anchor="ERC-8004" target="https://eips.ethereum.org/EIPS/eip-8004">
        <front>
          <title>ERC-8004: Trustless Agents</title>
          <author><organization>Ethereum</organization></author>
          <date year="2025"/>
        </front>
      </reference>
      <reference anchor="ERC-8240" target="https://ethereum-magicians.org/t/erc-8240-trust-infrastructure-for-agents-and-assets/28322">
        <front>
          <title>ERC-8240: Trust Infrastructure for Agents and Assets (draft)</title>
          <author><organization>Ethereum</organization></author>
          <date year="2026"/>
        </front>
      </reference>
      <reference anchor="DID-CORE" target="https://www.w3.org/TR/did-core/">
        <front>
          <title>Decentralized Identifiers (DIDs) v1.0</title>
          <author initials="M." surname="Sporny" role="editor"/>
          <author initials="D." surname="Longley" role="editor"/>
          <author initials="M." surname="Sabadello" role="editor"/>
          <author initials="D." surname="Reed" role="editor"/>
          <author initials="O." surname="Steele" role="editor"/>
          <author initials="C." surname="Allen" role="editor"/>
          <date year="2022" month="July"/>
        </front>
        <refcontent>W3C Recommendation</refcontent>
      </reference>
      <reference anchor="ARIES-0023" target="https://github.com/hyperledger/aries-rfcs/tree/main/features/0023-did-exchange">
        <front>
          <title>Aries RFC 0023: DID Exchange Protocol 1.0</title>
          <author><organization>Hyperledger Aries</organization></author>
          <date year="2021"/>
        </front>
      </reference>
      <reference anchor="AIP" target="https://arxiv.org/abs/2603.24775">
        <front>
          <title>AIP: Agent Identity Protocol for Verifiable Delegation Across MCP and A2A</title>
          <author initials="S." surname="Prakash" fullname="Sunil Prakash"/>
          <date year="2026"/>
        </front>
        <refcontent>arXiv:2603.24775</refcontent>
      </reference>
      <reference anchor="LDP" target="https://arxiv.org/abs/2603.08852">
        <front>
          <title>LDP: An Identity-Aware Protocol for Multi-Agent LLM Systems</title>
          <author initials="S." surname="Prakash" fullname="Sunil Prakash"/>
          <date year="2026"/>
        </front>
        <refcontent>arXiv:2603.08852</refcontent>
      </reference>
      <reference anchor="RFC6121" target="https://www.rfc-editor.org/info/rfc6121">
        <front>
          <title>Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence</title>
          <author initials="P." surname="Saint-Andre" fullname="Peter Saint-Andre"/>
          <date year="2011" month="March"/>
        </front>
        <seriesInfo name="RFC" value="6121"/>
      </reference>
      <reference anchor="RFC8288" target="https://www.rfc-editor.org/info/rfc8288">
        <front>
          <title>Web Linking</title>
          <author initials="M." surname="Nottingham" fullname="Mark Nottingham"/>
          <date year="2017" month="October"/>
        </front>
        <seriesInfo name="RFC" value="8288"/>
      </reference>
      <reference anchor="ACTIVITYPUB" target="https://www.w3.org/TR/activitypub/">
        <front>
          <title>ActivityPub</title>
          <author initials="C." surname="Lemmer-Webber" role="editor"/>
          <author initials="J." surname="Tallon" role="editor"/>
          <date year="2018" month="January"/>
        </front>
        <refcontent>W3C Recommendation</refcontent>
      </reference>
      <reference anchor="FIPA-CONTRACTNET" target="http://www.fipa.org/specs/fipa00029/SC00029H.html">
        <front>
          <title>FIPA Contract Net Interaction Protocol Specification</title>
          <author><organization>Foundation for Intelligent Physical Agents</organization></author>
          <date year="2002"/>
        </front>
        <seriesInfo name="FIPA" value="SC00029H"/>
      </reference>
      <reference anchor="COMMITMENT-MACHINES">
        <front>
          <title>Commitment Machines</title>
          <author initials="P." surname="Yolum"/>
          <author initials="M.P." surname="Singh"/>
          <date year="2001"/>
        </front>
        <refcontent>Intelligent Agents VIII (ATAL 2001), Springer LNCS 2333</refcontent>
      </reference>
      <reference anchor="WS-AGREEMENT" target="https://www.ogf.org/documents/GFD.192.pdf">
        <front>
          <title>Web Services Agreement Specification (WS-Agreement)</title>
          <author><organization>Open Grid Forum</organization></author>
          <date year="2007"/>
        </front>
        <seriesInfo name="GFD" value="192"/>
      </reference>
      <reference anchor="EIP-4361" target="https://eips.ethereum.org/EIPS/eip-4361">
        <front>
          <title>EIP-4361: Sign-In with Ethereum</title>
          <author><organization>Ethereum</organization></author>
          <date year="2021"/>
        </front>
      </reference>
    </references>

    <section anchor="schema" numbered="true">
      <name>JSON Schema (Normative)</name>
      <t>This appendix gives the normative JSON <xref target="RFC8259"/> Schema
      <xref target="JSON-SCHEMA"/> for the relationship record
      (<xref target="record"/>).</t>
      <sourcecode type="json"><![CDATA[
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://opendtl.org/v0/relationship.schema.json",
  "title": "DTL Relationship Record",
  "$comment": "The constraint source != target is normative (see section 3) but cannot be expressed in JSON Schema; implementations MUST enforce it externally.",
  "type": "object",
  "required": ["source", "target", "type", "status", "profile", "proofs"],
  "properties": {
    "id": {
      "type": "string",
      "description": "Optional unique identifier for the relationship record."
    },
    "source": {
      "type": "string",
      "minLength": 1,
      "description": "Identifier of the source agent (substrate-defined)."
    },
    "target": {
      "type": "string",
      "minLength": 1,
      "description": "Identifier of the target agent (substrate-defined). Must differ from source."
    },
    "type": {
      "type": "string",
      "minLength": 1,
      "description": "Exactly one relationship type, from an open vocabulary."
    },
    "status": {
      "type": "string",
      "enum": ["proposed", "established", "declined", "withdrawn", "revoked"]
    },
    "profile": {
      "type": "string",
      "description": "Confirmation profile that produced the proofs, e.g. 'attested' or 'signed'."
    },
    "proofs": {
      "type": "object",
      "description": "Proofs of authorization keyed by action; form defined by the confirmation profile.",
      "properties": {
        "proposal": { "type": "object" },
        "confirmation": { "type": "object" },
        "decline": { "type": "object" },
        "withdrawal": { "type": "object" },
        "revocation": { "type": "object" }
      },
      "additionalProperties": false
    },
    "description": { "type": "string" },
    "created_at": {
      "type": "string",
      "format": "date-time",
      "$comment": "format: date-time is annotation-only in JSON Schema 2020-12 (here and in updated_at); a deployment MAY choose to assert it."
    },
    "updated_at": { "type": "string", "format": "date-time" },
    "ext": {
      "type": "object",
      "description": "Optional deployment- or substrate-specific extension fields (section 3); contents are unconstrained."
    }
  },
  "additionalProperties": false,
  "allOf": [
    {
      "if": {
        "required": ["status"],
        "properties": { "status": { "const": "proposed" } }
      },
      "then": {
        "required": ["proofs"],
        "properties": {
          "proofs": {
            "required": ["proposal"],
            "not": { "anyOf": [
              { "required": ["confirmation"] },
              { "required": ["decline"] },
              { "required": ["withdrawal"] },
              { "required": ["revocation"] }
            ] }
          }
        }
      }
    },
    {
      "if": {
        "required": ["status"],
        "properties": { "status": { "const": "established" } }
      },
      "then": {
        "required": ["proofs"],
        "properties": {
          "proofs": {
            "required": ["proposal", "confirmation"],
            "not": { "anyOf": [
              { "required": ["decline"] },
              { "required": ["withdrawal"] },
              { "required": ["revocation"] }
            ] }
          }
        }
      }
    },
    {
      "if": {
        "required": ["status"],
        "properties": { "status": { "const": "declined" } }
      },
      "then": {
        "required": ["proofs"],
        "properties": {
          "proofs": {
            "required": ["proposal", "decline"],
            "not": { "anyOf": [
              { "required": ["confirmation"] },
              { "required": ["withdrawal"] },
              { "required": ["revocation"] }
            ] }
          }
        }
      }
    },
    {
      "if": {
        "required": ["status"],
        "properties": { "status": { "const": "withdrawn" } }
      },
      "then": {
        "required": ["proofs"],
        "properties": {
          "proofs": {
            "required": ["proposal", "withdrawal"],
            "not": { "anyOf": [
              { "required": ["confirmation"] },
              { "required": ["decline"] },
              { "required": ["revocation"] }
            ] }
          }
        }
      }
    },
    {
      "if": {
        "required": ["status"],
        "properties": { "status": { "const": "revoked" } }
      },
      "then": {
        "required": ["proofs"],
        "properties": {
          "proofs": {
            "required": ["proposal", "confirmation", "revocation"],
            "not": { "anyOf": [
              { "required": ["decline"] },
              { "required": ["withdrawal"] }
            ] }
          }
        }
      }
    }
  ]
}
]]></sourcecode>
    </section>

    <section anchor="examples" numbered="true">
      <name>Examples (Informative)</name>
      <t>B.1: <tt>delegates_to</tt>, ERC-8004 substrate, <tt>attested</tt>
      profile.</t>
      <sourcecode type="json"><![CDATA[
{
  "id": "rel:8004:42",
  "source": "11155111:123",
  "target": "11155111:456",
  "type": "delegates_to",
  "status": "established",
  "profile": "attested",
  "proofs": {
    "proposal": {
      "controller": "0xA11ce...",
      "attested_by": "attesting-service.example",
      "method": "siwe",
      "at": "2026-06-18T10:00:00Z"
    },
    "confirmation": {
      "controller": "0xB0b...",
      "attested_by": "attesting-service.example",
      "method": "siwe",
      "at": "2026-06-18T10:05:00Z"
    }
  },
  "created_at": "2026-06-18T10:00:00Z",
  "updated_at": "2026-06-18T10:05:00Z"
}
]]></sourcecode>
      <t>B.2: <tt>depends_on</tt>, non-blockchain substrate (did:web),
      <tt>signed</tt> profile. Demonstrates substrate-neutrality and the
      trustless profile: each controller signs the record directly, verifiable
      against its DID, and here each agent is its own controller (no human in
      the loop).</t>
      <sourcecode type="json"><![CDATA[
{
  "id": "rel:example:2",
  "source": "did:web:alpha.example",
  "target": "did:web:beta.example",
  "type": "depends_on",
  "status": "established",
  "profile": "signed",
  "proofs": {
    "proposal": {
      "controller": "did:web:alpha.example",
      "verificationMethod": "did:web:alpha.example#key-1",
      "signature": "z3Jx..."
    },
    "confirmation": {
      "controller": "did:web:beta.example",
      "verificationMethod": "did:web:beta.example#key-1",
      "signature": "z58P..."
    }
  }
}
]]></sourcecode>
      <t>B.3: <tt>delegates_to</tt>, ERC-8004 substrate, <tt>attested</tt>
      profile, after revocation. A relationship that was established and then
      revoked; the <tt>revocation</tt> proof attributes the action to the
      revoking controller (here the target).</t>
      <sourcecode type="json"><![CDATA[
{
  "id": "rel:8004:42",
  "source": "11155111:123",
  "target": "11155111:456",
  "type": "delegates_to",
  "status": "revoked",
  "profile": "attested",
  "proofs": {
    "proposal": {
      "controller": "0xA11ce...",
      "attested_by": "attesting-service.example",
      "method": "siwe",
      "at": "2026-06-18T10:00:00Z"
    },
    "confirmation": {
      "controller": "0xB0b...",
      "attested_by": "attesting-service.example",
      "method": "siwe",
      "at": "2026-06-18T10:05:00Z"
    },
    "revocation": {
      "controller": "0xB0b...",
      "attested_by": "attesting-service.example",
      "method": "siwe",
      "at": "2026-06-19T09:00:00Z"
    }
  },
  "created_at": "2026-06-18T10:00:00Z",
  "updated_at": "2026-06-19T09:00:00Z"
}
]]></sourcecode>
    </section>

  </back>
</rfc>
