Skip to main content

Social

A decentralized content distribution network built on Mehr primitives. No central servers, no algorithmic recommendations, no ads. Authors pay to publish — skin in the game. Readers pay bandwidth to access — infrastructure sustains itself. Popular content self-funds and propagates wider. Unpopular content expires. Economics replaces algorithms.

While "social" implies short text posts, the same architecture handles any content type: music albums, scientific papers, video courses, games, software, journalism, podcasts — anything that can be stored as a DataObject. The envelope/post split, kickback economics, and propagation rules are content-agnostic.

Content TypeEnvelope ShowsPaid ContentTypical Kickback
Text postFull text (under 280 chars)Full text + linksLow (cheap to read)
Photo essaySummary + blurhash thumbnailsFull-resolution imagesModerate
Music albumTrack listing + artist + durationAudio filesHigh (large files)
Video courseLesson titles + descriptionsVideo filesHigh
Scientific paperTitle + abstract + authorsFull PDFModerate
Game / softwareName + description + screenshotsBinary + assetsHigh
Podcast episodeTitle + show notesAudio fileModerate
Curated collectionCurator notes per itemReferences to originalsCurator earns on collection; authors earn on items

Architecture

Every publication on Mehr has two layers: a free envelope that propagates everywhere (browsable at zero cost), and paid content that requires retrieval fees. Users browse envelopes to decide what's worth accessing, then pay only for content they actually want.

PostEnvelope (Free Layer)

The envelope is a lightweight, separate DataObject that propagates freely across the mesh. It contains everything a reader needs to decide whether to fetch the full post:

PostEnvelope {
post_hash: Option<Blake3Hash>, // hash of the full SocialPost (None for boost-only envelopes)
author: NodeID,
headline: Option<String>, // title (~100 chars, author-set)
summary: Option<String>, // author-written preview (None for boosts — use the original's)
media_hints: Vec<MediaHint>, // lightweight descriptions of attachments
scopes: Vec<HierarchicalScope>, // geographic + interest tags
reply_to: Option<Blake3Hash>, // parent post hash (threading)
boost_of: Option<Blake3Hash>, // boosted/reposted content hash
references: Vec<Blake3Hash>, // related posts (bidirectional content graph)
content_size: u32, // full post size in bytes (0 for boost-only)
created: Timestamp,
kickback_rate: u8, // author's desired share of retrieval fees (0-255)
signature: Ed25519Sig, // signed by author (proves authenticity)
}

MediaHint {
content_type: String, // "image/jpeg", "video/mp4", etc.
size: u32, // bytes
blurhash: Option<String>, // visual placeholder (~30 bytes)
alt_text: Option<String>, // accessibility description
}

Envelope size: ~300–500 bytes. Fits in a single LoRa frame with min_bandwidth: 0. A reader on a LoRa-only node can browse headlines, summaries, and blurhash thumbnails without paying anything.

SocialPost (Paid Layer)

The full post is an immutable DataObject containing the actual content. Fetching it costs retrieval fees:

SocialPost {
author: NodeID,
content: PostContent {
text: Option<String>, // full post body (UTF-8)
media: Vec<Blake3Hash>, // references to media DataObjects
links: Vec<String>, // external URLs (for internet-connected nodes)
},
signature: Ed25519Sig,
}

The SocialPost itself is lean — scopes, timestamps, and metadata live on the envelope. The post contains only the content that costs money to retrieve. There is no back-reference from post to envelope; the envelope's post_hash is the only link between them. Going from post to envelope (if ever needed) is a DHT lookup for envelopes containing a given post_hash.

Profile

A mutable DataObject containing identity information:

UserProfile {
node_id: NodeID,
display_name: String,
bio: Option<String>,
avatar: Option<Blake3Hash>, // reference to image DataObject
scopes: Vec<HierarchicalScope>, // from TrustConfig
claims: Vec<Blake3Hash>, // references to IdentityClaims
sequence: u64, // monotonic version counter
signature: Ed25519Sig,
}

Feed Types

Mehr social supports five feed types. All feeds are assembled locally — no server decides what you see.

1. Direct Follow Feed

Follow specific users. Unchanged from the basic MHR-Pub model.

// Follow Alice — see everything she posts
subscribe(Node(alice_node_id), Push);

This is the foundation. You follow people you trust, and you see their posts in reverse-chronological order.

2. Geographic Feed

Subscribe to content from a geographic area at any level of the scope hierarchy:

// Everything from my neighborhood
subscribe(Scope(Geo("north-america", "us", "oregon", "portland", "hawthorne"), Exact), Push);

// Everything from Portland (all neighborhoods)
subscribe(Scope(Geo("north-america", "us", "oregon", "portland"), Prefix), Digest);

// Everything from Oregon
subscribe(Scope(Geo("north-america", "us", "oregon"), Prefix), PullHint);

Geographic feeds are the local newspaper — events, news, discussions relevant to where you physically are. Content is cheapest and fastest at the neighborhood level, progressively more expensive at higher scopes.

3. Interest Feed

Subscribe to content by topic, independent of geography:

// All Pokemon content globally
subscribe(Scope(Topic("gaming", "pokemon"), Prefix), Digest);

// Only competitive Pokemon
subscribe(Scope(Topic("gaming", "pokemon", "competitive"), Exact), Push);

// All science content
subscribe(Scope(Topic("science"), Prefix), PullHint);

Interest feeds are sparse — they connect people across geography. A Pokemon feed connects Portland, Tokyo, and Berlin. Content propagates through interest relay nodes that bridge geographic clusters, but only after local validation — the author's local community must engage with the content (boost, retrieve, or curate) before interest relays forward it globally.

4. Intersection Feed

Combine geographic and interest scopes client-side:

// Subscribe to Portland AND Pokemon
subscribe(Scope(Geo("...", "portland"), Exact), Push);
subscribe(Scope(Topic("gaming", "pokemon"), Prefix), Push);

// Client-side: show only posts that appear in BOTH feeds
// Result: Portland Pokemon community

The protocol delivers by individual scope. The application composes intersection feeds locally by filtering posts that match multiple subscriptions. This keeps the protocol simple while enabling powerful queries.

5. Curated Feed

Follow a curator — a human who selects the best content from a broader scope:

CuratedFeed {
curator: NodeID,
name: String, // "Portland's Best", "Quantum Physics Weekly"
description: String,
entries: Vec<CuratedEntry>, // max 256 entries per feed page
scope: HierarchicalScope, // what this feed covers
updated: Timestamp,
sequence: u64, // monotonic version counter
kickback_rate: u8, // curator's share of retrieval fees
signature: Ed25519Sig,
}

CuratedEntry {
post_hash: Blake3Hash, // reference to original post
added: Timestamp,
note: Option<String>, // curator's commentary
}

A single CuratedFeed holds at most 256 entries. For larger archives, the curator publishes multiple feed pages as separate DataObjects, each covering a time period or sub-topic. This keeps individual feed objects small enough for constrained devices to fetch and parse.

How curation works:

  1. Alice follows 200 people and reads the Portland geographic feed daily
  2. She publishes a CuratedFeed selecting the best posts — "Portland Daily Digest"
  3. Bob subscribes to Alice's curated feed instead of following 200 people
  4. Bob fetches the CuratedFeed DataObject — Alice earns kickback on it (the curation list has its own kickback_rate)
  5. Bob's client fetches the PostEnvelopes for each curated entry — free, showing headlines + summaries + Alice's curator notes
  6. Bob taps posts that interest him — fetches the full SocialPost, and the original author earns kickback (the post has its own kickback_rate)

These are two independent kickback flows on two different DataObjects — the curator's rate and the author's rate don't interact. Bob pays once per DataObject he retrieves, and each DataObject's kickback goes to its respective creator.

The browsing experience: Bob sees Alice's curator notes ("Must-read thread on the new bike lanes") alongside each post's envelope (headline, summary, blurhash). He can scroll the entire curated feed for nearly free — only paying when he opens a full post. This makes curated feeds the most bandwidth-efficient way to discover content.

The curation hierarchy:

Producers (authors)
│ create content, earn kickback from readers

Curators (human editors)
│ select best content, earn from subscribers

Meta-curators (curators of curators)
│ select best curators, earn from subscribers

Readers
pay bandwidth, choose what to subscribe to

Every level has skin in the game:

  • Producers pay to post (anti-spam)
  • Curators pay to store their curated feed (anti-spam for curation)
  • Readers pay bandwidth (infrastructure sustains itself)
  • Kickback flows backward at every level

Publishing Flow

When an author creates a post, two DataObjects are published:

1. Author writes post content + sets headline/summary
2. Client generates SocialPost (paid layer) first:
→ hashed to produce post_hash
→ stored as DataObject with normal storage agreement
→ only fetched when a reader requests the full content
3. Client generates PostEnvelope (free layer) using post_hash:
→ stored as DataObject with min_bandwidth: 0
→ propagates via MHR-Pub to scope subscribers
→ no storage agreement needed within trust network

The SocialPost is created and hashed first so the envelope can reference it via post_hash. The envelope costs almost nothing to store and propagate (under 500 bytes). The full post costs proportional to its size. Authors pay for content storage, not for letting people know the content exists.

Content Economics

Browse Before You Pay

Envelopes propagate freely through MHR-Pub notifications. Readers browse without spending:

Reader's feed experience:
1. Receive PostEnvelopes via MHR-Pub subscription (free)
2. Browse headlines, summaries, blurhash thumbnails (free)
3. See content_size and estimated retrieval cost (free)
4. Tap to fetch full SocialPost + media (paid)

LoRa-only node:
→ Sees all envelopes (text headlines + blurhash)
→ Cannot fetch large media (min_bandwidth too low)
→ Can still fetch text-only posts (small enough for LoRa)

WiFi node:
→ Sees all envelopes
→ Fetches full posts + images on demand
→ Fetches video only on high-bandwidth links

This solves the "pay before you know what you're getting" problem. The envelope is the shopfront window; the full post is what you pay for inside.

Author Pays to Post

Every post is a DataObject that requires a storage agreement. Posting costs money:

Cost to post (neighborhood scope):
Text-only (~200 bytes): ~1-5 μMHR per epoch
With image (~50 KB): ~50-100 μMHR per epoch
With video (~5 MB): ~500-1000 μMHR per epoch

Within trust network: free (no agreement, no payment)

This is the anti-spam mechanism. Every post costs tokens. Spam is economically irrational because you're paying for content nobody will read. No ML moderation needed — posting costs money, and money is limited.

Readers Pay for Bandwidth

When someone outside your trust network retrieves your post, they pay relay fees:

Reader cost:
Within trust network: free
Cross-trust retrieval: ~5 μMHR per packet per hop
Typical 5-hop path: ~25 μMHR per retrieval

Total reader cost for a text post: ~25-75 μMHR
Total reader cost for an image post: ~250-750 μMHR

Kickback to Author

When readers pay to retrieve content, a portion flows back to the author via the kickback mechanism:

Reader pays 100 μMHR to storage node
→ Storage node keeps (255 - kickback_rate) / 255 of retrieval fee
→ Storage node forwards kickback_rate / 255 to author

At default kickback_rate of 128 (~50%):
→ Storage node keeps ~50 μMHR
→ Author receives ~50 μMHR

Self-Funding Content

Popular content earns more kickback than it costs to store. It becomes self-sustaining and propagates upward through the scope hierarchy automatically:

PopularityScopeFunding Model
UnreadNeighborhoodAuthor pays entirely
Local interestCityKickback offsets some storage cost
Regional hitRegionKickback exceeds storage cost (self-funding)
ViralCountry/GlobalSelf-funding at all levels

Content that nobody reads expires when the author stops paying. Content that everyone reads lives forever, funded by its own readership. No platform decides — economics decides.

Why No Likes or Upvotes

Mehr has no reactions, likes, upvotes, or downvotes. This is deliberate.

The problem with reactions: Any free reaction can be Sybil-farmed (create 50 accounts, like your own post 50 times). Any paid reaction where the money returns to the sender can be self-tipped in a loop (post → tip own post → kickback returns the tip). Even burn-to-signal (destroy tokens to upvote) creates a vanity metric that people optimize for — the same engagement treadmill that centralized platforms run on.

Mehr's quality signals are economic, not social:

SignalWhat It MeansSybil-Resistant?
Retrieval countReal people paid real tokens to read thisYes — each retrieval costs the reader relay fees that don't return to the author
Self-funding thresholdKickback exceeds storage cost — readership sustains the contentYes — requires many distinct paying readers
Scope promotionContent bubbled up from neighborhood to city/regionYes — driven by retrieval demand from geographically distributed nodes
Curator inclusionA human with skin in the game selected this as worth readingYes — curator's reputation is on the line
Boost countMultiple people amplified this to their followersPartially — boosts are free envelopes, but boosting Sybil content wastes your followers' attention

An author self-retrieving their own post pays relay fees that don't come back via kickback (the storage node keeps its share, and the author is both payer and kickback recipient — net loss). A Sybil cluster retrieving each other's posts bleeds tokens on relay fees with no external demand to sustain it. The economics make fake popularity expensive.

What readers see instead of like counts: retrieval-driven propagation scope (neighborhood → city → region tells you how widely read something is), curator endorsements, and boost count from people in their trust graph.

Clickbait Resistance

The envelope's headline and summary are author-written and free-form. An author can write a misleading preview. The protocol does not attempt to enforce summary accuracy — there is no way to mechanically verify that a summary "fairly represents" an image, video, or audio post. Instead, clickbait is handled by the same economic and social systems that handle everything else:

Why clickbait is less profitable on Mehr than on ad-supported platforms:

Ad-Supported PlatformMehr
Cost to postFreeAuthor pays storage
Revenue modelInfinite recurring ad impressionsOne-time retrieval fee per reader
AmplificationAlgorithm promotes high-engagement contentNo algorithm — only boosts and curators
Second waveAlgorithm keeps serving it to new victimsZero boosts + zero curation = no second wave
Reader costFree (attention only)μMHR per retrieval — small but nonzero

Defense layers:

  1. Local-first propagation — Content doesn't spread globally on publication. Geographic content starts at neighborhood scope and promotes upward only when retrieval demand justifies it. Interest content starts in the author's local cluster and only propagates to distant clusters when locally validated — at least one boost, multiple distinct retrievals, or curator inclusion. A garbage post tagged with a popular topic never leaves the author's neighborhood because nobody locally endorses it.

  2. Curators are the quality filter — Raw geographic and interest feeds are unfiltered. Curated feeds are human-verified. For expensive content (video, large media), readers naturally prefer curator-endorsed content over unknown authors. A curator who includes clickbait loses subscribers and kickback revenue.

  3. Client-side author reputation — After fetching from an author and finding garbage, the client locally downgrades that author. Future envelopes from flagged authors can be marked with a warning or hidden entirely. This is purely local — no protocol change, no centralized blocklist.

  4. Economic self-correction — Clickbait earns from the first wave of disappointed readers. But with zero boosts, zero curator inclusion, and zero re-reads, the content never self-funds, never promotes to wider scope, and expires when the author stops paying storage. The clickbait author's profit is capped at one wave of retrieval fees minus ongoing storage costs.

  5. Low stakes per read — A text post retrieval costs ~25–75 μMHR. Being clickbaited once is cheap. Expensive content (video at ~1000+ μMHR) is where the risk is higher — but that's exactly where readers naturally rely on curators rather than browsing raw feeds.

Clickbait on Mehr is a diminishing-returns attack: it works once per reader, generates no organic amplification, and the author pays ongoing storage for content that nobody will read a second time.

Threading and Interaction

Replies

Replies reference the parent post via reply_to on the envelope:

Reply to a post:
PostEnvelope {
reply_to: Some(parent_post_hash),
summary: "Great point!",
...
}
SocialPost {
content: PostContent { text: "Great point! Here's why..." },
...
}

Thread assembly is local — each client collects reply envelopes by querying the DHT for envelopes referencing a given hash. Threads are assembled client-side in chronological order. The envelope's summary is enough to display the thread tree — full posts are fetched only when a reader opens a specific reply.

Clients should limit thread traversal depth (recommended: 64 levels). Deeply nested reply chains beyond the limit are still accessible — the client just stops auto-fetching and shows a "load more" prompt. At mesh scale, threads rarely go deep; the economics of reply storage naturally limits chain length.

Boosts

A boost (repost) references the original via boost_of on the envelope:

Boost a post:
PostEnvelope {
post_hash: None, // no SocialPost — boost is envelope-only
boost_of: Some(original_post_hash),
summary: None, // original's envelope has the summary
content_size: 0,
...
}

Boosts are envelope-only — post_hash is None and no SocialPost is created. When a reader fetches the boosted content, the original author receives kickback — not the booster. Boosts are pure amplification without capturing revenue.

References

References declare that a post is related to other posts — without threading (reply) or amplification (boost). They create a queryable content graph: the DHT can answer "what other posts reference this one?", enabling discovery of related discussions, counterarguments, and follow-ups across communities.

Reference other posts:
PostEnvelope {
references: [post_hash_a, post_hash_b, post_hash_c],
headline: "Why the bike lane debate misses the point",
summary: "Alice, Bob, and Carol each analyzed the new bike lanes...",
...
}

What references enable:

  • Related discussions: Query the DHT for all envelopes where references contains a given hash. A reader viewing a popular post can discover every post that references it — counterarguments, analyses, translations, remixes.
  • Cross-community linking: A Portland post referenced by a Tokyo post creates a connection between geographic communities. Interest relay nodes can surface cross-references.
  • Knowledge webs: Scientific papers referencing other papers, course lessons linking to prerequisites, music remixes pointing to originals — any content type benefits from declared relationships.

How clients render references is application-dependent. A client might:

  1. Show referenced envelopes as linked cards below the post (free — envelope fetch)
  2. Show a "referenced by N posts" count with expandable list
  3. Build a graph visualization of connected posts
  4. Ignore references entirely (minimal client)

When a reader fetches a referenced post's full content, the referenced author gets kickback — same as any retrieval.

ReplyBoostReference
Creates new contentYesNo (envelope-only)Yes
RelationshipVertical (parent → child)Amplification (repost)Horizontal (related posts)
Protocol-level fieldreply_to on envelopeboost_of on envelopereferences on envelope
Queryable via DHT"What replied to X?""Who boosted X?""What references X?"
Who earns kickback on originalOriginal authorOriginal authorOriginal author
Multiple targetsNo (one parent)No (one target)Yes (any number)

Scoped Content

Every post declares its scopes — where it's relevant and how it propagates:

Local Post (Geographic Only)

PostEnvelope {
scopes: [Geo("north-america", "us", "oregon", "portland")],
headline: "Hawthorne Farmers Market",
summary: "Farmers market on Hawthorne this Saturday! Fresh produce, live music...",
...
}

Envelope appears in Portland geographic feeds. Propagates cheaply within Portland. May bubble up to Oregon if popular.

Interest Post (Topic Only)

PostEnvelope {
scopes: [Topic("gaming", "pokemon", "competitive")],
headline: "VGC Meta Analysis",
summary: "New VGC meta analysis after the latest patch...",
media_hints: [MediaHint { content_type: "image/png", size: 85000, ... }],
...
}

Envelope appears in Pokemon interest feeds globally. Readers see the headline and summary for free. The 85KB image is only fetched (and paid for) when a reader opens the full post. Propagates through interest relay nodes. No geographic bias.

Cross-Scoped Post (Geographic + Interest)

PostEnvelope {
scopes: [
Geo("north-america", "us", "oregon", "portland"),
Topic("gaming", "pokemon"),
],
headline: "Portland Pokemon League Meetup",
summary: "Meetup next Friday at Pioneer Square — all skill levels welcome",
...
}

Envelope appears in both Portland geographic feeds and Pokemon interest feeds. Portland Pokemon intersection subscribers see it automatically.

Neighborhood-Only Post (Private)

PostEnvelope {
scopes: [], // no declared scopes
summary: "Block party at our place this weekend — neighbors only!",
...
}

Visible only within trust neighborhood. No propagation beyond trusted peers. The most private form of social posting. Since the audience is trusted peers only, the envelope and full post are both free to access.

Privacy depends on MHR-Pub scope routing: an envelope with no declared scopes matches no Scope(...) subscriptions, so it is never forwarded beyond direct MHR-Pub gossip between trusted peers. Nodes only gossip unscoped envelopes to their trusted peer set.

Media Tiering

The envelope/post split naturally creates a tiered browsing experience. Envelopes carry blurhash thumbnails via MediaHint; full media lives in the paid SocialPost as separate DataObjects with min_bandwidth constraints:

LayerContentSizeCostAvailable On
EnvelopeHeadline + summary~300-500 bytesFreeEverywhere, including LoRa
EnvelopeBlurhash thumbnails (in MediaHint)~30-64 bytes eachFreeEverywhere, including LoRa
PostFull text body~200 bytes - 10 KBRetrieval feeEverywhere
PostCompressed image~50 KBRetrieval feeWiFi and above
PostFull resolution image~500 KBRetrieval feeWiFi and above
PostVideo1+ MBRetrieval feeHigh-bandwidth links only

The application decides what to fetch based on current link quality:

// Envelopes always arrive via MHR-Pub (free)
display(envelope.headline, envelope.summary, envelope.media_hints);

// On user tap — fetch full content
let link = query_link_quality(storage_node);

if link.bandwidth_bps < 1000 {
// LoRa: text content only
fetch(post.content.text);
} else if link.bandwidth_bps < 100_000 {
// Moderate: text + compressed images
fetch(post.content.text);
fetch(post.content.media, max_size: 50_000);
} else {
// High bandwidth: everything
fetch(post.content.text);
fetch(post.content.media);
}

Privacy

  • Public posts (scoped): Propagate per declared scopes and propagation economics. Anyone can pay to read them.
  • Neighborhood-only posts (unscoped): Visible only within trust neighborhood. Gossip only between trusted peers. The most private social posting.
  • Interest-only posts: No geographic scope. Propagate through interest graph only — no geographic trail.
  • No social graph leakage: Following is a local MHR-Pub subscription. No central server has a copy of the social graph. Only the subscriber and the publisher know about the subscription.
  • Unfollowing is silent: Stop subscribing. No notification, no record.

Comparison: Economics vs. Algorithms

Centralized SocialMehr Social
Spam preventionAI moderation (arms race)Posting costs tokens (economically irrational)
Content rankingOpaque algorithm optimizing engagementEconomic signal (what people pay to read)
Content lifespanPlatform decidesFunded by readership
MonetizationAds; platform takes 100%Direct author-reader kickback; no middleman
CensorshipPlatform discretionNo central point of control
Feed curationAlgorithmic, engagement-optimizedHuman curators with skin in the game
Cost to read"Free" (you're the product)μMHR for strangers; free for friends
InfrastructureCompany-owned data centersSelf-sustaining through service fees