This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

openletter / DESIGN.md
4.4 kB

openletter — design#

openletter is an ATProto-native petition system: anyone can write an open letter (a petition) and anyone can endorse or object to any number of them. openletter.pub is the lexicon (pub.openletter.*); openletter.vote is the AppView. See the README for the pitch.

Principles#

These fall out of ATProto's grain, and everything below follows from them:

  • Account-centric ownership. A petition lives in its author's repo; each endorsement, objection, and co-author attestation lives in that person's repo. Nobody's signature is held by a central service.
  • CID-pinned, so signatures are honest. Every signature references the petition by content hash, so you can always prove exactly what was signed — the property a centralized petition site can't offer.
  • Single-writer. A record is signed by one account. "Collaboration" is modeled as handshakes between repos, never shared writes.
  • The AppView interprets; it never owns or gatekeeps. openletter.vote aggregates records off the network and computes the views below. Counts are eventually-consistent, and the author can't truly prevent a signature — anyone can write an endorsement to their own repo.

Records — pub.openletter.*#

record lives in what it is
petition author an immutable open letter
draft author a mutable work-in-progress that publishes a petition
endorsement signer support for a petition
objection objector dissent against a petition
contribution co-author the attestation half of co-authorship

petitiontitle, markdown body (CommonMark, no raw HTML), recipients[] (each a name plus an optional ATProto identity and/or URL), createdAt, contributors[] (DIDs the author claims as co-authors), and optional summary / langs / tags / banner. Once published it is never edited (see Immutability).

draft — the same content fields, mutable and edited in place. Publishing creates a petition, so the petition collection only ever holds finished, signable letters. A draft lives on the PDS, so it is unlisted, not private.

endorsement / objection — a CID-pinned reference to a petition, createdAt, and a reason-for-signing comment (optional on an endorsement, required on an objection — dissent has to say why). The signer's DID is always on the record, so there is no "anonymous" signature. The record key is derived from the petition, so a signer holds at most one of each per petition and re-signing is idempotent. Holding both on the same petition is resolved in the AppView by recency.

contribution — published by a claimed co-author: a CID-pinned reference to the petition they affirm. A co-author is confirmed only where the author's contributors[] and the co-author's contribution agree — a two-sided handshake.

Immutability#

A published petition is never edited. Drafts are where a letter is worked out; once published it is frozen, and every signature is pinned to that exact text by CID. To change a published letter the author withdraws it (deletes the record, which tombstones it) and publishes a new one — which starts over with no signatures. This keeps the integrity story simple: you signed exactly this, and it can't change underneath you. Versioning and amendments are deferred (see below).

Tradeoffs we accept#

  • No privacy at the data layer. Repos are public: drafts are unlisted not secret, and an "unlisted" endorsement only hides a name in the UI.
  • No edits after publishing. Fixing even a typo means withdraw-and- republish, which resets signatures. Drafts make this rare; versioning is a later addition.
  • Meaning lives in convention + AppView. The lexicon stores records; the count and confirmation semantics are ours. Interop requires others to adopt pub.openletter, which is why the schemas are published (resolvable via _lexicon DNS).

Deferred past v1#

Petition versioning and amendments (editing a published letter while keeping its signatures; first-class amendments as their own endorsable records), comments/discussion, suggestion-based collaborative editing, signature goals, advisory close dates, structured target responses, and real-time co-editing. Each is a clean additive extension; none requires reworking the above.