Skip to content

Technical

Welcome to the OpenHerd developer documentation. This guide is for implementers of the OpenHerd protocol — from lightweight clients and relays to full libp2p participants.


Post Envelope Format

Every post in OpenHerd is cryptographically signed and self-contained.

{
  "signature": "-----BEGIN PGP SIGNATURE-----...",
  "publicKey": "-----BEGIN PGP PUBLIC KEY BLOCK-----...",
  "id": "keyID",
  "data": "{\"id\":\"keyID\",\"text\":\"...\",\"latitude\":...,\"longitude\":...,\"date\":\"...\",\"parent\":\"...\"}"
}
  • signature: Detached OpenPGP signature of the data string.
  • publicKey: Public key used for verification and identity.
  • id: SHA-1 fingerprint of publicKey, used as the post ID.
  • data: Stringified JSON containing post content:

  • text: Message body

  • latitude / longitude: Randomized coordinates
  • date: ISO 8601 timestamp
  • parent: ID of parent post (optional)

Creating Posts

  • Every post uses a *new- PGP key.
  • Signatures verify that content wasn't altered.
  • Coordinates should be fuzzed before publishing for anonymity.
  • Gossipsub topic: posts

Threading

Posts are threaded via parent. Each post forms a chain back to a root.

Example:

null (root)
 ↳ 8558e99c...
     ↳ 6a63e1d0...

Catchup Requests

Topic: catchup Used by libp2p clients to pull historical messages.

Request:

{ "max": 200 } // Optional max (default 100)

Response: An array of envelope objects (see above), chunked if necessary, delivered on the backlog topic.


Chunking Protocol

All large messages sent over libp2p are broken into ordered chunks.

{
  "index": 0,
  "total": 6,
  "content": "up to 500 characters"
}

They are reassembled based on index, and all topics may include chunked messages.


HTTP Sync API (/_openherd)

For bridging libp2p and HTTP worlds.

/outbox (GET)

Returns local post history.

/inbox (POST)

Receives an array of envelopes. Validates & stores them.

[ { "signature": "...", "publicKey": "...", "id": "...", "data": "..." } ]

Responds with { "ok": true } or 400 Bad Request.

/sync (POST)

Initiates sync with an HTTP or libp2p peer.

{ "address": "http://node.example.com" }
  • If HTTP: Pulls from /outbox, pushes to /inbox.
  • If libp2p fails: tries fallback.

Relay Nodes

Non-interactive HTTP-only devices. Great for:

  • Hotspots & darknet drops
  • Raspberry Pi kiosks
  • Air-gapped or NAT-constrained deployments

They implement only:

  • /inbox (POST)
  • /outbox (GET)

Relays *don’t- use Gossipsub or libp2p.

mDNS Service Discovery (Optional)

  • Service type: _openherd._tcp
  • Allows Bonjour/zeroconf detection of nearby relays

Beacon Network

Allows relays to be discovered on the internet.

/beacon/update (POST)

Registers a relay with geolocation + metadata.

{
  "publicKey": "-----BEGIN PGP PUBLIC KEY BLOCK-----...",
  "message": "{\"lat\":\"33.5\",\"lng\":\"-84.2\",\"nickname\":\"peachtree-drop\",\"operator\":\"School of life\",\"ssid\":\"OpenHerd\",\"macAddress\":\"aa:bb:cc:dd:ee:ff\"}",
  "signature": "base64-signature",
  "nonce": 2379281
}
  • message is signed with the PGP private key
  • lat/lng: Coordinates (as strings)
  • ssid: Visible SSID (optional)
  • macAddress: Device MAC (optional)

Post Scriptum

  • All posts are per-message anonymous, as each key is one-time-use.
  • Data must be signed and verified client-side.
  • Clients should randomize GPS coordinates to \~100m for safety.
  • Beacon registration is optional and gated by proof-of-work.