| Internet-Draft | Sygil Protocol | July 2026 |
| Carr | Expires 7 January 2027 | [Page] |
This document specifies the Sygil Protocol, an open schema and query grammar for cross-domain personal data designed to make user data interoperable across systems, vendors, and AI agents. The protocol defines a content-addressable record envelope, a reverse-DNS namespace identifier scheme, a deterministic JSON canonicalization rule, an optional vocabulary of proof objects for conveying provenance and other trust evidence on the wire, a minimal query grammar, and three adoption tiers from envelope-shaped data through queryable surfaces to vault-certified runtimes. The protocol is runtime-neutral: it specifies what travels on the wire, not how implementations store, encrypt, authorize, or audit records. This separation lets independent systems produce, consume, and exchange Sygil-shaped data without depending on any specific vault infrastructure.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 7 January 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
Personal data -- calendar events, financial transactions, health observations, messages, location history, identity attributes, documents, preferences -- is fragmented across hundreds of vendor systems, each with its own data model, identifier scheme, access mechanism, and trust posture. AI agents operating on behalf of a person must today perform brittle, ad-hoc translation between these systems to reason across domains. There is no shared schema framework comparable to what FHIR [FHIR-R4] provides for clinical data, what iCalendar [RFC5545] provides for scheduled events, or what the Financial Data Exchange API [FDX] provides for financial transactions, that spans these domains together.¶
This document specifies the Sygil Protocol, an open schema and query grammar designed to fill that gap. The Protocol defines:¶
A record envelope with a small set of required base fields and a larger set of optional reserved fields covering subject scope, derivation lineage, retention, soft-delete state, and language.¶
A content-addressable URI scheme (sygil://) that identifies a record
version by a hash of its canonical serialization.¶
A logical-identity scheme (sygil-stable:) that identifies a record
across versions.¶
A reverse-DNS namespace identifier scheme (NSID) that allows the ecosystem to extend permissionlessly while keeping core namespaces stable.¶
Deterministic JSON canonicalization per RFC 8785 [RFC8785], the basis for reproducible content hashes.¶
A minimal query grammar of six required primitives plus optional trust-dimension filters.¶
An optional vocabulary of proof objects (sygil.proof.*) for
conveying provenance, capability, consent, attestation, and audit
evidence alongside records. Integrity is implicit at every tier via
the content-addressed id.¶
Three adoption tiers ranging from Sygil-shaped data (Tier 1) through Sygil-queryable surfaces (Tier 2) to vault-certified runtimes (Tier 3).¶
The motivation for this work -- why translation at the language-model layer cannot supply the provenance, consent, audit, portability, and conformance guarantees that agents operating on personal data require, and why a shared semantic substrate is the layer where those guarantees can hold -- is developed at length in the Sygil Protocol Whitepaper [SYGIL-WP].¶
The Protocol specifies what Sygil-shaped data is on the wire. It does not specify:¶
A storage substrate. Records may be stored in any database, file system, or in-memory representation.¶
An encryption-at-rest scheme. Storage encryption is a runtime concern.¶
A specific authorization mechanism. The Protocol defines a vocabulary for capability and consent proofs but does not require any specific authorization framework (OAuth, UCAN, OpenFGA, Cedar, ODRL, or any other) to underlie that vocabulary.¶
A federation protocol. Multi-vault synchronization, cross-user record sharing, and replication are runtime concerns.¶
A transport protocol. Records may be carried over HTTP, the Model Context Protocol [MCP], or any other transport.¶
An identity provider. The Protocol uses Decentralized Identifiers ([W3C-DID]) to identify data subjects but does not issue, verify, or resolve them; resolution semantics are bound by DID method.¶
These boundaries are load-bearing. The Protocol is useful precisely because it can be adopted without committing to any specific vault, authorization framework, or transport. Sygil-shaped records can be produced by a connector wrapping a third-party API and consumed by a local-first application, with no intermediary vault, no authorization server, and no network protocol shared between producer and consumer beyond the medium that carries the bytes.¶
Sygil distinguishes the Protocol -- the schema and query grammar specified by this document -- from vault implementations, which operationalize storage, encryption, authorization, audit, and trust enforcement on top of Sygil-shaped data. The Protocol/vault relationship is analogous to the relationship between the Linux kernel ABI and a specific Linux distribution: the kernel ABI is the open standard that multiple distributions share; each distribution makes its own opinionated runtime choices. Conformance to the Protocol does not require adoption of any specific vault implementation, and competing vault distributions are expected.¶
This document is an Internet-Draft submitted as an Independent Submission. Its intended status is Informational. It specifies a data protocol -- a schema, identifier and serialization conventions, an optional proof-object vocabulary, and a minimal query grammar -- rather than a transport protocol or interaction model (see Section 3.2 for the classification rationale and prior-art comparison). The document documents an open schema and query grammar developed by Sygil PBC and published under the IETF Trust Legal Provisions to facilitate community review, alignment with related IETF work (including OAuth 2.0 [RFC6749] extensions, DID resolution, and JSON canonicalization), and eventual standards-track follow-on work in relevant working groups.¶
A narrative companion to this specification, the Sygil Protocol Whitepaper [SYGIL-WP], sets out the motivation, the history of cross-domain personal-data standardization, the design principles, and the conditions that motivate the Protocol. That document is informational background; this Internet-Draft is the normative specification, and where the two differ this document governs.¶
This document does not obsolete or update any existing RFC.¶
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 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
Throughout this document, the terms "Producer" and "Consumer" refer to the party that creates a Sygil record and the party that receives it, respectively. The terms "Subject" and "Vault" refer to the data subject the record is about and to a runtime that stores and serves Sygil records on a Subject's behalf, respectively. Section 2 defines these and other terms normatively.¶
Examples in this document are non-normative and use the example identifiers and domain names reserved by [RFC2606].¶
The conformance keywords are defined in the Conventions section of the Introduction (Section 1.4).¶
This section defines the terms used normatively throughout this document.¶
A software entity, typically an AI model or AI-driven application, that produces or consumes Sygil records on behalf of itself or of a Subject. Agents are external to the Protocol and are mentioned here only because the Protocol's design goals are oriented toward agent-native consumption (Section 3).¶
The conformance keywords defined in [RFC2119] and [RFC8174].¶
The deterministic JSON serialization specified in Section 4.5, conforming to [RFC8785]. Sometimes referred to as "JCS" (JSON Canonicalization Scheme) by the name of the specification it follows.¶
A Producer that imports records from an upstream non-Sygil source
system (for example, a calendar provider, a financial data
aggregator, an electronic health records system) and produces Sygil
records representing that data. Connectors are external to the
Protocol; this document mentions them only because some Protocol
fields (source_system, connector_id in sygil.proof.provenance)
refer to them.¶
The state of an implementation that satisfies the requirements of one of the three adoption tiers defined in Section 6 for at least one Sygil namespace. Conformance is asserted per (namespace, tier) pair; it is not asserted at the implementation level as a whole.¶
A party that receives a Sygil record. Consumers are responsible for schema validation, reference handling, and (where applicable) proof verification per the rules in Section 7 (Failure Semantics) and Section 8 (Security Considerations).¶
The cryptographic hash of a record's canonical serialization (with
hash exclusions per Section 4.5), used to construct the record's
id URI. The hash algorithm is BLAKE3 [BLAKE3]; the hash output
is encoded as a base64url string without padding, of the form
blake3-{base64url} (Section 4.5.3).¶
A Decentralized Identifier as defined in [W3C-DID]. Sygil uses DIDs to identify Subjects and other principals. The Protocol treats DIDs as opaque except for the method tag (Section 4.9); resolution is delegated to the DID method.¶
The set of base fields common to every Sygil record, defined in Section 4.2. The envelope distinguishes Sygil-shaped data from arbitrary JSON.¶
A software system that produces, consumes, or both produces and consumes Sygil records. An implementation MAY be a Tier 1, Tier 2, or Tier 3 implementation per Section 6, and MAY assert different conformance tiers for different namespaces.¶
JSON Canonicalization Scheme [RFC8785], the canonicalization rule specified in Section 4.5.¶
A reverse-DNS-style identifier of the form
sygil.v1.{domain}.{type} for core namespaces, or
{publisher.domain}.{type} for third-party namespaces. NSIDs
identify the type of a record and govern the schema the record
validates against. NSID structure and rules are defined in Section
4.3.¶
A party that creates a Sygil record. Producers are responsible for emitting only valid records per the rules in Section 7.¶
An optional object attached to a record's _proofs array that
conveys evidence of integrity, provenance, capability, consent,
attestation, or audit. Proof objects are vocabulary; their
interpretation and verification are out of scope for the Protocol
and are addressed by vault implementations (Section 5).¶
A view of a record produced by a Vault implementation according to a
privacy classification policy (Section 4.2.5). The wire-time
envelope field redaction_state (Section 4.2) labels the projection
level the served record represents.¶
An instance of a Sygil namespace. A record is structurally a JSON object [RFC8259] with the envelope fields defined in Section 4.2 plus namespace-specific fields defined by the record's NSID.¶
The naming convention used for NSIDs, proof object types, connector
identifiers, and community-extension namespace publisher identifiers
(Section 4.2.5) throughout the Protocol. Names read in reverse-DNS
order -- most-significant component first (sygil.v1.calendar.event,
sygil.community.acme.example.com.media.album) -- to ensure
publisher-controlled namespacing without central coordination. The
convention follows [RFC6648]'s recommendation against
X--prefixed extensions.¶
sygil:// URI:The content-addressed URI scheme used as a record's id. Defined
in Section 4.4.¶
sygil-stable: URI:The logical-identity URI scheme used as a record's stable_id. All
v1 records carry both identifiers, including inherently immutable
records (which carry version: 1 and never increment). Defined in
Section 4.6.¶
The natural or legal person whom a record is about. Identified by a
DID. The Subject's DID appears in the sygil:// URI prefix and may
also appear in optional envelope fields (subject_did,
subjects[]).¶
The three adoption tiers defined in Section 6. Tier 1 implementations produce or consume Sygil-shaped data without any runtime services. Tier 2 implementations expose a Sygil-queryable surface. Tier 3 implementations operate as vault-certified runtimes.¶
A runtime that stores Sygil records and serves them under access control on a Subject's behalf. The Protocol does not specify how a Vault operates; it specifies only what records look like on the wire between a Vault and other parties. Vault operation is addressed by separate vault-implementation specifications.¶
Information a Vault may attach to records for its own purposes
(storage hints, access logs, internal indices) that is not part of
the Sygil envelope or any Sygil namespace. Vault-private metadata
MUST NOT be emitted on the wire under the sygil.* or any other
Sygil-specified field name.¶
This section describes the shape of the Protocol so that the rest of the document is comprehensible. Wire-level normative requirements are specified in subsequent sections.¶
The Protocol is designed to satisfy four goals. The architectural commitments behind these goals -- in particular the decision to compose from existing standards rather than replace them, and to keep the Protocol orthogonal to storage, authorization, and runtime concerns -- are discussed further in [SYGIL-WP].¶
Cross-domain coverage. The Protocol provides a single coherent schema framework that spans identity, calendar, messages, finance, health, location, documents, preferences, media, tasks, commerce, claims, and channels (the v1 namespaces; see Section 4.7). Records in any namespace share the same envelope structure, the same identifier scheme, and the same canonicalization rule, so that Consumers reasoning across namespaces can do so uniformly.¶
Standards alignment. Each namespace declares mappings to existing external standards where they exist (vCard [RFC6350] for identity, iCalendar [RFC5545] for calendar, FHIR [FHIR-R4] for health, FDX [FDX] for finance, Internet Message Format [RFC5322] for messages, Schema.org [SCHEMA-ORG] for general entity vocabulary). Sygil does not replace these standards; it composes them under a uniform envelope and identifier scheme.¶
Runtime neutrality. A developer with a JSON Schema validator, an HTTP stack, and the canonicalization rule from Section 4.5 can produce and consume Sygil-shaped data without any vault, authorization server, or other runtime infrastructure. This is enforced architecturally: nothing in this document describes how a Vault stores, encrypts, or authorizes records.¶
Agent legibility. Sygil records are designed to be legible to AI
agents without out-of-band context. Stable, predictable record types
(NSIDs); predictable resource identifiers (sygil://); declared
relationships between records; typed fields with documented semantics;
a minimal, predictable query grammar; and optional proof metadata that
agents can consume without verifying -- these properties together let
an agent that has never encountered a particular Sygil-shaped record
identify its type, parse it, follow its references, and reason about
it.¶
This document specifies a data protocol: a schema, a set of identifier and serialization conventions, an optional proof-object vocabulary, and a minimal query grammar. It does not specify a wire protocol in the sense of a request/response interaction model, a session lifecycle, or a transport binding. Sygil records are carried over whatever transport the deployment chooses (HTTP, the Model Context Protocol [MCP], file-based exchange, others); the Protocol is what makes a JSON object recognizably and validatably a Sygil record on either side of that transport.¶
This classification is consistent with prior IETF practice for data-protocol specifications:¶
[RFC8259] (The JavaScript Object Notation (JSON) Data Interchange Format) specifies a syntax and semantics without specifying any interaction model.¶
[RFC5545] (Internet Calendaring and Scheduling Core Object Specification, iCalendar) specifies a record format, a set of property and component definitions, and conventions for cross-system exchange -- without specifying a wire protocol per se. (iCalendar Transport-Independent Interoperability Protocol, RFC 5546, is a separate document.)¶
HL7 FHIR [FHIR-R4] (referenced informatively here, as it is not an IETF specification) follows the same shape: a resource model with normative wire format, with REST and other transport bindings defined separately.¶
Sygil follows the same shape. The wire format (envelope, identifier scheme, canonicalization, namespace declarations, proof object vocabulary) is normative; transport bindings, request/response patterns, and runtime composition are out of scope. A future Sygil specification may define a transport binding; this document does not.¶
The Protocol explicitly does not require, and rejects any attempt to require:¶
A specific storage substrate.¶
Encryption at rest.¶
A specific transport protocol.¶
A specific authorization mechanism, framework, or policy language.¶
A specific federation primitive, replication scheme, or cross-Vault synchronization protocol.¶
A specific identity-provider relationship beyond the use of DIDs.¶
Witness cosigning, transparency logs, or other trust infrastructure
beyond the optional sygil.proof.audit and sygil.proof.attestation
proof objects, whose verification is out of scope.¶
The Protocol MAY define fields and proof object types that allow
these systems to express output (for example, sygil.proof.capability
references a capability token by ID and hash; sygil.proof.attestation
references an attestation report by URI). It does not require those
systems to exist or to be used.¶
This document does not specify how a Vault implementation computes an authorization decision, derives a proof object from underlying policy state, or evaluates trust across multiple proof objects. These are runtime concerns. The Protocol specifies only the on-the-wire vocabulary by which the result of such a computation may be conveyed.¶
A Sygil-shaped data system is built from five components, each specified in subsequent sections of this document. This subsection introduces them at the conceptual level so that subsequent sections have an established vocabulary to reference.¶
Every Sygil record carries a small set of base fields that identify
it, locate it in the namespace ecosystem, and bind it to its
canonical content. These are the required fields (@type, id,
stable_id, version, created_at, updated_at -- required for
all v1 records, including inherently immutable records which carry
version: 1 and never increment), and a defined set of optional and
reserved fields covering subject scope, derivation lineage, retention,
soft-delete state, and language. The envelope is what makes a JSON
object a Sygil record. Section 4.2 specifies the envelope in full.¶
Each Sygil record's type is identified by an NSID -- a reverse-DNS
identifier such as sygil.v1.calendar.event or
sygil.community.acme.example.com.media.album. The NSID names the
schema the record validates against. Core Sygil namespaces use the
sygil.v1. prefix and follow a release-tagged versioning scheme
(sygil.v1.*, sygil.v2.*) in which constraint sets are immutable
once published. Third parties define their own namespaces under the
sygil.community.{publisher}.* prefix per the NSID extension pattern
(Section 4.2.5). Section 4.3 specifies NSID structure and rules;
Section 4.7 enumerates the v1 namespaces.¶
Sygil uses two identifier forms. The sygil:// URI is a
content-addressed identifier whose final component is the BLAKE3 hash
of the record's canonical serialization (with defined exclusions); it
identifies a specific version of a specific record. The
sygil-stable: URI identifies the logical record across versions,
for record types that mutate over time (calendar events, financial
transactions that may be updated). The two forms together let a
Consumer verify integrity (sygil:// is a hash) while still tracking
record evolution (sygil-stable: survives updates). Section 4.4
specifies sygil://; Section 4.6 specifies sygil-stable:.¶
A record MAY carry zero or more proof objects in its _proofs field.
Each proof object asserts a specific kind of claim about the record:
that it was sourced from a named upstream
system (sygil.proof.provenance), that the access producing it was
authorized by a capability token (sygil.proof.capability), that the
access was covered by a consent receipt (sygil.proof.consent), that
the record was produced inside a trusted execution environment
(sygil.proof.attestation), or that the access was logged in an
audit log (sygil.proof.audit). Integrity is implicit at every tier
via the content-addressed id; no separate proof object is required
because any party with the record can canonicalize and hash it to
verify against the id. Proof objects are wire vocabulary;
the Protocol specifies their shape and meaning but not how they are
produced or verified. Section 5 specifies the proof object vocabulary.¶
The Protocol defines three adoption tiers. Tier 1 is Sygil-shaped
data: records carry valid envelopes, validate against schemas, and
canonicalize reproducibly. Tier 2 adds a queryable surface
implementing the six required query primitives. Tier 3 adds vault
runtime semantics -- proof attachment under Agent access, audit log
operation, per-Subject isolation. Each tier is a strict superset of
the previous. Conformance is asserted per (namespace, tier) pair: an
implementation can be Tier 2 for sygil.v1.calendar.event while
silent for sygil.v1.health.observation. Section 6 specifies the
tiers.¶
The Protocol contemplates four roles that interact through Sygil- shaped records:¶
+------------+ produces +-----------+
Subject | Producer | ---------------------> | Vault |
(DID) | (Connector,| <- - - - - - - - - - - | (storage, |
| Agent, | optional sync | access |
| Subject | | control) |
| herself) | +-----+-----+
+------------+ |
| serves
v
+------------+ queries +-----------+
| Agent | <--------------------- | Consumer |
| (LLM, | ---------------------> | (Agent, |
| app, ...) | records | app, or |
+------------+ | another |
| Vault) |
+-----------+
Wire boundary: Sygil records (envelope + namespace fields + _proofs)
Out of scope: Vault internals, transport, authorization computation
¶
The wire boundary -- what crosses between parties -- is the subject of this document. What happens inside the Vault to produce records served to a Consumer is the subject of vault-implementation specifications.¶
The Protocol composes with existing standards in three ways.¶
Aligned namespaces (Section 4.7) declare their primary external
binding. A sygil.v1.calendar.event record aligns to iCalendar
[RFC5545] and Schema.org Event; a sygil.v1.health.observation
record aligns to FHIR Observation [FHIR-R4]; a
sygil.v1.identity.person record aligns to vCard 4.0 [RFC6350] and
Schema.org Person. Implementations are not required to emit external
forms; the alignment exists so that Consumers already speaking the
external vocabulary can map Sygil records into it via published
JSON-LD contexts (Section 4.7).¶
Referenced vocabularies (Section 5) appear in proof object types.
The sygil.proof.consent proof object refers to consent receipts that
may follow the W3C Data Privacy Vocabulary, ISO/IEC TS 27560:2023
[ISO-27560], or other consent-receipt schemes. The
sygil.proof.capability proof object refers to a capability token by
identifier and hash; the token format itself is unspecified by the
Protocol but is commonly UCAN, OAuth 2.0 access token, or a similar
construct.¶
Informative comparators include the AT Protocol repository format
[ATPROTO] (whose Lexicon discipline inspires the Sygil NSID
immutability rule), W3C Verifiable Credentials [W3C-VC2] (which the
reserved sygil.v1.credential.* namespace will adopt verbatim when
specified), and the Model Context Protocol [MCP] (a common transport
for agent-mediated record retrieval). None of these are normative
dependencies of this document.¶
The Protocol does not require any specific authorization framework. Implementations are free to compose policy frameworks (OAuth 2.0 [RFC6749], OAuth 2.0 Demonstrating Proof of Possession [RFC9449], OAuth 2.0 Rich Authorization Requests [RFC9396], capability tokens, authorization engines such as OpenFGA or Cedar, or policy languages such as ODRL [W3C-ODRL] or the W3C Data Privacy Vocabulary) as best fits their deployment; the Protocol's role is to define the vocabulary by which the result of such authorization (a proof object) travels with a record. How the proof object was derived is a runtime concern.¶
The boundary between Protocol and runtime is enforced throughout this document. Anywhere this document slips into runtime specification -- storage, encryption, authorization computation, audit log structure, Vault federation -- the text is wrong and should be moved to a vault-implementation specification.¶
The reverse holds for vault-implementation specifications: anywhere they specify the on-the-wire shape of a record, identifier, hash, or proof object, they are duplicating this document. The Protocol is the single source of truth for wire format; vault specifications are the single source of truth for runtime behavior.¶
The table below makes the boundary explicit. For each Sygil-relevant concern, the table indicates whether the Protocol defines it, defines vocabulary for it without specifying behavior, or treats it as out-of-scope. The latter two columns are not normative for this document; they are shown to make the runtime delegation auditable.¶
| Concern | Protocol | Vault implementation |
|---|---|---|
| Personal data schemas | Defines | Implements |
| NSIDs | Defines | Uses |
sygil:// URIs |
Defines | Resolves |
stable_id format |
Defines | Uses |
| Canonical serialization (JCS) | Defines | Uses |
| Query grammar | Defines minimal semantics | Enforces access; executes |
| Proof object types | Defines vocabulary | Produces, verifies |
| Privacy classification | Defines descriptive metadata | Enforces projection policy |
| Storage substrate | Out of scope | Implements |
| Encryption at rest | Out of scope | Implements |
| Authorization runtime | Out of scope (vocabulary only) | Implements |
| OAuth, UCAN, capability tokens | Optional proof reference only | Implements |
| ODRL, W3C DPV | Optional proof vocabulary | Implements, enforces |
| Audit log structure | Optional proof reference | Operates log |
| TEE attestation flows | Optional proof object | Produces, verifies |
| Connectors | Out of scope | Implements |
| Transport (HTTP, MCP, etc.) | Out of scope | Implements |
| Federation between Vaults | Out of scope | Implements (where present) |
| Cross-Subject record sharing | Out of scope | Out of scope (typically) |
A row that says "Defines" in the Protocol column means the specification for that concern lives in this document; vault implementations use what the Protocol defines. A row that says "Out of scope" means this Protocol will reject any attempt to specify the concern; the vault implementation's specification is where it belongs. A row that says "Optional proof vocabulary" or "Optional proof reference" means the Protocol defines a way for the result of the runtime concern to be carried on the wire (as a proof object or proof field) without specifying the runtime concern itself.¶
This section specifies the wire format of Sygil records. It is the normative core of this document.¶
A Sygil record is a JSON object [RFC8259] carrying the envelope fields defined in this section plus namespace-specific fields defined by the record's NSID.¶
Record identity is defined strictly by the id URI (Section 4.4):
two records with the same id are the same record version, and two
records with the same stable_id (Section 4.6) are versions of the
same logical record. Semantic equivalence beyond identity -- whether
two records "represent the same thing" in some application sense
when their id URIs differ -- is out of scope for this Protocol.
Applications and Consumers that need semantic equivalence relations
construct them outside the Protocol.¶
Identity entails deduplication. Records with identical id
URIs represent the same canonical content; differences in fields
excluded from the content hash (_proofs, updated_at, version,
supersedes, obsolete, obsolete_reason -- see Section 4.5) MUST
NOT be treated as creating distinct record identities for caching,
deduplication, storage, or transport purposes. Two encounters with
the same id are encounters with the same record, even if the
encounters differ in proof attachments.¶
This rule prevents a class of implementation divergences in
storage and transport layers. An implementation that stored two
records with the same id separately because their _proofs
arrays differed would be holding what the Protocol considers one
record as two; downstream Consumers retrieving via either copy
would receive divergent views of the same canonical content. The
current text makes this explicit so that storage, caching, and
deduplication implementations align on what counts as one record.¶
A Consumer that needs to track multiple proof variants of the same
record (for example, an audit log that records every proof
attachment seen for a given id) MUST use a separate
implementation-private metadata structure keyed on the id URI;
it MUST NOT model these as separate records under the Protocol's
identity rules.¶
Every Sygil record MUST carry the following fields:¶
| Field | Type | Semantics |
|---|---|---|
@type
|
string | NSID of the record type. Format defined in Section 4.3. |
id
|
string | Content-addressed sygil:// URI for this version of the record. Format defined in Section 4.4. |
created_at
|
string | ISO 8601 timestamp with timezone [RFC3339], indicating when the record was first created in any system. |
updated_at
|
string | ISO 8601 timestamp with timezone, indicating when the record was last modified. |
Every v1 record MUST additionally carry the logical-identity and versioning fields below. These are REQUIRED for all record types, mutable and immutable alike:¶
| Field | Type | Semantics |
|---|---|---|
stable_id
|
string | Logical record identity that persists across updates. Format defined in Section 4.6. |
version
|
integer | Monotonically increasing integer per stable_id, starting at 1. |
For inherently immutable record types (a logged event, a cryptographic
attestation captured at a point in time), stable_id and version are
still REQUIRED. Such records carry version: 1 and never increment it,
and their stable_id is computed exactly as for mutable records
(Section 4.6). Requiring both identifiers uniformly on every record --
rather than conditioning them on a per-type mutability flag -- lets
validators, indexes, reference resolution, replay and export pipelines,
generated types, and policy code treat every record the same way, with
no special case for the immutable subset. The namespace specification
declares whether records of a given type are mutable, which governs
whether version is ever expected to advance, not whether these fields
are present.¶
The following optional fields MAY appear on any record:¶
| Field | Type | Semantics |
|---|---|---|
supersedes
|
string |
sygil:// URI of the immediately preceding version of this record (i.e., the record with the same stable_id and version - 1). |
subject_did
|
string | DID of the data subject. Defaults to the DID encoded in the id URI prefix; explicit when the relationship needs to be unambiguous. |
issuer_did
|
string | DID of the party that produced this record (e.g., a connector, a Vault, an Agent). |
source_system
|
string | Identifier of the upstream non-Sygil system the record was derived from (e.g., google_calendar, plaid, apple_health). |
_proofs
|
array | Array of zero or more proof objects per Section 5. |
The following fields are part of the v1 envelope, are optional, and are reserved for runtime semantics that the Protocol does not itself define. v1 implementations are not required to populate them or to enforce behavior based on them. Producers MAY emit them. Consumers MUST preserve and pass them through unchanged when forwarding or re-emitting records, per Section 6.5.1 (Forward compatibility).¶
| Field | Type | Default | Semantics |
|---|---|---|---|
subject_scope
|
enum |
sole
|
Whether the record's subject set is sole, bilateral, multilateral, observed, or claim. v1 implementations handle sole only. Other values are reserved for the multi-party data story (group messages, Subject-claims-by-others, observation records). |
subjects
|
array |
[]
|
Array of peer subject DIDs for non-sole records. Empty for sole. |
derived_from
|
array |
[]
|
Array of derivation-reference objects describing records this one was derived from (calendar event extracted from email; transaction-category claim derived from a bank transaction; AI inference output). Each entry is an object whose source_record field carries the sygil:// URI of the source record; the object shape is defined immediately following this table. Distinct from supersedes, which is single-record version history. For each entry, the record referenced by source_record MUST have a created_at value strictly earlier than the deriving record's created_at; this temporal constraint prevents derivation cycles. Producers emitting derived_from MUST verify the temporal ordering before emitting. |
expires_at
|
string | absent | ISO 8601 timestamp at which the record's content should be considered expired by retention policy. Required when retention_policy is present. |
retention_policy
|
string | absent | Reverse-DNS identifier of the governing retention policy. The Protocol does not define policy semantics; the field is a runtime hook. When retention_policy is present, expires_at MUST also be populated; a record carrying retention_policy without expires_at is malformed. |
obsolete
|
boolean |
false
|
Cross-namespace soft-delete flag. Per-namespace status fields keep their domain-specific meanings; obsolete is the uniform "no longer current" signal. |
obsolete_reason
|
enum | absent | Required when obsolete is true. One of superseded, user_deleted, source_deleted, expired, corrected, withdrawn_consent, unknown. |
language
|
array |
[]
|
Array of BCP 47 language tags identifying the human-readable languages present in the record. Empty array indicates no language assertion. Multiple tags are valid for records carrying content in multiple languages (a calendar event with English title and Japanese description, an identity record with native-script and romanized name forms). |
Each entry in derived_from is a derivation-reference object (@type =
sygil.common.derivation_ref) with the following fields:¶
source_record (string, REQUIRED)The sygil:// URI of the source record this record was derived from.¶
derivation_method (string, REQUIRED)Identifier of the method used to derive this record from
source_record (for example, an extraction, inference, or
transformation method).¶
derivation_at (string, REQUIRED)ISO 8601 timestamp with timezone indicating when the derivation occurred.¶
derivation_agent (string, OPTIONAL)Identifier of the agent or skill that performed the derivation.¶
derivation_model (string, OPTIONAL)Identifier of the model used during the derivation, when applicable.¶
derivation_confidence (number, OPTIONAL)Confidence score in the range 0.0 to 1.0 assigned to the derivation.¶
An earlier draft modeled derived_from as a bare array of sygil://
URI strings. The object form is normative for v01: the source-record
URI is carried in source_record, and the remaining fields capture the
derivation method, time, agent, model, and confidence that constitute
the derivation's provenance.¶
The forcing function for reserving these fields at v1 rather than
adding them in a later release is that envelope changes after v1 lock
are catastrophic: they cascade through every namespace, every
connector, every conformance test, every running record store. The
cost of reserving the field names and shapes now, with v1
implementations only required to handle the trivial case (sole
subject scope, no derivation, no retention, not obsolete, no language
assertion), is bytes; the cost of needing them later is years.¶
Envelope interaction rules. The following rules govern how envelope fields combine and are normative for v01 implementations:¶
obsolete and expires_at. A record MAY carry both: obsolete: true with obsolete_reason: expired and a populated expires_at is the canonical form for retention-driven obsolescence. A record with obsolete: false and expires_at in the past is legal (the obsolescence pipeline has not run yet); Consumers SHOULD treat such records as effectively obsolete for query purposes but MUST preserve the field values verbatim when forwarding.¶
retention_policy requires expires_at. Producers MUST NOT emit a record with retention_policy populated and expires_at absent; doing so is malformed. Consumers receiving such a record SHOULD log the malformation but MUST preserve the record per the lenient-input discipline of Section 7.¶
derived_from[] cycles. Each entry's referenced record MUST have a created_at strictly earlier than the deriving record's created_at. This prevents cycles by construction (no record can be its own ancestor). Consumers performing derivation traversal MAY rely on the temporal constraint to bound traversal depth.¶
Earlier drafts of the v1 envelope reserved four additional fields --
jurisdiction[], provenance_quality, redaction_state, and
_extensions -- that did not survive the v0.3 reconciliation that
produced this v01 increment. Jurisdiction binding was determined to
be properly a runtime concern derivable from subject_did and source
content, contradicting the Protocol's regulatory-agnostic stance.
provenance_quality substantially overlapped with the trust
dimensions (cooperation_mode, freshness, completeness,
verifiability) already conveyed by sygil.proof.provenance (Section
5.4); the proof-object form is the canonical home. redaction_state
was relocated to the query response envelope (Section 4.10), since
the same record content can be served as different projections in
different responses; the projection state belongs to the response,
not the record. _extensions was replaced by the NSID extension
pattern (Section 4.2.5), in which custom record types live under
sygil.community.{publisher}.* community-namespace records rather
than as embedded extension bags. The language field was changed
from a single BCP 47 tag (string) to an array of tags, since
multilingual records are common in practice.¶
Two prefix conventions in the envelope are reserved by the Protocol:¶
Field names beginning with _ are reserved for Sygil-defined
metadata excluded from the content hash (Section 4.5). The field
currently using this prefix is _proofs (Section 5).
Implementations MUST NOT introduce arbitrary leading-underscore
field names; third-party metadata MUST use the NSID extension
pattern (Section 4.2.5).¶
The @type field name is reserved at the top of every record
and every supporting object. The leading @ aligns Sygil records
with JSON-LD (Section 4.2.6). Implementations MUST NOT use other
@-prefixed field names; the @-prefix space is reserved for
Sygil-defined or JSON-LD-defined keywords.¶
Implementations needing record-shaped data not covered by the v1
namespace set MUST use the NSID extension pattern rather than embedding
extension data in records under the core sygil.v1.* namespace. The
pattern has two components: a publisher namespace and a community-
namespace prefix.¶
Implementations identify themselves with a reverse-DNS-shaped publisher identifier. Publisher identifiers MUST be valid DNS labels joined by dots; common shapes include:¶
A controlled domain (e.g., acme.example.com for a publisher at
acme.example.com)¶
A versioned product identifier (e.g., vendor.product.v2 for a
publisher's specific product line)¶
Publisher identifiers MUST be globally unique across all Sygil implementations. Implementations operating under a controlled domain SHOULD use the domain itself or a sub-component as the publisher identifier; implementations without a controlled domain SHOULD register their identifier through the Sygil NSID Extension Registry (Section 10).¶
Records published outside the core sygil.v1.* namespace set use the
prefix sygil.community.{publisher}. for the NSID. The grammar:¶
nsid = core-nsid / community-nsid
core-nsid = "sygil." version "." namespace "." record-type
; e.g., "sygil.v1.calendar.event"
community-nsid = "sygil.community." publisher "." namespace "."
record-type
; e.g.,
; "sygil.community.acme.example.com.media.album"
publisher = label *( "." label )
; reverse-DNS publisher identifier
¶
Records under sygil.community.{publisher}.* are valid Sygil records
and travel through the same envelope, canonicalization, identifier, and
proof object infrastructure as core records. Consumers process them
using the unknown-NSID rule (Section 4.3): preserve the record verbatim,
log if unknown, do not reject. A Consumer that recognizes a particular
community namespace MAY interpret records under that namespace as that
publisher's specification dictates; a Consumer that does not recognize
it treats records as opaque.¶
When a record type that has been used widely under
sygil.community.{publisher}.{namespace}.{record-type} formally lands
in the core sygil.v1.* namespace set in a future Protocol version,
the corresponding community-namespace records can be migrated. The
Protocol does not specify a migration mechanism; vault implementations
and tooling provide the migration path. The community-namespace record
type and the core record type MAY coexist during the migration period.¶
Without an explicit extension pattern, implementations needing custom
record types had three options: (1) abuse a top-level _extensions
envelope field (the reservation pattern that earlier drafts of this
Protocol had reserved and that v0.3 reconciliation removed), (2) emit
records under the core sygil.v1.* namespace with custom fields (which
would fragment the namespace), or (3) emit records under arbitrary non-
Sygil-prefixed NSIDs (which would lose the Sygil envelope and proof
infrastructure). The NSID extension pattern provides a fourth option
that preserves the envelope and infrastructure while clearly marking
records as community-extension rather than core-Protocol.¶
Each field in each Sygil namespace declares a default privacy classification as part of its schema definition. The classifications are descriptive metadata; the Protocol does not enforce them. They exist to give Vault implementations a consistent input for projection policy decisions.¶
Three classes are defined:¶
| Class | Semantic |
|---|---|
public
|
The field may be exposed by default in any projection that includes the record. |
redacted
|
The field may be replaced with a placeholder, masked, or null in low-trust projections, and included verbatim in high-trust projections. |
invisible
|
The field may be omitted entirely from low-trust projections; included only in high-trust projections with explicit consent. |
The classifications belong in the Protocol (rather than in implementation-private policy) because field sensitivity is intrinsic to the field, not to the deployment. A health observation is sensitive everywhere; a calendar event location is sensitive everywhere. Encoding the classification in the schema gives every conformant implementation the same input to operate on, supports federation across trust boundaries (both sides agree on what is sensitive), and enables consistent agent behavior across runtimes.¶
The redaction_state envelope field (Section 4.2.4) is the wire-time
counterpart: it labels which projection level the served record
represents (original, redacted, summary, hash_only). The
classification governs which fields a Vault may include or omit at
each projection level; redaction_state records which level was
served. Per-namespace specifications declare the classification for
each field.¶
The Protocol does not define what specific projections look like or how a Vault decides which projection to serve. Those are runtime concerns. Common projection patterns include:¶
A free_busy projection for calendar availability checks (time and
availability fields only).¶
A summary projection for typical Agent context (public plus
redacted with placeholders).¶
A full projection for user-authorized full access (all fields
including invisible).¶
An audit projection for compliance review (all fields plus audit
metadata).¶
These are illustrative, not normative. A Vault implementation MAY
define any number of projections; this Protocol commits only to
labeling which level was served in redaction_state.¶
Sygil records carry @type on every record and on every supporting
object. This is a deliberate design choice: it makes Sygil records
JSON-LD-shaped at the syntax level without committing to JSON-LD as
the canonical form.¶
Sygil records do not carry an inline @context field by default.
The canonicalization rule (Section 4.5) operates on the JSON form,
not on the JSON-LD-expanded form; adding inline @context to records
would require either including context URLs in the canonicalization
input (binding context resolution to record identity) or excluding
them (creating a new exclusion rule). Keeping contexts external
avoids both.¶
Per-namespace @context files are published as external generated
artifacts (Section 6.4), at stable URLs under the Protocol's
publication infrastructure. A Consumer that already understands a
target vocabulary -- Schema.org [SCHEMA-ORG], W3C Verifiable
Credentials [W3C-VC2], FHIR R4 [FHIR-R4] -- can fetch the
appropriate context and apply it at processing time, mapping Sygil
field names to the target vocabulary's URIs without a custom Sygil
parser.¶
Adoption of the published contexts is OPTIONAL for Sygil-native Consumers. Sygil-aware implementations do not need contexts to interpret records; they already know the schema. The contexts exist for the asymmetric interop case: a Schema.org-aware tool reading a Sygil record. The reverse direction -- a Sygil-native Consumer reading an arbitrary Schema.org record and treating it as a Sygil record -- generally requires connector logic, not just context publication.¶
NSIDs use reverse-DNS structure to distinguish core Sygil namespaces
(prefix sygil.) from third-party namespaces (prefix is the
publisher's reverse-DNS domain).¶
Examples:¶
sygil.v1.calendar.event sygil.v1.identity.person sygil.v1.finance.transaction com.example.customapp.myrecord¶
The reverse-DNS pattern is consistent with prior practice for vendor extensions, including the AT Protocol Lexicon system [ATPROTO] and the recommendation in [RFC6648] to use reverse-DNS or domain-prefixed naming for vendor extensions to existing protocols.¶
Versioning is at the namespace level, not the record level.
sygil.v1.* is a stable, frozen series. sygil.v2.* is a separate,
independent series. The two series coexist indefinitely; there is no
transition deadline.¶
Once published, an NSID's constraint set is immutable. Adding optional fields in a minor schema release is permitted. Removing fields, changing types, adding required fields, or tightening constraints requires a new NSID. This rule is enforced by implementation tooling (continuous integration in the reference schema repository); it is also a normative wire rule: a Producer MUST NOT emit a record whose NSID is published but whose fields violate the published constraints for that NSID.¶
Unknown NSIDs MUST be passed through unchanged. A Consumer that
does not recognize a record's @type MUST NOT reject the record on
that basis alone. The Consumer MAY log unknown NSIDs and MAY route
the record to a generic-record handler that preserves base envelope
fields and treats namespace-specific fields as opaque, per Section
7.2.¶
The immutability rule borrows from the AT Protocol Lexicon discipline [ATPROTO]. The reasoning is the same: in a federated ecosystem with no central coordinator, breaking changes cannot be coordinated to every Consumer. Immutability is the only discipline that keeps the ecosystem self-consistent. The cost is namespace verbosity (every breaking change spawns a new NSID); the benefit is that fragmentation, when it comes, is explicit rather than silent.¶
sygil:// URI scheme
The sygil:// URI scheme is the content-addressed identifier scheme
used as a record's id. Its grammar is:¶
The grammar of the sygil:// URI, in ABNF [RFC5234], is:¶
sygil-URI = "sygil://" subject-did "/" nsid "/" content-hash
subject-did = "did:" method-name ":" method-specific-id
; structure governed by [W3C-DID];
; method-specific-id is opaque to this Protocol
; (see Section 4.9)
method-name = 1*( ALPHA / DIGIT )
method-specific-id = 1*( unreserved / pct-encoded / ":" )
nsid = label *( "." label )
; reverse-DNS structure (see Section 4.3)
label = ( ALPHA / DIGIT ) *( ALPHA / DIGIT / "_" / "-" )
content-hash = algorithm "-" 1*base64url-char
algorithm = 1*( ALPHA / DIGIT )
; v1 implementations MUST emit "blake3"
base64url-char = ALPHA / DIGIT / "-" / "_"
; base64url alphabet per [RFC4648] Section 5,
; encoded WITHOUT padding ("="). A BLAKE3-256
; digest (32 octets) encodes to exactly 43
; characters.
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded = "%" HEXDIG HEXDIG
¶
ALPHA, DIGIT, and HEXDIG are the core rules defined in [RFC5234] Appendix B.1.¶
Example:¶
sygil://did:web:vault.example.com/sygil.v1.calendar.event/blake3-Cn8vJk2qR7sT1uV4wX9yZ0aB3cD6eF8gH1iJ2kL4mN5¶
The DID component is the Subject DID. It identifies the data
subject -- the person the record is about. The Vault operator, the
issuer, and the source system are separate concerns and MAY be
expressed in the optional subject_did, issuer_did, and
source_system envelope fields.¶
The content hash is BLAKE3 [BLAKE3] over the canonical
serialization of the record body (Section 4.5), encoded as a
base64url string without padding, of the form blake3-{base64url}.
The hash MUST be reproducible by any conforming implementation given
the same record body.¶
The URI is implementation-neutral. It does not encode hostname, port, path, or API surface. Where to fetch the record is a discovery concern, addressed by Vault implementations or by the carrier protocol (e.g., MCP [MCP]); it is not encoded in the identifier.¶
A record about a Subject typically involves multiple parties: the data Subject, the upstream source system that authored the original data, the Vault operator that hosts the record, and the connector or Producer that produced the Sygil record from the upstream data. The Protocol puts the Subject DID in the URI because the Protocol is personal-data-centered: the record's identity is bound to the person the record is about, not to any specific operator or producer.¶
The other parties are recorded, when relevant, in the optional
subject_did (redundant with the URI but allowed for clarity),
issuer_did, and source_system envelope fields.¶
The sygil URI scheme is to be registered with IANA as a provisional
URI scheme per [RFC7595]. See Section 10 (IANA Considerations).¶
Content-addressed identifiers require deterministic serialization.
Without a precise canonicalization rule, two implementations can
produce different id values for the same logical record, and the
content-addressing model collapses.¶
Sygil mandates JSON Canonicalization Scheme (JCS) per [RFC8785].¶
UTF-8 encoding with no byte-order mark.¶
Object key ordering by code-point order.¶
No insignificant whitespace between tokens. Whitespace inside string values is preserved.¶
String escaping uses only \", \\, \b, \f, \n, \r,
\t; all other control characters use \u escapes.¶
Number serialization per [RFC8785] number-serialization rules:
integers as integers (no .0), non-integer numbers in shortest
round-trip representation.¶
Null preservation. null is preserved; it is not equivalent to
"field absent."¶
The id content hash is computed over the canonical serialization of
the record with the following fields excluded:¶
id (cannot include itself).¶
_proofs (proof objects may be added or removed without changing
record identity).¶
updated_at (mutable metadata).¶
version (mutable metadata).¶
supersedes (mutable metadata).¶
obsolete, obsolete_reason (soft-delete flags can change without
changing the underlying record content).¶
The following reserved envelope fields are included in the hash input (they are part of the record's content identity):¶
Hash exclusions are organized in three tiers. The base-tier
exclusions above apply to every record. A second, mixin-inherited
tier applies to records whose source object extends the
source_provenance mixin (the cross-namespace provenance mixin
shared by every namespace's source object): the fields
source.imported_at, source.cooperation_mode, and
source.mode_transition_history are excluded, because they are
operational metadata that changes on re-synchronization without
changing the record's content. (The source.source_updated_at
field is by contrast included in the hash: it carries a
content-change semantic -- producers advance it only when upstream
content actually changes, not on operational re-emission -- and is
therefore content, not operational metadata.)¶
Per-namespace specifications MAY exclude additional fields from the
hash input (the third tier); any such exclusions MUST be documented in
the namespace specification. For example, the social namespace
excludes the aggregate engagement_counts subobject on posts, because
platform-computed engagement totals change as a post accrues
interaction without changing the post's content.¶
The hash algorithm is BLAKE3 [BLAKE3]. The 32-octet BLAKE3-256 hash
output is encoded as base64url without padding ([RFC4648] Section 5),
prefixed with blake3-, and used as the content-hash component of the
sygil:// URI. A BLAKE3-256 digest therefore encodes to exactly 43
characters, and a complete content-hash component has the form blake3-
followed by those 43 characters.¶
The choice of BLAKE3 over alternatives (SHA-256, SHA-3) reflects
performance characteristics relevant to high-record-volume
implementations and is consistent with prior content-addressable
systems' direction. Implementations MUST emit blake3- hashes for v1.
Future major versions of the Protocol MAY introduce alternative
algorithms; v1 implementations are not required to support them.¶
stable_id (logical-identity URI)
Every v1 record carries a stable_id, which identifies the record
across versions; for mutable record types it is the stable handle that
successive versions share. Its grammar, in ABNF [RFC5234], is:¶
sygil-stable = "sygil-stable:" nsid-short ":" logical-hash
nsid-short = label ":" label
; the last two dot-separated components of the NSID,
; with the dot replaced by a colon
; (e.g., "calendar:event", "identity:person")
logical-hash = algorithm "-" 1*base64url-char
; algorithm, base64url-char, and hash format identical
; to those used in content-hash (Section 4.4)
¶
(label and algorithm are as defined in Section 4.4.)¶
Example:¶
sygil-stable:calendar:event:blake3-3a4b5c...¶
The logical-hash is computed over a stable subset of the record's identifying fields, declared per namespace. The rule that holds across all namespaces:¶
The logical-hash MUST NOT include any field that mutates as part of normal record updates.¶
For example, sygil.v1.calendar.event declares the logical-hash inputs
to be (subject_did, source_system, source_record_id_hash,
recurring_master) -- fields that uniquely identify the logical event
regardless of how its title, description, attendees, or start time
change.¶
The per-namespace declaration of logical-hash inputs is part of that namespace's specification.¶
Sygil's two URI forms -- sygil:// (content-addressed, identifies a
specific version) and sygil-stable: (logical-identity, identifies a
record across versions) -- present different resolution properties.
This section specifies the resolution model the Protocol expects of
Consumers, while remaining silent on the mechanism by which
resolution is performed (mechanism is a runtime concern).¶
A Consumer attempting to resolve any Sygil URI to a record body MUST distinguish four resolution states:¶
Resolved. The URI was resolved to exactly one record body, and the Consumer is granted access to that body.¶
Unresolved. The URI is well-formed but no record body could be retrieved. The record may not exist, may have been deleted, may be held by an unreachable Vault, or may be unknown to the resolver.¶
Forbidden. The URI was resolved to a record body but the Consumer is not authorized to access it. The Consumer learns the record exists but not its contents.¶
Ambiguous. The URI was resolved to more than one record body
(see "Stable-ID resolution" below). This state applies only to
sygil-stable: URIs and is described further below.¶
The four states form a partition: every resolution attempt MUST end in exactly one of them.¶
A Tier 2 surface returning a collection that contains references to other records SHOULD include a per-reference resolution state in the response envelope, so that downstream Consumers can distinguish "resolved successfully" from "deliberately omitted" from "denied access."¶
A Consumer MUST NOT fabricate referenced record data when resolution fails. Returning a stub marked unresolved or forbidden is correct; returning a synthesized record without indication is a Protocol violation.¶
sygil://)
A sygil:// URI is content-addressed: the URI uniquely identifies a
specific record body, and any two records resolving to the same
sygil:// URI MUST be byte-for-byte identical after canonicalization
(or the implementation has a Protocol violation per Section 7.6).¶
Content-hash resolution properties:¶
At most one record body per URI. Distinct record bodies have distinct hashes; therefore distinct URIs.¶
Resolution is exact-match. A Consumer that retrieves a record
body claimed to satisfy a sygil:// URI MUST verify the hash
before treating the body as resolved. If the hash does not match,
the resolution result is Unresolved (not Resolved with a
hash-mismatch flag); fabricating resolved-state for a record body
whose hash does not match its claimed URI is a Protocol violation.¶
Resolution is location-independent. A Consumer MAY resolve the
same sygil:// URI through any number of intermediaries and MUST
obtain the same record body; the URI does not encode location.¶
sygil-stable:)
A sygil-stable: URI identifies the logical record across
versions. Multiple sygil:// versions of the same logical record
share a sygil-stable: URI; this is the URI's purpose.¶
Stable-ID resolution requires additional rules because the relation
between a sygil-stable: URI and a record body is one-to-many
across the lifetime of the record.¶
Resolution returns the current version by default. A Consumer
resolving a sygil-stable: URI without further qualification MUST
receive the version the resolver considers current -- typically the
highest-version record under that stable_id whose obsolete
field is false. The criteria for "current" are runtime concerns;
the rule the Protocol specifies is that the resolver returns
exactly one version unless the resolver enters the Ambiguous
state below.¶
Resolution to a specific version requires the sygil:// URI. A
Consumer that wants a specific version of a record MUST use the
sygil:// URI for that version, not a qualified form of the
sygil-stable: URI. The Protocol does not define a stable-ID
qualification syntax.¶
The Ambiguous state arises in three scenarios. A resolver
reports Ambiguous when, despite best effort, it cannot
identify a single current version: (i) two or more records share
the same stable_id with the same version value (a Producer
bug); (ii) two or more records share the same stable_id with
different version values, none marked obsolete: true, and the
resolver lacks enough context to choose (a coordination failure
between Producers); (iii) the resolver holds records under the
stable_id from multiple Vaults that disagree on the current
version. In all three scenarios, a Consumer encountering
Ambiguous state MUST NOT pick one record arbitrarily; it MUST
surface the ambiguity to its caller.¶
Resolution lifetime. A Consumer MAY cache sygil-stable:
resolution results. Such caches MUST honor the version field's
monotonicity: a cached result with version N MAY be invalidated
on receipt of a fresher result with version > N for the same
stable_id. A cached result MUST NOT be returned in preference to
a fresher one observed via any channel.¶
All-obsolete edge case. When the only records under a given
stable_id available to the resolver have obsolete: true, the
resolver MUST return the highest-version such record (the
"most-recent obsolete version") with the obsolete flag visible
to the Consumer. The resolver MUST NOT return Unresolved in
this case; the record exists, the Consumer is entitled to learn
it exists, and the obsolete flag carries the runtime semantics
the Consumer needs to decide whether to act on the record.
Consumers performing audit, recovery, or regulatory operations
legitimately require visibility into fully-obsolete histories;
treating all-obsolete as Unresolved would hide that visibility.
A Consumer that wishes to filter obsolete records out of its
view applies the filter on its own (obsolete: false) and is
not dependent on resolution-state hiding to do so.¶
Resolved does not imply valid or current. Successful
resolution of a sygil-stable: URI returns exactly one record
body to the Consumer; it does not assert that the record is
current, valid, or usable for any specific purpose. Consumers
MUST inspect the record's obsolete field, expires_at field
(if present), and any other usability-relevant envelope state
before treating the resolved record as currently authoritative.
This is particularly important after the all-obsolete rule
above: a sygil-stable: URI under which every version is
obsolete: true resolves successfully (the most-recent obsolete
version), but a Consumer that does not inspect the obsolete
flag could mistakenly treat the record as current. Resolution
is identity retrieval, not validity assertion.¶
Version monotonicity violation handling. Records under a
given stable_id carry monotonically increasing version
values; this is a Producer obligation (Section 4.6). When a
Consumer encounters a version-monotonicity violation -- a
record with version N arriving after the Consumer has already
observed a record with version > N for the same stable_id --
the Consumer MUST treat the lower-version record as stale:¶
The lower-version record MUST NOT be treated as a current
candidate for sygil-stable: resolution.¶
The lower-version record MUST NOT replace any cached resolution result that points at a higher-version record.¶
The lower-version record MAY be retained for audit, forensic,
or historical-reconstruction purposes; its version value
locates it in the version sequence regardless of arrival
order.¶
This rule prevents three implementation divergences: (i) one
implementation accepting the late-arriving lower-version record
as current while another rejects it; (ii) one implementation
reordering its cache by arrival time while another respects
version ordering; (iii) divergent results when the same
stable_id is resolved through two implementations after the
same out-of-order delivery.¶
Envelope-state conflict resolution. When the Consumer
observes two records sharing an identical id URI but
differing in any envelope field excluded from the content hash
(_proofs, obsolete, obsolete_reason, updated_at, etc.,
per Section 4.5), the Consumer MUST treat the situation as a
Producer or relay bug and MUST surface a warning to its caller.
The Consumer:¶
MUST NOT silently pick one envelope variant over another and treat the chosen variant as authoritative.¶
MAY apply a runtime-defined reconciliation policy (e.g., last-
written by updated_at if the Consumer has reliable arrival
ordering and the updated_at values differ; preference for
the variant whose obsolete flag is true when conservative-
deletion semantics are required) provided the policy is
documented and the warning is still surfaced.¶
MUST NOT treat the differing envelope states as creating distinct record identities (per Section 4.1's identity- entails-deduplication rule).¶
MUST NOT, when applying any reconciliation policy, produce a
result that contradicts an explicitly restrictive envelope
state. A reconciliation that resolves obsolete: true vs.
obsolete: false by selecting false is forbidden, because
doing so silently overrides a soft-delete signal; a
reconciliation that resolves a stricter redaction_state
against a looser one by selecting the looser projection is
forbidden, because doing so widens disclosure beyond what
the more-restrictive variant claimed. The general rule is
that reconciliation chooses the more-restrictive envelope
state when the variants disagree on a restrictive-vs-permissive
axis.¶
Envelope-state conflict is structurally analogous to the
Ambiguous resolution state above (Section 4.6.1's third
Ambiguous scenario): the Consumer cannot mechanically determine
the correct envelope state, and the Protocol's response is to
surface the ambiguity rather than to mandate a single
reconciliation. In well-behaved deployments this case does not
arise -- Producers generating new envelope state generate a new
record with a new id -- so the rule exists for failure
detection, not common-case behavior.¶
Both sygil:// and sygil-stable: URIs may resolve to Unresolved
or Forbidden states. The two states are distinct:¶
Unresolved means the resolver could not retrieve a record body. The Consumer learns nothing about whether the record exists or whether the Consumer would be authorized.¶
Forbidden means the resolver retrieved a record body and determined the Consumer was not authorized to see it. The Consumer learns the record exists but not its contents.¶
The distinction matters in trust models. A Vault implementation that collapses the two states (returning Unresolved when it actually means Forbidden, to avoid existence-leaks) is making a deliberate trade-off; the Protocol allows this collapsing but does not require it. A Vault that distinguishes the two states is providing more information to the Consumer at the cost of revealing the existence of forbidden records.¶
The Protocol does not specify which Vaults should collapse and which should distinguish; this is a deployment-policy concern and is addressed in vault-implementation specifications.¶
A Consumer that receives an Unresolved or Forbidden result for a required reference (i.e., a reference whose absence breaks the Consumer's intended use of the parent record) SHOULD treat the parent record as having a missing relation, not as invalid. Records carrying unresolved or forbidden references in optional fields remain structurally valid; how the Consumer surfaces the missing relation in its UI or downstream output is a Consumer concern.¶
A Consumer that receives an Ambiguous result for a sygil-stable:
reference SHOULD treat the parent record as if the reference were
unresolvable for downstream purposes; the Consumer MUST NOT
arbitrarily pick a candidate version. This is the load-bearing rule
that prevents silent ecosystem fragmentation under multi-version
disagreement.¶
Records reference other records by sygil:// URI. Two reference
patterns are defined.¶
A field holds a sygil:// URI pointing to another record of a declared
type. Used when the referenced record has independent identity.¶
"organizer": "sygil://did:example:user/sygil.v1.identity.person/blake3-abc..."¶
A sub-object is embedded directly in the parent record. Used when the sub-object has no identity outside the parent.¶
"attendees": [
{
"@type": "sygil.v1.calendar.attendance",
"person": "sygil://did:example:user/sygil.v1.identity.person/blake3-xyz...",
"response_status": "accepted"
}
]
¶
The namespace specification declares which pattern applies per field. Mixing patterns for a single field is not permitted.¶
DIDs appear throughout the Protocol: in the sygil:// URI prefix, in
the optional subject_did, issuer_did, and subjects[] envelope
fields, and in foreign references in namespace-specific fields. Because
DID methods proliferate (did:web, did:key, did:plc, did:ion,
did:ethr, did:cheqd, others), any conforming implementation will
encounter unfamiliar DID methods over time.¶
DIDs in identifier-bearing fields are opaque to Consumers except
for the method tag -- the segment between the first two colons in
did:METHOD:identifier. Specifically:¶
Consumers MAY parse the method tag to determine resolution strategy.¶
Consumers MUST NOT parse the method-specific identifier (everything
after the second colon). The internal structure of did:web,
did:plc, did:key, and other methods is method-defined and not
Protocol-defined.¶
Consumers MUST pass through unknown DID methods unchanged. A record
whose subject_did is did:newmethod:identifier MUST NOT be
rejected solely because the Consumer does not understand
did:newmethod:.¶
Consumers SHOULD log unknown DID methods to support ecosystem-drift detection.¶
Producers MUST emit DIDs in the did:METHOD:identifier format. DIDs
that do not parse as did:METHOD:identifier (bare strings, non-DID
URIs in DID-typed fields) are protocol violations and SHOULD be
rejected by validators.¶
Conformant Tier 2 and higher implementations (Section 6) MUST be able to resolve the following DID methods:¶
did:web [DID-WEB] -- DIDs anchored to a domain name, resolved
by fetching https://{domain}/.well-known/did.json (or the path
indicated by the DID). Suitable as a primary identifier for entities
with stable web presence.¶
did:key [DID-KEY] -- DIDs that encode a public key directly
in the identifier. Resolution is local; no network required.
Suitable for ephemeral or self-sovereign cases.¶
Conformant Tier 2 and higher implementations SHOULD be able to resolve:¶
did:plc [DID-PLC] -- Public Ledger of Credentials, used by
AT-Protocol-aligned ecosystems for portable identifiers.¶
Conformant implementations MAY resolve any other DID method, including
did:ion, did:ethr, did:cheqd, and others. Tier 1 implementations
have no resolution requirement; for Tier 1 purposes, DIDs may be
treated as opaque strings throughout.¶
The v1 schema, specified canonically in the companion Sygil Protocol Schema document referenced in Section 11 (Informative References), defines a namespace set structured as 10 production-depth namespaces, 2 minimal-shape namespaces, and 3 NSID-reserved namespaces. The production-depth ten are specified at full depth in the Schema (every field, enum, supporting object, normalization mapping, and conformance test resolved). The minimal-shape two ship in v1 with a single record type each at minimal-but-extensible depth. The NSID- reserved three commit reverse-DNS namespace identifiers in v1 without committing internal structure; full specification awaits a v1.x patch when forcing functions accumulate.¶
| Namespace | Depth | Primary external binding |
|---|---|---|
sygil.v1.identity
|
Production | Schema.org Person/Organization; vCard 4.0 [RFC6350]
|
sygil.v1.calendar
|
Production | iCalendar [RFC5545]; Schema.org Event
|
sygil.v1.message
|
Production | Internet Message Format [RFC5322] (with extensions for channels and rooms) |
sygil.v1.preference
|
Production | (Sygil-original; weak external alignment) |
sygil.v1.document
|
Production | Schema.org CreativeWork family |
sygil.v1.location
|
Production | Schema.org Place; geoJSON; trip and movement extensions |
sygil.v1.finance
|
Production | FDX [FDX]; ISO 20022; FIGI/ISIN identifier vocab for positions |
sygil.v1.health
|
Production | FHIR R4 Observation/Condition/Medication [FHIR-R4]; IEEE 11073 device-data references |
sygil.v1.social
|
Production | AT Protocol (Bluesky) Lexicon; ActivityPub (Mastodon); closed-platform export formats deferred |
sygil.v1.conversation
|
Production | No standard exists; canonicalizes the two flagship LLM-export shapes (ChatGPT node-graph, Claude flat list); ImportOnly |
sygil.v1.media
|
Minimal v1.0 (media.item only) |
Schema.org MediaObject family; EXIF |
sygil.v1.task
|
Minimal v1.0 (task.task only) |
Schema.org Action (informal alignment) |
sygil.v1.commerce
|
NSID-reserved | (deferred) Schema.org Order; ISO 20022 commercial credit transfer for commerce-to-finance bridge |
sygil.v1.claim
|
NSID-reserved | (deferred) W3C Verifiable Credentials data model [W3C-VC2] when verifiable; otherwise Schema.org Claim (informal) |
sygil.v1.channel
|
NSID-reserved | (deferred) Schema.org Organization (workspace-level abstraction) |
The sygil.v1.credential.* namespace is reserved for a future
specification that will adopt the W3C Verifiable Credentials data model
[W3C-VC2] verbatim.¶
The sygil.v1.social namespace models the data subject's social
presence: content the subject deliberately published to a public
audience (posts, replies, reposts, quote-posts) and the relationships
and actions the subject owns (follows, blocks, mutes, likes, lists,
and list memberships). It is scoped to subject-authored-and-subject-
owned data; third-party statements about the subject (tags, mentions,
posts by others) and identity-level inbound engagement (the identities
of accounts that interacted with the subject's posts) are out of v1
scope. Two classes of social-platform data route to other namespaces
rather than to sygil.v1.social: profiles map to
sygil.v1.identity (a profile is an identity record; the platform
handle is carried as an identity attribute), and direct messages map
to sygil.v1.message (a direct message is structurally a message).
The social namespace is the first to use the intent-posture
classification axis described in Section 9 (Privacy Considerations).¶
The sygil.v1.conversation namespace models the data subject's
archive of conversations with AI models: threads and turns (core),
plus standing instructions, persisted model-held memory, and projects
(extended). It is an ImportOnly namespace -- the major LLM providers
expose conversation completions over their APIs but not the subject's
conversation archive, so the only acquisition path is the provider's
self-serve data export, and the subject's upload of that export is the
grant event (Section 7 cooperation modes export_only and
user_mediated_capture; no new mode is introduced). A thread is the
subject's archived artifact (subject_scope sole); a turn carries the
archival subject explicitly and represents authorship separately, via
a role and an author-kind plus an optional model slug, so that
non-human turns are owned by the subject without being authored by the
subject and the model is never modeled as a person. No conversation-
archive standard exists; the two flagship export shapes (a branch-
capable node graph and a flat ordered list) both normalize to turns
plus a parent-turn edge, with branch state preserved. Content blocks
use a closed type enumeration for query stability plus an open subtype
and a lossless source-native escape hatch, so that block types a
future model product invents are preserved rather than dropped. Every
conversation record is highly sensitive by default (Section 9).¶
The Protocol does not require implementations to support all v1 namespaces. Conformance is asserted per (namespace, tier) pair (Section 6.2). For minimal-v1.0 namespaces, conformance is against the single record type that v1 specifies; for NSID-reserved namespaces, no v1 conformance surface exists until the full structure ships in a v1.x patch.¶
Third parties MAY define their own namespaces using the NSID extension
pattern (Section 4.2.5): records are emitted under
sygil.community.{publisher}.{namespace}.{record-type}, where
{publisher} is a reverse-DNS-shaped publisher identifier the third
party controls (e.g.,
sygil.community.acme.example.com.media.album). Records in
community-extension namespaces travel through the same envelope,
canonicalization, identifier, and proof object infrastructure as
core records. Consumers process them per the unknown-NSID rule in
Section 4.3.¶
Third parties MUST NOT use the sygil.v1. prefix or any other
sygil. prefix outside the documented sygil.community. extension
namespace. The sygil. namespace outside sygil.community. is
reserved for the Sygil specification's change controller.¶
A query response wraps zero or more records in the following envelope:¶
{
"type": "sygil.v1.calendar.event",
"cursor": "opaque-pagination-cursor",
"records": [ /* zero or more records */ ]
}
¶
Optional fields:¶
| Field | Type | Semantics |
|---|---|---|
total
|
integer | Total number of matching records. MAY be omitted; SHOULD be omitted when counts leak privacy-sensitive information or are expensive to compute. |
partial
|
boolean |
true if the implementation returned a subset due to authorization restrictions, rate limiting, or other runtime constraints. |
redaction_state
|
enum | One of original, redacted, summary, hash_only. Describes the projection level the response represents. Default original when omitted. The same record content can be served as different projections under different access policies; redaction_state labels the projection level the Consumer is seeing in this response, not the underlying record. Vault implementations producing projections SHOULD set this field accurately and SHOULD enforce that projections actually omit the excluded content. |
Per-record proof objects travel inside each record's _proofs field.
The query response envelope itself does not embed authorization
metadata, aggregate proof information, or audit information; aggregate
runtime concerns are not part of the Protocol.¶
This section specifies a minimal, portable query semantics that any Tier 2 implementation MUST honor. The grammar is deliberately small -- its purpose is to define a stable interoperability surface, not a full query language. Implementations MAY expose richer query surfaces (GraphQL, MCP tool primitives, multi-hop traversal, full-text ranking, aggregation) on top of the Protocol's grammar; those richer surfaces are out of scope.¶
A Sygil query is encoded as a sequence of key-value parameter pairs in the application/x-www-form-urlencoded form, in the same shape used for HTTP query strings. The following ABNF [RFC5234] specifies the abstract syntax. Transport bindings determine how the syntax is carried on the wire; the syntax itself is transport-independent.¶
query = parameter *( "&" parameter )
parameter = type-param
/ time-range-param
/ equality-param
/ reference-param
/ text-search-param
/ pagination-param
/ quality-param
type-param = "type=" nsid
time-range-param = ( "start_after=" iso8601 )
/ ( "start_before=" iso8601 )
/ ( "end_after=" iso8601 )
/ ( "end_before=" iso8601 )
equality-param = field-name "=" field-value
reference-param = field-name "=" sygil-URI
text-search-param = "q=" 1*VCHAR
pagination-param = ( "limit=" 1*DIGIT )
/ ( "cursor=" opaque-token )
quality-param = freshness-min-param
/ completeness-min-param
/ verifiability-min-param
/ cooperation-mode-in-param
freshness-min-param = "freshness_min=" freshness-value
completeness-min-param = "completeness_min=" completeness-value
verifiability-min-param = "verifiability_min=" verifiability-value
cooperation-mode-in-param = "cooperation_mode_in="
mode-value *( "," mode-value )
freshness-value = "realtime" / "hours" / "days" / "weeks" / "unknown"
completeness-value = "authoritative" / "best_effort" / "partial"
/ "known_incomplete" / "unknown"
verifiability-value = "source_signed"
/ "sygil_signed_after_ingestion"
/ "unsigned" / "disputed" / "unknown"
mode-value = "native_sygil" / "cooperative_api" / "restricted_api"
/ "export_only" / "user_mediated_capture"
/ "manual_subject_assertion" / "unknown"
field-name = 1*( ALPHA / DIGIT / "_" )
field-value = 1*VCHAR
; URL-percent-encoded if necessary
nsid = label *( "." label )
; per Section 4.3
iso8601 = 1*VCHAR
; an ISO 8601 timestamp per [RFC3339]
sygil-URI = "sygil%3A%2F%2F" 1*VCHAR
; URL-percent-encoded form of a `sygil://` URI
; per Section 4.4
opaque-token = 1*VCHAR
; an implementation-defined cursor; treated as
; opaque by the Consumer
¶
ALPHA, DIGIT, and VCHAR are the core rules from [RFC5234]
Appendix B.1.¶
Tier 2 implementations MUST support the following six primitives. Each implementation MUST recognize the parameter form, MUST evaluate the primitive's match semantics deterministically, and MUST NOT silently ignore any of the six parameters.¶
| Primitive | Parameter | Match semantics |
|---|---|---|
| Filter by namespace |
type
|
A record matches if its @type value is exactly equal to the parameter value. |
| Filter by time range |
start_after, start_before, end_after, end_before
|
A record matches if the namespace-declared time field (typically start.datetime for events; per-namespace declared elsewhere) lies in the parameter-described half-open interval. |
| Filter by field equality |
{field}={value}
|
A record matches if the named field's value is exactly equal to the parameter value, where equality is JSON-value equality (string identical bytes; integer identical numeric value; etc.). |
| Reference traversal (one hop) |
{reference_field}={sygil-URI}
|
A record matches if the named reference field's value is exactly equal to the parameter URI, byte-for-byte after URL-decoding. |
| Text search |
q
|
A record matches by an implementation-defined text-relevance function over a namespace-declared set of searchable fields. The relevance function is not specified. |
| Pagination |
limit, cursor
|
The implementation returns at most limit records (default and maximum implementation-defined). When more records exist, the response carries a cursor; supplying that cursor on a subsequent call returns the next page. |
When a query carries multiple parameters, evaluation is conjunctive: a record is included in the response if and only if it matches every parameter present in the query. The Protocol does not specify the order in which the implementation evaluates the parameters; the implementation MAY reorder them for performance.¶
Three rules constrain implementations to deterministic behavior:¶
An unsupported parameter (a parameter recognized by name but not understood by the implementation, or a parameter whose value does not parse) MUST cause the query to fail with a structured error; the implementation MUST NOT silently ignore unsupported parameters. This is consistent with Section 7 (Failure Semantics).¶
Conjunction is the only logical operator. Disjunction (OR) and
negation (NOT) are out of scope. Implementations exposing richer
surfaces MUST NOT use Sygil parameter syntax for non-conjunctive
semantics.¶
The text-search relevance function (q) is implementation-defined.
Two conformant implementations MAY return different records or
different orderings for the same q value; this is the only
Protocol-permitted source of non-determinism in query evaluation.¶
Apart from the text-search exception above, query evaluation is
deterministic: given the same record set and the same query
parameters, two conformant implementations MUST return the same
records in the same order, where order is determined by the
namespace-declared default sort field (typically the time field used
in time-range parameters; per-namespace declared elsewhere) breaking
ties on id. An implementation MAY return records in a different
order if the query specifies an alternative ordering primitive (none
specified in this Protocol; future versions may add an order_by
primitive).¶
The Protocol's determinism guarantee is partial: it applies to queries containing only non-text-search predicates, and to the non- text-search portion of mixed queries. Specifically:¶
A query containing no q parameter is fully deterministic across
conformant implementations.¶
A query containing q is not required to be cross-
implementation identical. Two implementations evaluating the same
q-containing query against the same record set MAY return
different result sets and different orderings, because text-
search relevance is implementation-defined (Section 4.10.3).
Mixed queries (combining q with other predicates) inherit this
non-determinism in both result membership and ordering: the
deterministic predicates are evaluated conjunctively against
whatever records the text-search portion selects, but the text-
search portion itself is the source of cross-implementation
variation.¶
Implementations MUST NOT introduce non-determinism for any predicate
other than q. A Consumer needing fully-deterministic results
across implementations MUST construct queries containing only non-
text-search predicates.¶
Determinism (in its partial form above) is the basis of cross-
implementation interoperability for queries: two Vault
implementations holding the same records and receiving the same
non-q query produce identical responses, modulo records the
implementation's runtime authorization filters out (which is
communicated by the partial flag in the response envelope; see
Section 4.9).¶
Query evaluation operates on the projection view of records
that the implementation would return to the requesting Consumer,
not on the canonical (redaction_state: original) records as
stored. This rule resolves an interaction between the query grammar
(Section 4.10) and the privacy classification framework (Section
4.2.5) that would otherwise leak determinism.¶
Two consequences follow:¶
Fields excluded by the projection's redaction policy evaluate as
non-matching for equality predicates. A query of the form
?email_hash={value} MUST NOT match a record whose email_hash
field is omitted from the projection the implementation would
serve, regardless of whether the field is present in the
underlying canonical record. The Consumer's view of the record is
the projection; queries evaluate against the Consumer's view, not
against the canonical content the Consumer would not be permitted
to see.¶
Fields masked by the projection's redaction policy do not match
on the masked value. A field served as a placeholder
([redacted]) or hash-only marker MUST NOT match a query for the
unmasked value. A field served at redaction_state: hash_only
MAY match a query for the hash value if and only if the query
parameter explicitly carries a hash; equality between an unmasked
query value and a hashed served value is non-matching.¶
This rule applies symmetrically across implementations: if two
implementations would serve the same Consumer the same projection
of the same record, they MUST evaluate the query identically with
respect to that projection's contents. Different projections served
by different implementations to the same Consumer (e.g., one
implementation serves original, another serves summary) are not
errors; they are implementation-policy differences that the Protocol
explicitly allows. The partial flag and the redaction_state
field in served records communicate the projection difference to
the Consumer.¶
A Consumer that needs to query against unmasked content MUST request
a projection level that includes the unmasked fields, through a
mechanism the runtime defines (the Protocol does not specify
projection-selection mechanisms). A Consumer querying with no
projection-level signal receives whatever projection the
implementation's default policy provides; equality predicates that
match original-projection content but not the served projection
return zero results, not an error.¶
Range predicates against partial-precision fields. When a range
predicate (start_after, start_before, end_after, end_before)
is evaluated against a field whose served projection has lower
precision than the predicate requires, the field MUST evaluate as
non-matching, regardless of whether the underlying canonical value
would match.¶
The canonical example: a Consumer issues start_after=2026-04-26T10:
00:00Z, and the served projection of the target record's
start.datetime field is redacted to date-only precision
(2026-04-26). The Consumer's predicate requires hour-level
precision to determine inclusion. Three behaviors are defensible
without normative guidance -- exclude the record, include the record,
return an error -- and the v03 text was silent on which to choose.
v04 selects exclusion: the record MUST evaluate as non-matching.¶
The exclusion rule aligns with the equality rule above (excluded fields evaluate as non-matching for equality predicates). It avoids both the false-negative risk of including records that may not actually match and the divergence risk of two implementations choosing differently. A Consumer that needs records whose served precision is insufficient for its predicate MUST request a projection level that includes finer precision, through the same runtime-defined projection-selection mechanism that applies to unmasked-content queries.¶
Tier 2 implementations SHOULD additionally support four quality-aware
filter primitives that operate on the trust-dimension fields defined
in sygil.proof.provenance (Section 5.5):¶
| Primitive | Parameter | Match semantics |
|---|---|---|
| Minimum freshness |
freshness_min
|
Threshold filter; see ordering below. |
| Minimum completeness |
completeness_min
|
Threshold filter; see ordering below. |
| Minimum verifiability |
verifiability_min
|
Threshold filter; see ordering below. |
| Cooperation-mode set membership |
cooperation_mode_in
|
Set membership; see below. |
The three *_min primitives are threshold filters operating on
enums with documented orderings. A query at threshold V returns
records whose field value is at or above V in the ordering. Records
whose field value is unknown are excluded from any *_min filter
at a non-unknown value (they are returned only when the filter is
absent or is set to unknown explicitly).¶
The orderings are:¶
freshness: realtime > hours > days > weeks > unknown¶
completeness: authoritative > best_effort > partial >
known_incomplete > unknown¶
verifiability: source_signed > sygil_signed_after_ingestion
> unsigned > disputed > unknown¶
The fourth primitive, cooperation_mode_in, is a set-membership
filter. The cooperation modes (Section 5.5) are not orderable --
Mode 1 (native integration) is more cooperative than Mode 5
(user-mediated capture), but the modes do not lie on a single
quality axis. cooperation_mode_in accepts a comma-separated list of
mode values and returns only records whose cooperation_mode is in
the list.¶
Missing proof fields under quality-aware filters. When a
quality-aware filter is applied to a record that lacks the
referenced proof field -- either because the record carries no
sygil.proof.provenance proof at all, or because the proof is
present but does not populate the specific trust dimension -- the
record's value for that dimension MUST be treated as unknown for
filter evaluation, and the record MUST be excluded from any
threshold filter at a non-unknown threshold (per the threshold
rule earlier in this subsection). For
cooperation_mode_in, missing values MUST be treated as unknown
and included only when unknown is in the comma-separated list.¶
This rule replaces the v03 text that allowed implementations to
choose between treating-missing-as-unknown and returning-all-
matching. The v03 text was explicitly non-deterministic; v04
selects the deterministic behavior. The rule aligns the missing-
proof case with the unknown-enum-value case: both are evaluated
the same way, both are excluded from non-unknown threshold
filters, and both can be retrieved by querying with unknown as
the threshold or by including unknown in the set-membership
list.¶
The implication for Producers is that records intended to be
visible under quality-aware filters MUST carry a populated
sygil.proof.provenance proof with the relevant dimensions set.
Records without such a proof are protocol-valid but quality-filter-
invisible. This is the trade-off Producers explicitly make when
they decline to populate provenance trust dimensions.¶
The Protocol defines a vocabulary of proof objects that MAY accompany a Sygil record to convey evidence of provenance, capability, consent, attestation, or audit. This section specifies the shape and meaning of each proof object type and the rules for their composition.¶
This section does not specify how a Producer derives a proof object, how a Vault implementation computes the underlying authorization or provenance state, or how a Consumer cryptographically verifies a proof. Those are runtime concerns. The Protocol's role is the on-the-wire vocabulary by which the result of such computation may be conveyed.¶
Note: earlier drafts of this Protocol specified a sixth proof type,
sygil.proof.integrity, that explicitly carried the BLAKE3 content
hash. v01 removes this proof type because the content hash is already
encoded in the id URI and any party with the record can verify
integrity by canonicalizing and hashing -- no separate proof object is
needed. Sections of this document that refer to integrity-verification
responsibilities (notably Section 5.1 Role of proof objects, Section 7
Failure semantics, Section 8.2 Integrity) describe the verification
procedure against the id directly.¶
Proof objects are optional vocabulary. A record without any
_proofs is structurally valid. Consumers MAY ignore proof objects
entirely; doing so does not invalidate the record. The presence of a
proof object on a record asserts that the Producer claims the relevant
property (provenance, capability, consent, attestation, or audit);
whether the claim is correct is a separate question that
verification (an out-of-scope runtime activity) determines.¶
The expectation that proof objects are populated rises with the adoption tier (Section 6):¶
Tier 1 records do not require any proof objects.¶
Tier 2 records sourced from upstream systems SHOULD carry
sygil.proof.provenance. Records imported from a connector
classified by the runtime as authoritative MUST carry it (Section
5.4).¶
Tier 3 records served under agent access carry capability and
consent proofs, with provenance baseline and attestation and audit
proofs added as their respective trust claims are made. Integrity
is implicit at every tier via the content-addressed id; no
separate proof type is required.¶
The Protocol's vocabulary establishes consistent shapes for these claims so that Consumers across implementations can recognize them without per-implementation parsing.¶
All proof object types defined in this section share a common shape. Each proof object is a JSON object carrying:¶
A required @type field whose value is the proof type's NSID
(sygil.proof.provenance, sygil.proof.capability,
sygil.proof.consent, sygil.proof.attestation,
sygil.proof.audit, or a third-party reverse-DNS extension).¶
A required @type-specific body of fields whose semantics are
defined per type in Section 5.4 through Section 5.8.¶
Where applicable, an issued_at field (ISO 8601 timestamp with
timezone, per [RFC3339]) indicating when the proof was issued by
the producing party.¶
The Protocol does not require proof objects to carry signatures inline. A signed proof object MAY embed a signature (typically as a JWS-shaped [RFC7515] field over the canonical serialization of the remaining fields), MAY reference an out-of-band signature, or MAY remain unsigned. The choice is per-type and per-deployment; signed forms allow Consumers to verify the proof against a public key, and unsigned forms are useful when the binding to the record's content-addressed identifier is sufficient.¶
The proof object's binding to the record is positional: the proof
appears in the record's _proofs array. The record's id URI binds
the proof to the record's content-addressed identity (because the
_proofs array is excluded from the content hash, the proof can be
added or removed without changing the id; the proof's claim is
about the record identified by that id, not about the bytes
including the proof).¶
A proof object MUST NOT depend on its position within the _proofs
array; arrays are ordered but the order is not significant for any
proof type defined in this document.¶
The remaining subsections specify the type-specific body for each defined proof type. Section 5.3 first specifies the interpretation model that applies across all types.¶
This section specifies the wire-vocabulary semantics that apply to proof objects across types: how a Consumer interprets multiple proofs on a record, how proof types compose, what conflicts mean, and what minimum behavior the Protocol expects.¶
The Protocol does not specify how a Consumer evaluates trust given the presence or absence of proofs -- that is a runtime, deployment, and trust-anchoring concern. The Protocol does specify the structural rules a Consumer follows to read the wire vocabulary correctly.¶
Each proof object on a record carries an independent claim about
the record. A sygil.proof.provenance claim asserts upstream source
and trust dimensions; it asserts nothing about integrity, capability,
consent, attestation, or audit. (Integrity is verified independently
of any proof object: a Consumer canonicalizes the record body per
Section 4.5 and compares the BLAKE3 hash to the value encoded in the
record's id URI. A record's provenance proof can be intact even if
the content hash does not verify; a Consumer obtains integrity
assurance only by hash verification against the id, not by
inference from any proof.)¶
The independence rule means a Consumer evaluating one proof type MUST NOT infer properties associated with other proof types. The absence of a proof object MUST NOT be interpreted as a positive claim about the absent property; it is simply absence of evidence.¶
A record's _proofs array MAY contain multiple proof objects of
distinct types. The Protocol places no a priori limits on which
combinations are sensible; producers and runtimes may attach any
combination they consider appropriate.¶
When a record carries multiple proofs, the Consumer's evaluation of each proof is independent per the rule of Section 5.3.1 -- each proof's claim succeeds or fails on its own, and a proof's verification result asserts nothing about properties associated with other proof types.¶
For Consumer trust aggregation, the Protocol distinguishes two operations:¶
Conjunction over present proofs. When a Consumer aggregates
trust across multiple proofs that are present on the record, the
aggregate result is the conjunction of the individual verification
results. A record carrying a sygil.proof.provenance proof and a
sygil.proof.consent proof is fully trusted with respect to
both properties only if both verifications succeed. Failure of
one verification does not invalidate the other; it simply means
the corresponding property is not established.¶
Absence is silence, not failure. A proof's absence from a
record's _proofs array MUST NOT be interpreted by the Consumer
as a positive claim that the corresponding property fails or is
unsupported. A record carrying only a sygil.proof.provenance
proof and no sygil.proof.consent proof asserts nothing about
consent -- neither that consent was obtained nor that it was not.
A Consumer that requires consent for a particular access pattern
obtains that requirement from its deployment policy and treats
the absence of a consent proof as policy-failure, not as a
Protocol-level negative claim by the Producer.¶
The conjunction rule and the absence rule together prevent two common Consumer-side errors. The conjunction rule prevents the "present-but-unverified" error in which a Consumer attaches weight to a proof object's mere presence without verifying it. The absence rule prevents the "missing-proof-implies-failure" error in which a Consumer downgrades a record's overall trust because some proof type is absent, when in fact the absence carries no information.¶
A Consumer that requires specific proof types for specific access
patterns (e.g., "I will not act on records lacking
sygil.proof.consent") is making a deployment policy choice, not a
Protocol-level interpretation. The Protocol allows such Consumer
policies; it does not specify them.¶
A record MAY carry multiple proof objects of the same type. A
record might carry both a sygil.proof.provenance proof from the
original Producer and a second sygil.proof.provenance proof from
a relay vouching for the integrity of its forwarding (these are
distinct claims by distinct parties about the same record's
provenance).¶
When multiple same-type proofs appear, evaluation is per-issuer, not blanket-conjunctive. The Protocol distinguishes:¶
Per-proof verification. Each individual proof object's signature is verified against the public key of its issuer. A proof whose signature does not verify against its claimed issuer's key is failed (per Section 5.3.4) for that issuer; the failure asserts nothing about other issuers' proofs of the same type.¶
Issuer-keyed Consumer judgment. The Consumer's aggregate judgment with respect to a proof type is keyed by issuer: the Consumer's deployment policy specifies which issuers it trusts for which trust property, and the Consumer's overall judgment is the conjunction of the verified proofs from issuers whose claims the Consumer's policy treats as load-bearing for the property in question.¶
The issuer-keyed rule prevents a specific divergence: implementation A treating multiple same-type proofs as requiring all-of-them-verify (strict-conjunctive), implementation B treating any-one-verifies from a trusted issuer as sufficient (issuer-selective), both reading v03's ambiguous "conjunction over same-type proofs" text and arriving at incompatible behavior on the same record. Under v04's rule:¶
A Consumer MUST NOT require all same-type proofs to verify when some of those proofs come from issuers the Consumer's policy does not treat as load-bearing.¶
A Consumer's policy specifies the load-bearing issuer set for each proof type and trust property; what counts as load-bearing is a deployment concern.¶
The default behavior, in the absence of explicit policy, is for a Consumer to treat any-one-issuer's-verified-proof as sufficient for the corresponding trust claim, while preserving all proofs on the record for downstream forwarding (per Section 6.5).¶
The default is permissive because the alternative (strict all-issuers-verify default) would silently fail records whose relays or transit-time vouchers happened to break, which is exactly the case relays are supposed to make resilient.¶
The order of proof objects in _proofs is not significant. A
Consumer MUST NOT treat order as carrying information.¶
Two proofs are said to conflict when both claim a property of the record but make incompatible assertions. The Protocol identifies three meaningful conflict cases at the wire-vocabulary level:¶
Provenance-provenance conflict. Two sygil.proof.provenance
proofs name different source_system values for the same record's
origin. This is internally inconsistent -- a record has one upstream
source, even if multiple parties vouch for that source -- and is a
Producer bug. A Consumer encountering provenance-provenance
conflict SHOULD treat the record as having unresolved provenance:
no proof's source_system claim is sustained; the Consumer's
trust judgment with respect to provenance falls to whatever it
would be in the absence of any provenance proof.¶
Hash-content conflict. A record's recomputed BLAKE3 content
hash does not match the value encoded in the record's id URI
(per the rules in Section 4.5). This is a hard failure per
Section 7.6: the record is corrupt or has been tampered with.
The Consumer MUST treat the record as integrity-failed.¶
For all other apparent disagreements between proof objects, the
Protocol takes the position that each proof's claim stands or falls
on its own merits. Two sygil.proof.consent proofs referencing
different consent receipts, for instance, are not in conflict: a
record may legitimately carry multiple consent receipts covering
different aspects of the access. A sygil.proof.capability proof
that authorizes access overlapping with a sygil.proof.consent
proof's purpose is similarly not in conflict.¶
The Protocol does not specify a precedence ordering among proof
types. A Consumer that requires all of provenance, capability,
consent, attestation, and audit to be verified -- alongside the
implicit integrity check against the id -- is making a stronger
trust demand than a Consumer that requires only integrity; either
is permissible per the Protocol.¶
The Protocol specifies minimum evaluation expectations conditional on the trust claim a Consumer makes:¶
A Consumer that claims to verify integrity of a record MUST
recompute the content hash and compare to the record's id URI.
Acceptance without verification is a Protocol violation per
Section 7.6.¶
Integrity-first ordering for content-acting Consumers. A
Consumer that intends to act on the content of a record --
applying its values, treating it as authoritative for any
application purpose, or surfacing its values to a downstream
caller as record content -- MUST verify integrity (per the rule
above) before performing any other proof evaluation that
would feed into the content-acting decision. Integrity failure
short-circuits content-acting evaluation: a record whose
recomputed hash does not match its id URI MUST NOT be acted on
for content purposes regardless of which other proof objects it
carries or whether they would otherwise verify.¶
This rule prevents a class of evaluation-order divergences in
which one implementation filters records by provenance (e.g.,
verifiability_min=source_signed) and then verifies integrity,
while another implementation verifies integrity first and then
filters: the resulting record sets would otherwise differ on a
corrupt record whose provenance proof was intact.¶
Non-content-acting uses of a record -- audit logging, forensic analysis, attack investigation, debugging -- are exempt from the integrity-first ordering rule. A Consumer that processes a record solely to record that it was received, without acting on its content, MAY evaluate its proofs in any order. The exemption is narrow: the moment a Consumer's processing influences any downstream content-acting decision, the integrity-first rule applies.¶
A Consumer that claims to act on provenance of a record (e.g.,
filtering records by cooperation_mode_in per Section 4.10.6, or
treating a record from an authoritative connector as
authoritative) MUST verify that the sygil.proof.provenance
proof's connector_id matches the connector identity the Consumer
trusts. The Protocol does not specify how connector identity is
trust-anchored (out-of-band exchange, registry, deployment-time
configuration); it specifies only that acting on provenance
requires the proof to be present and the connector_id to be
validated.¶
A Consumer that claims to act on capability or consent (e.g., treating the access producing the record as authorized) MUST retrieve the referenced capability token or consent receipt and verify it under whatever trust framework the deployment expects. Acting on capability or consent based solely on the proof's presence -- without retrieving and verifying the referenced artifact -- is not a Protocol violation but is documented as insufficient: the proof object identifies the artifact, it does not contain it.¶
A Consumer that claims to verify attestation MUST verify the
attestation report referenced by the proof's attestation_report_uri
against the trust roots applicable to the named tee_type.
Acceptance without report verification is documented as
insufficient.¶
A Consumer that claims to act on audit evidence MUST verify that the referenced log entry exists and is consistent with the record. The Protocol does not specify how the log is operated; acting on audit evidence requires whatever verification the deployment's audit infrastructure prescribes.¶
The minimum expectations above are conditional: a Consumer that does not claim a particular trust property is not required to do anything with the corresponding proof type. This is the Protocol-level expression of the principle that proof objects are evidence of assertion, not of policy correctness; the Consumer chooses which assertions to credit and at what verification depth.¶
For clarity, the following are not specified by this Protocol and are out of scope for the wire-vocabulary semantics here:¶
The cryptographic verification procedure for any specific proof type beyond the integrity proof's hash recomputation. (Other proof types' verification depends on out-of-band signing infrastructure, which is not specified here.)¶
Revocation of proof objects after issuance.¶
Trust establishment between Consumers and unfamiliar issuers of proof objects.¶
The lifetime of a proof object's claim and the relationship of
that lifetime to the record's expires_at envelope field.¶
These are runtime, deployment, and governance concerns addressed by vault-implementation specifications and by deployment-specific trust documents.¶
sygil.proof.provenance
Attests the upstream source from which the record was derived, including trust dimensions describing how the data was acquired.¶
{
"@type": "sygil.proof.provenance",
"source_system": "google_calendar",
"source_record_id_hash": "blake3-source-id-hash...",
"connector_id": "sygil.connector.google_calendar.v1",
"imported_at": "2026-04-26T10:14:00Z",
"cooperation_mode": "cooperative_api",
"freshness": "hours",
"completeness": "authoritative",
"verifiability": "sygil_signed_after_ingestion",
"mode_transition_history": []
}
¶
| Field | Required | Type | Semantics |
|---|---|---|---|
@type
|
Required | string | Always sygil.proof.provenance. |
source_system
|
Required | string | Identifier of the upstream source system. |
source_record_id_hash
|
Recommended | string | BLAKE3 hash of the source-system record identifier. Hashed rather than raw to avoid leaking source-side opaque identifiers; deterministic for deduplication and reconciliation. |
connector_id
|
Required | string | Reverse-DNS identifier of the connector that produced the record. |
imported_at
|
Required | string | ISO 8601 timestamp with timezone -- when the record was imported. |
cooperation_mode
|
Recommended | enum | One of native_sygil, cooperative_api, restricted_api, export_only, user_mediated_capture, manual_subject_assertion, unknown. Source-cooperation mode (Section 5.4.1). Documented ordinals 1-6 (and unknown) are preserved for cross-reference with v0.x-era integer-form examples; the canonical wire form is the string. |
freshness
|
Recommended | enum | One of realtime, hours, days, weeks, unknown. Expected staleness ceiling. |
completeness
|
Recommended | enum | One of authoritative, best_effort, partial, known_incomplete, unknown. Whether the record is the authoritative copy. |
verifiability
|
Recommended | enum | One of source_signed, sygil_signed_after_ingestion, unsigned, disputed, unknown. Whether content ties cryptographically to the source. |
mode_transition_history
|
Optional | array | Past cooperation states for this record's stable_id lineage. Each entry: {mode, started_at, ended_at, reason}. |
The cooperation_mode enum identifies the integration posture of the
upstream source system.¶
| Value | Ordinal | Semantics |
|---|---|---|
native_sygil
|
1 | Native Sygil integration (the source system speaks Sygil directly). |
cooperative_api
|
2 | Cooperative API (the source system has a documented machine-readable API the connector uses). |
restricted_api
|
3 | Restricted API (the source system has an API but with significant rate limits, scoping limits, or undocumented behavior). |
export_only
|
4 | Authorized export (the source system supports user-initiated bulk export, e.g., via data-takeout features). |
user_mediated_capture
|
5 | User-mediated capture (the connector observes the source system through a user-initiated flow such as browser instrumentation, screen capture, or print-to-PDF). |
manual_subject_assertion
|
6 | Manual subject assertion (the Subject typed the data into a Sygil-aware interface; no upstream system involved). |
unknown
|
-- | The connector cannot determine the cooperation mode. |
The ordinal column is informative; producers and consumers SHOULD use the named string on the wire.¶
Cooperation mode affects what a Consumer can rely on. A
medication-reconciliation Agent might reasonably refuse user_mediated_capture
(captured) health data; a casual lifestyle Agent might accept it. The
Protocol exposes the trust envelope; the Consumer decides what is
acceptable per use case.¶
sygil.proof.capability
Attests that the access represented by this record was authorized by a capability token.¶
{
"@type": "sygil.proof.capability",
"token_id": "ucan:blake3-tokenid...",
"token_hash": "blake3-tokenhash...",
"issued_at": "2026-04-26T10:14:00Z"
}
¶
| Field | Required | Type | Semantics |
|---|---|---|---|
@type
|
Required | string | Always sygil.proof.capability. |
token_id
|
Required | string | Capability token identifier. The format is token-format-specific (e.g., a UCAN content-id, an OAuth jti). |
token_hash
|
Required | string | BLAKE3 hash of the token itself, not the token. Lets a Consumer verify that a token retrieved out-of-band is the same one referenced by the proof. |
issued_at
|
Required | string | ISO 8601 timestamp when the token was issued. |
The Protocol does not specify the capability token format. UCAN, OAuth 2.0 access tokens with rich authorization requests [RFC9396], custom capability formats, and other constructs are all permitted. The proof identifies a token by ID and hash; verification -- fetching the token, checking signatures, evaluating caveats -- is a runtime concern.¶
sygil.proof.consent
Attests that a consent receipt covers the access that produced this record.¶
{
"@type": "sygil.proof.consent",
"receipt_id": "rcp:blake3-receiptid...",
"dpv_categories": ["dpv:Schedule", "dpv:Communication"],
"purpose": "scheduling_assistance",
"legal_basis": "dpv:Consent",
"issued_at": "2026-04-26T10:14:00Z"
}
¶
| Field | Required | Type | Semantics |
|---|---|---|---|
@type
|
Required | string | Always sygil.proof.consent. |
receipt_id
|
Required | string | Identifier of the consent receipt. |
dpv_categories
|
Recommended | array | DPV (Data Privacy Vocabulary) terms describing the data categories covered by the consent. |
purpose
|
Recommended | string | Free-form or DPV-aligned purpose statement. |
legal_basis
|
Recommended | string | DPV-aligned legal basis (dpv:Consent, dpv:LegitimateInterest, etc.) or other vocabulary equivalent. |
issued_at
|
Required | string | ISO 8601 timestamp when the consent receipt was issued. |
Consent receipts MAY follow the W3C Data Privacy Vocabulary, ISO/IEC TS 27560:2023 [ISO-27560], or other consent-receipt schemes. The Protocol specifies the proof-object shape; the receipt format itself is a runtime concern.¶
sygil.proof.attestation
Attests that the record was produced inside a verifiable execution environment.¶
{
"@type": "sygil.proof.attestation",
"attestation_report_uri": "sygil://did:web:vault.example.com/sygil.v1.attestation.report/blake3-...",
"tee_type": "amd-sev-snp",
"issued_at": "2026-04-26T10:14:00Z"
}
¶
| Field | Required | Type | Semantics |
|---|---|---|---|
@type
|
Required | string | Always sygil.proof.attestation. |
attestation_report_uri
|
Required | string | URI of the attestation report. The report is referenced rather than embedded because attestation reports can be large. The URI MAY be a sygil:// URI to an attestation-report record, or any other URI scheme. |
tee_type
|
Required | string | Identifier of the trusted execution environment (amd-sev-snp, intel-tdx, arm-cca, etc.). |
issued_at
|
Required | string | ISO 8601 timestamp when the attestation was issued. |
The Protocol does not mandate that a record carry an attestation proof, nor that Consumers verify one. Attestation verification is typically tied to specific TEE platforms and trust-anchor management disciplines (RATS [RFC9334] provides the architectural framing) and is out of scope for this document.¶
sygil.proof.audit
Attests that the access generating this record was logged in a per-user audit log.¶
{
"@type": "sygil.proof.audit",
"log_entry_uri": "sygil://did:web:vault.example.com/sygil.v1.audit.entry/blake3-...",
"logged_at": "2026-04-26T10:14:00Z"
}
¶
| Field | Required | Type | Semantics |
|---|---|---|---|
@type
|
Required | string | Always sygil.proof.audit. |
log_entry_uri
|
Required | string | URI of the audit log entry referencing this access. |
logged_at
|
Required | string | ISO 8601 timestamp of the log entry. |
The structure of audit log entries, the cryptographic protections of the log (signed records, transparency log integration, witness cosigning), and the rules under which entries are produced are runtime concerns and out of scope for this document.¶
A record's _proofs field is an array of zero or more proof objects.
Multiple proof objects of the same @type MAY appear (for example, a
record with both a subject-attested integrity proof and a
Vault-attested integrity proof). The order of proof objects in the
array is not significant.¶
Proof object types are extensible. A Producer MAY define a new proof
object type using the reverse-DNS pattern (e.g.,
com.example.custom-proof-type). Unknown proof types MUST NOT cause a
Consumer to reject the record. Consumers MAY ignore unknown proof
types; doing so does not invalidate the record. Consumers MUST preserve
unknown proof types when forwarding records.¶
The sygil.proof.* namespace is reserved for proof types defined by
the Sygil specification. Future Sygil-defined proof types will appear
in this namespace; third-party extensions MUST use the third party's
own reverse-DNS prefix.¶
A Sygil Proof Object Types registry is to be established with IANA per Section 10 (IANA Considerations) to track the Sygil-namespace proof types and provide a stable reference for extensions registered through the Specification Required policy.¶
For clarity, this section does not specify:¶
How a Producer decides whether to issue a proof object.¶
How a Vault implementation composes underlying policy frameworks (OAuth 2.0 [RFC6749] and its extensions [RFC9449] [RFC9396], capability tokens, authorization engines, policy languages such as ODRL [W3C-ODRL], and so on) to derive the state that a proof object describes.¶
How proof objects are revoked.¶
How trust is established between a Consumer and an unfamiliar Producer of a proof object.¶
The cryptographic verification procedure for any specific proof type beyond the integrity proof's hash recomputation.¶
These are runtime, deployment, and governance concerns addressed by vault-implementation specifications and by deployment-specific trust documents.¶
This section defines the three adoption tiers, the per-namespace conformance model, the compatibility rules that apply across all conformant implementations, and the normative behavior for invalid input.¶
The Protocol defines three adoption tiers. Each is a strict superset of the previous.¶
A Tier 1 implementation MUST:¶
Emit records carrying valid @type (NSID format per Section 4.3),
valid id (sygil:// URI per Section 4.4), created_at, and
updated_at.¶
Emit stable_id and version for every record. Records of
immutable types carry version: 1 and never increment it
(Section 4.2.2).¶
Emit record bodies that validate against the schema artifact for the declared namespace.¶
Compute content hashes via JCS canonicalization [RFC8785] and BLAKE3 [BLAKE3] per Section 4.5.¶
Preserve unknown fields when reading records (Section 6.5).¶
Pass through unknown NSIDs (Section 6.5).¶
A Tier 1 implementation is NOT required to:¶
Implement any specific access control, encryption, audit, or transport.¶
Verify content hashes, signatures, or any proof object.¶
Resolve DIDs or sygil:// references.¶
Expose a query surface.¶
Tier 1 covers use cases such as a calendar application exporting Sygil-shaped events as a portability format, a research tool ingesting Sygil records from various sources, or a local-first application storing Sygil records in a local database.¶
A Tier 2 implementation MUST satisfy all Tier 1 requirements, and MUST additionally:¶
Implement the query grammar of Section 4.10 (six required primitives).¶
Return records in canonical JSON encoding.¶
Resolve DID-based resource identifiers per Section 4.9 (required
methods: did:web [DID-WEB], did:key [DID-KEY]; recommended:
did:plc [DID-PLC]).¶
Support an implementation-defined access mechanism. OAuth 2.0 [RFC6749] is RECOMMENDED but not required.¶
A Tier 2 implementation SHOULD support the quality-aware filter primitives of Section 4.10.6.¶
Tier 2 covers personal-cloud services exposing user data via the Sygil query surface, connectors wrapping third-party APIs and serving them as Sygil records, and enterprise systems exposing employee data under Sygil namespaces with internal authorization.¶
A Tier 3 implementation MUST satisfy all Tier 2 requirements, and MUST additionally:¶
Operate as a vault implementation that satisfies the proof, audit, and isolation invariants applicable to vault implementations. Specific runtime choices (storage substrate, encryption posture, authorization framework, federation primitive, transparency log technology, attestation platform) are not specified by this document and are addressed by vault-implementation specifications.¶
Attach sygil.proof.capability and sygil.proof.consent to records
served under Agent access where the Vault's runtime semantics
produce capability- or consent-derived state.¶
Operate a per-Subject audit log (the sygil.proof.audit proof
object's log_entry_uri MUST resolve to a real entry).¶
Generate sygil.proof.attestation for records produced inside a
trusted execution environment, when applicable.¶
Tier 3 is the boundary at which vault specifications take over. Multiple Tier 3 implementations are anticipated and welcome; conformance to this Protocol does not require adoption of any specific vault implementation's runtime choices.¶
Conformance is asserted per (namespace, tier) pair. An implementation
that supports sygil.v1.calendar.event fully but does not support
sygil.v1.finance.transaction at all is conformant for calendar and
silent for finance. There is no requirement to implement the full v1
namespace set to claim Tier 1 conformance.¶
An implementation MAY claim Tier 1 conformance for one namespace and Tier 2 conformance for another. The conformance assertion is fine-grained.¶
The Sygil schema is authored in LinkML [LINKML], a YAML-based schema modeling language with multi-target code generation. LinkML serves as the single source of truth for namespace structure; from the LinkML source the Protocol's specification maintainers generate the artifacts implementations consume directly:¶
JSON Schema 2020-12 ({namespace}.schema.json) -- the wire
validation artifact. Records validate against the JSON Schema for
their declared NSID; this is the artifact the Tier 1 schema-
validation conformance test category references.¶
JSON-LD context ({namespace}.context.jsonld) -- the
vocabulary-mapping artifact described in Section 4.2.6. Optional
for Sygil-native Consumers; the path to interop for tools speaking
Schema.org, W3C VC, or FHIR vocabularies.¶
GraphQL SDL fragments ({namespace}.graphql) -- informative;
for Tier 2 implementations exposing GraphQL surfaces.¶
SHACL shapes ({namespace}.shacl.ttl) -- informative; for
semantic-web consumers requiring shape constraints.¶
SDK type definitions per language ({namespace}.types.ts,
.py, .go, .rs, .swift) -- informative; convenience
artifacts for application authors.¶
Example record corpora ({namespace}.examples.json,
{namespace}.invalid.json) -- the test fixtures referenced by the
conformance test categories below.¶
Normalization rule documents ({namespace}.normalization.md)
-- informative; mappings to and from external source systems.¶
The JSON Schema artifact is normative for conformance: a Tier 1 implementation that emits records claiming to be of a given NSID MUST emit records that validate against the JSON Schema for that NSID. The other artifacts are informative; their availability is a deliverable commitment of the Protocol's specification maintainers but their use is not required for any tier of conformance.¶
The artifacts are byte-reproducible from the LinkML source: the specification maintainers operate continuous integration that regenerates artifacts on every schema source change and rejects commits where committed artifacts diverge from regenerated artifacts. The byte-reproducibility property lets implementations rely on the artifacts without re-running the LinkML generator locally.¶
A claim of Tier 1 conformance against a namespace means passing the schema validation, identifier, canonicalization, and proof-object preservation tests for that namespace. A claim of Tier 2 conformance adds the query tests. Tier 3 conformance is asserted against a separate test suite, specified by vault-implementation documents, that exercises proof attachment, audit log presence, and per-Subject isolation.¶
The test categories are:¶
| Category | Tier | What it tests |
|---|---|---|
| Schema validation | 1 | Records validate against the schema artifact for their declared NSID; invalid records fail with the expected error. |
| Identifier | 1 |
sygil:// URIs parse correctly; content hashes reproduce; stable_id persists across updates. |
| Canonicalization | 1 | JCS canonicalization is byte-stable across implementations. |
| Proof preservation | 1 | Unknown proof types are preserved; multiple proofs per record are allowed. |
| Query grammar | 2 | All six query primitives behave per spec; pagination works; response envelope is correctly shaped. |
| Quality-aware query | 2 (SHOULD) | Threshold and set-membership semantics on trust-dimension filters. |
| Tier 3 invariants | 3 | Proof attachment under Agent access; audit log presence; per-Subject isolation. |
Test fixtures, expected outputs, and the test harness itself are deliverables of the Sygil Protocol companion documents and are out of scope for this Internet-Draft.¶
The compatibility rules below apply across all conformant implementations.¶
Unknown optional fields. Consumers MUST preserve unknown optional fields when reading records. When forwarding or re-emitting records, Consumers MUST pass these fields through unchanged. Stripping unknown fields silently is a Protocol violation.¶
Unknown NSIDs (whole record types). Consumers MUST pass through
unknown NSIDs. Consumers MUST NOT reject a record solely because its
@type is not recognized. Consumers MAY log unknown NSIDs and MAY
route them to a generic-record handler that preserves the envelope
and treats namespace-specific fields as opaque.¶
Unknown enum values. Consumers SHOULD treat unknown enum values
as equivalent to the enum's unknown member for purposes of
querying, filtering, and rendering, while preserving the original
value verbatim in stored records.¶
Unknown proof types. Consumers MUST pass through unknown
_proofs entries unchanged. Consumers MAY ignore unknown proof
types when evaluating trust; doing so does not invalidate the
record.¶
Unknown major Protocol versions. A Consumer that supports
sygil.v1.* records and encounters a sygil.v2.* record handles
it under rule 2 (unknown NSID): pass through, log, do not reject.
Major versions coexist indefinitely; there is no transition
deadline.¶
Constraint immutability. Once an NSID is published in a
release-tagged Sygil schema version, its required-fields set, type
constraints, and enum members are frozen. New optional fields MAY
be added in a minor schema release; nothing else changes within an
NSID. Constraint changes require a new NSID
(e.g., sygil.v2.calendar.event).¶
The immutability rule decomposes into three operational sub-rules:¶
6a -- No tightening. A v1.x patch MUST NOT introduce
validation rules that would reject previously-valid records.
Specifically: a field that was optional MUST NOT become required;
a type that accepted string | null MUST NOT become string-
only; an enum that had value "other" MUST NOT remove "other";
a regex pattern MUST NOT become more restrictive; a field-length
limit MUST NOT decrease.¶
6b -- No semantic redefinition. A field's meaning, once
specified, MUST NOT change in a v1.x patch. Specifically:
expires_at always means "time at which this record's validity
expires"; subject_scope enum values always carry their
originally-specified semantics; cooperation_mode integers
always carry their original meaning.¶
6c -- No identifier reinterpretation. Identifier formats
(NSIDs, DIDs, sygil:// URIs, sygil-stable: URIs) MUST NOT
have their parsing rules changed in a v1.x patch.¶
These sub-rules apply only within a major version. Major-version bumps (v1 to v2, etc.) MAY break any of them, but only via the migration-table mechanism out of scope for this document and addressed in subsequent Sygil specifications.¶
Producers MUST emit only field values, NSIDs, enum values, and proof types that are declared in some published Sygil schema version. Producing arbitrary or undocumented values is a Protocol violation, even though Consumers must tolerate them under the forward-compatibility rules above.¶
Consumers SHOULD log when they encounter unknown NSIDs, unknown enum values, or unknown proof types, so that ecosystem-wide drift becomes detectable. Logging is recommended, not required.¶
These rules together produce the Postel's-law stance the Protocol depends on: be strict in what you produce, lenient in what you accept, and never silently drop information you do not understand.¶
A schema version MAY be deprecated when its successor has been published and adopted. Deprecation is non-breaking by design.¶
Records emitted under a deprecated version remain valid forever.¶
Consumers MAY warn users when they encounter records under a deprecated version.¶
Consumers MUST NOT reject deprecated-version records.¶
A schema version is retired only when the Protocol's specification maintainers determine that no implementations remain that produce or consume it. Retirement is a documentation update, not a runtime breaking change. Retired versions remain published; Consumers encountering a record under a retired version SHOULD log it for ecosystem-drift monitoring but MUST NOT reject it.¶
A protocol that specifies what valid records look like but not what implementations should do with invalid input is incomplete. This section specifies normative behavior for seven failure modes.¶
A record is invalid when it fails to validate against the schema for its declared NSID.¶
Producers MUST NOT emit invalid records.¶
Consumers MUST reject records that fail schema validation against their declared NSID. Acceptance of an invalid record is itself a Protocol violation.¶
Tier 2 surfaces SHOULD return a structured error envelope identifying which constraint failed.¶
Consumers MUST NOT attempt to repair invalid records by inferring missing fields, coercing types, or substituting defaults.¶
Covered by compatibility rule 2 above.¶
A reference is malformed when it does not parse as a sygil:// URI
(Section 4.4) or a sygil-stable: URI (Section 4.6).¶
Consumers MUST treat malformed references in required fields as invalid record content. Records containing such references fail schema validation.¶
Records containing malformed references in optional fields SHOULD be accepted with the malformed reference field elided from the Consumer's view; the malformed value is preserved in implementation- private metadata for diagnostic purposes.¶
Consumers MUST NOT silently substitute a default value (e.g., null
or a placeholder URI) for a malformed reference.¶
A reference is unresolvable when its URI is well-formed but the referenced record cannot be retrieved.¶
The Protocol does not specify how references are resolved; resolution is a runtime concern. The Protocol does specify how Consumers represent the result:¶
Consumers SHOULD distinguish three resolution states: resolved (the referenced record was retrieved), unresolved (well-formed reference, no record found or accessible), and forbidden (the reference resolved but access was denied).¶
Consumers MUST NOT fabricate referenced record data when resolution fails. Returning a stub marked unresolved is correct; returning an empty record without indication is not.¶
Tier 2 surfaces returning collections containing unresolved references SHOULD include a per-reference resolution status in the response envelope.¶
Covered by compatibility rule 3 above.¶
A hash mismatch occurs when a record's id is supposed to equal
BLAKE3(JCS(record_body)) (with the standard exclusions from Section
4.5) but does not.¶
Tier 1 implementations are NOT required to verify hashes.¶
Any implementation that claims to verify integrity (whether by
recomputing the BLAKE3 hash and comparing to id, or by any other
explicit integrity check) MUST treat hash mismatch as a hard
failure: the record is corrupt or has been tampered with.¶
A Consumer that detects a hash mismatch MUST NOT silently use the record as if it were valid. The minimum acceptable response is to mark the record as integrity-failed in any output that includes it.¶
A Consumer that asserts integrity to its own callers (e.g., emits
a "verified" flag, returns content as authoritative, persists the
record under its id) MUST verify the content hash before doing
so.¶
A Consumer that supports sygil.v1.* and encounters a sygil.v2.*
record handles it under the unknown-NSID rule (compatibility rule 2):
pass through, log, do not reject. The Consumer SHOULD log the
unsupported version specifically so that operators can detect when
their implementation is lagging the published schema. A Consumer
asked to interpret a sygil.v2.* record as if it were sygil.v1.*
MUST decline. There is no implicit version downgrade.¶
| Failure mode | Producer responsibility | Consumer responsibility |
|---|---|---|
| Invalid record | MUST NOT emit | MUST reject; SHOULD return structured error |
| Unknown namespace | (cannot produce) | MUST pass through; MAY log |
| Malformed reference | MUST NOT emit | MUST treat as invalid in required fields; MAY elide in optional |
| Unresolvable reference | (runtime concern) | SHOULD distinguish resolved/unresolved/forbidden; MUST NOT fabricate |
| Unsupported enum value | MUST NOT emit | MUST preserve verbatim; SHOULD treat as unknown for query |
| Hash mismatch | MUST NOT attach integrity proof if hash fails | If verifying, MUST treat as hard failure |
| Unsupported schema version | (n/a) | MUST pass through; SHOULD log; MUST NOT downgrade |
The "MUST NOT emit" Producer rules describe the strict-output side of the Postel's-law stance from Section 6.5. The Consumer rules describe the lenient-input side, with the constraint that leniency does not extend to silent corruption -- unknown content is preserved and surfaced, never dropped or fabricated.¶
This section addresses security considerations applicable to the Sygil Protocol, structured per the threat-model framing of [RFC3552].¶
Per [RFC3552], the threat environment includes deployment across the global Internet across multiple administrative boundaries without assuming that firewalls are in place.¶
For Sygil, the threat model assumes:¶
Producers, Consumers, Vaults, Subjects, and any intermediaries are each individually capable of being honest, compromised, or adversarial.¶
Network paths between parties are fully adversarial: an attacker can observe, drop, modify, replay, and inject traffic.¶
Endpoint compromise is in scope: a Producer's signing key, a Vault's storage, or a Consumer's verification logic may each be compromised.¶
Pervasive monitoring [RFC7258] is in scope: an attacker capable of observing large volumes of traffic across the Internet is part of the adversary class.¶
The Protocol does not assume any specific transport-layer security posture. Implementations carry Sygil records over transports of their choosing (HTTP, MCP [MCP], others); transport security is the transport's responsibility.¶
The table below summarizes the principal attack classes considered in this Section, the Protocol-level mitigations (where any), and the sections that address each in detail. Implementations adopting Sygil SHOULD use this table as a starting point for their own deployment- specific threat-model documents; the table is not exhaustive.¶
| Attack class | Protocol-level mitigation | Detailed in |
|---|---|---|
| In-flight record modification | Content-addressable identifiers; integrity proof (Section 5.4) | Section 8.4 |
| In-flight metadata modification | None at Protocol level (excluded fields are not hash-protected) | Section 8.4 |
| Record-body forgery (synthesized record from non-Producer) | Provenance proof signature; trust-anchored connector identity | Sections 8.5, 8.8 |
| Capability-token forgery | Out of scope (token format-specific; runtime concern) | -- |
| Proof-object forgery (synthesized proof claiming a record property the Producer did not assert) | Signature on proof object; trust-anchored issuer identity | Section 8.8 |
| Replay of recorded responses |
expires_at envelope field; nonce binding via out-of-Protocol mechanisms |
Section 8.6 |
| Trust downgrade via provenance manipulation (downgrading a record's apparent quality to evade authoritative-source rules) | Conditional MUST on authoritative connectors (Section 5.5.2); provenance-warning propagation rule | Section 8.9 |
Cross-domain correlation (re-identification by joining records across namespaces sharing a subject_did) |
None at Protocol level; Subject DID is by-design linkable | Sections 8.10, 9.4 |
DID-method spoofing (attacker emits records with unfamiliar did: method that Consumer cannot verify) |
Opaque-method-tag rule; required-methods commitment (Section 4.9.2) | Section 8.5 |
Hash collision against the id URI |
Cryptographic strength of BLAKE3 ([BLAKE3]) | Section 8.4 |
Algorithm-confusion attacks (e.g., Consumer accepts a blake2- URI as if it were blake3-) |
Algorithm tag is part of the URI; v1 implementations MUST emit and accept blake3- only |
Sections 4.5, 8.11 |
| Side-channel leakage (timing, power) on integrity verification | Out of scope (general implementation hardening concern) | -- |
| Pervasive monitoring; traffic analysis | Mitigations are transport-layer; Protocol envelope reveals Subject DID and record type | Section 8.12 |
| Producer key compromise | Out of scope at Protocol level; key rotation is DID-method-specific | Section 8.13 |
| Vault compromise (records served are not authoritative for the apparent Subject) | None at Protocol level; mitigated by Producer-level authenticity and DID-method cryptography | Section 8.14 |
| Denial of service via pathological inputs | None at Protocol level; size, depth, and rate limits are runtime concerns | Section 8.15 |
The Protocol provides:¶
Structural integrity of records, via content-addressable identifiers (Section 4.4) and a deterministic canonicalization rule (Section 4.5). A Consumer that recomputes a record's content hash detects any modification that occurred after the Producer computed the original hash, modulo the standard hash exclusions.¶
A vocabulary for trust evidence in the form of proof objects (Section 5). The vocabulary is sufficient for a Producer to claim integrity, provenance, capability, consent, attestation, or audit properties about a record, and for a Consumer to recognize and preserve those claims.¶
The Protocol does NOT provide:¶
Confidentiality of records on the wire. The Protocol does not specify any encryption mechanism. Confidentiality is delegated to the transport (TLS for HTTP transport, encryption inherent to the transport for other carriers) and, where applicable, to Vault-level encryption-at-rest.¶
Authenticity of unsigned records. A sygil:// URI is
content-addressed, not signed. A record carrying no proof object is
structurally valid but does not assert anything about who produced
it. Authenticity comes from proof objects (notably
sygil.proof.provenance) and from the underlying signing
infrastructure that produces them.¶
Authorization decisions. The Protocol's proof object vocabulary conveys evidence of authorization; the Protocol does not specify how a Vault decides to grant or deny access. Authorization is a runtime concern.¶
Records on the wire are not confidential by Protocol design. A deployment requiring confidentiality MUST employ a transport that provides it (e.g., HTTPS with TLS 1.2 or later) or wrap records in an application-layer encryption envelope before transmission.¶
The hash exclusions in Section 4.5 do not affect confidentiality of
the excluded fields: a record's _proofs, updated_at, version,
supersedes, obsolete, and obsolete_reason fields all travel on
the wire alongside the rest of the record. They are excluded from
the content hash, not from the serialization. (The query response
envelope's redaction_state field, defined in Section 4.10, is
similarly visible on the wire; it is not part of the record envelope
at all.)¶
The query response envelope's redaction_state field (Section 4.10)
signals that a served record is a projection (redacted, summary,
or hash_only) rather than the full original. Vault implementations
that produce projections are responsible for ensuring that projected
records do not inadvertently include redacted content; the Protocol
provides the labeling but does not enforce the redaction.¶
Integrity protection is provided by content-addressable identifiers. A Consumer that verifies hashes detects post-Producer modification of the canonicalized hash inputs.¶
Integrity is verified by recomputing the BLAKE3 content hash over the
canonical serialization of the record (with the hash exclusions from
Section 4.5) and comparing to the value encoded in the id URI. No
separate proof object is required; the content hash is the integrity
guarantee.¶
Integrity verification is OPTIONAL at Tier 1. Implementations that accept records without recomputing hashes are exposed to in-flight modification; the trade-off is a runtime decision. Implementations that claim to verify integrity (whether at Tier 1 by choice, or at Tier 2/Tier 3 as a baseline expectation) MUST treat hash mismatch as a hard failure per Section 7.¶
The hash exclusions in Section 4.5 mean that a malicious party can:¶
Add, remove, or modify proof objects without changing the content hash.¶
Update updated_at, version, supersedes, obsolete, or
obsolete_reason fields without changing the content hash.¶
Consumers that depend on the integrity of these fields MUST obtain
their assurances from elsewhere -- typically from a sygil.proof.audit
proof object referencing a tamper-evident audit log, or from
transport-layer signatures, or from a Vault implementation's
out-of-band integrity guarantees.¶
A bare Sygil record asserts no authenticity. The producing party is
implicit in the id URI's Subject DID (which identifies the data
subject, not the producer) and in the optional issuer_did envelope
field (which identifies the producer if populated, but is not signed
by the Protocol).¶
Authenticity is conveyed by proof objects:¶
sygil.proof.provenance (Section 5.5) asserts the upstream source
and connector that produced the record. A Consumer that has a trust
relationship with the named connector and that verifies the
connector's signature on the proof can attribute the record to that
connector.¶
sygil.proof.attestation (Section 5.8) asserts that the record was
produced inside a verifiable execution environment.¶
The Protocol does not specify how proof objects are signed. Common choices include JWS [RFC7515] over the canonicalized record with the proof object as the payload, or detached signatures referenced by URI.¶
The opaque-string-with-method-tag rule for DIDs (Section 4.9.1) means
that a Consumer that does not understand a particular DID method MUST
NOT trust assertions tied to that DID more than it would trust an
assertion tied to an opaque string. A record whose subject_did is
did:newmethod:identifier is structurally valid; whether the Consumer
can resolve and verify that DID is method-specific.¶
A Consumer that resolves DIDs via the required methods (did:web,
did:key) and the recommended method (did:plc) per Section 4.9.2
inherits the security properties of those methods. did:web depends
on the security of the served DID document and the TLS connection that
delivers it; did:key depends on the key being correctly encoded and
the algorithm being supported; did:plc depends on the PLC operator
and the directory's integrity.¶
A sygil:// URI is content-addressable: the same record body
produces the same URI. A Consumer cannot distinguish a replayed
delivery of a known record from a fresh delivery solely from the URI.¶
Where replay matters (e.g., a sygil.proof.capability proof should
not authorize the same access twice), Consumers MUST rely on
out-of-Protocol mechanisms: the capability token's own nonce or
expiry, the audit log entry referenced by sygil.proof.audit, or
transport-layer freshness signals (e.g., DPoP [RFC9449] when OAuth
2.0 is in use).¶
The envelope expires_at field (Section 4.2.4) signals retention
expiry, not authentication freshness. A record whose expires_at has
passed should be treated as expired by retention-aware Consumers but
this is not a defense against replay of an authentication artifact.¶
The Protocol's proof object vocabulary is sufficient for a Consumer to verify what a Producer claims:¶
The claim's structure is valid (the proof object validates against
its @type schema).¶
The claim is correctly bound to the record (the proof appears in the
record's _proofs array).¶
The record's integrity can be verified locally against the
canonicalized record by recomputing the BLAKE3 content hash and
comparing to the value encoded in the id URI; this verification is
performed without any proof object.¶
The Protocol's proof object vocabulary is NOT sufficient for a
Consumer to verify whether a Producer's underlying claim is correct
under any specific runtime policy. A Producer could be configured with
a permissive runtime authorization policy and issue technically-valid
sygil.proof.capability proofs for records that would not pass a
stricter Consumer's policy. Protection against this -- typically by
trust-anchoring Producers to a known issuer infrastructure, by
verifying the underlying capability token, or by maintaining a
Consumer-side policy that filters records by Producer trust -- is a
deployment and trust-establishment concern, not a Protocol concern.¶
Consumers SHOULD NOT treat the presence of a proof object as evidence of underlying policy correctness. Proof objects are evidence of assertion by the Producer; verification of the assertion is a separate, runtime-defined activity.¶
A proof object asserts a property of a record. The mechanism by which a Consumer concludes the assertion is genuine is signature verification: the proof's signature, computed over the proof's canonicalized body, must verify against the public key of the issuing party. The Protocol does not specify the signing mechanism; common choices include JSON Web Signatures [RFC7515] over the canonical serialization of the proof object body and detached signatures referenced by URI.¶
A proof forgery occurs when an attacker produces a proof object that appears valid but is not signed by the party it purports to come from. The Protocol's defenses are:¶
Connector identity verification. A sygil.proof.provenance
proof's connector_id field names the connector that produced the
record. A Consumer that acts on provenance MUST verify the
connector_id matches the connector's known identity per the
minimum evaluation expectations of Section 5.3.4. Without that
check, an attacker that knows a connector's identifier can mint
forged provenance proofs at will.¶
Issuer signature. A signed proof object binds the proof's contents to the issuing party's signing key. Forgery requires compromise of the signing key (Section 8.10) or a cryptographic break in the signature scheme.¶
Independence rule. The Protocol's proof-independence rule (Section 5.3.1) means a forged proof of one type does not infer properties associated with other proof types. Forgery of a single proof type does not yield record-level forgery of all properties.¶
A Producer MUST NOT attach a proof object whose underlying claim it cannot defend; doing so is a Producer-side Protocol violation (a Producer that emits forged proof objects is a malicious Producer). The Protocol cannot prevent malicious Producers from emitting syntactically valid records; defense is at the Consumer side, by trust-anchoring the Producers and Vaults the Consumer is willing to accept proof objects from.¶
A trust downgrade attack is one in which an attacker manipulates trust-bearing fields on a record to lower the apparent trust level the record claims, in a way that lets the attacker substitute a lower-trust record for a higher-trust one without triggering Consumer protections.¶
Three concrete attack patterns are addressable at the Protocol level:¶
Provenance downgrade. An attacker substitutes a
cooperation_mode: "user_mediated_capture" (user-mediated capture)
provenance proof for a cooperation_mode: "native_sygil" (native
integration) one, hoping the Consumer's quality-aware filter
(cooperation_mode_in=native_sygil,cooperative_api, Section
4.10.6) will exclude the record from results -- denying the
Consumer access to a record it was entitled to. Defense: the
provenance proof is signed; substitution by a non-issuer fails
signature verification.¶
Authoritative-source bypass. An attacker emits a record from
a connector locally known to the Consumer as authoritative, but
without attaching a sygil.proof.provenance proof, hoping the
Consumer will treat the record as authoritative without examining
whether the proof is present. Defense: the conditional rule of
Section 5.4.2 requires authoritative-source records to carry the
proof; the Consumer MUST treat missing-proof cases as carrying a
provenance-warning state and MUST propagate the warning to its
caller, and MUST NOT silently treat the record as authoritative.¶
Verifiability downgrade. An attacker claims verifiability:
source_signed on a sygil.proof.provenance proof to mislead the
Consumer's quality filter, while the underlying record is not
source-signed. Defense: a Consumer that acts on the
verifiability claim (e.g., requires verifiability_min=
source_signed) MUST verify the source signature is actually
present and verifies; the proof's claim alone is insufficient
per the minimum evaluation expectations of Section 5.3.4.¶
The general principle is that trust claims at the wire level are evidence of assertion, not of correctness; a Consumer that needs correctness MUST verify the underlying cryptographic or external property, not rely solely on the proof's stated value.¶
Sygil's design intentionally enables cross-domain reasoning: an Agent
holding records under subject_did = did:web:user.example.com for
calendar, finance, health, location, and message namespaces can join
across them by subject_did. This is a feature; it is also a
re-identification surface.¶
The attack scenario is direct. An adversary who obtains records from
multiple namespaces under the same subject_did can construct a
profile far more identifying than any individual namespace's records
provide. A calendar event for a doctor's appointment, a financial
transaction for a copay, a health observation for a diagnosis, and a
location record for a clinic -- joined by subject_did -- disclose
information no individual record discloses.¶
Mitigations are deployment-level and policy-level, not Protocol-level:¶
Authorization scoping. A Vault implementation SHOULD scope
Consumer authorization per-namespace (or finer); a Consumer
authorized for sygil.v1.calendar.event SHOULD NOT thereby be
authorized for sygil.v1.health.observation under the same
Subject. The Protocol's tier definitions (Section 6) require
per-namespace scoping at Tier 2 and beyond.¶
Per-context Subject DIDs. Subjects MAY adopt distinct DIDs for
distinct contexts (e.g., a did:key per Consumer relationship);
records under different DIDs are not joinable. The Protocol does
not require this practice but allows it; the trade-off is that
unlinkable records cannot be joined by Agents that should
legitimately reason across them.¶
Quasi-identifier discipline. Even with Subject DID concealed,
envelope fields (created_at, updated_at, language[],
connector_id) and per-namespace fields can themselves identify
a Subject by joining attributes. A serious privacy posture
requires Vault implementations to apply data-minimization at the
projection layer (Section 4.2.6) and consider quasi-identifier
exposure when serving cross-namespace results. Earlier drafts
also listed an envelope jurisdiction[] field as a strong
quasi-identifier; that field was removed in the v0.3
reconciliation, but runtime systems that derive jurisdictional
binding from subject_did and source-system content should be
aware that the same quasi-identifying signal exists in those
derivations and should be handled with the same care.¶
The Protocol does not provide an in-band correlation-prevention mechanism. Section 9 (Privacy Considerations) addresses re-identification and linkability further; the formal Privacy Properties subsection (Section 9.1) makes explicit which protections the Protocol does and does not provide. Section 9.5 (Derived data amplification) addresses a related concern: derived records may disclose information beyond what their source records disclose individually, even before any cross-namespace join.¶
The Protocol pins:¶
Algorithm agility is provided by major-version protocol bumps
(sygil.v2.* may select different algorithms). Within v1, all
implementations MUST agree on BLAKE3 and JCS; mixing algorithms within
v1 produces non-reproducible content hashes and breaks the
content-addressing invariant.¶
Implementations preparing for post-quantum-relevant changes should note that:¶
BLAKE3 is a hash function; post-quantum cryptanalysis affects preimage and collision resistance and current consensus is that hash-function security degrades less than asymmetric primitives under quantum attack. BLAKE3 is acceptable for the v1 Protocol horizon.¶
The Protocol does not specify any asymmetric primitive. Signatures on proof objects, transport-layer authentication, and DID-method cryptographic primitives are all out of Protocol scope. The cryptographic agility of these is the responsibility of the runtime layer that uses them.¶
Per [RFC7258], pervasive monitoring is an attack on confidentiality and on user privacy at scale. Sygil records, if observed in transit, reveal:¶
The Subject DID (in the id URI prefix).¶
The record type (@type NSID).¶
The record contents (the body and the _proofs array).¶
The first two are revealed even when the body is encrypted, because they are part of the URI and the JSON envelope. Implementations that require subject-DID confidentiality on the wire MUST employ a transport or application-layer scheme that conceals them; the Protocol does not provide concealment for identifying envelope fields.¶
The proof-bearing response shape arguably increases traffic-analysis revelation compared to opaque-blob protocols, because each record carries its own metadata trail. Implementations sensitive to traffic analysis (high-stakes journalism, source protection, regulated populations under surveillance) SHOULD employ transport-layer mitigations (mixing networks, padding, dummy traffic) and SHOULD consider whether the Protocol's tier of detail is appropriate to their threat model.¶
A Producer's signing key (used to produce signed proof objects) is the hinge of authenticity for that Producer. Compromise of the key allows an attacker to forge proof objects asserting any property under that Producer's identity.¶
The Protocol does not specify a key-rotation, revocation, or key-compromise-recovery mechanism. These are runtime concerns, typically addressed by the underlying DID method's key-rotation support (where present) and by Vault-level revocation and re-issuance discipline.¶
A Consumer that detects a compromised Producer key SHOULD invalidate or downgrade trust in records carrying proofs signed by that key, through a Consumer-side policy outside the Protocol's scope.¶
The Subject DID in a sygil:// URI is the identifier of the data
subject; it does not authenticate them. A malicious party can mint
records with any Subject DID and emit them as syntactically valid
Sygil records. Defenses are:¶
Producer-level authenticity (the Consumer trusts only records carrying proof objects from known Producers).¶
Vault-level authentication (the Consumer obtains records only via a trust relationship with a Vault that is expected to authenticate Subject access).¶
DID-method cryptographic primitives (e.g., signed Subject statements derived from the Subject's DID-controlled keys, as in Verifiable Credentials [W3C-VC2]).¶
A compromised Vault can produce records that appear to be authoritative
for any Subject the Vault hosts. Consumers relying on a Vault as a
trust anchor inherit the Vault's compromise. The Protocol does not
specify Vault attestation; vault-implementation specifications may
specify it via sygil.proof.attestation.¶
The Protocol specifies content hashes (computationally bounded by serialization size), schema validation (computationally bounded by schema size), and reference resolution (potentially network-bounded).¶
A malicious Producer can emit records:¶
With pathologically large bodies, increasing canonicalization and hash cost.¶
With many cross-references, increasing resolution cost on the Consumer.¶
With deeply nested structure, stressing JSON parsers.¶
These vectors are general JSON-processing vectors and not Sygil-specific. Implementations SHOULD apply size limits to record bodies, depth limits to JSON parsing, and rate limits to reference resolution. The Protocol does not specify limits because they depend on deployment.¶
Privacy considerations specific to personal data carried by the Protocol are addressed in Section 9.¶
The Protocol carries personal data by design. This section addresses privacy-specific considerations that complement the security considerations in Section 8.¶
This subsection makes explicit what the Protocol does and does not guarantee at the privacy level. The framing is deliberately formal: privacy guarantees that are not stated here are not provided. Implementations seeking specific privacy properties beyond those listed here must obtain them from runtime, deployment, or policy mechanisms outside the Protocol.¶
The Protocol commits to the following privacy properties at the wire level:¶
Per-field sensitivity classification. Every namespace
specification declares a privacy classification (public,
redacted, invisible) for each field (Section 4.2.5). The
classification travels with the schema, not with individual
records, so two implementations classifying the same field
inconsistently is a Protocol violation detectable by inspection.¶
Wire-level projection labeling. Query responses carry a
redaction_state field in the response envelope (Section 4.10)
labeling the projection level the served record represents in
that response. A Consumer can distinguish an original record
from a redacted, summary, or hash_only projection without
out-of-band signaling. The same record content can be served as
different projections in different responses; the projection
state belongs to the response, not the record.¶
Soft-delete semantics with reason. Records carry obsolete
and obsolete_reason envelope fields. A Subject's withdrawal of
consent is communicated by obsolete: true with obsolete_reason:
withdrawn_consent, providing wire-level visibility into the
reason without Consumer guesswork.¶
Wire-level consent evidence. When a record is served under a
consent-bearing access, the sygil.proof.consent proof object
(Section 5.6) carries consent-receipt evidence on the wire
alongside the record. The Consumer learns that consent was
asserted and what receipt was referenced; the underlying receipt
itself is referenced, not embedded.¶
Wire-level provenance evidence. The sygil.proof.provenance
proof (Section 5.4) carries upstream-source identification and
trust dimensions, so a Consumer reasoning about whether to trust
a record for a given purpose has wire-visible inputs to that
reasoning.¶
Subject-protective defaults. Default values across the
envelope (subject_scope: sole, obsolete: false, empty
language[]) are chosen so that records constructed without
explicit privacy decisions make minimal claims, reducing the
risk of overstated trust assertions to Consumers (Section 9.12).¶
The Protocol does NOT provide the following, even where they may appear suggested by the structure of the wire format. Implementations requiring these properties must obtain them elsewhere.¶
Confidentiality of records on the wire. Records are not encrypted by Protocol design. Confidentiality depends on the transport (typically TLS over HTTP, or transport-inherent encryption for other carriers); the Protocol does not specify a cryptographic envelope.¶
Confidentiality of identifying envelope fields. Even when
record bodies are encrypted, the Subject DID (in the sygil://
URI prefix), the record @type (NSID), and metadata fields like
created_at, language[], and connector_id are visible to
any party that observes the URI or the JSON envelope.
Implementations requiring concealment of identifying envelope
fields MUST employ a transport or application-layer scheme that
conceals them.¶
Unlinkability of records about the same Subject. Records
about the same Subject share a subject_did by design and are
linkable across all records about that Subject. The Protocol does
not provide an unlinkability primitive; implementations requiring
unlinkability for specific records or Subjects MUST employ
per-context Subject DIDs at the cost of cross-namespace
joinability (Section 8.10).¶
Resistance to cross-domain correlation. A party with access to records across namespaces under the same Subject DID can join them. The Protocol provides no in-band defense against cross-domain correlation; defenses are at the Vault and deployment level (Section 8.10).¶
Quasi-identifier protection. Envelope and per-namespace fields collectively form a fingerprint that may identify a Subject even when explicit identifiers are concealed. The Protocol does not defend against this; implementations requiring k-anonymity or differential privacy guarantees MUST apply such transformations at the Vault layer.¶
Forgetability of record existence. A record's id is a
content hash; the same canonicalized body always produces the
same id. Erasing a record from a Vault's storage does not
remove the URI from any cache, log, or downstream Consumer
that observed it. The obsolete field provides soft-delete
semantics, not cryptographic forgetting.¶
Consent enforcement. The sygil.proof.consent proof carries
evidence that consent was asserted, not that consent is being
honored. A Vault may emit consent proofs against access patterns
that are inconsistent with the underlying receipt; the Protocol
provides no mechanism for the Consumer to detect such
inconsistency. Enforcement is a Vault responsibility.¶
Audit log integrity beyond reference. The
sygil.proof.audit proof references an audit log entry by URI;
the Protocol provides no guarantee that the referenced log
entry exists, is consistent with the record, or has not been
altered. Such guarantees are properties of the audit log
infrastructure (transparency log, witness cosigning) operated
by the Vault implementation.¶
Semantic correctness of asserted content. A record can be
structurally valid (validates against its declared schema, has a
reproducible content hash, is well-formed in every wire-level
sense) while making misleading or incorrect semantic claims about
the Subject's life -- a transaction record with the wrong
merchant category, a calendar event with a misleading title, a
health observation with an incorrect value. The Protocol provides
structural guarantees only. Records that are subject-asserted
(typed in by the Subject) or that result from inference rather
than direct source-system import are particularly exposed to
this: no upstream system signs them, and no proof object exists
that a Consumer can verify to establish content correctness. The
sygil.proof.provenance trust dimensions (cooperation_mode,
freshness, completeness, verifiability) and the
derived_from[] envelope field collectively let a Consumer
distinguish source-imported records from subject-asserted or
derived ones, but they do not establish content correctness for
any class. Consumers that act on the content of records without
further validation inherit the Producer's correctness, whatever
it is. The Protocol provides no defense against semantically-
misleading-but-structurally-valid records; defense is a
deployment, trust-anchoring, and Producer-vetting concern.¶
The following are explicit non-goals and are not within the scope the Protocol claims:¶
Differential privacy or k-anonymity guarantees.¶
Onion-routed record retrieval or other transport-anonymity primitives.¶
Multi-party computation or secure aggregation of records across Subjects.¶
Zero-knowledge proof of record properties without revealing the record.¶
Private set intersection, encrypted query, or other query-time-confidentiality primitives.¶
Forward secrecy of past records given current key compromise.¶
These are areas of active research and engineering; the Protocol takes the position that they are best provided as composable layers above or below Sygil-shaped data, not as Protocol-level mandates.¶
The Protocol does not enforce data minimization on records. A namespace specification declares which fields a record may carry; a Producer chooses which optional fields to populate.¶
Two Protocol features support data minimization at the runtime level:¶
The redaction_state envelope field (Section 4.2.4) labels a
served record as original, redacted, summary, or hash_only.
Vaults producing projections for less-trusted Consumers SHOULD use
these labels and SHOULD enforce that projections actually omit the
excluded content.¶
Per-namespace privacy classification. Each namespace
specification declares default privacy classes (public, redacted,
invisible) for individual fields. These are descriptive metadata
for runtimes; the Protocol does not enforce them.¶
Implementations SHOULD apply data minimization at the projection layer: records served to Agents performing narrow tasks should carry only the fields necessary for the task. The Protocol provides the labels that make this discipline possible; the Vault implementation applies it.¶
The sygil.proof.consent proof object (Section 5.7) carries
consent-receipt evidence on the wire alongside a record. Consent
receipts MAY follow the W3C Data Privacy Vocabulary, ISO/IEC TS
27560:2023 [ISO-27560], or other consent-receipt schemes; the
Protocol specifies the proof shape but not the receipt format.¶
The presence of a sygil.proof.consent proof object asserts that the
Producer claims a consent receipt covers the access. As discussed in
Section 8.7 (Limits of Protocol-level guarantees), the proof's
presence is evidence of assertion, not of correctness. A Vault
implementation is responsible for actually obtaining, recording, and
honoring consent; the Protocol provides the wire vocabulary for
referencing the resulting receipt.¶
A Subject's withdrawal of consent is reflected in the envelope via
obsolete: true with obsolete_reason: withdrawn_consent. Runtime
cascades -- propagating the withdrawal to derived records, to caching
Consumers, to downstream Agents -- are runtime concerns and not
specified by the Protocol.¶
Sygil records carry rich personal data and explicit cross-namespace
references. A record's subject_did is by design stable across all
records about the same Subject; this enables interoperability but also
makes cross-domain join attacks straightforward for an attacker with
access to records across namespaces.¶
The Protocol's subject_did is intentionally linkable. Implementations
that require unlinkable Subject identifiers MUST employ a different
identifier scheme outside the Protocol; the trade-off is that
unlinkable records are not interoperable across namespaces, which
defeats much of the Protocol's purpose.¶
Specific re-identification considerations:¶
Cross-namespace joins. A subject_did shared across calendar,
health, and finance records yields a much more identifying profile
than any single namespace's records. Implementations serving records
across namespaces SHOULD apply per-namespace authorization and
SHOULD NOT serve unrestricted cross-namespace queries without policy
controls.¶
Quasi-identifiers in metadata. Envelope fields such as
created_at, updated_at, language[], and the connector_id
and imported_at fields of sygil.proof.provenance can
themselves be quasi-identifying. A record claiming language
["pt-BR"] and import via a specific Brazilian banking connector
identifies the Subject's locale and banking relationship even if
the Subject DID is concealed. Earlier drafts also included a
jurisdiction[] envelope field which would have been a strong
quasi-identifier; that field was removed in v01, but runtime
systems that derive jurisdictional binding from subject_did and
source-system content should be aware that the same quasi-
identifying signal exists in those derivations and should be
handled with the same care.¶
Reference graphs. The derived_from[] lineage and inline
references between records form a graph that may be more identifying
than any individual record. Anonymization of records does not
anonymize the reference graph.¶
Social graphs are strong quasi-identifiers. The sygil.v1.social
namespace carries the Subject's follow, block, mute, and like edges.
A social graph is among the strongest quasi-identifiers in the
Protocol: an individual's set of follows is frequently near-unique,
and block and mute lists reveal conflict, estrangement, and private
judgment that the Subject specifically chose not to make public. The
Protocol classifies follow and like edges as redacted and block and
mute edges as invisible by default for this reason (the social
namespace's privacy classification hints), but implementations should
treat the aggregate social graph as more sensitive than any single
edge, and should be aware that joining a Subject's social graph with
their public posts (which the Subject deliberately published) is a
powerful correlation surface even though the posts themselves are
public.¶
The sygil.v1.social namespace introduces content that is public by
the Subject's deliberate act -- posts, replies, reposts, and
quote-posts the Subject broadcast to a public audience. This is a
different privacy posture from every other namespace in the Protocol,
where the default is protect-unless-told-otherwise. To represent it,
the Schema defines a second field-classification axis, the intent
posture (public_by_intent), orthogonal to the sensitivity axis
(public / redacted / invisible).¶
The intent posture makes a narrow assertion: that re-exposing content
the Subject deliberately published is not a new disclosure of
originally-private data, because the content was never private. It
does not assert that the content is safe to surface in any
context -- re-surfacing appropriateness remains the joint product of
the sensitivity axis and the projection context. A Subject can
deliberately publish sensitive content (a public post disclosing a
medical condition); such a field is public_by_intent (the Subject
broadcast it) and may also warrant redacted sensitivity handling
(an implementation should not casually re-surface it in unrelated
contexts). The two axes are independent; neither is derivable from the
other.¶
The posture attaches only to content the Subject authored or
affirmatively published. It does not attach to content that is merely
about the Subject, merely visible on a public platform, or merely
retrievable through an API. In particular, a Subject's social graph
(follows, blocks, mutes, likes) is not public_by_intent even
when a platform exposes it publicly: platform exposure is the
platform's decision, not the Subject's act of publication. This
distinction is what prevents the publicness of a post from leaking
onto the surrounding graph -- the most sensitive social data -- when an
implementation reasons about social records.¶
The intent posture is descriptive classification metadata that runtime
projection policy consumes; it does not override projection. The
authorship constraint (the posture is invalid for records where the
Subject is referent rather than author) is enforced by the social
namespace's validation rules in the companion Schema. Implementations
processing sygil.v1.social records SHOULD honor the intent posture
as an input to projection decisions and MUST NOT treat it as a
blanket license to re-surface published content without regard to the
sensitivity axis and the projection context.¶
The sygil.v1.conversation namespace carries the data subject's
archived conversations with AI models. These are among the most
sensitive payloads the Protocol can carry -- often more candid than any
other source, because subjects reason out loud with an assistant in a
way they may not with any person. A conversation archive routinely
contains health, legal, financial, relationship, and other intimate
disclosures; political and religious views; and unfiltered first-draft
thinking, including abandoned branches the subject may consider more
private than the conclusion they reached.¶
Two properties of the data class warrant specific note. First, the
content frequently concerns other people who were not party to the
conversation and did not consent to its archiving -- a subject
discussing a colleague, a family member, or a third party. The Protocol
does not represent this as a subject_scope distinction (the turn
remains the subject's archived artifact regardless of whom it
discusses); it is handled by the sensitivity axis, with every
conversation record classified highly sensitive (concealed) by
default, so that third-party content within a transcript is concealed
along with everything else. Second, the content commonly contains
embedded secrets -- pasted credentials, private keys, proprietary
source. The Protocol treats conversation content bodies as opaque
highly-sensitive material; an implementation MAY scan for secrets on
import, but any such scan result is implementation-private and is not
part of the Protocol's record shape, and scanning MUST NOT silently
alter content (which would break the record's content-addressed
identity).¶
Because the namespace is ImportOnly, the Protocol's revocation model for it is purge rather than token revocation: the subject's grant is the act of uploading an export, and revocation is the deletion of the materialized records. Implementations SHOULD treat conversation content bodies as ineligible for any informational log stream and SHOULD retain raw uploaded archives only as long as parsing requires.¶
Sygil's derived_from[] envelope field (Section 4.2.4) captures the
case where a record was produced by combining or transforming other
records. This case is common -- an agent producing a weekly health
summary from daily wearable observations, an inference engine
extracting a calendar event from an email thread, an analyst
aggregating financial transactions into a quarterly cash-flow
projection.¶
The privacy concern this subsection addresses: a derived record can have higher sensitivity than the records it was derived from. The classic example: ten individually low-sensitivity location records (a coffee shop, a gym, a grocery store) aggregated into a single record may reveal a home address with high precision. Ten individually low-sensitivity transaction records may aggregate into a record that discloses health conditions through inference (a sequence of pharmacy charges, copay amounts, and lab fees). Each source record carries its namespace's standard privacy classification; the derived record's classification is not mechanically derivable from the sources.¶
The Protocol provides the mechanisms by which derived records declare their lineage:¶
derived_from[] carries derivation-reference objects whose
source_record fields hold the sygil:// URIs of the source records.¶
sygil.proof.provenance (Section 5.4) carries the source-system
trust dimensions for source-imported records. Records produced
by inference or aggregation rather than direct source import
generally do not carry a provenance proof in the same form;
Producers SHOULD instead document the derivation lineage through
derived_from[] and through a derivation-specific proof type if
one is registered (the sygil.proof.derivation proof type is a
candidate for future registration but is not specified by this
document).¶
The privacy classification framework (Section 4.2.6) lets the derived record's namespace declare per-field classifications that may be more restrictive than the source records'.¶
The Protocol does NOT provide:¶
Automatic re-classification of derived records based on source
classification. The Protocol does not specify a derivation
arithmetic -- a record derived from public sources is not
automatically public, nor is a record derived from redacted
sources automatically redacted. Per-field classification on
the derived record is the namespace specification's
responsibility.¶
Detection or prevention of sensitivity amplification through inference. The Protocol cannot, in general, determine whether a derived record discloses information beyond what its source records disclose individually.¶
A Producer creating a derived record SHOULD classify the derived record's fields independently of the source records' classifications. If the derivation method is known to amplify sensitivity (statistical aggregation across many source records, machine-learning inference across heterogeneous source records, joins across sensitive namespaces), the Producer SHOULD apply more restrictive privacy classifications to the derived record's fields than the average source record carries.¶
A Vault implementation serving derived records SHOULD apply projection policies appropriate to the derived record's classification, not policies inherited from the source records. A weekly health summary aggregating daily observations is a health observation in its own right; serving it under the daily observations' policy understates its sensitivity.¶
A Consumer receiving a derived record (a record carrying a non-empty
derived_from[] array) SHOULD treat the derivation as a sensitivity
signal independent of any individual proof object: derived records
may carry higher sensitivity than the source records the Consumer
might otherwise be authorized for, regardless of the trust
dimensions on any source-system provenance proof.¶
derived_from[] is query-filterable
A Consumer concerned about derived-data sensitivity has a wire-level
handle to control its exposure: the derived_from[] envelope field
(Section 4.2.4) is filterable via the standard reference-traversal
predicate (Section 4.10.2). A Consumer that wishes to exclude
derived records altogether can issue queries that filter on the
field's emptiness; a Consumer that wishes to receive only records
derived from a particular source can issue a query traversing the
specific source URI. The Protocol does not provide a "not-equal" or
"is-empty" predicate, so finer filters require runtime-side
post-processing; nonetheless, the reference-traversal primitive on
derived_from[] is the wire-level mechanism by which a Consumer's
sensitivity policy can be expressed at query time. The
sygil.proof.provenance.cooperation_mode query filter
(cooperation_mode_in=..., Section 4.10.6) provides an additional
trust-dimension handle for filtering by the source-system's
cooperation posture.¶
This is the explicit linkage between the privacy classification framework (which describes per-field sensitivity intrinsic to namespaces) and the query mechanism (which lets a Consumer's deployment policy filter records by their derivation lineage and by their source-system cooperation mode).¶
(Earlier drafts of this Protocol surfaced derivation kind as an
envelope-level enum field, provenance_quality. That field was
removed in the v0.3 reconciliation that produced this v01 increment;
its semantics now distribute across derived_from[] for lineage and
the trust dimensions of sygil.proof.provenance for source-import
quality. A future Protocol revision MAY introduce a
sygil.proof.derivation proof type to carry derivation-specific
trust dimensions; this document does not specify it.)¶
A protocol that mechanically prevented derived records from being served at lower sensitivity than their sources would either:¶
Require the Protocol to specify an arithmetic of sensitivity classes (which would constrain runtime privacy policy in ways that vary substantially across deployments), or¶
Require runtimes to refuse to serve derived records at all whenever amplification might be present (which would defeat the use case of derived records).¶
The Protocol takes the position that derivation arithmetic is a deployment policy concern: the namespace specification declares per-field classifications, the Producer applies a derivation discipline, the Vault applies a projection discipline, and the Consumer applies a use-policy discipline. The Protocol provides the labels and the structural framework; the discipline lives at the runtime layer.¶
By design, records about the same Subject share a subject_did and
are linkable. This is a deliberate trade-off; it enables cross-domain
agent reasoning, which is the primary use case the Protocol exists to
serve.¶
Implementations that require unlinkability for specific records or
specific Subjects MUST employ separate Subject DIDs (e.g., per-context
did:key identifiers) and accept that records under those identifiers
are not joinable to records under the Subject's primary DID. The
Protocol does not provide an in-band linkage-control mechanism beyond
this segregation.¶
Most jurisdictions in which Sygil is likely to be deployed (EU GDPR,
US state-level CCPA-equivalents, Canadian PIPEDA, Brazilian LGPD,
others) recognize Subject rights including access, rectification, and
erasure. Sygil's content-addressable identifiers complicate naive
erasure: the id URI is bound to the canonicalized record body and
the same body always hashes to the same URI, so an erased record's URI
remains a stable referent.¶
The Protocol provides:¶
Soft-delete via obsolete: true with obsolete_reason (Section
4.2.4). The original record's id URI remains stable, but the
record is marked as no longer current. Runtimes that honor
soft-delete filter obsolete: true records out of query results by
default.¶
The obsolete_reason: withdrawn_consent value specifically
signals consent withdrawal, supporting GDPR Article 17 erasure
flows.¶
The NSID extension pattern (Section 4.2.5) and _proofs
extensibility allow vault implementations to attach
erasure-specific metadata. Deletion-receipt records can be
published under the implementation's community namespace
(sygil.community.{publisher}.deletion_receipt.*); retention-
honoring audit log entries are referenced via sygil.proof.audit
per Section 5.8. Neither requires modifying the canonical record
being soft-deleted.¶
Hard erasure -- actually removing the record from storage -- is a Vault runtime concern. The Protocol does not specify how a Vault implements erasure under regulatory requirement; vault-implementation specifications address this.¶
The expires_at envelope field and retention_policy reverse-DNS
identifier (Section 4.2.4) support retention-driven expiry. Records
whose expires_at time has passed are signaled as expired; how a
Vault implements expiry-driven deletion is a Vault concern.¶
A reserved invariant of the Protocol, surfaced during the v0.3
reconciliation that produced this v01 increment, is that all v1
records are canonical self-contained Sygil records. Every record
carries a complete envelope; the id is hash-over-canonical-form
(per Section 4.4-4.5); content addressing is byte-stable across
implementations.¶
Any future transmission optimization that omits fields from
individual records on the wire -- for example, a token-efficient
batch projection that strips repeated subject DIDs across a batch
of records returned to an Agent -- MUST preserve id as
hash-over-canonical-form. The optimization can transmit fewer
bytes; the records' identity must remain hash-equivalent to what
canonical-form transmission would produce.¶
This invariant is normative for the Protocol's evolution: future specification increments that introduce batch optimizations, columnar projections, agent-shaped formats, or any other non-canonical wire forms MUST specify how each form maps back to a canonical Sygil record before content-hash verification. v01 does not specify any such optimization; the invariant exists to preserve the design space.¶
The Protocol's regulatory-agnostic stance (a value preserved
across all v1 increments) means that jurisdictional binding,
cross-border data transfer rules, and similar regulatory-routing
concerns are runtime, deployment, and legal concerns, not
Protocol-level concerns. Earlier drafts of this Protocol reserved
a jurisdiction[] envelope field for jurisdictional binding; v01
removes the field per the v0.3 reconciliation because runtime
derivation from subject_did, source system, and record content
is the more honest model. Implementations operating across
jurisdictional boundaries SHOULD ensure that runtime policies
honor jurisdiction-specific requirements; the Protocol does not
provide a wire-level mechanism for declaring or enforcing
jurisdictional bindings.¶
A Subject DID embedded in every sygil:// URI for that Subject's
records is, by design, a stable identifier of the Subject. Where DID
methods support pairwise-pseudonymous identifiers (e.g., generating a
fresh did:key per relying party), Subjects may employ them to limit
cross-relying-party correlation; the Protocol does not require or
prohibit this practice.¶
The source_record_id_hash field of sygil.proof.provenance (Section
5.4) hashes rather than embeds the upstream source-system identifier,
to avoid leaking that identifier to downstream Consumers.
Implementations MUST NOT include un-hashed upstream identifiers in
this field.¶
The Protocol's query grammar (Section 4.10) lets Consumers retrieve records by namespace, time range, field equality, reference traversal, text search, and quality dimensions. Even when individual records are appropriately classified, redacted, and projected, the queries themselves can leak sensitive information through side channels that the Protocol does not defend against.¶
The principal classes of query-based inference attack:¶
Presence/absence inference. A query like ?q=specific_term
returning zero results vs. one or more results discloses that
the queried term does or does not appear in any record visible
to the querying Consumer. For sensitive terms (medical
conditions, legal proceedings, particular relationships),
presence/absence is itself disclosure, even when the underlying
records would have been served redacted.¶
Count inference. A query returning a specific count discloses how many records of a given shape exist for the Subject. Counts across queries can be combined to infer attributes the records themselves are redacted to conceal (e.g., counts of records in pharmacy, lab, and clinic namespaces over a time range can imply health conditions even when the records are individually hash-only or summary-projected).¶
Timing side channels. The latency at which a Vault responds to a query can disclose whether the query traversed an index, hit a cache, was filtered by an authorization rule, or required a cross-namespace join. A Consumer measuring response timings can infer record existence, projection level applied, or authorization policy structure.¶
Pagination cursor leakage. Opaque pagination cursors may encode position information that, in aggregate, discloses ordering or count properties of the underlying record set. Cursors that round-trip through Consumer storage can also unintentionally persist record-existence signals.¶
The Protocol does not provide defenses against any of the above. Mitigations are runtime concerns and depend on properties of the Vault implementation, the transport, and the deployment posture:¶
Constant-time response policies that pad to a deployment-defined minimum response latency.¶
Differential-privacy-style noise injection at the count- or histogram-aggregate level for queries known to be at risk of inference.¶
Authorization rules that refuse queries whose result-set size would itself disclose information (e.g., refusing queries that would return exactly zero or exactly one record).¶
Cursor formats that contain only opaque identifiers and no position information, sized identically across the cursor space.¶
These mitigations are deployment-level engineering choices, not Protocol-level mandates. The Protocol's position is that query- based inference is real and material, that the wire format does not defend against it, and that Consumers needing protection against these attack classes obtain it from the Vault implementation and the transport, not from the Protocol.¶
This subsection complements Section 9.1's "What the Protocol does not guarantee" list, where wire-level confidentiality, quasi- identifier protection, and unlinkability are also stated as non-guarantees. Query-based inference is the active counterpart of those static non-guarantees: a Consumer with access to the query surface has more inference power than a Consumer reading static records would have, and the Protocol does not constrain the query surface to remove that power.¶
The Protocol's proof-object vocabulary means that records served to a Consumer carry metadata about their provenance, the consents that authorize their access, and (where applicable) the audit log entries referencing the access. This is by design -- agents reasoning about trust need this metadata -- but it has privacy implications:¶
Proof objects increase the data footprint of each record on the
wire. A sygil.proof.consent proof carrying DPV categories and
legal basis reveals more about the access pattern than a record
served without provenance metadata.¶
Audit log URIs are themselves data. A sygil.proof.audit proof
with log_entry_uri reveals the existence and location of an audit
log entry; in some threat models this metadata is sensitive.¶
Implementations sensitive to these leaks MAY omit specific proof types from records served to less-trusted Consumers; doing so does not invalidate the records (proofs are optional). The trade-off is that Consumers cannot then verify the corresponding trust property.¶
Implementations producing records on behalf of a Subject SHOULD apply subject-protective defaults:¶
subject_scope defaults to sole (the most restrictive interpretation).¶
obsolete defaults to false (no soft-delete by default).¶
language[] defaults to empty (no language assertion until one is
needed).¶
derived_from[] defaults to empty (no derivation lineage until
one is asserted).¶
The defaults are conservative: a record produced with default values makes minimal claims, which limits the Consumer's exposure to overstated trust assertions.¶
The sygil.proof.consent proof's dpv_categories, purpose, and
legal_basis fields align to the W3C Data Privacy Vocabulary (DPV),
which provides standardized terms for consent records, processing
purposes, and legal bases under GDPR and equivalent frameworks. This
alignment is informative; the Protocol does not require the use of DPV
terms, but recommends them where applicable.¶
ISO/IEC TS 27560:2023 [ISO-27560] consent record information
structure is similarly aligned with DPV via the W3C DPV community
group's published implementation guidance. Implementations using
27560-shaped consent receipts as the substrate for
sygil.proof.consent proofs are encouraged to populate the DPV-aligned
fields for cross-system interoperability.¶
This document requests three IANA actions: the provisional registration
of the sygil URI scheme, the registration of the
application/sygil+json media type, and the establishment of a Sygil
Proof Object Types registry.¶
sygil URI scheme (provisional)
This document requests the provisional registration of the sygil URI
scheme per [RFC7595].¶
sygil¶
Provisional¶
The Sygil Protocol, an open schema and query grammar for cross-domain personal data, as specified in this document.¶
Evan Carr <evan@sygil.id>¶
Sygil PBC, until such time as a community-governed entity (e.g., a W3C Community Group, an IETF working group, or an independent foundation) assumes change control. Subsequent changes will be recorded in updates to this registration.¶
This document.¶
sygil-URI = "sygil://" subject-did "/" nsid "/" content-hash
subject-did = "did:" method-name ":" method-specific-id
; per [W3C-DID]
nsid = label *( "." label )
; reverse-DNS, per Section 4.3
content-hash = algorithm "-" 1*base64url-char
algorithm = "blake3"
; v1 uses BLAKE3; future major Protocol versions
; may register additional algorithms
base64url-char = ALPHA / DIGIT / "-" / "_"
; base64url alphabet per [RFC4648] Section 5,
; without padding (see Section 4.5.3)
¶
A sygil URI identifies a Sygil record by the cryptographic hash of
its canonical serialization. The URI is implementation-neutral; it
does not encode hostname, port, or path. Resolution to a record
representation is a separate concern handled by the carrier protocol
or by Vault implementations.¶
The URI is composed of US-ASCII characters. The DID component, NSID component, and content-hash component are all already restricted to US-ASCII per their respective specifications.¶
All v1 implementations of the Sygil Protocol use BLAKE3 as the
content-hash algorithm and JCS [RFC8785] as the canonicalization
rule. Implementations that produce or consume sygil URIs MUST
agree on these or interoperability fails.¶
See Section 8 of this document.¶
application/sygil+json media type
This document requests the registration of the
application/sygil+json media type per [RFC6838].¶
application¶
sygil+json¶
None.¶
None.¶
Binary; UTF-8 only. Records are serialized in canonical JSON per [RFC8785] (Section 4.5 of this document).¶
See Section 8 of this document.¶
Records labeled with this media type MUST validate against the
Sygil envelope specified in Section 4.2 and against the schema for
the namespace declared by the record's @type field. The canonical
serialization rules of Section 4.5 apply.¶
This document.¶
Implementations of the Sygil Protocol; storage systems handling Sygil records; Vault implementations; Consumer applications (including AI Agents).¶
None defined by this document.¶
None.¶
None.¶
.sygil, .sygil.json¶
None.¶
Evan Carr <evan@sygil.id>¶
Common.¶
None.¶
Evan Carr¶
Sygil PBC, until such time as a community-governed entity assumes change control.¶
This document requests the establishment of a new IANA registry named "Sygil Proof Object Types" per [RFC8126].¶
Sygil Proof Object Types¶
Identifiers for proof object types that may appear in the _proofs
array of a Sygil record (Section 5).¶
Designated experts are responsible for ensuring that:¶
The proposed @type value follows the reverse-DNS pattern (e.g.,
sygil.proof.{name} for proof types defined by the Sygil
specification, or {publisher.domain}.{name} for proof types
defined by other parties).¶
The @type value does not collide with an existing registration.¶
The proof object's intended semantics, field set, and verification procedure are documented in a published specification.¶
The registration includes a stable contact and change controller.¶
Experts SHOULD reject registrations whose @type value uses the
sygil.proof.* prefix unless the registration is made by the Sygil
specification's change controller.¶
Proof object type identifier (@type value).¶
Brief description of the proof's semantics.¶
Reference to the specification defining the proof object's field set and verification procedure.¶
Change controller (party responsible for future changes to the registration).¶
Contact information.¶
| @type | Reference | Change controller |
|---|---|---|
sygil.proof.provenance
|
Section 5.4 of this document | Sygil PBC |
sygil.proof.capability
|
Section 5.5 of this document | Sygil PBC |
sygil.proof.consent
|
Section 5.6 of this document | Sygil PBC |
sygil.proof.attestation
|
Section 5.7 of this document | Sygil PBC |
sygil.proof.audit
|
Section 5.8 of this document | Sygil PBC |
Once registered, a proof type's @type value, semantics, and field
set are immutable per the Protocol's compatibility policy (Section
6.5). Additional optional fields may be added in successor
registrations under a different @type (e.g.,
sygil.proof.provenance.v2); no in-place modification of an existing
proof type is permitted.¶
This document requests the establishment of a new IANA registry named "Sygil NSID Extension Publishers" per [RFC8126].¶
Sygil NSID Extension Publishers¶
Identifiers for publishers of records under the
sygil.community.{publisher}.* extension namespace (Section
4.2.5).¶
Expert Review (per [RFC8126] Section 4.5) for publisher identifiers not under controlled domains. Publisher identifiers identical to a domain controlled by the registrant MAY be registered without expert review, subject to verification of domain control by the change controller.¶
Designated experts are responsible for ensuring that:¶
The proposed publisher identifier follows the reverse-DNS label-dot-label grammar.¶
The publisher identifier does not collide with an existing registration.¶
The registrant has a credible affiliation with the namespace they propose to publish under (e.g., they control the domain, they operate the product, they are the maintainer of the open-source project).¶
The registration includes a stable contact and change controller.¶
Publisher identifier (the reverse-DNS-shaped value).¶
Brief description of the publisher and the records they
intend to publish under
sygil.community.{publisher}.*.¶
Change controller (party responsible for future changes to the registration).¶
Contact information.¶
(none -- the registry opens empty)¶
Publisher identifiers are immutable once registered. To change an identifier, register a new one and migrate; the old registration MAY be marked deprecated but MUST NOT be reassigned.¶
Initial version. Defines the Sygil protocol: the record envelope and content-addressed identifier scheme, the NSID namespace grammar, the v1 namespace ladder (10 production-depth, 2 minimal-shape, and 3 NSID-reserved data namespaces, plus infrastructure-reserved prefixes), the canonicalization and hash-input rules, the cooperation-mode and provenance vocabulary, the query and conformance model, and the privacy considerations including the sensitivity axis and the social-namespace intent posture.¶
The author thanks the contributors to the AT Protocol specification
for the Lexicon discipline that informs this document's NSID
immutability rule, the LinkML project for the schema-language tooling
that underlies the Sygil schema toolchain, and the W3C DPV community
group for the consent-receipt vocabulary that informs the
sygil.proof.consent proof object.¶
This document benefits from prior published work on Verifiable Credentials, Decentralized Identifiers, JSON Canonicalization, BLAKE3, and the OAuth 2.0 family of specifications. The composition framing of the Protocol -- runtime-neutral schema and query grammar over existing standards -- is informed by the Linux/distribution relationship in the open-source operating system community and by prior personal-data work in the Solid project, the MyData community, and the OpenPDS research lineage.¶
Errors of omission or commission in this document remain the author's.¶
The Sygil Protocol specification and the companion Schema document referenced in this Internet-Draft are the work of Sygil PBC Contributors to those specifications are acknowledged in the respective documents.¶