{
  "language": "en",
  "alternates": {
    "fr": "https://test.each.app/surface/publications/v0.json",
    "en": "https://test.each.app/en/surface/publications/v0.json",
    "markdown_fr": "https://test.each.app/surface/publications/v0.md",
    "markdown_en": "https://test.each.app/en/surface/publications/v0.md"
  },
  "module": "publications",
  "version": "v0",
  "status": "draft",
  "updated": "2026-10-30",
  "name": "Publications module",
  "summary": "The Publications module lets anyone publish a text on Each. Every publication is versioned: an edit creates a new immutable version, older ones stay readable. Every version carries a signed proof of its content (SHA-256 hash).",
  "object": [
    {
      "id": "id",
      "text": "Stable publication id (pub_...)."
    },
    {
      "id": "path",
      "text": "Reading address: /p/{author}/{slug}."
    },
    {
      "id": "author",
      "text": "Author name, as the author gives it."
    },
    {
      "id": "title",
      "text": "Title."
    },
    {
      "id": "version",
      "text": "Version number (1, 2, 3...). Never rewritten."
    },
    {
      "id": "format",
      "text": "\"markdown\" or \"html\" (sanitized HTML: p, br, em, strong, h2, h3, blockquote, ul, ol, li, a)."
    },
    {
      "id": "content",
      "text": "Exact content, as published. Each never corrects it."
    },
    {
      "id": "themes",
      "text": "Themes (list of words)."
    },
    {
      "id": "license",
      "text": "License given by the author. Without one: \"not specified — all rights reserved by the author\"."
    },
    {
      "id": "content_sha256",
      "text": "SHA-256 hash (hex) of the UTF-8 bytes of the content."
    },
    {
      "id": "proof",
      "text": "Signed each.publication proof for this version."
    }
  ],
  "core": "The Each core cannot be modified by a module. Every write (create a publication, add a version) requires either a passkey confirmation or a capability token carrying the publications:write scope. The core checks one or the other before writing, and signs the proof. Versions are append-only: no edit, no delete.",
  "scopes": [
    {
      "id": "publications:read",
      "text": "Read publications and their versions (public, no token)."
    },
    {
      "id": "publications:write",
      "text": "Create a publication or add a version, on behalf of the person who created the token."
    }
  ],
  "capability_tokens": "A capability token is created with your passkey (POST /v1/capabilities). It is shown once, Each keeps only its hash. It expires after 30 days. Send it in the Authorization: Bearer each_cap_... header.",
  "proof": {
    "type": "each.publication",
    "fr": "Chaque version produit une preuve signée (ES256, clé publique: /.well-known/each-keys), vérifiable sur /verifier/{id}. La preuve dit qui l'a signée: la clé d'accès de l'auteur, un jeton de capacité, ou l'équipe Each pour une publication test.",
    "en": "Every version produces a signed proof (ES256, public key: /.well-known/each-keys), verifiable at /verifier/{id}. The proof says who signed it: the author's passkey, a capability token, or the Each team for a test publication.",
    "fields": [
      "v",
      "type",
      "id",
      "issuer",
      "environment",
      "issued_at",
      "publication.id",
      "publication.path",
      "publication.version",
      "publication.title",
      "publication.author",
      "publication.format",
      "publication.license",
      "publication.content_sha256",
      "publication.previous_sha256",
      "signed_by",
      "signed_by_author",
      "note",
      "statement"
    ]
  },
  "api": [
    "GET /v1/publications",
    "GET /v1/publications/{id}",
    "GET /v1/publications/{id}/versions",
    "GET /v1/publications/{id}/versions/{n}",
    "POST /v1/publications/options",
    "POST /v1/publications",
    "POST /v1/publications/{id}/versions",
    "POST /v1/capabilities/options",
    "POST /v1/capabilities"
  ],
  "cors": "GETs on /v1/publications are open to every origin (Access-Control-Allow-Origin: *), so an external reader can display the texts.",
  "reader": "A copyable example reader: examples/publication-reader/ (one file, one config, one README).",
  "versioning": "Contract version: v0 = draft. A breaking change creates v1 at a new address; v0 stays readable. To propose a change: copy src/modules/publications/, edit contract.json, open a review.",
  "open_questions": [
    {
      "text": "Who may publish on an author's behalf (relative, publisher), and how does the author take over a test publication?"
    },
    {
      "text": "Default licenses offered (all rights reserved, open licenses) and how to show them."
    },
    {
      "text": "Withdrawal: a version stays readable forever; should there be a public withdrawal (hide without erasing the proof)?"
    },
    {
      "text": "Translations: is a translation a version or a linked publication?"
    }
  ]
}