LinkedClaims is a decentralized web-of-trust framework. Claims are signed assertions about URI-identified subjects that are themselves URI-addressable, forming a graph where claims can reference other claims.
The ecosystem is transport-agnostic. Claims can flow through HTTP APIs, ATProto (Bluesky), blockchain, W3C Verifiable Credentials, or any other mechanism. What matters is the structure, not how it gets there.
Subject (URI) <── Claim (has URI, is signed) <── Claim-about-Claim (has URI, is signed)
│ │ │
└─ any entity └─ creates Node + Edge └─ endorsement, dispute,
with a URI in the graph revocation, superseding
Nodes emerge from subjects, objects, and sources. Edges emerge from claims. The graph grows organically as attestations are added from any source.
The LinkedClaims specification defines what a valid claim looks like. It's published at the Decentralized Identity Foundation. This is the contract everyone follows.
TypeScript library in sdk/. Provides:
- Types —
Claim,CreateClaimInput,HowKnown, etc. - Validators —
validateClaim(),isValidUri()— enforce field rules - Normalizers —
starsToScore(),normalizeUri()— convert between formats - API Client —
LinkedClaimsclass for talking to any backend
Use this when building a web app or backend that creates/queries claims via HTTP.
TypeScript library at github.com/Cooperation-org/claim-atproto. Provides:
- Lexicon —
com.linkedclaims.claimrecord type - ClaimBuilder — fluent API for constructing valid claims
- ClaimClient — publish, query, delete claims on ATProto
- Helpers —
createEndorsement(),createDispute(),createRevocation() - Content hashing —
computeDigestMultibase()for source integrity
Use this when publishing claims to the ATProto network (Bluesky).
Node.js/Express/Prisma backend at github.com/Whats-Cookin/trust_claim_backend.
Live at live.linkedtrust.us.
This backend serves as an AppView — it aggregates claims from multiple sources:
- Claims created through the web UI
- Claims published via the REST API
- Claims from ATProto (via Jetstream firehose subscription)
- Claims from W3C VCs, blockchain, or other transports (via import)
Key services:
- ATProto Publisher — when a claim is created via the API, it's also published to
ATProto under the server's DID. The AT-URI is stored in
claimAddress. - ATProto Indexer — subscribes to the ATProto firehose, filters for
com.linkedclaims.claimrecords, and indexes ALL publishers (not just ours). - Graph Engine — builds Node/Edge graph from claims. Subjects, objects, and sources become nodes. Claims become edges.
React app at github.com/Whats-Cookin/trust_claim.
Live at live.linkedtrust.us.
Includes an ATProto feed view (/at route) and a <linked-claims-atproto> web component
for embedding ATProto claim feeds in any page.
- User creates claim in LinkedTrust web UI
- Backend stores claim in database
- Backend publishes to ATProto via Publisher service (non-blocking)
- AT-URI stored in
claim.claimAddress - Other ATProto AppViews can discover and index the claim
- Anyone publishes a
com.linkedclaims.claimrecord to their ATProto PDS - Jetstream firehose emits the event
- Backend Indexer picks it up, validates, creates Claim + Image rows
- Claim appears in the graph alongside web-created claims
claimAddress= the AT-URI,issuerId= the publisher's DID
- External app calls
POST /api/claimswith a valid claim body - Backend validates, stores, publishes to ATProto (same as Path A)
- Claim gets an AT-URI and participates in both ecosystems
- Read the Field Reference
- Build your own backend, use your own database
- Publish claims to ATProto using
@cooperation/claim-atproto - Other AppViews (including ours) can index your claims
- Or don't use ATProto at all — just follow the spec and use URIs
A claim's subject can be another claim's URI. This creates a graph of attestations:
Claim A: "Alice has skill React"
URI: at://did:plc:alice/com.linkedclaims.claim/abc
Claim B: "I endorse Claim A" (subject = Claim A's URI)
URI: at://did:plc:bob/com.linkedclaims.claim/def
Claim C: "I dispute Claim A" (subject = Claim A's URI)
URI: at://did:plc:carol/com.linkedclaims.claim/ghi
The @cooperation/claim-atproto SDK has helpers for this:
createEndorsement(claimUri, statement, options)— endorse another claimcreateDispute(claimUri, statement, options)— dispute another claimcreateSuperseding(claimUri, statement)— supersede/update another claimcreateRevocation(claimUri, reason)— revoke a claim
- You don't need our backend. The spec is open. Build your own.
- You don't need ATProto. Claims can be published and linked via any transport.
- You don't need our frontend. Build your own UI. Use the SDK or raw API calls.
- You don't need to ask permission. The spec is public, the SDK is MIT-licensed.
What you DO need: follow the Field Reference so claims are
interoperable. Use the field names as specified. Validate inputs. Don't invent new
howKnown values. If claims from your app are going to be indexed by other AppViews,
they need to be valid.