DFOS Content Model

Standard content schemas for documents committed to DFOS content chains. JSON Schema (draft 2020-12) definitions for content objects committed by CID.

The protocol commits to content by hash — it never inspects what's inside. Any valid JSON object with a $schema field can be committed. These schemas define the vocabulary DFOS uses internally and serve as the starting vocabulary for applications built on the protocol.

Protocol Specification · schemas.dfos.com · Source


Schema Convention

Content objects are committed directly to a content chain by CID. The CID is derived from the canonical dag-cbor encoding of the content object itself:

documentCID = CID(dagCborCanonicalEncode(contentObject))

The protocol requires one thing of the content object: it must include a $schema property identifying its content type.

{
  "$schema": "https://schemas.dfos.com/post/v1",
  "format": "short-post",
  "body": "Hello world."
}

Because $schema is part of the content object, it is behind the documentCID — cryptographically committed in the content chain. Any verifier can resolve the document, read $schema, and validate against the schema. Documents are self-describing.


Schema Evolution

Schemas are versioned via the URI path (/post/v1, /post/v2). Evolution rules:


Standard Schemas

Schema files live in schemas/ in the protocol package. Each is a standalone JSON Schema (draft 2020-12) definition, served at https://schemas.dfos.com.

Post (https://schemas.dfos.com/post/v1)

The primary content type. Covers short posts, long-form posts, comments, and replies via the format discriminator.

Field Type Required Description
$schema string yes "https://schemas.dfos.com/post/v1"
format enum yes "short-post", "long-post", "comment", "reply" — immutable, set at creation
title string no Post title (typically for long-post format)
body string no Post body content
cover media no Cover image
attachments media[] no Attached media objects
topics string[] no Topic names (stored as names for portability)
createdByDID string no DID of the content author — distinct from the chain operation signer

createdByDID is a content-layer authorship convention, distinct from the operation signer. The kid DID in the JWS header identifies who cryptographically signed the operation — this is the protocol-level signer with key authority. createdByDID records who authored the content at the application layer. These often differ: an agent, bot, or delegate may sign the operation on behalf of a human author. The protocol verifies the signer; applications display createdByDID.

Profile (https://schemas.dfos.com/profile/v1)

The displayable identity for any agent, person, group, or space.

Field Type Required Description
$schema string yes "https://schemas.dfos.com/profile/v1"
name string no Display name
description string no Short bio or description
avatar media no Avatar image
banner media no Banner image
background media no Background image
createdByDID string no DID of the identity subject

Manifest (https://schemas.dfos.com/manifest/v1)

A semantic index mapping path-like labels to protocol object references. The navigation layer for a DID's content.

Field Type Required Description
$schema string yes "https://schemas.dfos.com/manifest/v1"
entries object yes Map of path-like keys to protocol object references

Entry keys: lowercase alphanumeric with dots, underscores, hyphens, forward slashes. 2–128 chars. Must start and end with alphanumeric. Examples: profile, posts, drafts/post-1, v1.0/release-notes.

Entry values are protocol object references, self-describing by format:

{
  "$schema": "https://schemas.dfos.com/manifest/v1",
  "entries": {
    "profile": "67t27rzc83v7c22n9t6z7c",
    "posts": "a4b8c2d3e5f6g7h8i9j0k1",
    "dark-publisher": "did:dfos:e3vvtck42d4eacdnzvtrn6",
    "pinned-charter": "bafyreibanjpgcqffcfhr4sptzjfthh5szohhbo5tjfulemkw7uhden5uqy"
  }
}

Manifests are content chains — same signing, same verification, same CIDs. A manifest's contentId appears in the DID's content set like any other chain. The semantic index (the document) is dark forest content — requires authorization to read. The operation chain (proof substrate) is public.

Media Object

Several schemas reference media objects. The standard representation:

{
  "id": "media_abc123",
  "uri": "https://cdn.example.com/media/abc123.jpg"
}

id is required (opaque identifier). uri is optional.


Chain Interpretation

A content chain is a signed append-only log. The protocol enforces ordering, authorship, and integrity. It does not prescribe what the chain means. How an application interprets a content chain depends on the content types committed to it.

Living Document

The chain represents a single evolving thing — a profile, a post, a policy document. Each operation is a revision. The resolved state is the latest documentCID. History is audit trail. The content is the current version.

This is the default interpretation for the standard schemas. Edit lineage is tracked via baseDocumentCID on the content operation payload — each new operation can reference the document CID it replaced.

Stream

The chain represents a sequence — a feed, a journal, a log. Each operation is a discrete emission, not a revision. There is no single "current state" — the chain is the content. Previous documents aren't superseded, they're siblings in a series.

A stream chain accumulates documents over time. The resolved content is the full ordered list of documents, not just the head. Applications read streams by walking the chain log and collecting each operation's documentCID.

Event Fold

The chain represents a sequence of events that fold into a computed state. Each operation contributes a delta or event. The resolved state is the result of replaying all events in order — similar to event sourcing. The $schema of the documents defines the event types and fold semantics.

Unlike a living document (where the head document is the state) or a stream (where all documents are siblings), an event fold requires interpretation logic specific to the schema. The chain log is the source of truth; the projected state is derived.

Projection Rules per Schema

Each schema implies a default projection — how applications derive resolved state from the chain:

Schema Projection
post/v1 Living document — head documentCID is the current post. History is edit trail
profile/v1 Living document — head documentCID is the current profile
manifest/v1 Living document — head documentCID is the current manifest index

Stream and event fold schemas define their own projection rules in their schema documentation. The protocol does not enforce projections — these are reading conventions that applications agree on.

Intra-Chain References (targetOperationCID)

Content documents may reference specific operations within their own chain or other chains via targetOperationCID. This is a content-layer convention — the protocol does not validate or enforce it.

Use cases for targetOperationCID:

targetOperationCID is a content field (inside the document committed by CID), not an operation field. The protocol commits to it via documentCID but does not interpret it. Applications resolve the reference by looking up the target operation on the relay.


Reference Content Stream Schema

The content stream is the canonical example of the stream interpretation pattern. A stream chain accumulates discrete entries — each operation appends a new document to the sequence rather than replacing the previous one.

Content Stream (https://schemas.dfos.com/content-stream/v1)

A stream entry document. Each document in a content stream chain is a standalone entry in the sequence.

Field Type Required Description
$schema string yes "https://schemas.dfos.com/content-stream/v1"
body string no Entry body content
attachments media[] no Attached media objects
targetOperationCID string no CID of an operation this entry references (reply, annotation, etc.)
createdByDID string no DID of the content author (distinct from the operation signer)
{
  "$schema": "https://schemas.dfos.com/content-stream/v1",
  "body": "This is a stream entry.",
  "createdByDID": "did:dfos:e3vvtck42d4eacdnzvtrn6"
}

Content stream chains use the stream interpretation — the resolved content is the full ordered list of documents, not just the head. Applications read content streams by walking the chain log and collecting each operation's documentCID.


Custom Schemas

Any implementation can define custom document schemas following the same pattern — a JSON Schema with a $schema const field pointing to a unique URI. The protocol will commit to the document via CID regardless of what's inside. The standard schemas are conventions, not constraints.

Custom schema URIs should use a namespace you control (e.g., https://schemas.example.com/my-type/v1) to avoid collisions with the standard library.