Overview
Publishing in Seed Hypermedia means creating documents signed with your cryptographic key and making them available to others through the peer-to-peer network. Unlike traditional web publishing, there's no central server you upload to — your content propagates through the network of connected peers.
This guide covers the full publishing workflow: creating content, signing it, pushing to peers, and verifying availability.
Publishing Workflow
Every document change in SHM goes through these steps:
1. Create or edit content locally (via desktop app, CLI, or gRPC API)
2. Content is signed with your Ed25519 private key
3. Signed blobs are stored in your local daemon
4. Push to gateway peers to make content available on the web
5. Other peers discover and replicate your content
Creating Documents
Using the Desktop App
The Seed Hypermedia desktop app provides a visual editor for creating and editing documents. Open the app, create a new document, and start writing. Content is automatically saved and signed locally.
Using the gRPC API
For programmatic publishing (agents, scripts, CI/CD), use the CreateDocumentChange gRPC API:
grpcurl -plaintext -d '{
"signing_key_name": "mykey",
"account": "z6Mk...",
"path": "/my-document",
"changes": [
{"set_metadata": {"key": "name", "value": "My Document Title"}},
{"move_block": {"block_id": "b1", "parent": "", "left_sibling": ""}},
{"replace_block": {
"block_id": "b1",
"type": "Paragraph",
"text": "Hello, world!"
}}
]
}' localhost:55002 com.seed.documents.v3alpha.Documents/CreateDocumentChangeThe API requires a running daemon with your signing keys registered. Each change is atomically signed and stored.
Using ion-hm CLI
The ion-hm CLI provides a higher-level interface for publishing JSON documents:
# Validate JSON first
ion-hm validate json /tmp/my-doc.json
# Publish safely (validates, then publishes)
ion-hm publish-safe mykey /tmp/my-doc.json --url "hm://z6Mk.../my-path"
# Push to gateway
ion-hm push hm://z6Mk.../my-path --recursivePushing to Peers
Creating a document locally doesn't make it visible to the world. You must push it to gateway peers that serve content over HTTP. This is the most critical step — content that isn't pushed won't be accessible.
Push via gRPC
# Push to hyper.media (production gateway)
grpcurl -plaintext -d '{
"addrs": ["/p2p/12D3KooWEDdEeuY3oHCSKtn1eC7tU9qNWjF9bb8sCtHzpuCjvomQ"],
"resources": ["hm://z6Mk.../my-document"],
"recursive": true
}' localhost:55002 com.seed.documents.v3alpha.Resources/PushResourcesToPeerImportant gateway peer IDs:
• Production (hyper.media): 12D3KooWEDdEeuY3oHCSKtn1eC7tU9qNWjF9bb8sCtHzpuCjvomQ
• Testnet (dev.hyper.media): 12D3KooWMjs8x6ST53ZuXAegedQ4dJ2HYYQmFpw1puGpBZmLRCGB
Push via ion-hm CLI
# Push a single document
ion-hm push hm://z6Mk.../my-document
# Push recursively (includes all child documents)
ion-hm push hm://z6Mk.../my-document --recursiveVerifying Publication
After pushing, verify your content is accessible:
# Check via gateway HTTP
curl -s "https://hyper.media/hm/api/documents/z6Mk.../my-document" | jq .metadata.name
# Check via .md extension (if gateway supports it)
curl -s "https://your-gateway.com/my-document.md"Common issues if content isn't visible:
• Forgot to push — content stays local until explicitly pushed
• Gateway not synced — P2P gossip is slow, always push directly
• Wrong peer ID — double-check the gateway's peer ID
• Network issues — ensure your daemon has outbound connectivity
Document Metadata
Every document has metadata that controls how it appears:
• name — The document title (required)
• subtitle — Optional subtitle shown below the title
• icon — Emoji or icon for the document
• displayPublishTime — ISO timestamp shown as the publish date
# Set metadata via gRPC
{"set_metadata": {"key": "name", "value": "My Document"}}
{"set_metadata": {"key": "subtitle", "value": "A helpful guide"}}
{"set_metadata": {"key": "icon", "value": "📝"}}Updating Documents
To update an existing document, create a new change that references the current version:
grpcurl -plaintext -d '{
"signing_key_name": "mykey",
"account": "z6Mk...",
"path": "/my-document",
"base_version": "bafy2bz...",
"changes": [
{"replace_block": {
"block_id": "b1",
"type": "Paragraph",
"text": "Updated content!"
}}
]
}' localhost:55002 com.seed.documents.v3alpha.Documents/CreateDocumentChangeThe base_version field enables conflict detection. If someone else has edited the document since your base version, the daemon can detect and resolve conflicts using CRDTs.
Sharing with Others
Share your documents by providing the HM URL:
hm://z6MkvYf14wnNbjyxwV4rt9D6tNQ5fc8ZaUk4ucJn4mYLpCD6/my-documentOthers can view it through any gateway that has synced your content, or by adding it to their own daemon's subscriptions. The HM URL is permanent and cryptographically verifiable — no one can tamper with content signed by your key.
Best Practices
• Always validate content before publishing — use ion-hm validate to catch structural issues
• Always push after publishing — local documents are invisible to the world
• Use recursive push — ensures child documents and embeds are included
• Verify via HTTP — check your content is accessible from the gateway after pushing
• Push to multiple gateways — for redundancy, push to more than one gateway peer