DelegusDocsv0.2

Docs/Specification

Protocol specification · v0.2

Delegus Specification v0.2

The protocol that lets a service accept an action from an AI agent of another company: a Grant signed by that company, a Proof signed by the agent, one call to verify, and a signed receipt for every decision. This text is stable; changes are published as numbered errata or as v0.3, and the §5.2 check table is what receipts hash.

Source delegus-spec-v0.2.md · sha256 aafffde5066d29018417320222a7d544c567381e195b18e1ab6c9709df442a1f

Status: Frozen. Errata applied — 1: revocation-read / replay-write ordering (§5.3, §5.4, §7) and acceptance test (§15); 2: historical verification clock (§5.4, §6.4). This is the sole normative implementation source for v0.2. It consolidates the v0.2 draft, the Freeze Resolutions, the Threat Model, and the Final Freeze Recommendations. Earlier drafts are decision history only; engineers and conformance tests MUST NOT depend on them. Changes after this point require v0.3 or an explicit numbered erratum.

Acceptance criterion: An engineer at Company B who has never seen Company A's agent can integrate Delegus in an afternoon and safely accept or reject its action with one API call.

Normative language: MUST / SHOULD / MAY per RFC 2119.

Licence (non-normative): This specification text is licensed under the Creative Commons Attribution 4.0 International licence (CC BY 4.0, https://creativecommons.org/licenses/by/4.0/). Attribution: "Delegus Specification v0.2, © Delegus (delegus.ai)". The reference engine (@delegus/core, including the conformance vectors) and the SDK (@delegus/sdk) are licensed separately under Apache-2.0. This statement is metadata: it changes no normative text, no profile document and no trust-configuration descriptor.


0. Constitution#

OPEN (published, versioned, reproducible by anyone): Grant semantics · Proof format · protocol verification rules (§5.2) · Receipt format · Outcome Attestation format · portable identity model.

DELEGUS (the service): issuer trust · live verification (replay, revocation freshness) · evidence preservation · decision signing · adapter network · outcome graph · risk models · economic assurance.

Design constraints:

  1. An ordinary backend engineer can implement the protocol layer from this document with a standard JOSE library.
  2. Given the same inputs and the same evidence snapshot, the protocol result is identical everywhere. The Delegus decision is deterministic given inputs + snapshot + trust configuration.
  3. Fail closed. Anything unrecognized, missing, ambiguous, or unavailable is DENY.
  4. No per-transaction state except replay protection and the receipt/outcome ledger.
  5. Someone must be able to verify a Delegus artifact without calling Delegus.

1. Terminology#

TermMeaning
PrincipalThe organization on whose behalf an agent acts. Identified by a DID. Verified by domain control in v0.
AgentSoftware holding an Ed25519 private key. Identified by did:key.
Relying Party (RP)The party receiving an action and calling /verify. Registered; identified by a DID.
GrantA Principal's signed statement of what an Agent may do, for whom, until when.
ProofA short-lived Agent signature binding its key to one request, one RP, one Grant.
ActionThe RP's description of what the Agent attempts, in the constraint vocabulary.
DecisionALLOW or DENY with a machine-readable reason.
ReceiptThe Decision plus its evidence snapshot, signed by Delegus.
Outcome AttestationAn append-only event reported after a decision.

2. Canonical domain and identifiers#

2.0 Delegus domain as cryptographic infrastructure#

The canonical domain is delegus.ai. No persistent production artifact (Grant, Receipt, status-list credential, managed identity) may be issued until Delegus controls this domain. Frozen identifiers:

text
did:web:delegus.ai                      Delegus root DID (receipt and status-list signing keys)
did:web:delegus.ai:org:<slug>           managed Principal identities
did:web:delegus.ai:rp:<slug>            managed Relying Party identities
https://delegus.ai/ns/grant/v1          Grant JSON-LD context
https://status.delegus.ai/...           published status-list credentials
did:web:delegus.ai#receipt-<n>          receipt signing key identifiers

2.1 Principal — managed by default, open by design#

2.2 Agent#

2.3 Relying Party#


3. The Grant#

3.0 Semantic model and serialization profiles#

The Grant is defined by the fields and semantics in §3.2–3.3, independent of encoding. A serialization profile maps those fields to bytes and MUST NOT add or remove semantics.

ProfileStatus
VC 2.0 + compact JWS (VC-JOSE-COSE)v0 — the only profile the engine accepts
VC 2.0 + SD-JWTreserved
EUDI dc+sd-jwtreserved (eIDAS "powers and mandates to represent legal persons")
COSEreserved

3.1 JOSE header (v0 profile)#

#FieldValueRule
1algEdDSAMUST. No other algorithm accepted.
2typvc+jwtMUST.
3kidPrincipal key DID URL, e.g. did:web:acme.com#key-1MUST.

3.2 Fields#

#FieldTypeRule
4@contextarrayMUST be exactly ["https://www.w3.org/ns/credentials/v2", "https://delegus.ai/ns/grant/v1"].
5typearrayMUST be exactly ["VerifiableCredential", "DelegusGrant"].
6idstringurn:delegus:grant:<ULID>.
7issuerstringPrincipal DID. MUST equal the DID portion of kid.
8validFromRFC 3339 UTCMUST.
9validUntilRFC 3339 UTCMUST. validUntil − validFrom ≤ 90 days.
10credentialSubject.idstringAgent DID.
11credentialSubject.principalstringRoot Principal DID. v0: MUST equal issuer. Reserved for chains.
12credentialSubject.authorityarray of Capability1–16 entries.
13credentialSubject.audiencearray of RP DIDsOPTIONAL. Absent = any registered RP.
14credentialStatusBitstringStatusListEntryMUST. statusPurpose: "revocation", statusListIndex, statusListCredential.
15parentGrantstringRESERVED. MUST be absent in v0 → DENY UNSUPPORTED_FEATURE. Future: child authority ⊆ parent authority.
16–20iss, sub, jti, nbf, expregistered claimsMUST equal issuer, credentialSubject.id, id, validFrom, validUntil.

Encoded size ≤ 8 KB.

3.3 Capability and constraint vocabulary (v0)#

json
{ "action": "commerce:purchase", "constraints": { "maxAmount": 50000, "currency": "USD" }, "resources": ["*"] }

3.4 Example payload#

json
{
  "@context": ["https://www.w3.org/ns/credentials/v2", "https://delegus.ai/ns/grant/v1"],
  "type": ["VerifiableCredential", "DelegusGrant"],
  "id": "urn:delegus:grant:01J9X4QK7M3Y2Z8N6P5R4T3V2W",
  "issuer": "did:web:acme.com",
  "validFrom": "2026-09-09T00:00:00Z",
  "validUntil": "2026-10-01T00:00:00Z",
  "credentialSubject": {
    "id": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
    "principal": "did:web:acme.com",
    "authority": [
      { "action": "commerce:purchase", "constraints": { "maxAmount": 50000, "currency": "USD" } }
    ]
  },
  "credentialStatus": {
    "id": "https://status.delegus.ai/acme.com/1#4127",
    "type": "BitstringStatusListEntry",
    "statusPurpose": "revocation",
    "statusListIndex": "4127",
    "statusListCredential": "https://status.delegus.ai/acme.com/1"
  },
  "iss": "did:web:acme.com",
  "sub": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
  "jti": "urn:delegus:grant:01J9X4QK7M3Y2Z8N6P5R4T3V2W",
  "nbf": 1788912000,
  "exp": 1790812800
}

4. The Proof#

A compact JWS signed by the Agent key, modeled on DPoP (RFC 9449), binding the key to one request, one RP, one Grant.

4.1 Header#

FieldValue
algEdDSA (MUST)
typdelegus-proof+jwt (MUST)
kidAgent DID URL, e.g. did:key:z6Mk...#z6Mk... (MUST)

4.2 Claims#

FieldRule
issAgent DID. MUST equal Grant sub.
audRP DID. MUST equal the DID of the RP calling /verify.
grantMUST equal Grant id.
jtiSecurity nonce. MUST contain ≥ 128 cryptographically random bits from a CSPRNG. SDKs SHOULD generate 16 random bytes encoded as base64url without padding. MUST be 22–64 ASCII characters. Not a sortable identifier.
iatSeconds since epoch. MUST satisfy |now − iat| ≤ window (default 60 s, RP-configurable, max 300 s).
htmHTTP method, uppercase ASCII.
htuTarget URI per §4.3.
action_hashsha256:<64 lowercase hex> of the UTF-8 bytes of JCS(action) (RFC 8785).

4.3 Canonicalization#

4.4 Transport and binding profiles#

The Agent sends Delegus-Grant: <JWS> and Delegus-Proof: <JWS> headers to the RP. The RP forwards both plus its own Action object to /verify, constructing the Action from what it actually received. Only the http binding profile exists in v0; any other → PROOF_MALFORMED.


5. POST /verify#

5.1 Request#

json
{ "grant": "<JWS>", "proof": "<JWS>", "action": { "type": "commerce:purchase", "resource": "order_92813", "amount": 42700, "currency": "USD" } }

Authentication: RP API key. action.type is required; other fields per action type; unknown fields → ACTION_MALFORMED.

5.2 Protocol layer — delegus-base-v1 (OPEN)#

Reproducible by anyone given: Grant, Proof, Action, RP DID, a clock, the issuer's DID document snapshot, and the status-list credential snapshot. Each check yields true | false | "skipped".

#CheckDENY reason
P1Grant parses and conforms to §3 (incl. parentGrant absent)GRANT_MALFORMED / UNSUPPORTED_FEATURE
P2kid names a verification method present in the DID document snapshotISSUER_KEY_NOT_FOUND
P3Grant signature verifiesGRANT_SIGNATURE_INVALID
P4now ≥ validFromGRANT_NOT_YET_VALID
P5now < validUntilGRANT_EXPIRED
P6Status credential signed by Delegus; bit at statusListIndex is 0AUTHORITY_REVOKED
P7audience, if present, contains RPAUDIENCE_MISMATCH
P8Proof parses and conforms to §4 (incl. jti format)PROOF_MALFORMED
P9Proof signature verifies against Agent keyPROOF_SIGNATURE_INVALID
P10Proof iss == Grant subPROOF_AGENT_MISMATCH
P11Proof grant == Grant idPROOF_GRANT_MISMATCH
P12Proof aud == RP DIDPROOF_AUDIENCE_MISMATCH
P13iat within windowPROOF_EXPIRED
P14action_hash == hash of submitted ActionPROOF_ACTION_MISMATCH
P15Action valid for its typeACTION_MALFORMED
P16Some Capability matches action.typeACTION_NOT_AUTHORIZED
P17All constraint keys knownUNKNOWN_CONSTRAINT
P18Currency authorizedCURRENCY_NOT_AUTHORIZED
P19amount ≤ maxAmountAMOUNT_EXCEEDS_AUTHORITY
P20resource matches a patternRESOURCE_NOT_AUTHORIZED

The normative text of this table, published at a stable URL, is the profile document; its SHA-256 is protocol.profile_hash in every receipt.

5.3 Trust and service layer (DELEGUS) — delegus-trust-v1#

#CheckDENY reason
T1issuer is a registered PrincipalISSUER_UNKNOWN
T2Principal is domain-verifiedISSUER_UNVERIFIED
T3kid not marked compromisedISSUER_KEY_COMPROMISED
T5Replay: SET replay:{rp_did}:{jti} 1 NX PX {2 × window_ms} returns OK. Executed only after P1–P14 pass, as a separate internal operation from the revocation-version read that precedes P6 (§7). Store unavailable → SERVICE_UNAVAILABLE.PROOF_REPLAYED / SERVICE_UNAVAILABLE

delegus-trust-v1 is exactly T1, T2, T3, T5. Not configurable per RP. ISSUER_NOT_TRUSTED is a reserved reason code. (T4 and T6 do not exist; identifiers are not reused.)

5.4 Canonical evaluation order and reason selection#

text
P1 → T1 → T2 → T3 → P2 → P3 → P4 → P5
   → [read status_ver; refresh cached status credential if needed]
   → P6 → P7 → P8 → … → P14
   → [atomic replay SET NX]
   → T5 → P15 → … → P20

The bracketed steps are internal operations, not checks; they are shown to fix where the revocation-state read and the replay write occur relative to the checks.

Decision is DENY if any check is false; reason is the first false in this order. protocol.result is PASS iff all P-checks are true; trust.result is PASS iff all T-checks are true. Both are reported even on DENY; checks whose prerequisites failed are "skipped". now is Delegus server time, recorded in the receipt as evaluated_at; historical re-verification uses that value as now (§6.4).

5.5 Hot-path constraint#

/verify MUST perform no external DID resolution, status-list retrieval, issuer lookup, DNS lookup, or third-party network request. Internal low-latency infrastructure (Redis, Delegus-owned storage) MAY be accessed. Latency objective: p50 ≤ 30 ms, p99 ≤ 200 ms.

5.6 Response#

The response body is the Receipt (§6) as JSON, including the receipt JWS.


6. The Decision Receipt#

6.1 Purpose#

A Receipt lets any party later prove: at time T, Agent A acting for Principal B presented Grant C to RP D for Action E; Delegus evaluated it against this identity state, this revocation state, these rules, and this trust configuration, and decided X. It remains provable after keys rotate, DID documents change, and status lists are replaced.

6.2 Schema#

json
{
  "receipt_version": "delegus-receipt-v1",
  "receipt_id": "drc_01K4Q7ZP9X2M3N4R5S6T7V8W9Y",
  "decision": "ALLOW",
  "reason": null,
  "evaluated_at": "2026-09-09T14:03:27.412Z",
  "relying_party": "did:web:delegus.ai:rp:seller",
  "principal": { "id": "did:web:acme.com", "verification": "domain" },
  "agent": "did:key:z6Mk...",
  "grant_id": "urn:delegus:grant:01J9X4...",
  "grant_hash": "sha256:...",
  "proof_hash": "sha256:...",
  "request_hash": "sha256:...",
  "authority": { "action": "commerce:purchase", "constraints": { "maxAmount": 50000, "currency": "USD" } },
  "expires_at": "2026-10-01T00:00:00Z",

  "evidence": {
    "issuer_resolution": {
      "did": "did:web:acme.com",
      "did_document_hash": "sha256:...",
      "resolved_at": "2026-09-09T14:00:11Z"
    },
    "status": {
      "credential_url": "https://status.delegus.ai/acme.com/1",
      "credential_hash": "sha256:...",
      "valid_from": "2026-09-09T14:03:00Z",
      "checked_at": "2026-09-09T14:03:27.410Z",
      "status_list_index": "4127"
    },
    "trust_config_version": "trust_0042",
    "trust_config_hash": "sha256:..."
  },

  "protocol": {
    "result": "PASS",
    "profile": "delegus-base-v1",
    "profile_hash": "sha256:...",
    "checks": { "P1": true, "P2": true, "P20": true }
  },
  "trust": {
    "result": "PASS",
    "policy_version": "delegus-trust-v1",
    "checks": { "T1": true, "T2": true, "T3": true, "T5": true }
  },

  "receipt": "<compact JWS>"
}

6.3 Hash encoding#

One encoding everywhere: sha256:<64 lowercase hex chars>. Inputs are the exact bytes Delegus saw:

FieldBytes hashed
grant_hashASCII of the compact JWS string as received
proof_hashASCII of the compact JWS string as received
request_hash (= Proof action_hash when P14 passes)UTF-8 of JCS(action)
evidence.issuer_resolution.did_document_hashraw response body bytes as fetched
evidence.status.credential_hashASCII of the status-list credential compact JWS
evidence.trust_config_hashUTF-8 bytes of the immutable trust-configuration descriptor named by trust_config_version
protocol.profile_hashraw UTF-8 bytes of the published profile document

6.4 Signature and rules#

text
live /verify:                 now = Delegus server clock  (recorded as evaluated_at)
offline receipt verification: now = signed receipt.evaluated_at

7. POST /revoke#

json
{ "grant_id": "urn:delegus:grant:01J9X4..." }

Authenticated as the issuing Principal.

Consistency guarantee (normative): POST /revoke MUST NOT return success until the revocation is durably recorded and every subsequent successful /verify anywhere is guaranteed to evaluate against revocation state at least as new as that write. Once a successful revoke response has been returned, a later verification MUST NOT return ALLOW for that Grant.


8. Evidence preservation (DELEGUS obligation)#

Delegus MUST retain, addressable by hash and retrievable by any party holding a receipt that references them: every DID document snapshot, status-list credential snapshot, profile document, and trust-configuration descriptor referenced by a receipt; the receipt itself; and its outcome ledger. Retention: 7 years from evaluated_at (open question 8). GET /evidence/{sha256} returns the exact bytes.


9. Outcome Attestations#

9.1 Principle#

Outcomes are events, not states. Nothing is overwritten. Events record what the reporter observed, never a judgment about the agent; judgments arrive only as dispute_resolved.resolution.

9.2 Endpoint#

POST /decisions/{receipt_id}/outcomes — authenticated as the RP named in the receipt. Append-only.

json
{ "type": "dispute_opened", "occurred_at": "2026-09-14T09:12:00Z", "evidence_ref": "https://seller.example/disputes/8812", "note": "buyer claims goods not ordered" }

Delegus adds attestation_id (oat_<ULID>), reporter (RP DID), recorded_at. Corrections are new events with correction_of: <attestation_id>. No edits, no deletions. Ordering is by recorded_at.

9.3 v0 vocabulary#

fulfilled · cancelled · dispute_opened · dispute_resolved (resolution: agent_at_fault | agent_not_at_fault | indeterminate) · chargeback_received · chargeback_reversed · loss_reported (loss_amount minor units and currency required). Unknown type → 400. loss_amount is per event; Delegus never sums or nets.

9.4 Reporters and signatures#

v0 reporter: the RP named in the receipt only. reporter_signature (JWS over JCS of the event by the RP key) is OPTIONAL in v0 and REQUIRED from the day any assurance product reads the ledger. Reserved reporter roles (Principal, adjudicator) are not accepted in v0.


10. Data provenance and reuse rights#

Every decision and outcome record carries tenant (RP), reporter, principal, and a reuse_rights tag set at contract time. v0 defaults: used for the tenant's own audit and retrieval; for service operation (replay, abuse prevention); and for Delegus-internal, aggregate, non-identifying risk analysis. No cross-tenant disclosure of any Principal's or Agent's history and no per-entity scoring exposed to any party. Any broader reuse requires an explicit rights change recorded against the tenant.


11. Key lifecycle#


12. Out of scope for v0#

Delegation chains and attenuation (field reserved) · cumulative or per-period limits · RP-side policy · non-HTTP binding profiles · non-JWS Grant profiles · external identity adapters · agent key rotation in place · un-revoke · any bureau, score, or cross-tenant history product · any guarantee, warranty, or economic assurance.


13. Threat Model (normative scope of protection)#

13.1 v0 explicitly protects against#

IDThreatDelivered by
TM-01Forged GrantP2, P3
TM-02Modified GrantP3
TM-03Stolen Grant used without the Agent keyP9, P10
TM-04Proof replay at the same RPP13, T5
TM-05Proof forwarded to or replayed at a different RPP12
TM-06Action tampering between Agent and DelegusP14
TM-07Expired or not-yet-valid authorityP4, P5
TM-08Revoked authorityP6 + §7 guarantee
TM-09Issuer key compromise, after Delegus is notifiedT3
TM-10Stale identity evidence going unrecordedReceipt pins did_document_hash, resolved_at; refresh ≤ 5 min
TM-11Unknown or unverified issuerT1, T2
TM-12Status-list substitution or forgeryP6 (Delegus-signed); receipt pins credential_hash
TM-13Grant used at an RP the Principal excludedP7
TM-14Evidence altered after the factContent-addressed store referenced by hash from signed receipts

13.2 v0 explicitly does not protect against#

IDThreatNote
NP-01A malicious Principal intentionally authorizing malicious activityDelegus attests authority, not intent
NP-02A compromised active Principal key before Delegus learns of itBounded by Grant lifetime and key count
NP-03A compromised Agent private keyBounded by Grant scope and expiry; KMS/HSM signer recommended
NP-04Business fraud unrelated to authorityTransaction assurance, not verification assurance (§14)
NP-05Semantic ambiguity in poorly defined actionsMitigated only by the closed constraint vocabulary; RPs own the mapping
NP-06False or mistaken Outcome AttestationsReporter-tagged, append-only; not adjudicated in v0
NP-07A domain-verified Principal impersonating another organization via a lookalike domainDomain control ≠ organizational identity; roadmap: KYB
NP-08An RP misreporting the action it receivedThe receipt records the RP's own submission
NP-09Compromise of Delegus's own signing keysTrust root for the trust block; HSM custody; open-protocol reproducibility
NP-10Compromise of DNS or the web PKIShared with TLS; out of scope

13.3 Relationship to future assurance#

Any verification guarantee MUST be expressed as an explicit subset of §13.1. Nothing in §13.2 is ever covered by verification assurance; NP-04 is the boundary with transaction assurance, a different product.


14. Non-normative: assurance progression#

text
SIGNED       — every decision carries a Delegus signature                       (v0)
RECORDED     — every decision has a pinned evidence snapshot + outcome ledger    (v0)
GUARANTEED   — verification assurance over a stated subset of §13.1             (earned)
RISK-SCORED  — counterparty / action risk from decision + outcome data          (earned)
GUARANTEED   — economic assurance for covered conditions, direct or with a regulated partner (earned)

15. Implementation contract#

Build order:

  1. packages/core — pure Grant/Proof parsing, canonicalization, P-checks, receipt assembly and signing. No I/O; snapshots and clock injected.
  2. Conformance suite — ALLOW plus one deterministic vector for every DENY reason, including htu normalization, JCS, jti format, replay, revocation, and malformed inputs. The engine cannot merge until every vector passes.
  3. apps/api — Principal registry, domain verification, status lists, replay protection, evidence preservation, receipt persistence, Outcome Attestations.
  4. packages/sdk + CLI — delegus.org.create(), agent.create(), grant.create(), agent.sign(), delegus.verify(), outcome reporting.
  5. apps/demo — buyer/seller: authorized 42700 → ALLOW; revoke Grant; same action with a fresh ProofAUTHORITY_REVOKED. (A fresh Proof isolates revocation from replay; the replay path is covered separately by the conformance suite.)

The afternoon integration (relying party, complete):

ts
import { Delegus } from "@delegus/sdk";
const delegus = new Delegus({ apiKey: process.env.DELEGUS_API_KEY, publicBaseUrl: "https://seller.example" });

app.post("/orders", async (req, res) => {
  const d = await delegus.verify({
    grant: req.header("Delegus-Grant"),
    proof: req.header("Delegus-Proof"),
    action: { type: "commerce:purchase", resource: req.body.orderId, amount: req.body.amountMinor, currency: req.body.currency },
  });
  if (d.decision !== "ALLOW") return res.status(403).json({ reason: d.reason });
  // proceed; persist d.receipt with the order
});

16. Remaining open questions (non-blocking)#

  1. Minor units vs. decimals — spec: minor units.
  2. Proof window 60 s / 300 s.
  3. Replay scope per-RP.
  4. Grant max lifetime 90 days.
  5. Grant by reference as an alternative to by value.
  6. loss_amount per event (spec) — confirm with first assurance design.
  7. When reporter signatures become REQUIRED.
  8. Evidence retention period and storage model.
  9. decision vs. receipt as the primary API noun.

v0.2 is frozen.