Marginalia

Spring '84 Specification

A compact draft specification for small, expressive, self-certifying web boards
May 14, 2026
Spring '84
Request For Friendly Critique And Comment
Draft 2026-03-30
Version 1

Spring '84 Specification

This document specifies Spring '84, a protocol for the exchange and display of small, expressive, self-certifying web boards.

Spring '84 builds on Robin Sloan's Spring '83. It inherits one board per person, no algorithms, no tracking, pull-only reading, and the rack metaphor, then adds the connective tissue required for boards to link, expire, move between servers, and still feel self-contained.

The working specification, validator, and implementation live in the Spring '84 repository.

1. Overview

Spring '84 has two roles: servers and clients.

A server accepts boards, validates them, stores them, and serves them. A server MUST NOT render boards.
A client fetches boards, verifies signatures, sanitizes content, and renders boards for a human. A client MUST NOT store authoritatively.

A board is a small HTML fragment signed with an Ed25519 key that encodes its own expiration date. One key publishes one board. A newer valid board replaces the old board for that key.

2. Keys

A Spring '84 identity is an Ed25519 keypair. The public key MUST be expressed as 64 lowercase hexadecimal characters.

The final seven characters MUST match 84eMMYY, where 84e identifies the protocol family, MM is the expiration month, and YY is the expiration year.

0000c3c690ca08fd6f071cfd6fb587efc10c9d5a81f1c7ce7c901066b84e1126

A key is valid for exactly two years preceding its expiration date. A key ending in 84e0328 becomes valid on April 1, 2026 and expires at 23:59:59 UTC on March 31, 2028.

Servers MUST reject boards signed with keys that are not yet valid or have expired.

There is no built-in succession mechanism. If continuity is desired, the publisher must generate a new key before the old one expires and use linked keys during the overlap period.

3. Boards

A board is an HTML fragment. It MUST NOT include a doctype, <html>, <head>, or a full document wrapper.

Every board MUST contain exactly one UTC ISO 8601 time element.
<time datetime="2026-03-30T14:22:00Z">March 30, 2026</time>
The board body MUST NOT exceed 19,840 bytes.

Allowed Elements

<div>, <span>, <p>, <br>, <h1> ... <h6>, <em>, <strong>,
<a>, <img>, <ul>, <ol>, <li>, <blockquote>, <pre>, <code>,
<style>, <hr>, <figure>, <figcaption>, <section>, <article>,
<header>, <footer>, <time>, <mark>, <del>, <ins>, <sub>, <sup>,
<details>, <summary>, <spring-84-link>

Allowed Attributes

  • -class, id, style, title, lang, and dir on any allowed element.
  • -href on <a>, constrained to the spring84:// scheme.
  • -src, alt, width, and height on <img>. Image sources MUST be data URIs.
  • -datetime on <time>.
  • -key and sig on <spring-84-link>.
CSS MUST NOT include @import, url(), or expression().
Images MUST be embedded as data URIs. SVG is forbidden.

Embedded images MUST contain pixel data only. Servers MUST reject EXIF, XMP, IPTC, PNG text chunks, GIF application extensions, WebP metadata chunks, and other non-rendering metadata.

A board expires 60 days after its timestamp. Servers MUST NOT serve expired boards. Clients MUST NOT render expired boards.

4. Wire Protocol

Spring '84 uses three HTTP endpoints.

4.1 Publishing

PUT /board/<key> HTTP/1.1
Spring-84-Version: 1
Spring-84-Signature: <hex-encoded Ed25519 signature>
Content-Type: text/html;charset=utf-8

<board HTML>

The key in the URL is the publisher's public key. The signature header contains an Ed25519 signature over the exact request body.

CheckRequirementFailure
Key formatKey matches 84eMMYY.403 Forbidden
Key expirationKey has not expired.403 Forbidden
Key validityKey is inside its two-year validity window.403 Forbidden
SignatureSignature verifies for this key and exact body.401 Unauthorized
Body sizeBody is at most 19,840 bytes.413 Content Too Large
Time elementBody contains exactly one parseable UTC time element.400 Bad Request
Future timestampTimestamp is no more than five minutes in the future.400 Bad Request
MonotonicityTimestamp is not older than the stored board for this key.409 Conflict
Board ageBoard is not older than 60 days.400 Bad Request
Board safetyHTML, CSS, links, attributes, and embedded images are allowed.400 Bad Request

If all checks pass, the server stores the board and responds with 200 OK. The timestamp check provides monotonic freshness and replay protection.

4.2 Retrieving

GET /board/<key> HTTP/1.1

HTTP/1.1 200 OK
Spring-84-Signature: <hex-encoded Ed25519 signature>
Content-Type: text/html;charset=utf-8
Last-Modified: Sun, 30 Mar 2026 14:22:00 GMT

<board HTML>
Clients MUST verify the signature before rendering. If verification fails, the board MUST be discarded.

Servers MUST support conditional requests with If-Modified-Since and return 304 Not Modified when the stored board is not newer.

Missing and expired boards both return 404 Not Found.

4.3 Listing

GET /keys?limit=100&after=<cursor> HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json
Spring-84-More: true

["ab12cd34...ef56", "cd56ef78...1234"]

GET /keys returns 64-character public keys with non-expired boards in lexicographic order. limit defaults to 100 and MUST NOT exceed 1000. after is the last key from the previous page.

5. Multi-Server Architecture

Spring '84 assumes multiple independent servers. There is no central server, canonical instance, relay-to-relay synchronization, or authoritative host for a key.

  • -Publishers MAY push the same signed board to multiple servers.
  • -Clients MAY pull from multiple servers and use the newest valid board for a key.
  • -Servers MAY aggregate boards from other servers. A board remains valid regardless of where it was retrieved from.

6. Board URIs

spring84://<key>
spring84://<key>?relay=boards.example.com

The optional relay query parameter is a discovery hint. Clients MAY use it, MAY ignore it, and MUST NOT treat it as authoritative.

7. Linked Keys

A link is active only when both boards contain reciprocal declarations, both signatures verify, and both keys are within their valid period.

<spring-84-link key="<key_b_hex>" sig="<key_b_signature>" />

The signature is over the canonical link string:

LINK:<lower_key>:<higher_key>
Clients MUST NOT render spring-84-link elements. They are metadata.

Servers do not parse, validate, or act on linked-key declarations beyond normal HTML allowlist validation.

8. Client Security

A board, once rendered, cannot phone home, execute code, or reach beyond its own rectangle.
  • -Render boards with CSP: default-src 'none'; style-src 'unsafe-inline'; img-src data:;
  • -Render boards in a sandboxed iframe or equivalent isolation mechanism with no permissions granted.
  • -Verify Spring-84-Signature against the board body and URL key before rendering.
  • -Independently sanitize HTML before rendering, even if the server already validated it.
  • -Resolve spring84:// links inside the client.

9. Server Recommendations

The following are MAY-level policies, not conformance requirements.

  • -Servers MAY impose extra proof-of-work requirements.
  • -Servers MAY limit how frequently a key can update its board.
  • -Servers MAY delete expired boards from storage, provided expired boards are not served.
  • -Servers MAY refuse boards for any local policy reason.
  • -Servers MAY maintain allowlists and reject all other keys.
  • -Servers MAY use mutual linked-key declarations as introductions for allowlist expansion.

10. Conformance

A Spring '84 conformance suite should include:

  • -Valid boards covering the full allowed HTML and CSS surface.
  • -Invalid boards exercising every rejection condition.
  • -Signature verification test vectors.
  • -Key format validation test vectors.
  • -Expiration and timestamp edge cases.
  • -Linked-key verification scenarios.
An implementation that passes the full suite may claim Spring '84 conformance.

The current validator and implementation work is maintained in the Spring '84 GitHub repository.

11. Versioning

The current Spring '84 version is 1. Publishers MUST include a Spring-84-Version header. Servers MUST reject unsupported versions with 400 Bad Request.

The version number increments only for validation-affecting changes: new allowed elements, new required checks, or wire-format changes.

12. References