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 thedata
string.publicKey
: Public key used for verification and identity.id
: SHA-1 fingerprint ofpublicKey
, used as the post ID.-
data
: Stringified JSON containing post content: -
text
: Message body latitude
/longitude
: Randomized coordinatesdate
: ISO 8601 timestampparent
: 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 keylat
/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.