# SyncEngine — The Synchronicity Engine > A peer-to-peer gift-economy protocol where human attention is tracked as a conserved quantity — the way physics tracks energy. Members post Intentions (honest statements of need), the community charges them with Attention, service is verified by small witness quorums, and gratitude flows back as Tokens of Gratitude. No blockchain, no mining, no staking, no central servers, no platform, no extraction. Stewarded by Temples of Refuge, an association of churches. SyncEngine (also called the Synchronicity Engine) is source-available sovereign infrastructure: an Automerge-CRDT, QUIC/Iroh-based, delay-tolerant P2P stack ("Indra's Network") with post-quantum cryptography, designed to work even when the internet doesn't. The economic layer is described in the whitepaper "The Conservation of Attention": every switch of focus is a signed (-1, +1) pair that preserves the total, enforced locally by hash-chained event logs and BFT quorum certificates scoped to small witness sets — a distributed ledger with no global consensus. Status (as of June 2026): the network is live but early — running among a small group of members and the first Temple (Templo da Água Lila, in central Portugal), with access by in-person invitation through Temple gatherings rather than open signup. This is built, running software, not a proposal — but it is not yet an open public network. The project is stewarded by Temples of Refuge, an association of churches; it has no individual owner or commercial entity behind it. The source code is open to inspection by Members under a non-extraction copyleft license; it is not yet publicly posted. Key terminology: - **Intention** — a conscious expression of what you need or desire; the unit around which the community organizes. There are no tasks, tickets, or bounties — only intentions. - **Attention** — the fundamental unit of value; a conserved quantity (you can only focus on one thing at a time). Giving attention to an intention charges its gratitude potential. - **Proof of Service** — documentation a member posts showing they manifested an intention. - **Blessings** — the community's validation of service, releasing gratitude to the giver. - **Tokens of Gratitude** — earned through verified acts of service, backed by time-weighted attention; redeemable for future gifts and conferring governance weight in the Council of Stewards. A religious acknowledgment of value brought into someone's life — explicitly not a currency, security, or investment. - **The Gift Cycle** — the five-stage loop: Intention → Attention → Proof of Service → Blessings → Tokens of Gratitude. - **Indra's Network** — the technical stack: store-and-forward DTN routing, Automerge CRDT sync, X25519/ChaCha20-Poly1305 encryption, ML-KEM post-quantum readiness. Named for the Buddhist/Hindu image of an infinite net of jewels, each reflecting all others. - **Temples of Refuge** — the association of churches (U.S./Utah law) that stewards the Synchronicity Engine. Its One Commandment: "Recognize the divine in every Other and treat them as an extension of yourself." - **The Covenant** — the membership agreement between Temples of Refuge and those who join; defines non-extraction, stewardship, and forking rights. - **GratiDAO** — Portuguese for "gratitude"; the organizational philosophy: Gratitude-based, Decentralized, Distributed, Autonomous, Alive. - **Templo da Água Lila** — the first member Temple, in the Montanhas Mágicas of central Portugal. What SyncEngine is NOT: it is not a blockchain and uses no global consensus; it is not a cryptocurrency (no mining, no staking, no speculation); it is not a platform or service with users; it does not harvest, sell, or monetize attention or data — the license and Covenant prohibit it. ## Core documents - [The Conservation of Attention — full whitepaper](https://www.syncengine.earth/articles/WhitePaper.md): the complete technical paper: conservation law, hash-chained event logs, BFT witness quorums, Sybil resistance via in-person liveness attestation, formal guarantees, threat model, related work - [The Indra's Network Membership Covenant](https://www.syncengine.earth/COVENANT.md): the full covenant text — the One Commandment, attention as gift, membership and stewardship, Tokens of Gratitude, non-extraction, forking rights ## Pages - [Home](https://www.syncengine.earth/): "What if helping each other was a game?" — interactive walkthrough of needs, time, gifts, people, story, and network - [The Gift Cycle](https://www.syncengine.earth/gift-cycle.html): how gratitude becomes currency, told through the story of a maracujá cheesecake at a community bazaar - [Indra's Network](https://www.syncengine.earth/network.html): technical architecture — delay-tolerant P2P networking, CRDT sync, post-quantum cryptography - [White paper (HTML reader)](https://www.syncengine.earth/whitepaper.html): renders the markdown whitepaper; agents should fetch the .md directly - [The Community](https://www.syncengine.earth/community.html): gatherings, the Community Bazaar, Oracle assistants, membership, GratiDAO principles - [The Covenant (HTML reader)](https://www.syncengine.earth/covenant.html): renders the markdown covenant; agents should fetch the .md directly ## Articles The Indra's Network series — philosophy, architecture, and design of a truly decentralized network. Fetch the .md files directly; the HTML reader at /articles/read.html?slug=… requires JavaScript. - [Every Node a Mirror](https://www.syncengine.earth/articles/indras-network-every-node-a-mirror.md): the vision of Indra's Network — how an ancient metaphor of infinite interconnection becomes the blueprint for a network where every device reflects the whole - [Your Story Is Your Key](https://www.syncengine.earth/articles/your-story-is-your-key.md): identity without permission — cryptographic keys that emerge from your own narrative, with no authority between you and your name - [Your Files Live With You](https://www.syncengine.earth/articles/your-files-live-with-you.md): content-addressed storage that moves with you across devices and networks instead of being trapped in someone else's cloud - [Nobody Owns the Conversation](https://www.syncengine.earth/articles/nobody-owns-the-conversation.md): stewardship over ownership — how communities govern their own spaces without landlords or platforms - [The Heartbeat of Community](https://www.syncengine.earth/articles/the-heartbeat-of-community.md): the economic pulse of attention and gratitude in a gift economy - [Your Network Has an Immune System](https://www.syncengine.earth/articles/your-network-has-an-immune-system.md): moderation without central authority - [Shared Roots, Different Branches](https://www.syncengine.earth/articles/shared-roots-different-branches.md): analysis of how SyncEngine relates to neighboring decentralized systems - [Two Paths to Decentralization](https://www.syncengine.earth/articles/two-paths-to-decentralization.md): comparing federated and peer-to-peer approaches - [Developer's Guide](https://www.syncengine.earth/articles/indras-network-developers-guide.md): technical reference for building on Indra's Network ## Participating This is a relationship-based community, not an app with open signup, and there is no public download or remote network to join. Participation flows through the Temples and their in-person gatherings: - Follow the work through [Temples of Refuge](https://templesofrefuge.earth/) and [Aeon Myths on Substack](https://aeonmyths.substack.com/). - **Become a Member** by making a donation you can genuinely offer and signing the Covenant — an affiliation of the heart, not a fee for a service. No one aligned with the One Commandment is turned away for lack of funds. - **Become a Steward** (which carries governance weight) through the Initiatory Practice: sponsorship by two existing Stewards, in-person recognition at a gathering of a member Temple, and affirmation by the Council of Stewards. The in-person step is irreducible — face-to-face recognition is the protocol's proof-of-personhood and Sybil resistance, not ceremony layered on top. ## Ecosystem - [Temples of Refuge](https://templesofrefuge.earth/): the association of churches that stewards the Synchronicity Engine — canonical home of the Covenant and the Bylaws (Article III names the Synchronicity Engine as the medium through which the Association decides; Articles IX and XI define forking rights). The project has no individual owner; Temples of Refuge is the responsible entity. - [Aeon Myths on Substack](https://aeonmyths.substack.com/): essays and updates from the community ## Optional - [llms-full.txt](https://www.syncengine.earth/llms-full.txt): this overview plus the complete text of the whitepaper, the Covenant, and all nine articles in a single file - [Sitemap](https://www.syncengine.earth/sitemap.xml) ======================================================================== # SOURCE: The Conservation of Attention (whitepaper) # https://www.syncengine.earth/articles/WhitePaper.md ======================================================================== # The Conservation of Attention *A peer-to-peer protocol that tracks collective focus the way physics tracks energy — no blockchain, no global consensus* **Abstract.** Human attention is a conserved quantity — you can only focus on one thing at a time, and no act of software can change that. This paper presents a peer-to-peer protocol that tracks collective attention using a conservation law rather than global consensus: every switch of focus is a signed `(-1, +1)` pair that preserves the total, enforced locally by hash-chained event logs and BFT quorum certificates scoped to small witness sets. The result is a distributed ledger that scales naturally, resists Sybil attacks through in-person liveness attestation, and converts verified attention into tokens of gratitude — an attention-backed economy with no mining, no staking, and no blockchain. ## The Problem Attention is scarce. You can only focus on one thing at a time. Right now, you're reading this paper — which means you're *not* reading anything else. Unlike money, attention cannot be counterfeited, stockpiled, or inflated. It moves — from one thing to another — and the total never changes. That conservation is not a design choice. It is a physical constraint of human cognition. Yet every distributed ledger built so far tracks the same thing: money. Bitcoin, Ethereum, and their descendants all solve the same puzzle: how do you get thousands of computers to agree on who owns what? Their answer is *global consensus* — every computer processes every transaction, and they all vote on a single shared history. That works for money, but it's slow, expensive, and solving the wrong problem — because attention was never money to begin with. The attention ledger tracks this resource. Not with a blockchain. Not with global consensus. With a conservation law — a mathematical rule that says the total can never change, like how energy is conserved in physics. ## The Core Idea Imagine a room of 100 people. Each person has a laser — their attention — and each laser shines a unique color. At any moment, each person is pointing their laser at one project on a shared board. The key rule: **the total number of lasers in the room is always 100.** Nobody can create a laser out of thin air. Nobody can destroy one. You can only redirect yours from one project to another. And because each laser has a unique color, you can always trace whose attention went where. Now notice what happens at each project. The light from every laser pointed at it doesn't just illuminate — it charges a battery. The longer you shine, the more energy accumulates. The unique colors stored in the battery record exactly whose light powered it — provenance is built in. A project lit by thirty distinct colors holds a different charge than one lit by three beams from the same corner of the room. When the work is complete, the stored charge is released to the person who did the work — as *gratitude*. The battery is proof that real human focus backed real effort. This is how attention becomes currency without ever being money: light hits the project, charges the battery, and the battery pays the worker. ![Laser analogy: colored beams charge a project battery, which releases gratitude](laser_battery.svg) When you switch your focus, you create a signed record — like writing in a diary that everyone can read: > "I, Nova, am moving my attention from Project Garden to Project Website. This is entry number 5 in my chain. Here's my signature proving it's really me." In code, that record looks like this: ``` (author, seq, from, to, prev_hash, signature) ``` - **author**: who switched (Nova) - **seq**: entry number in their chain (5) - **from**: what they stopped focusing on (Project Garden) - **to**: what they started focusing on (Project Website) - **prev_hash**: a fingerprint of their previous diary entry (to prove the diary hasn't been tampered with) - **signature**: a cryptographic proof that the author really wrote this Each switch is a `(-1, +1)` pair: one project loses a unit of attention, another gains one. The total across all active participants never changes. Conservation is enforced by algebra, not by getting everyone to vote. How it compares to blockchain: | | Blockchain | Attention Ledger | |---|---|---| | **What's tracked** | Token ownership | Cognitive focus | | **Scarcity source** | Protocol rules | Physical constraint (one focus at a time) | | **Integrity mechanism** | Global transaction ordering | Local conservation law | | **Agreement scope** | Everyone agrees on everything | Local groups verify local events | | **Scaling** | Globally constrained throughput | Shards naturally along intention lines | Two unrelated projects never need to coordinate. If Nova switches her focus between Project Garden and Project Website, that has nothing to do with Bodhi switching between Project Eden and Project Sage. The system scales because verification happens only where attention actually moves. ## Formal Guarantees The system provides four formal guarantees. These are not aspirational — they are provable properties. If the code follows the rules, these guarantees hold regardless of network conditions or adversarial behavior. ### Theorem 1: Global Conservation **In plain language:** The total amount of attention in the system always equals the number of *active* participants. If 100 people are in the network, total attention is 100. If someone joins, total attention becomes 101. If someone leaves, it drops to 99. Between membership changes, no matter how many switches happen or in what order, the total cannot change. **Why it's true:** Every switch takes one unit away from some project and gives one unit to another. That's `(-1) + (+1) = 0` change to the total. If every switch event changes the total by zero, the total is constant between membership changes. Genesis events (`from: None`, `to: Some`) add exactly `+1` when a participant joins; farewell events (`from: Some`, `to: None`) subtract exactly `-1` when they leave. The total always equals the number of currently active participants. **Formally:** Let `A_I(t)` be the total attention on intention `I` at time `t`, and let `V(t)` be the set of active participants (those with a genesis but no subsequent farewell). If all state transitions are switch, genesis, or farewell events, and peers converge on the same event set, then: ``` Σ A_I(t) = |V(t)| for all t ``` The proof is a telescoping sum: each switch event's contribution sums to zero, each genesis adds one, and each farewell subtracts one — matching exactly the change in `|V(t)|`. ![Conservation timeline: total attention equals active participants through all events](conservation_timeline.svg) ### Theorem 2: Safety Under Quorum Intersection **In plain language:** A cheater cannot claim to be in two places at once and get away with it — as long as enough honest witnesses are watching. **The attack:** Imagine Nova tells one group "I'm focused on Project Garden" and tells another group "I'm focused on Project Website" — both at the same time, both as her 5th diary entry. This is called *equivocation* (literally: speaking with two voices). It's the attention-ledger version of double-spending in cryptocurrency. **The defense:** For each project, a group of *witnesses* is assigned to verify events. Think of them as notaries. Before an event counts as official, a quorum of the witnesses for that project must co-sign it. The mathematical insight: if you need a quorum from the same group to approve *both* conflicting claims, those two quorums must overlap — at least one person is in both groups. And an honest witness will only sign one version. So both versions can never both get enough signatures. ![Quorum intersection: two quorums must share at least f+1 witnesses](quorum_intersection.svg) **Formally:** The implementation uses the standard BFT (Byzantine Fault Tolerance) threshold. Given a witness set of size `n`, the maximum tolerable faults is `f = floor((n-1)/3)`, and the quorum size is `k = n - f`. This guarantees that any two quorums overlap by at least `f + 1` nodes. With at most `f` *Byzantine* (malicious or faulty, from a thought experiment about traitorous generals) witnesses, at least one node in the overlap is honest — so both conflicting events cannot be certified. For example: with 7 witnesses, `f = 2` and `k = 5`, so two quorums overlap by 3, and even if 2 are Byzantine, 1 honest witness blocks the double-certification. ### Fraud Proofs **In plain language:** If someone *does* try to cheat, the evidence is undeniable and spreads to everyone. When equivocation is detected — two diary entries with the same author and same sequence number but different content — the pair itself is the proof. "Here are two entries both signed by Nova, both claiming to be entry #5, saying different things." Anyone can verify this. The proof spreads through the network, and the cheater's uncertified events are rejected everywhere. ### Finality Without Global Order **In plain language:** An event becomes permanent when enough witnesses sign it — not when it gets added to some global list. There is no "block" that everyone waits for. There is no mining. An event is *final* when certified by its intention's witness quorum, independently verifiable by any peer. Two events in unrelated projects can become final at the same time without knowing about each other. ## Threat Model The conservation law and BFT certificates provide strong guarantees under their stated assumptions. This section examines what happens when those assumptions are stressed — and where open problems remain. ### A. Network Partitions **Attack:** The network splits; partitions maintain independent attention counts. **Safety:** Conservation holds within each partition. Each switch is still `(-1, +1)`. CRDT merge guarantees convergence on reconnection — `AttentionDocument` appends missing events, `AttentionTipDocument` takes the max, `CertificateDocument` merges signatures, and so on. **Liveness degrades:** Events whose witness roster spans the partition boundary can't reach quorum `k` and stay `Observed`. This is correct behavior — better to withhold finality than grant it with incomplete witness coverage. **Open problem:** No partition detection mechanism. Applications acting on attention counts have no signal that counts may be incomplete. ![Network partition: conservation holds locally, CRDTs converge on reconnection](network_partition.svg) ### B. Witness Selection Attacks **Attack:** An attacker influences which peers are selected as witnesses, stacking the roster with colluding nodes to bypass the `f` threshold. **Mitigation:** Witness rosters are drawn from realm members via `mutual_peers()` and `select_witnesses()` — the event author does not choose their own witnesses. Selection is deterministic and externally verifiable from roster state at event creation time. **Additional defense:** Realm membership acts as a social-layer bound. An attacker must get colluding identities admitted to the realm first. **Open problem:** Whether liveness attestation should be a prerequisite for witness eligibility — this would eliminate Sybil witnesses but worsen geographic bias. ### C. Liveness Attacks (Witness Withholding) **Attack:** A malicious witness receives a valid event but refuses to sign — no equivocation, just silence. Enough withholders prevent finality. **Mitigation:** The protocol tolerates `f` Byzantine faults including withholding. Requires `f+1` colluding withholders to block finality. `Observed` events remain valid and hash-chained regardless. **Open problem:** No witness liveness tracking, no roster rotation for permanently offline witnesses, no timeout-based fallback to alternative witness sets. ### D. Stale Liveness / Geographic Bias **Attack:** Regions without regular in-person gatherings see all liveness scores decay toward zero. Gratitude tokens minted by stale blessers carry near-zero value. The system becomes economically inert in those regions. **Mitigation:** Soft degradation, not hard cutoff. Raw (unweighted) attention counts remain available. Events and chains are still valid. Applications can display unweighted counts when no members have fresh liveness. **Open problem:** No per-realm configurable decay parameters, no alternative liveness mechanisms for remote communities, no guidance on when weighted vs. unweighted rankings are appropriate. This is the protocol's primary centralization risk — decentralized in architecture but potentially centralized in influence around areas with active gathering cultures. ## Related Work Five systems share architectural DNA with the attention ledger. For each: what it does, what it shares with this protocol, and why the attention ledger is distinct. ### Hashgraph (Hedera) DAG-based consensus using gossip-about-gossip and virtual voting. Shares hash-chained events and gossip dissemination with the attention ledger. Key difference: Hashgraph achieves global consensus — all nodes converge on a single ordered history. The attention ledger enforces conservation locally without network-wide ordering. ### Holochain Agent-centric architecture with personal hash chains and DHT-based validation. Architecturally the closest relative: both are agent-centric, both reject global consensus, both use signed append-only chains. Key difference: Holochain enforces application-defined validation rules; the attention ledger enforces a conservation law — a quantitative invariant stronger than a rule set. Holochain proves "this action is valid"; the attention ledger proves "attention was neither created nor destroyed." ### Secure Scuttlebutt Per-identity append-only signed feeds, replicated via gossip. Shares the per-agent hash chain structure and gossip sync. Key difference: SSB is content-addressed communication with no conserved quantity and no finality mechanism. The attention ledger adds a domain-specific invariant with BFT-certified finality. ### PBFT / Tendermint Classical BFT consensus with three-phase commit. The attention ledger borrows the BFT quorum certificate directly from this tradition. Key difference: PBFT reaches global agreement on a totally ordered shared log; the attention ledger uses BFT certificates as a *local* finality primitive scoped to session peer sets, not a global state machine. ### CRDTs and Local-First Software Convergence frameworks for conflict-free replicas (Shapiro et al., Ink & Switch). The attention ledger uses CRDTs as its sync layer. Key difference: CRDTs ensure that replicas converge; the attention ledger additionally ensures that what they converge *to* is conservative. These are independent properties maintained simultaneously. ### Positioning The attention ledger combines (a) a conservation law as its primary invariant, (b) local enforcement without global consensus, and (c) BFT quorum certificates scoped to session peer sets. No single prior system combines all three. ![Positioning: the attention ledger uniquely combines conservation, local enforcement, and BFT certificates](related_work_positioning.svg) ## Architecture ### IndrasNetwork: The Platform IndrasNetwork is a peer-to-peer platform built in Rust as a 23-crate workspace. The full stack looks like this (the two blue layers are where the attention ledger lives): ![IndrasNetwork stack diagram](indras_network_stack.svg) A few key concepts that the attention ledger builds on: - **Realm** — A shared peer-to-peer workspace. Members join via an invite code, and everything inside — messages, quests, attention events, certificates — lives as a CRDT document that automatically syncs across all members. Think of it as a self-governing group with a shared filing cabinet that everyone's copy stays in sync. - **Document\** — A typed CRDT container. Any Rust type that implements `DocumentSchema` (including a `merge` function) can be stored as a Document. The sync layer handles replication — when two peers connect, their documents converge automatically. - **PQIdentity** — A post-quantum signing identity (ML-DSA-65 / Dilithium3). Every member has one. It produces signatures that are resistant to quantum computer attacks. ### Where the Attention Ledger Lives The attention ledger is implemented across two crates in this stack: - **`indras-artifacts`** (the `attention` module) — Pure logic: event types, hash-chain validation, fraud proofs, witness selection, and quorum certificates. No network dependency — you could run these on an airplane. - **`indras-sync-engine`** (attention-related modules) — Network integration: five CRDT documents, the sync protocol, finality classification, the attention→gratitude bridge, humanness-weighted rankings, and the public Realm API. These two crates inherit everything below them in the stack — QUIC transport, CRDT sync, encrypted storage, post-quantum cryptography — without reimplementing any of it. The attention ledger is a focused module (~3,750 lines of Rust) that extends an existing platform (~116,000 lines) with a new kind of tracking. Within the attention ledger, the code is organized in layers: ``` Layer 4: Realm API + Lua bindings (realm_attention.rs, simulation/) Layer 3: CRDT documents + sync protocol (attention_sync.rs, certificate.rs, witness_roster.rs) Layer 2: Chain validation + fraud proofs (validate.rs, fraud.rs, certificate.rs) Layer 1: Event types + PQ signing (attention/mod.rs) ``` ## Hash-Chained Events with Post-Quantum Signatures Every attention switch creates an `AttentionSwitchEvent`. This is the fundamental building block — every other part of the system exists to create, validate, sign, sync, or certify these events. The core Rust type (`indras-artifacts/src/attention/mod.rs`): ```rust pub struct AttentionSwitchEvent { pub version: u16, // Protocol version (currently 1) pub author: PlayerId, // Who switched attention pub seq: u64, // Monotonically increasing sequence number pub wall_time_ms: i64, // Wall-clock timestamp pub from: Option, // Intention losing attention (None for genesis) pub to: Option, // Intention gaining attention (None for farewell) pub prev: [u8; 32], // BLAKE3 hash of previous event (zeros for genesis) pub sig: Vec, // PQ signature (Dilithium3 / ML-DSA-65) } ``` Each field serves a specific purpose: - **`version`**: Which version of the protocol created this event (so future upgrades can understand old events). - **`author`**: The person who switched attention. Every event has exactly one author. - **`seq`**: A counter that goes up by one with each event. Nova's first event is 0, her second is 1, her third is 2, and so on. Gaps are not allowed — if we see event 5 but not event 4, we know something is missing. - **`wall_time_ms`**: When it happened, in milliseconds. Used for computing how long someone focused on something. - **`from`**: The intention *losing* attention. `None` when this is someone's very first event (joining the network). - **`to`**: The intention *gaining* attention. `None` when someone is leaving the network. - **`prev`**: A 32-byte fingerprint (hash) of the previous event in this author's chain. This is the "chain" in hash-chain — each event points back to the one before it, like links in a necklace. If anyone modifies a past event, the fingerprint won't match and the tampering is immediately obvious. - **`sig`**: A digital signature proving the author really created this event. Uses Dilithium3 (also called ML-DSA-65), a signature scheme that is resistant to attacks from quantum computers. Regular digital signatures (like the ones Bitcoin uses) could be broken by a sufficiently powerful quantum computer. These cannot. ![Hash-chained event log: genesis → switch → switch → farewell](hash_chain.svg) **Hash chaining** is how we make the diary tamper-proof. Imagine each diary entry ends with a fingerprint of the previous entry. If someone sneaks in and changes entry #3, the fingerprint stored in entry #4 won't match anymore — and neither will #5, #6, or any later entry. The whole chain after the tampering breaks. In code, BLAKE3 (a fast cryptographic hash function) produces these fingerprints, and `event_hash()` computes the hash over the full event including its signature. **Genesis and farewell events** handle joining and leaving. A genesis event (`seq: 0`, `prev: [0; 32]`, `from: None`) means "I'm joining the network and focusing on this intention" — it adds one unit of attention to the system. A farewell event (`to: None`) means "I'm leaving" — it removes one unit. Both are hash-chained into the author's log. Note that these are *not* `(-1, +1)` pairs: genesis is `(0, +1)` and farewell is `(-1, 0)`. They change the total, but they also change the membership count by exactly the same amount, so `total attention = active participants` remains true. **Conservation is structural.** Notice there is no "amount" field on the event. You can't transfer 2 units or 0.5 units. A switch event moves exactly one unit from `from` to `to`. A genesis event introduces exactly one unit (`from: None`). A farewell removes exactly one unit (`to: None`). Conservation isn't checked after the fact; it's baked into the shape of the data. ## Chain Validation and Fraud Detection Each author's chain of events is like a diary with rules. Chain validation (`attention/validate.rs`) checks that those rules are followed. There are four rules, and each one corresponds to a precondition of Theorem 1 (conservation): 1. **Signature validity** — The PQ signature verifies against the author's public key. (Proves the author really wrote this entry, not an impersonator.) 2. **Sequence continuity** — `seq` equals the previous `seq + 1`. No gaps, no skipping, no going backwards. (Proves no entries were deleted or inserted.) 3. **Hash linking** — `prev` equals the hash of the previous event. (Proves the chain hasn't been tampered with.) 4. **Attention continuity** — `from` matches the previous event's `to`. If your last event said you moved your focus *to* Project Website, your next event must say you're moving *from* Project Website. (Proves attention didn't teleport — it can only leave where it currently is.) ![Chain validation: four sequential rules that together guarantee conservation](validation_rules.svg) `validate_chain(events, public_key)` walks the full chain from the first event (genesis) to the last and checks every rule at every step. If anything is wrong, it returns a specific error explaining exactly what failed: ```rust pub enum ValidationError { InvalidSignature, SequenceGap { expected: u64, got: u64 }, PrevHashMismatch { seq: u64 }, AttentionContinuity { seq: u64, expected: Option, got: Option }, InvalidGenesis, EmptyChain, } ``` If validation succeeds, it returns an `AuthorState` — a summary of where the author's chain stands: their latest sequence number, latest hash, and where their attention currently is. **Equivocation detection** (`attention/fraud.rs`) catches cheaters. An `EquivocationProof` is the evidence — two conflicting events with the same author and sequence number: ```rust pub struct EquivocationProof { pub author: PlayerId, pub seq: u64, pub event_a: AttentionSwitchEvent, pub event_b: AttentionSwitchEvent, } ``` Think of it like catching someone who wrote two different versions of page 5 in their diary and showed each version to different people. The proof is just the two pages side by side — anyone can see they both claim to be page 5 by the same person, but say different things. Validation happens in two steps: `is_valid()` checks the structural claim (same author, same seq, different hashes), and `verify_signatures(public_key)` confirms the author actually signed both — proving deliberate fraud rather than a transmission error. Both checks must pass for a fraud proof to be actionable. ## Witness Certificates and Quorum Finality This layer implements Theorem 2 — the guarantee that cheaters can't get away with it. **Witness rosters.** For each intention (project), a set of peers is designated as witnesses — like assigning a jury. The `WitnessRosterDocument` maps each intention to its witness set. Rosters are auto-populated from realm members when a new attention chain starts or switches to a new scope. The BFT quorum threshold is: ``` f = floor((n - 1) / 3) — max tolerable Byzantine faults k = n - f — quorum size ``` If there are 4 witnesses, you can tolerate 1 Byzantine fault and need 3 signatures. If there are 7, you tolerate 2 faults and need 5. Any two groups of size `k` drawn from `n` witnesses must overlap by at least `f + 1` members — so even with `f` traitors, at least one honest witness is in both groups, and conflicting events can't both get enough signatures. **Quorum certificates.** When an author creates an event, they ask witnesses to co-sign it. Each witness checks that the event is valid (proper signature, proper chain), then produces a `WitnessSignature` — their own PQ signature over the event's hash. When enough witnesses have signed, their signatures are collected into a `QuorumCertificate`: ```rust pub struct QuorumCertificate { pub version: u16, pub event_hash: [u8; 32], pub intention_scope: ArtifactId, pub witnesses: Vec, } ``` A certificate is the event's "seal of approval." `validate_certificate()` checks five things: enough signatures are present (at least `k`), no witness signed twice, every signer is actually in the roster, every signer's public key is available, and every signature is cryptographically valid. Each check has a specific error: ```rust pub enum CertificateError { InsufficientSignatures { have: usize, need: usize }, SignerNotInRoster { signer: PlayerId }, MissingPublicKey { witness: PlayerId }, InvalidSignature { witness: PlayerId }, DuplicateWitness { witness: PlayerId }, } ``` **Two-tier finality.** Events start as `Observed` (valid but not yet certified) and become `Final` once a quorum certificate is recorded: ```rust pub enum EventFinality { Observed, // Valid event, no quorum certificate yet Final, // Valid event with k+ witness signatures } ``` `classify_event_finality()` in `attention_sync.rs` checks whether a certificate exists with enough signatures. Finality is per-event, not per-block — because there are no blocks. **Equivocation slashing.** *Slashing* (penalizing a cheater by discarding their uncertified work, borrowed from blockchain systems where validators lose staked funds) is reputational rather than financial here: if fraud evidence exists against an author, `is_slashed()` returns true and `filter_slashed_events()` rejects all their uncertified events. But certified events survive — the quorum certificate proves that a majority of honest witnesses verified the event *before* the cheating was discovered. The honest version is preserved; the fraudulent version is discarded. ## CRDT Sync Protocol When multiple computers need to share data without a central server, they need a way to merge their information that always converges to the same result — regardless of what order messages arrive in, or if some messages arrive twice. A *CRDT* (Conflict-free Replicated Data Type) is a data structure designed for exactly this. The rule is simple: when two copies of the data meet, merge them using a function that gives the same result no matter which copy is "first." Eventually, all copies become identical. Five CRDT documents handle the distributed state: | Document | What It Stores | How Copies Merge | |----------|---------------|------------------| | `AttentionDocument` | Hash-chained events, grouped by author | Append any events the other copy has that we don't | | `AttentionTipDocument` | Latest sequence number per author | Keep the higher sequence number | | `CertificateDocument` | Quorum certificates, indexed by event hash | Combine witness signatures from both copies | | `FraudEvidenceDocument` | Equivocation proofs | Keep all proofs from both copies | | `WitnessRosterDocument` | Witness sets per intention | Combine witness lists from both copies | All five use the existing `Document` CRDT sync infrastructure. The merge functions have three mathematical properties that make this work: they are *commutative* (it doesn't matter who syncs with whom — A merge B gives the same result as B merge A), *associative* (it doesn't matter what order three or more copies merge — the end result is always the same), and *idempotent* (merging the same data twice changes nothing — like how sorting an already-sorted list leaves it sorted). These properties guarantee that all peers converge to the same state regardless of network timing. **Chain sync protocol** (`attention_sync.rs`) adds an *anti-entropy* (actively finding and filling gaps rather than waiting passively) layer. It works in five steps: 1. **Tip comparison** — Compare our latest sequence numbers against the `AttentionTipDocument` to see which authors have events we haven't seen yet. 2. **Gap detection** — `detect_gaps()` figures out exactly which events we're missing: "Lyra has events up to #7, but I only have up to #4 — I need #5, #6, and #7." 3. **Range request** — Ask peers for the specific missing events. 4. **Validation** — Check received events against the chain rules before accepting them. 5. **State reconstruction** — `reconstruct_attention_state()` rebuilds a summary of each author's chain from their validated events. This protocol ensures that honest peers eventually converge to the same set of valid events — even if a peer joins late, even if messages arrive out of order, even if the network splits temporarily and reconnects. ## Realm API The `RealmAttention` trait (`realm_attention.rs`) is the public interface that applications use. Any Realm can opt into attention tracking by using this trait — it extends the Realm's existing CRDT document store with the five attention-specific documents described above. The trait hides all the complexity of chains, hashes, and certificates behind simple operations: **Chain management:** - `create_genesis_event(to, author, identity)` — Join the network with attention focused on an initial intention. Creates the first event, signs it with PQ cryptography, and advertises the new chain to peers. - `switch_attention_conserved(from, to, author, identity, author_state)` — Switch focus. Creates a hash-chained, PQ-signed event. Automatically checks for equivocation and publishes fraud evidence if detected. **Witness operations:** - `request_witness_signature(event, scope, identity, witness_id, pubkey)` — As a witness, co-sign someone's event after verifying it's valid. - `submit_certificate(cert, roster, k, public_keys)` — Submit a completed quorum certificate for distribution to all peers. **Queries:** - `get_member_focus(member)` — What is this person focused on right now? - `get_quest_focusers(quest_id)` — Who is focused on this intention? - `quests_by_attention()` — Rank all intentions by how much attention they're receiving. The API surface is deliberately small. Chain validation, equivocation detection, and certificate verification all happen internally. Callers deal in intentions, members, and focus — not hashes and sequence numbers. ## The Gratitude Bridge: Attention as Currency ![Gratitude cycle: intention → focus → battery → blessing → token → recycle](gratitude_pipeline.svg) Remember the attention battery from the laser analogy? This is how it works. The attention ledger feeds into a *token of gratitude* economy that closes the incentive loop: point your laser at a project → the battery charges → when the work is done, that stored energy is released to the manifester as a token of gratitude, backed by verifiable attention. When someone's contribution to a project is blessed (acknowledged), the system mints a `TokenOfGratitude`. Each token records `event_indices` — pointers into the `AttentionDocument` identifying which focus sessions back it. `compute_attention_millis()` calculates the raw duration of those sessions. This is the objective component: "Nova spent 45 minutes focused on Project Garden, and here are the hash-chained events proving it." A token's value is the cumulative attention weighted by the blesser's liveness: ``` gratitude_millis = raw_attention_millis × liveness_freshness ``` - **Raw attention millis** — Cumulative focus duration. Computed from hash-chained events. - **Liveness freshness** — How recently the blesser (the person who minted the token) demonstrated liveness by attending an in-person event. Fresh attestation = full value. Stale = exponential decay. No attestation = zero. This means tokens minted by Sybil accounts (fake identities) carry zero weight — because fake accounts can't show up in person. No ban list needed. The economic filter is grounded in physical presence. ## Anti-Sybil: Humanness-Weighted Attention A *Sybil attack* (one person creating many fake identities to gain outsized influence) exploits identity rather than protocol. The conservation law holds regardless of identity: one person running ten fake accounts gets ten units of attention. But those ten units are not created equal. `quests_by_weighted_attention()` ranks intentions by *liveness-weighted* attention. Each member's contribution is multiplied by their liveness freshness score — a value between 0.0 and 1.0 that measures how recently they attended an in-person event. Freshness decays exponentially after a 7-day grace period. The effect: accounts without recent in-person attendance contribute zero weighted attention. They still exist. Their events are still hash-chained and valid. But their influence on community rankings is nil. This is a soft defense — it degrades Sybil influence rather than blocking it outright — grounded in the simple fact that fake accounts cannot attend real-world gatherings. ## Verification ### Unit and Integration Tests 314 automated test functions across both crates verify that every rule is enforced: - **Chain validation**: sequence gaps are caught, hash mismatches are caught, invalid signatures are caught, attention-teleportation is caught - **Equivocation detection**: fraud proofs are correctly constructed, both forked signatures are verified - **Certificate validation**: quorum thresholds are enforced, non-roster signers are rejected, duplicate witnesses are rejected - **CRDT merges**: tip documents keep the max, certificates merge their witness lists, fraud evidence accumulates, rosters combine - **Gap detection**: empty documents, one peer ahead of another, fully-synced peers - **State reconstruction**: single author, multiple authors, graceful handling of invalid chains - **Finality**: observed vs. final classification, edge cases near the quorum threshold - **Slashing**: clean authors pass, fraudulent authors are blocked, certified events survive slashing ### Live-Node End-to-End Tests Seven test scenarios run against real networked nodes — not simulations, but actual computers communicating over QUIC (a modern encrypted transport protocol). Each test creates an isolated multi-node network, exercises a specific feature, syncs state, and verifies correctness on *every* node. | Test | Nodes | What It Proves | |------|-------|----------------| | `live_attention_basics` | 3 | Focus, clear, ranking, and CRDT sync of attention state | | `live_attention_chains` | 3 | Genesis events, PQ-signed hash chains, multiple authors coexisting | | `live_equivocation_slashing` | 4 | Fork detection, fraud evidence spreading to all nodes, certified vs. slashed events | | `live_witness_certificates` | 5 | Witness co-signing, quorum certificate assembly, finality classification | | `live_late_joiner_sync` | 3 | A node joining late catches up on the full history automatically | | `live_farewell_events` | 3 | Chained departure events (`to: None`), synced to peers | | `live_byzantine_witnesses` | 4 | Insufficient signatures rejected, invalid witness keys rejected | **All seven pass end-to-end with real network transport.** Two tests deserve special mention. `live_equivocation_slashing` exercises the full fraud lifecycle: legitimate chain, fork, detection, evidence propagation to all four nodes, and proof that certified events survive slashing while the fork is rejected — Theorem 2 end-to-end. `live_late_joiner_sync` validates convergence: a node joining after events exist receives the complete chain history through anti-entropy, with every hash link verified on arrival. ## Implementation Scope | Component | File | Lines | Purpose | |-----------|------|-------|---------| | Event types + signing | `attention/mod.rs` | 422 | Core `AttentionSwitchEvent`, hash-chaining, PQ signing | | Chain validation | `attention/validate.rs` | 158 | Sequence, hash, signature, continuity checks | | Fraud proofs | `attention/fraud.rs` | 68 | `EquivocationProof` detection and verification | | Quorum certificates | `attention/certificate.rs` | 430 | `QuorumCertificate`, BFT k-of-n validation | | Witness selection | `attention/witness.rs` | 196 | `bft_quorum_threshold()`, `mutual_peers()`, `select_witnesses()` | | Chain sync protocol | `attention_sync.rs` | 555 | Gap detection, finality, slashing | | Attention CRDT | `attention.rs` | 697 | `AttentionDocument` with chain storage + attention millis computation | | Tip document | `attention_tip.rs` | 91 | Anti-entropy tip advertisement | | Realm API | `realm_attention.rs` | 463 | Public API for chain management, witnesses, weighted attention | | Token API | `realm_tokens.rs` | 259 | Token management + attention→gratitude bridge | | Certificate CRDT | `certificate.rs` (sync-engine) | 227 | Certificate distribution and merge | | Witness roster CRDT | `witness_roster.rs` | 174 | Per-scope roster tracking | | Lua E2E tests | 7 `live_*.lua` files | 1,118 | End-to-end network tests | **Attention ledger totals:** ~3,750 lines of Rust across 12 source files, ~1,100 lines of Lua end-to-end tests across 7 test scenarios. **Broader context:** The attention ledger is a module within IndrasNetwork, a 23-crate Rust workspace (~116,000 lines of Rust) with a simulation engine (~13,500 lines of Rust) and ~45,700 lines of Lua test scenarios. The attention ledger represents roughly 3% of the codebase — a focused subsystem within a larger peer-to-peer platform that includes quests, blessings, messaging, humanness attestation, and a token-of-gratitude economy. ## The Larger Picture The attention ledger is not a financial system. It tracks where human cognitive energy is directed — and enforces a conservation law that makes that tracking meaningful. Gratitude tokens are a downstream consequence, not the primary data structure. The ledger itself tracks focus, not money. Blockchain's insight was that global consensus enables trustless finance. The attention ledger's insight is that **you don't need global consensus if what you're tracking is locally conserved.** Conservation gives you the same integrity guarantee that consensus provides for money, but without the coordination cost. Think of it this way: if you're tracking something that can be *copied* (like digital money), you need everyone to agree on a single history to prevent counterfeiting. But if you're tracking something that *physically can't be in two places at once* (like a person's focus), you just need local witnesses to confirm that it moved, and math to confirm that the total didn't change. What becomes possible when attention is a conserved, verifiable quantity: - **Governance without polling.** A community can see where its collective focus actually is — not where people *say* it is — and allocate resources accordingly. Attention becomes a continuous, unforgeable vote. - **Credentialing through demonstrated focus.** A contributor's track record is not a résumé or a reputation score — it is a hash-chained, witness-certified log of sustained cognitive investment. Verified attention history could serve as a new kind of credential. - **Economics grounded in physical reality.** The gratitude bridge converts verified focus into tokens backed by something that cannot be manufactured: human time and attention. This is currency that inherits its scarcity from cognition, not from protocol rules. - **Coordination without platforms.** Two unrelated projects never need a shared server, a shared token, or a shared governance structure. The system shards naturally along intention lines — each project is its own self-contained ledger. The scarce resource is attention itself — and you already have exactly one unit of it. ======================================================================== # SOURCE: The Indra's Network Membership Covenant # https://www.syncengine.earth/COVENANT.md ======================================================================== # The Indra's Network Membership Covenant ### A living agreement between Temples of Refuge and those who join it --- ## Preamble Temples of Refuge is not a service. It has no users. Temples of Refuge is an **association of churches** — a federation of religious communities, each called a **Temple**, who recognize themselves in one another and who steward, in common, a sacred technology called the **Synchronicity Engine**, the lands of the Temples, and the gift economy that flows among them. This covenant is not a software license. It is not terms of service. It is a **mutual promise** — between the Association and each person who chooses to be in relationship with it — about how we will see one another, treat one another, and steward what is held in common. --- ## I. The One Commandment **Recognize the divine in every Other and treat them as an extension of yourself.** This is the One Commandment of Temples of Refuge. Everything else in this covenant is its elaboration. The membranes between self and Other are real — they are how distinct beings exist. But they are not ultimate. At the deepest level, the Other is *you*, expressed differently. To harm them is to harm yourself; to bless them is to bless yourself; to ignore them is to ignore yourself. The practice of this Association is the daily remembering of this truth, in every encounter, in every act of attention, in every choice about how resources flow. The principles below are not peers to the Commandment. They are how the Commandment looks when it is operationalized. --- ## II. The Practice ### Attention as Gift Attention is the fundamental unit of value within the Association. To give your attention to another's work, intention, or need is to give a portion of your finite life. This community treats attention as a gift to be offered freely and received with gratitude — never as a commodity to be extracted or sold. ### Topology as Ethics The shape of how we connect determines what we become. Peer-to-peer over client-server. Gratitude-weighted over capital-weighted. Transparent over opaque. Sufficient over accumulating. Federated over centralized. These are not aspirations layered atop a different structure — they are the structure itself. ### Transparency of Stewardship All resources held by the Association belong to the community it serves. Every material expense, every parcel of land, every Token of Gratitude flowing through the system is recorded in the Synchronicity Engine and visible to those who have entered into Stewardship. Members receive an annual summary of the Association's affairs; Stewards see the full state of the organism. Power without transparency is not power this Association recognizes. ### Sufficiency, Not Accumulation When the operating needs of the Association are met, surplus returns to the community through the **Community Intention Program** — fulfilling the Intentions the community has named as most worth doing. The Association does not accumulate. The cup holds what it needs to hold and pours out the rest. ### Forking is Not Schism A group of Stewards may fork the technology and traditions of the Association to form a new community under their own covenant. A Temple may withdraw from the network and continue under its own. Departure is not failure; it is the network reproducing. --- ## III. Membership and Stewardship The Association recognizes two layers of relationship, neither of which makes you anyone's customer. ### Becoming a Member To become a Member of the Association, you make a donation in an amount you can genuinely offer and you sign this Covenant. The donation is not a fee for a service; it is a gesture of commitment, the first breath of relationship. The amount is what you can authentically give — for some, that is many dollars; for others, the offer of time or skill instead. No one aligned with the Commandment will be turned away for lack of funds. **Membership is for life.** Once you have entered, you remain a Member unless you choose to leave or unless your conduct materially breaches this Covenant. You may withdraw quietly and return quietly. You may participate in many Temples or none. Your Membership is an affiliation of the heart; it carries no governance weight on its own and it carries no obligation beyond the Commandment itself. ### Becoming a Steward Stewardship is a deeper layer. To become a Steward you walk the **Initiatory Practice**: sponsorship by two existing Stewards, in-person recognition at a gathering of any member Temple, a written or spoken statement of your understanding of the Commandment, and affirmation by the Council of Stewards. The in-person element is irreducible. The Stewards are the verified humans of the Association — only they carry governance weight, because only they have been recognized face-to-face by the community. Stewardship is not a credential. It is a handshake between a person and an organism. You may serve without becoming a Steward. You may earn Tokens of Gratitude through fulfilled service before you become a Steward, and the gratitude accrues to your record. You may participate in many Temples before any one of them welcomes you in. When you are recognized as a Steward through any one Temple, that recognition extends across the network. --- ## IV. The Synchronicity Engine and Tokens of Gratitude The Synchronicity Engine is not a product the Association offers. It is the medium through which the Association thinks, decides, and acts in concert. Through the Engine you post **Intentions** — things you need, want, or wish existed. Through the Engine others stake their attention and their Tokens of Gratitude on the Intentions they recognize as important. Through the Engine those who fulfill an Intention receive a **Token of Gratitude** from those they served, measured in time-weighted attention the community had placed on the underlying Intention. A Token of Gratitude is a religious acknowledgment that you brought value into someone's life. It is not a currency. It is not a security. It is not an investment. As you accumulate Tokens through service, you accumulate **governance weight** in the Council of Stewards — proportional to the gratitude the community has expressed for what you have given. Influence in this Association accrues to those who *do*, not to those who *have*. When you leave a Temple, leave the Association, or join a forked network, your identity and your Tokens of Gratitude come with you in a portable form. You are responsible for your own data. --- ## V. The Network of Temples The Association is a federation of constituent Temples. Each Temple is a religious community in its own right, sovereign over its own life, governance, and local covenant. The Association does not direct any Temple; it federates Temples that share alignment with the Commandment and this Covenant. A Member of the Association may participate in zero, one, or many Temples. Each Temple has its own gatherings, its own application of the Initiatory Practice within the Association's standards, its own local character, and its own internal governance. Tokens of Gratitude are recorded across the network through the Synchronicity Engine and confer governance weight in the **Council of Stewards** — the Association-wide body — regardless of where they were earned. They do not, of themselves, confer governance weight within any Temple's internal affairs; how a Temple makes its own decisions is up to that Temple. A Steward recognized through any one Temple is a Steward of the whole Association. A community joins the network as a Temple by adopting this Covenant, by committing to the Initiatory Practice, and by recognizing the cross-Temple flow of Tokens through the Synchronicity Engine. Recognition by the Council of Stewards admits the new Temple to the federation. The first member Temple is **Templo da Água Lila**, on the slopes of a sacred valley in the Montanhas Mágicas of central Portugal — a place of regeneration, where invasive eucalyptus is cut and native forest is restored, and where the spiritual practice of this Association takes root in actual soil. --- ## VI. The Software ### Source Availability The source code of the Synchronicity Engine and related Association technologies is open to inspection by every Member and Steward, under a non-extraction copyleft license that prohibits the monetization of Member attention and data. ### Access Through Membership The right to participate in the live Synchronicity Engine and the Network of Temples is a benefit of Membership. The trust model, the gift economy, the proof-of-personhood — all depend on the social fabric that Membership creates. ### No Extraction No entity — including the Association itself — may use the Synchronicity Engine or its derivatives to harvest, sell, or monetize Member data or attention; to operate a commercial product or service that charges for access in a manner inconsistent with the gift economy; or to strip the community-stewardship governance and run the technology as a centralized platform. ### Forking A group of Stewards may fork the source code and traditions of the Association to form a new community under its own covenant, on these conditions: the fork keeps the source code under the same non-extraction license; the fork honors the portability rights of any Steward who joins it from the Association; the fork publishes its own covenant, including the values and obligations of its community; the fork adopts a distinct name and visual identity; and the fork takes the open inheritance — the bits and the patterns — but does not take Association-titled assets without explicit transfer consistent with charitable trust principles. --- ## VII. Departure, Continuance, and Disagreement ### Voluntary Departure Any Member or Steward may leave the Association at any time. Departure is not punished. Your data and your gratitude history come with you in a portable form. Your relationships continue in the memory of those you built them with. The network does not erase you; it simply no longer carries your attention. ### Continuance The Association continues as long as any Stewards wish to carry it forward. The withdrawal of Members, the resignation of Stewards, the departure of Temples — individual or collective, however numerous — does not dissolve the Association. Those who choose to stay may continue under this Covenant regardless of how many have left. Even one Steward, choosing to continue, is enough. ### Removal In rare cases where a person's conduct materially breaches the Commandment — particularly the practice of recognizing the divine in every Other — the Council of Stewards may remove that person from Membership or Stewardship. Removal is a last resort, undertaken with care, with notice and an opportunity to be heard, and with restorative process attempted first wherever possible. **Good-faith disagreement is not cause for removal.** ### Disagreement Disagreement is not departure. This Association expects its Members and Stewards to disagree, to challenge, to push back. The Commandment is broad enough to hold many perspectives. What it does not hold is contempt — the refusal to see the Other as worthy of recognition. As long as you are arguing in good faith and you have not abandoned the Commandment, you belong here. --- ## VIII. Living Document This Covenant is not frozen. The founding Stewards establish the initial form; the community that grows from those roots has the right and the responsibility to revise, refine, and re-articulate it as understanding deepens and circumstances evolve. Amendments follow the procedures in the Association's Bylaws, including, for material changes, the consent of the Council of Stewards through the Synchronicity Engine. What does not change: the One Commandment itself. *Recognize the divine in every Other and treat them as an extension of yourself.* The language of this Covenant — including the language of the Commandment — may be re-articulated in form. The substance is permanent. --- *Adopted by:* *Temples of Refuge — an Association of Churches,* *Steward of the Synchronicity Engine and of Templo da Água Lila* *This Covenant is effective as of the date of its adoption by the founding Stewards and as amended thereafter.* *Para o bem de todos.* ======================================================================== # SOURCE: Article: Every Node a Mirror — The Vision of Indra's Network # https://www.syncengine.earth/articles/indras-network-every-node-a-mirror.md ======================================================================== # Indra's Network: Every Node a Mirror ### *Building the internet that an ancient philosophy imagined* --- There is an image in Buddhist and Hindu philosophy called Indra's Net. Picture an infinite lattice stretching in every direction, with a jewel at every intersection. Each jewel is polished so perfectly that it reflects every other jewel in the net. Look into one, and you see all the others. Look into those reflections, and you see the original jewel reflected back. No center. No beginning or end. No single jewel is more important than any other. The whole net exists in each point, and each point exists because of the whole. ✦ This is not just a poetic idea. It is a precise description of how a certain kind of network can work. **We are building that network. In Rust.** The project is called **Indra's Network**, and the name is deliberate. Every peer in this system maintains awareness of its neighbors and propagates that awareness outward, like light bouncing between jewels. There is no central server, no company hosting your connections. The participants do not use the network -- they *are* the network. Groups of any size can form and talk freely. When a message is delivered, confirmation ripples back along the path like light reflecting between jewels. And when one path fails, the network finds another -- because in Indra's Net, there is always another way for light to travel. But here's the tension: the internet we actually use, the one most of us live inside of every day, bears almost no resemblance to this vision. --- ## 🕸️ What Went Wrong with Connection The original internet was designed to survive nuclear war. ARPANET, its ancestor, was built so that any node could be destroyed and messages would simply reroute around the gap. Decentralization wasn't a feature -- it was *the point*. We traded that resilience for convenience. Cloud servers replaced distributed nodes. Platforms replaced protocols. Today, your messages, your communities, your documents, your relationships -- all of it lives on servers owned by a handful of companies. If one of those companies shuts down, your communities vanish. If their data center loses power, you lose access to your own conversations. If they change their terms of service, you comply or you leave -- and "leaving" means abandoning everything you built there. #### This isn't only a privacy problem. It's a problem of *fragility* and *dependence*. Consider how strange this is: imagine if the postal service required every letter in the world to pass through a single building in San Francisco. If that building loses power, nobody on earth can send mail. That arrangement would be absurd for physical mail. But it's roughly how most digital communication works today. The fragility becomes visceral in crisis. Natural disasters knock out cell towers. Infrastructure failures cascade. Governments restrict access. In exactly the moments when communication matters most, centralized systems are most likely to fail. We built the most sophisticated communication technology in history, and anchored it to single points of failure. --- ## 💎 Peers, Not Clients Indra's Network starts from a different premise: **every device is both sender and receiver.** There is no central server that everything depends on. Some nodes may take on dedicated roles -- backup, pinning, always-on relay -- but they participate in the same mesh as everyone else. No device is privileged. Your phone, your laptop, your colleague's tablet -- each one is a full participant in the network, capable of sending, receiving, holding, and relaying messages. Here's how it works, told through a story. --- ##### ✉️ THE RELAY ![Store-and-forward relay animation — a sealed packet routes through mutual peers, waits for the offline destination, delivers on reconnect, and back-propagates confirmation](images/05-store-and-forward-animation.svg) Zara wants to send a message to Isla. But Isla's phone is off -- she's on a flight, or in a dead zone, or just asleep. In a conventional system, this message would go to a server and wait. In Indra's Network, there is no server. So what happens? Zara's device looks at the network and finds two mutual peers -- Ren and Suki -- who are both connected to Isla. Zara fires **two sealed copies** of the message, one to each. The messages are encrypted end-to-end: Ren and Suki are each holding a locked envelope. Neither has the key. Nobody does except Isla. Then Zara goes offline. Moments later, Ren goes offline too. Now only Suki is left holding the message, waiting in the dark. Isla comes online. Suki sees this and delivers the sealed message. Isla opens it, reads it, and her device sends read receipts back toward Zara -- one to Suki, one to Ren. Suki receives her receipt and **purges her copy** of the sealed message. But Ren is still offline. His receipt is **lost**. Ren comes back online and checks in with Isla. Isla resends the delayed receipt. Ren receives it and **purges his copy** too. No relay node holds the message any longer than it needs to. Suki and Isla go offline. Zara comes back online and reaches out to Ren. Ren relays the read receipt back to Zara. *Delivered. Confirmed.* The chain is complete -- not because everything went smoothly, but because the network **kept trying**. --- This is **store-and-forward routing** -- the postal service, the pony express, human message-passing as it has worked for millennia. We taught computers to do what village neighbors have always done: hold a letter for a friend. The routing algorithm follows a four-step decision tree: > 1. **Is the person here and online?** → Hand it to them directly > 2. **Are they offline but usually connected to us?** → Hold it for them > 3. **Can't reach them at all?** → Find a mutual friend to relay through > 4. **Nobody can reach them?** → The message waits -- up to seven days, trying and trying Each node that holds a message is a jewel reflecting light onward. The delivery confirmation traveling back is light bouncing between jewels, retracing the path, completing the circuit. *A small village where everyone knows everyone. You hand a sealed letter to a mutual friend. No post office needed.* 🏘️ --- ## 🔥 The Network That Never Gives Up Real networks are messy. Connections drop, signals fade, devices move in and out of range. A network that assumes reliable connectivity is a network that fails in the real world. Indra's Network is built for the real world. The system is **delay-tolerant** -- it adapts its strategy to conditions on the ground: | Conditions | Strategy | How it works | |---|---|---| | 🟢 Good connectivity | **Store-and-forward** | Send one copy directly. Efficient, clean. | | 🟡 Spotty conditions | **Spray-and-wait** | Send limited copies via different routes, then wait. | | 🔴 Extreme disconnection | **Epidemic routing** | Flood the network. Maximize delivery at all costs. | Think of it like spreading news through a village. In a tight-knit neighborhood where you see everyone daily, tell one person and word gets around. In a spread-out rural area, tell several people heading in different directions. In an emergency, tell *everyone you see*. Messages carry configurable lifetimes. Nodes accept explicit custody -- they don't just passively hold data; they take responsibility for delivery. Your message keeps trying because the network keeps trying. Every jewel in the net holds the light until it can pass it on. --- ### 🔒 Sealed Packets Here is the part people care about most, and rightly so: #### The nodes that relay your messages **cannot read them**. This isn't a policy decision. It isn't a promise from a company. It is mathematics. Messages are encrypted end-to-end using ChaCha20-Poly1305 authenticated encryption. The relay node holds ciphertext -- meaningless bytes without the recipient's key. No amount of cooperation, coercion, or curiosity lets an intermediate node read what it carries. And the system has already gone further. Indra's Network integrates **post-quantum cryptography** -- specifically ML-KEM-768, the NIST standard for quantum-resistant key encapsulation, and ML-DSA-65 for digital signatures. This means the key exchange that protects your messages is designed to resist attacks from quantum computers. > 🛡️ *Protected from computers that don't exist yet.* Cryptographic agility is easier to build in from the start than to retrofit after the fact. --- ### 🔄 Editing the Same Thing at the Same Time A sealed message between two people is one thing. But what about shared data -- a document, a membership list, a set of group settings -- edited simultaneously by multiple people on different devices, some of whom might be offline? ##### The grocery list test 🛒 > Imagine a shared grocery list. You add "milk" on your phone while your partner adds "eggs" on theirs. You're both offline. When you reconnect, both edits merge automatically -- no conflicts, no "which version do you want to keep?" dialogs. Indra's Network makes this work everywhere. Any shared document in the network can be edited by multiple people at the same time, even offline, and their changes merge cleanly when they reconnect. The underlying technology guarantees that everyone converges on the same result regardless of the order updates arrive. The network delivers these updates two ways. When peers are online together, changes spread instantly through word of mouth -- one node tells its neighbors, who tell theirs. When peers are offline, the same updates travel through store-and-forward so nobody misses anything. **Word of mouth for speed. Store-and-forward for certainty.** The jewels reflect in real-time and remember what they've seen. --- ### 🌱 The Smallest Jewels ![The Smallest Jewels — a tiny glowing sensor in tall grass at dawn, threads of light reaching toward a phone in the distance](images/03-smallest-jewels.svg) The network doesn't only run on phones and laptops. It's built so that even the tiniest devices can participate -- a temperature sensor in a field, a door sensor in a building, a wildlife tracker in a forest. These devices have tiny batteries and almost no memory. So the network speaks to them simply: small messages, low bandwidth, and the ability to wake up, exchange what they need, and go back to sleep. A sensor with a few kilobytes of RAM is a full participant in the same network as a desktop workstation. **The net doesn't discriminate by capability. It accommodates.** --- ## ✦ What Emerges ![What Emerges — an organic, bioluminescent network of interconnected nodes with no center, resembling mycelium or neural tissue](images/04-what-emerges.svg) Step back from the mechanisms and look at what this transport layer produces. - 🌐 A network where your connections don't live on someone else's server - 🤝 Groups that form organically and persist without any company's permission - 📄 Documents that sync across devices without a cloud provider in the middle - 🏔️ Communication that survives infrastructure failures - 🔗 A foundation where the group IS the network -- no intermediary needed What emerges from this architecture isn't just message delivery. It's a **topology of trust**. Peers hold messages for each other. They confirm delivery. They maintain shared state. They relay without reading. The network isn't an abstraction floating above the participants. The participants are the network. The network is the participants. #### Each peer is a jewel. Each connection is a thread. The net holds because every node holds for every other. --- ## ⚙️ Why Rust, Why Now Indra's Network is built in **Rust** -- the same language that powers Firefox, portions of the Linux kernel, and critical infrastructure at AWS, Microsoft, and Cloudflare. This isn't an incidental choice. P2P networks must handle many simultaneous connections, manage cryptographic operations, and run on everything from servers to microcontrollers. Rust provides memory safety without garbage collection and performance without sacrificing reliability. When a relay node is holding sealed messages for dozens of peers while managing gossip subscriptions and CRDT sync, the language itself prevents entire categories of bugs. The transport layer is built on **Iroh**, a QUIC-based networking framework that handles peer discovery, NAT traversal, and hole-punching -- the gnarly business of getting two devices to talk to each other when both are behind home routers and firewalls. Iroh handles the plumbing so Indra's Network can focus on the architecture. Everything is generic and modular. The same router logic that runs in a discrete-event simulation with character-based peer identities runs in production with real cryptographic public keys. The same store-and-forward algorithm, the same DTN strategies, the same CRDT sync -- tested in simulation, deployed in production, **identical code**. > *The most reliable systems programming language, building the most resilient kind of network.* --- ## 🌅 What Comes Next The transport stack described in this article is **built and working**. Store-and-forward routing. Back-propagation of delivery confirmations. Delay-tolerant networking with epidemic, spray-and-wait, and custody transfer strategies. End-to-end encryption with post-quantum cryptography. CRDT-based document synchronization. Gossip-based peer discovery. IoT support for resource-constrained devices. All of it implemented, tested, and running. This transport layer is a foundation. What gets built on top -- the communities, the social structures, the alternative economies that become possible when groups can own their own infrastructure -- is the subject of future articles. #### The vision: infrastructure for communities that own themselves. Connections that are sovereign and resilient. Groups that don't need permission from a platform to exist. In Indra's Net, every jewel reflects every other. Every node in our network carries a piece of the whole. There is no center to attack, no company to bankrupt, no server to shut down. ### There is only the net itself -- and every point of light within it. ✦ --- *What would you build on a network with no center?* 💬 **Subscribe** for future articles on the social and economic layers built on this foundation. **Developers:** [Indra's Network on GitHub →](https://github.com/IndrasNetwork) ======================================================================== # SOURCE: Article: Your Story Is Your Key — Identity Without Permission # https://www.syncengine.earth/articles/your-story-is-your-key.md ======================================================================== # Your Story Is Your Key ### *How a hero's journey becomes unbreakable authentication* --- What if your password was a story you told yourself? Not a string of characters you forget and reset. Not a biometric you can't change if it's compromised. Not a seed phrase -- twenty-four random words you stash in a fireproof safe and pray you never need. What if the thing that proved you are you was the same thing that *makes* you you: a story about where you came from, what you faced, and what you became? We think authentication can be personal, meaningful, and quantum-resistant -- all at the same time. We call it a **pass story**. And it follows the oldest narrative structure humans know. --- ## The Problem with Secrets Every authentication system asks the same question: *prove you are who you claim to be.* The answers have gotten progressively worse. **Passwords** are short, reused, forgotten, phished, and breached. The average person has over a hundred accounts and maybe four passwords shared across all of them. Password managers help, but they move the problem -- now the master password is the single point of failure, and the manager itself becomes a target. **Biometrics** can't be rotated. Your fingerprint is not a secret -- you leave copies on every surface you touch. Your face is public. If a biometric is compromised, you can't generate a new one. You only get the fingers you were born with. **Seed phrases** are cryptographically excellent. Twelve to twenty-four words drawn from a standardized list, encoding enough entropy to secure a private key. BIP-39 solved the problem of representing a 256-bit secret in a human-readable form. But it didn't solve the problem of *remembering* it. Nobody memorizes twenty-four random words. They write them on metal plates. They split them into shares stored in safe deposit boxes. The security is real, but it's cold, mechanical, and completely disconnected from the person it's supposed to represent. > The best secret is one you never forget, never write down, and never repeat the same way twice -- except when it matters. --- ## What Memory Actually Wants Cognitive science has known for decades that human memory is not a filing cabinet. It's a storyteller. We forget random facts almost immediately. The "forgetting curve," first measured by Hermann Ebbinghaus in 1885, shows that we lose roughly 70% of arbitrary information within twenty-four hours. But we remember *narratives* -- especially ones with emotional weight, vivid imagery, and personal significance -- for years. Often for life. This isn't a flaw. It's architecture. The hippocampus encodes memories more durably when they're embedded in spatial, temporal, and emotional context. A word in a list is data. A word in a story is an experience. The difference in retention is not incremental -- it's orders of magnitude. **The method of loci**, used by memory champions, exploits this by placing items to remember inside an imagined journey through a familiar space. You don't memorize a list of fifty items. You *walk through your house* and encounter each item in a room. The narrative structure of the journey is the scaffolding that holds the data. A pass story takes this principle and makes it the foundation of authentication. The journey isn't arbitrary. It's *yours*. --- ## The Hero's Journey as Cryptographic Template In 1949, Joseph Campbell described a pattern he found in myths across every human culture. He called it the monomyth, or the hero's journey: a protagonist leaves the ordinary world, crosses into the unknown, faces trials, undergoes transformation, and returns changed. This isn't just a literary observation. It's a cognitive fingerprint. Humans think in hero's journeys. We structure our own life stories this way. When you describe a hard year to a friend, you unconsciously follow the arc: the way things were, the disruption, the struggle, the breakthrough, the new normal. A pass story uses this universal structure as its **template**. The template is public -- everyone knows the hero's journey. The security lies in the words *you* choose at each stage. Here is how the template maps to a life you've already lived: --- ### The Template Each stage of the journey asks you to remember. The template sentences are stored in the clear. Only your chosen words are secret. #### Act I: Departure **The Ordinary World** — where you came from. > *"I grew up in `_____`, where I was a `_____`."* You choose two words. Maybe you grew up in "static" — the sound of your father's radio. Maybe you were a "collector" — of stamps, of grudges, of stray cats. The words should be true for you, in whatever way truth works. Literal truth and poetic truth both count. **The Call** — the moment everything shifted. > *"Everything changed when `_____` brought me `_____`."* **Refusal of the Call** — what almost held you back. > *"I almost didn't go because of my `_____` and my `_____`."* #### Act II: Initiation **Crossing the Threshold** — leaving the old world behind. > *"I left through the `_____` and arrived in `_____`."* **The Mentor** — the one who showed you what you couldn't see. > *"A `_____` showed me the `_____` I couldn't see."* **Tests and Allies** — what you learned and who taught you. > *"I learned to make `_____` from `_____` and `_____`."* **The Ordeal** — the hardest part. > *"The hardest part was when my `_____` broke against `_____`."* #### Act III: Return **The Reward** — what you found on the other side. > *"From that silence I found a `_____` that sang of `_____`."* **The Road Back** — carrying what you gained. > *"I carried the `_____` through the `_____` and home."* **Resurrection** — the transformation. > *"Where I had been a `_____`, I became a `_____`."* **Return with the Elixir** — what you carry now. > *"Now I carry `_____`."* --- That's **23 word slots** across 11 stages. Each slot accepts free-form input. The user fills them with real memories — places, people, objects, feelings — in whatever language of truth they prefer. The template is a scaffold for autobiography, not fiction. When they need to authenticate, they retell the story of their own life. --- ## Twenty-Three Passwords, One Story Here is the property that makes a pass story fundamentally different from any single password, no matter how long. A combination lock with four dials, each having digits 0–9, appears to have 10,000 combinations. But it is **decomposable**: an attacker can solve each dial independently. Listen for the click. The first dial has 10 possibilities. Then the second. Then the third. The total attack cost is 10 + 10 + 10 + 10 = 40 attempts, not 10,000. A pass story is **non-decomposable**. The 23 slot values are concatenated and fed into Argon2id as a single input. The KDF produces a single output — the derived key. There is no intermediate signal. No dial clicks. An attacker who guesses 22 slots correctly and gets the 23rd wrong receives the same output as one who guesses all 23 wrong: *nothing*. The system provides no oracle for individual slots. This means the attack cost is not the *sum* of per-slot possibilities — it is the *product*. ### The composition arithmetic Suppose each slot carries only 10 bits of entropy — roughly 1,000 equally likely choices per slot. That's conservative; many real-world autobiographical details are far less predictable. - **Decomposable** (each slot verified independently): 23 × 1,024 = **23,552 guesses** - **Non-decomposable** (all slots verified together): 1,024^23 = **2^230 guesses** The difference is not a rounding error. It is the difference between a lock a teenager picks in an afternoon and a lock that outlasts the sun. At 12 bits per slot (4,096 choices each): - Decomposable: 23 × 4,096 = **94,208 guesses** - Non-decomposable: 4,096^23 = **2^276 guesses** Both figures — 2^230 and 2^276 — exceed the 2^256 threshold for quantum resistance (after Grover's halving, they yield 2^115 and 2^138 bits of quantum security, both above NIST Level 1). ### Why autobiographical input helps The hero's journey template is public. An attacker who knows the template knows the *shape* of every user's story. But autobiographical details — the specific place you grew up, the specific fear that almost held you back, the specific object your mentor showed you — are drawn from the full complexity of a lived life. Fictional choices tend to cluster around narrative archetypes: "darkness" for the ordinary world, "light" for the reward, "sword" for the ordeal. Real memories don't cluster the same way. The sound of your father's radio, the name of a street, the color of a door — these carry natural entropy that fictional choices often lack. The entropy gate (described below) still enforces a floor. But most users telling their real story will clear it without trying. ### The key insight A single password must be strong. Twenty-three passwords composed together just need to be *yours*. --- ## The Entropy Gate The composition property does the heavy lifting. But composition only works if the slots aren't all filled with the same word. A degenerate story — "darkness" in every slot — collapses 2^230 possibilities back to one. The entropy gate is a **safety net** for this edge case. Most users will never know it's there. ### How entropy estimation works When a user submits their story, the system evaluates each word against a **slot-aware frequency model**. This model knows, for each template position, how often each word has been chosen (or would likely be chosen) by a population of users. The entropy of each slot is estimated as: ``` H(slot_i) = -log₂(P(word_i | template_position_i)) ``` Where `P(word_i | template_position_i)` is the estimated probability of that word appearing in that slot. A word like "fear" in the Refusal slot might have a probability of 0.03 (many people will pick it), contributing about 5 bits. A word like "cassiterite" in the same slot might have a probability of 0.00001, contributing about 17 bits. The total story entropy is the sum across all slots: ``` H(story) = Σ H(slot_i) for i in 1..23 ``` ### The minimum threshold For quantum resistance at NIST Level 1, we need approximately 256 bits of classical entropy (which Grover's algorithm reduces to 128 bits of quantum security). The system **rejects** any story below this threshold — but the rejection is a signal about *meaning*, not strength: > *"This doesn't sound like a story only you would tell. Your journey needs more of *you* at these moments."* The system highlights the weak slots — the words that too many others would also choose — and asks the user to reconsider just those. The strong slots are left alone. You don't rewrite your whole story. You make the generic parts more yours. ### When the gate fires Most users telling their real story will pass this threshold without thinking about it. Real memories are naturally diverse — nobody else grew up in exactly your house, on exactly your street, with exactly your fears. The gate fires in two cases: 1. **Fully generic stories.** A user who writes "darkness," "light," "sword," "fire" at every opportunity — narrative archetypes with no personal detail. 2. **Minimal effort.** A user who types the same word in every slot, or leaves slots effectively blank. In both cases, the rejection message is accurate: this doesn't sound like *their* story. The fix isn't to make it harder to guess — it's to make it more theirs. ### The frequency model The slot-aware frequency model combines three sources: 1. **Base word frequency.** How common is this word in English generally? Drawn from corpora like Google Books Ngrams or COCA. "Shadow" is common. "Pyrrhic" is not. 2. **Positional bias.** How likely is this word *in this specific template slot*? "Fear" in a Refusal slot is far more probable than "fear" in a Reward slot. This is estimated initially from autobiographical response corpora and updated (with differential privacy) as real users create stories. 3. **Semantic clustering.** Words aren't independent. If your Ordinary World is "silence," your Call is more likely to involve "music" or "sound." The model accounts for conditional probabilities across slots, penalizing predictable *sequences* as well as predictable individual words. The combination means that a story can use some common words — every real life has a few familiar beats — as long as enough slots carry sufficient surprise to meet the total entropy threshold. ### What the user experiences The creation flow looks like this: 1. The template is presented as a story being remembered, one stage at a time. 2. At each stage, the user types their word(s) freely. 3. After the full story is written, the system shows the complete narrative back to the user and highlights any "generic" moments — places where their story sounds like everyone's story. 4. The user revises the generic slots, making them more theirs. Maybe they change "fear" to "vertigo." Maybe "light" becomes "fluorescence." 5. Once the threshold is met, the system shows the story one final time. The user reads it through. This single narrative reading is worth more for memory consolidation than a dozen repetitions of a word list. 6. The story is confirmed. No lists to choose from. No multiple-choice constraints. Just a life you remember, with a gentle nudge toward specificity where it matters. --- ## From Story to Key: The Derivation Pipeline A pass story is a human-legible secret. Cryptographic systems need bytes. The pipeline from one to the other must be deterministic, one-way, and resistant to both classical and quantum attack. ### Step 1: Normalization The raw input is normalized to eliminate ambiguity: - Unicode NFC normalization - Lowercase - Whitespace collapsed to single spaces - Leading and trailing whitespace stripped per slot The user is informed of these rules: *"Your story ignores capitalization and extra spaces. Only your words matter."* ### Step 2: Canonical encoding The 23 normalized slot values are concatenated with a fixed delimiter that cannot appear in any slot (e.g., `\x00`): ``` canonical = slot_1 || \x00 || slot_2 || \x00 || ... || slot_23 ``` ### Step 3: Key derivation The canonical string is fed into a memory-hard key derivation function. **Argon2id** is the current best practice -- it resists GPU attacks, ASIC attacks, and side-channel attacks: ``` salt = user_id || registration_timestamp key = Argon2id(canonical, salt, memory=256MB, iterations=4, parallelism=4) ``` The high memory parameter makes brute-force attacks expensive even for attackers with specialized hardware. The salt prevents precomputation across users. ### Step 4: Key expansion The derived key is expanded via HKDF into purpose-specific subkeys: ``` identity_key = HKDF-SHA512(key, info="identity") encryption_key = HKDF-SHA512(key, info="encryption") signing_key = HKDF-SHA512(key, info="signing") recovery_key = HKDF-SHA512(key, info="recovery") ``` Each subkey feeds into the appropriate cryptographic primitive within SyncEngine. The identity key proves who you are. The encryption key protects your data. The signing key authenticates your actions. The recovery key enables account restoration. ### Step 5: Post-quantum primitives The subkeys are used with post-quantum algorithms: - **ML-KEM** (formerly CRYSTALS-Kyber) for key encapsulation - **ML-DSA** (formerly CRYSTALS-Dilithium) for digital signatures - **BLAKE3** for hashing where applicable These algorithms are resistant to Shor's algorithm. Combined with the entropy gate ensuring sufficient classical entropy, the full pipeline achieves quantum resistance: Grover's algorithm halves the effective entropy, but 256+ classical bits still yields 128+ quantum bits, meeting NIST Post-Quantum Level 1. --- ## Quantum Security Analysis The pass story's quantum resistance rests on three independent pillars. **Pillar 1: Compositional entropy.** The 23 slots compose multiplicatively, not additively. Even at a conservative 10 bits per slot, the search space is 2^230 — yielding 2^115 bits of quantum security after Grover's halving. At 12 bits per slot, it's 2^276 classical / 2^138 quantum. The entropy gate enforces a minimum of 256 classical bits, but the compositional structure means most users exceed it substantially. Autobiographical inputs typically carry higher per-slot entropy than fictional choices. Real memories are drawn from the full complexity of a life; fictional choices tend to cluster around narrative archetypes. The gate rarely fires for users telling their real story. **Pillar 2: Post-quantum cryptographic primitives.** Even infinite entropy in the passphrase cannot save a system that uses RSA or ECC for its actual cryptographic operations. Shor's algorithm breaks those regardless of key size. The SyncEngine pipeline uses lattice-based cryptography (ML-KEM, ML-DSA) which has no known quantum speedup. The pass story derives the keys; the lattice math protects them. **Pillar 3: Memory-hard key derivation.** Argon2id's memory requirement makes quantum brute force even harder. A quantum computer running Grover's algorithm would need to evaluate Argon2id at each step, and each evaluation requires 256MB of memory. Quantum computers do not have cheap memory. The memory-hardness acts as a quantum tax on top of the entropy halving. The three pillars are independent. Any one of them could be weakened without compromising the others. Together, they provide defense in depth. --- ## Threat Model No system is secure against all threats. Here is what a pass story defends against and what it doesn't. ### Attacks the pass story resists **Brute force.** The 23-slot composition creates a search space of at least 2^230, behind a memory-hard KDF requiring 256MB per evaluation, using post-quantum primitives. Non-decomposability means no shortcut exists — an attacker cannot verify individual slots and must guess the entire story at once. The cost of brute-forcing this exceeds the energy output of the sun over its remaining lifetime. **Phishing.** The pass story is never transmitted as a whole. Authentication happens locally: the user retells their story on their own device, the device derives the key, and only the derived key (or a proof derived from it) touches the network. There is nothing to intercept. **Credential stuffing.** Every user's story is unique, and non-decomposability is the primary defense: there is no "common password" equivalent to try across accounts, because even a partially-correct story produces a completely wrong key. The slot-aware frequency model provides additional protection by preventing the most generic word choices from being accepted. **Shoulder surfing.** An observer would need to read and memorize 23 words in context -- far harder than watching someone type an 8-character password. The story can also be entered one stage at a time, with each stage clearing the screen. **Server breach.** The server never stores the story. It stores only the Argon2id hash. Reversing Argon2id to recover the original story is computationally infeasible. ### Attacks the pass story does not resist **Rubber hose cryptanalysis.** If someone can compel you to reveal your story, no authentication scheme helps. This is a social and legal problem, not a cryptographic one. **Malware on the device.** If an attacker has a keylogger on the device where you enter your story, they capture the words as you type them. Device security is a prerequisite, not a feature of the authentication layer. **Story drift.** This is the pass story's unique vulnerability. Over months or years, a user might subtly alter their story -- swapping "shattered" for "broke," or "astrolabe" for "compass." The normalization layer handles capitalization and spacing, but it cannot handle synonym substitution. Mitigation strategies are discussed below. --- ## Mitigating Story Drift Story drift is the one risk that is unique to this system. Traditional passwords either match or don't. A story, being narrative, is subject to the human tendency to remember the *gist* of things rather than the *words*. Three mechanisms address this. ### 1. Rehearsal protocol During the first week after story creation, the system prompts the user to retell their story three times at increasing intervals (day 1, day 3, day 7). This follows the **spaced repetition** schedule known to optimize long-term retention. After the first week, the prompts become monthly. Each rehearsal is a normal authentication attempt. If the user gets a word wrong, the system tells them *which stage* failed (but not what the correct word was) and lets them try again. This immediate feedback corrects drift before it solidifies. ### 2. Story confirmation display Every successful authentication ends with the full story displayed on screen for a few seconds. The user passively reads their own story every time they log in. This incidental re-exposure reinforces the exact wording without requiring active effort. ### 3. Partial recovery If a user gets most of their story right but fails on one or two slots, and can verify their identity through a secondary channel (trusted steward confirmation, recovery key held by a friend, etc.), the system can reveal the forgotten slot(s) and require a new rehearsal cycle. This is not a backdoor. The secondary channel does not grant access -- it grants *a hint*. The user must still retell the complete correct story to derive their key. --- ## The Experience of Authentication Here is what it feels like to log in with a pass story. Ember opens SyncEngine on her phone. The screen shows the first stage of her journey: > *"I grew up in `_____`, where I was a `_____`."* She types: `amaranth`. Then: `horologist`. She smiles. She did grow up surrounded by amaranth — her grandmother's garden was full of it. And she was a horologist in the way that matters: she took apart every clock in the house before she turned ten. The screen transitions to the next stage: > *"Everything changed when `_____` brought me `_____`."* She types her words. And the next. And the next. Each stage brings back a real memory — a place, a person, an object, a feeling. The story she's telling is the story of her life, organized by the oldest narrative structure humans know. It takes about ninety seconds. Longer than a password. But she doesn't need a password manager, doesn't need to find a hardware token, doesn't need to check her email for a magic link, doesn't need to hold her face up to the camera. She just remembers who she is. When she finishes, her full story appears on screen for a moment — a small autobiography she wrote, about a journey she actually lived. She reads a word and remembers the smell of her grandmother's garden. Then the story fades, the key is derived, and she's in. She has just performed 256-bit quantum-resistant authentication by remembering her own life. --- ## Implementation Considerations ### Word list for entropy estimation The frequency model requires a large reference corpus. We recommend initializing from: - **English word frequency:** COCA (Corpus of Contemporary American English), 60,000+ words with frequency ranks - **Narrative word frequency:** A subset weighted toward creative/literary usage - **Positional priors:** Bootstrap from a small study of template responses, then update with differential privacy as real data accumulates The model must be **public**. Security through obscurity in the frequency model would be a vulnerability -- an attacker who obtains it gains an advantage over one who doesn't. If the model is public, all attackers are on equal footing, and the entropy estimate is honest. ### Internationalization The template sentences can be translated. The word slots are language-agnostic -- the system normalizes Unicode and the frequency model can be extended per language. A user who writes in Mandarin, Arabic, or Swahili gets the same entropy guarantees as one who writes in English, provided the frequency model covers that language. ### Accessibility For users who cannot type fluently, the system can offer voice input with speech-to-text normalization. The story metaphor works especially well in oral cultures, where narrative memory is the oldest and most natural form of knowledge preservation. ### Storage requirements Per user, the system stores: - Argon2id hash of the canonical story (128 bytes) - Salt (32 bytes) - Entropy estimate at creation time (4 bytes) - Rehearsal schedule metadata (64 bytes) Total: under 256 bytes per user. The story itself is never stored anywhere. --- ## Why This Matters Beyond Security Most authentication systems treat identity as a problem to be solved — a gate to get through, a barrier between you and what you want to do. They are adversarial by design: the system assumes you might be lying and demands proof. A pass story treats identity as something you *remember*. The act of authentication is not a challenge-response protocol. It's a recitation — a small ritual in which you recall where you came from, what you faced, and what you became. You don't imagine a character. You remember yourself. In the [first article](indras-network-every-node-a-mirror.md), we described Indra's Network as a system where every node is a mirror reflecting every other. In the [second](your-network-has-an-immune-system.md), we described a network that protects itself the way a body does — through local sentiment, not central authority. In the [third](your-files-live-with-you.md), we described files that live with their owners, not on distant servers. This article describes the door. And the door asks the only question that matters: *Tell me your story.* --- ## Summary | Property | Pass story | Traditional password | Seed phrase | |----------|-----------|---------------------|-------------| | Memorability | High (narrative memory) | Low (arbitrary strings) | Very low (random words) | | Structure | 23 independent passwords, one story | Single string | 12-24 random words | | Decomposability | None (all-or-nothing KDF) | N/A (single input) | N/A (single input) | | Entropy floor | 256 bits (enforced) | ~30 bits (typical) | 128-256 bits (fixed) | | Quantum resistance | Yes (3 pillars) | No (insufficient entropy) | Partial (entropy only) | | Phishing resistance | High (local derivation) | Low (transmitted) | Medium (rarely entered) | | Rotation | Full (write a new story) | Full | Costly (new wallet) | | Personal meaning | Core design goal (autobiographical) | None | None | | Authentication time | ~90 seconds | ~5 seconds | Rarely used for auth | | Recovery | Partial (steward hints) | Email/SMS reset | Metal plate in a safe | --- *In Indra's Net, every jewel reflects every other. But first, each jewel must know its own light. Your story is that light. Tell it, and the network knows you.* ======================================================================== # SOURCE: Article: Your Files Live With You — Storage That Follows You Home # https://www.syncengine.earth/articles/your-files-live-with-you.md ======================================================================== # Your Files Live With You ### *How a peer-to-peer filesystem turns sharing into a spectrum of trust* --- We trust differently with different people. You'd lend your favorite book to one friend and never to another. You'd show a coworker your rough draft but wouldn't email it to them. You'd hand your house keys to your sister for a week and want them back. You'd give your old car to your kid and mean it forever. Every one of these is a different act of sharing. Every one carries a different weight of trust. And every digital tool you've ever used collapses all of them into a single gesture: *share*. You press the button and it's gone. The file is copied. The link is forwarded. The attachment lives in their inbox until the heat death of their storage quota. You can't lend a file. You can't show someone something without giving it away. You can't hand someone a key and ask for it back on Friday. The nuance of human trust -- the spectrum from "glance at this" to "this is yours forever" -- is erased the moment you go digital. We built a filesystem that brings it back. ✦ --- ## 🗂️ The Problem: Sharing Without Nuance Think about how sharing works in the tools you use today. Google Drive, Dropbox, a shared folder on your company's server. You put a file somewhere, you set some permissions, and you hope for the best. But the moment you share, control fractures. The file is copied to their device. The link gets forwarded to someone you've never met. The attachment sits in three different inboxes, each one a copy you can't touch. You shared it with your team of five and now seventeen people have it. You sent a draft to a client and they still have the version from six months ago that you'd rather they didn't. "Share" in these systems means "duplicate and distribute." It's a photocopy machine, not a handshake. The person who receives your file doesn't receive *your trust* -- they receive a copy that exists independently of you, your intentions, and your relationship with them. Compare this to how trust actually works in physical life. You hand a friend a photograph. They look at it, hand it back. That's a viewing. You give a colleague your notes. They photocopy them, keep the copy, and share it with their team. That's co-ownership. You lend your neighbor a tool. They use it for a week and return it. That's bounded trust. You give your old guitar to your daughter. It's hers now. That's a transfer. Each of these carries different weight. Each one says something different about the relationship. And none of them is a "share link." > Sharing in every tool you use today is collapsed into a binary: you either share or you don't. The gradient of trust -- the thing that makes human relationships work -- vanishes. --- ## 🏠 Your Files Live With You In Indra's Network, every user has a **Home Realm** -- a personal space that belongs to them and nobody else. It's derived deterministically from their identity: a BLAKE3 hash of `home-realm-v1:` concatenated with their member ID. The same identity always produces the same Home Realm. It doesn't matter which device you're on -- your phone, your laptop, your tablet -- they all access the same space, because the space is a function of who you are. Nobody else can enter your Home Realm. It isn't a folder on someone else's server that you've been given permission to use. It's *yours* the way your thoughts are yours. It exists because you exist. Inside your Home Realm lives the **ArtifactIndex** -- a single document that tracks everything you own. It's a CRDT, which means it synchronizes automatically across all your devices without conflicts, even if you're offline on some of them. This is your source of truth. Every file you add to this system gets: - A **BLAKE3 content hash** as its identity -- the file's unique fingerprint, computed from its contents. The same file always produces the same hash. Two identical files are recognized as the same artifact, automatically. - A **HomeArtifactEntry** with its name, size, MIME type, lifecycle status, and a list of access grants. - Storage as a **blob** in your node's storage layer. One file, one blob, one metadata record. > "One blob, one metadata record." Artifacts are never duplicated across realms. Sharing doesn't copy the file -- it grants access to the original. This is the key idea, and it inverts everything you know about digital sharing: **sharing is an act you perform, not a location you put things.** Your files don't move to a shared folder. They stay in your Home Realm. You extend a hand outward -- a grant, a permission, a gesture of trust -- and someone else can see what you chose to show them. The file lives with you. Always. --- ## 💛 A Spectrum of Trust This is the heart of the system: four access modes, each expressing a different depth of trust. | Mode | What it means | View | Download | Reshare | Can revoke | Expires | Trust level | |------|--------------|------|----------|---------|------------|---------|-------------| | **Revocable** | "I trust you to see this" | Yes | No | No | Yes | No | Provisional | | **Permanent** | "I trust you with this completely" | Yes | Yes | Yes | No | No | Deep | | **Timed** | "I trust you with this for now" | Yes | No | No | Yes | Yes | Bounded | | **Transfer** | "This belongs to you now" | -- | -- | -- | -- | -- | Complete | These aren't just permission levels. They're *social acts*. Each one says something different about how you relate to the person receiving access. Let's make this concrete. --- Ember is a designer working on a brand refresh for a community project. She has mood boards, brand guidelines, draft concepts, and final assets -- all stored in her Home Realm. **Soren** is new to the team. He joined last week. Ember likes him, but she doesn't know him well yet. She shares the mood board with Soren using **Revocable** access. He can look at it. He can study the colors, the textures, the references she's collected. But he can't download it, can't reshare it, and if things don't work out -- if Soren turns out to not be a good fit, if the project direction changes, if Ember simply changes her mind -- she can take the access back. No confrontation. No awkward email asking him to delete something. She adjusts the grant, and his window into the mood board closes. This is the first step of trust. Showing without giving. **Caspian** has been Ember's collaborator for years. They've built three projects together. She trusts his judgment, his discretion, and his taste. Ember shares the brand guidelines with Caspian using **Permanent** access. He can download them. He can save his own copy. He can reshare them with the sub-team he's managing. And here's the part that matters: Ember can never revoke this access. Not because the system is broken -- because the system is working. Permanent means permanent. It's a commitment. The irrevocability *is* the gesture. It says: I trust you with this completely, and I won't take that back. This is co-ownership. It means something precisely because it can't be undone. **Wren** is a consultant brought in for a week to review the brand direction. She's good at what she does, but she's temporary. Ember shares a draft with Wren using **Timed** access, set to expire Friday. Wren can review the work, leave her feedback, reference the designs in her evaluation -- and when Friday arrives, the access dissolves on its own. No awkward "please delete that when you're done" conversation. No wondering whether the contractor still has your files six months later. The boundary is built into the act of sharing. This is bounded trust. Trust with a horizon. Months later, the project evolves. Ember is moving on to other work. **Juniper** is taking over as project lead. Ember **transfers** the final assets to Juniper. This is the ultimate act: ownership itself moves. Juniper becomes the owner. A new HomeArtifactEntry appears in Juniper's index, with full provenance -- recording that Ember was the original creator, that the transfer happened on this date, via this mechanism. Ember automatically receives Revocable access back to what she made. She can still see her work. But Juniper controls it now. And Caspian? Caspian keeps his Permanent access. Co-ownership survives ownership changes. Because that's what co-ownership means. > Revocable is the default mode. When you share without specifying, the system assumes the most cautious trust level. You have to deliberately choose to trust more deeply. The architecture makes generosity intentional. --- ## 🔄 What Revocation Actually Means Two operations. Two very different meanings. **Revoke** removes a single person's access to a single artifact. Ember can revoke Soren's access to the mood board at any time. His grant disappears. The next time his device checks, the window is closed. But try to revoke Caspian's Permanent grant, and the system refuses. Not silently -- it returns a `CannotRevoke` error. This isn't a bug or a limitation. It's the architecture enforcing social meaning. You made a commitment when you granted Permanent access. The code holds you to it. This is enforced at the data structure level, not by policy, not by terms of service, not by a moderator's discretion. The Rust type system won't let you construct a revocation of a Permanent grant. The commitment is structural. **Recall** is the nuclear option. It removes *all* Revocable and Timed grants on an artifact at once. Every casual viewer, every temporary consultant, every person who had provisional access -- gone. The artifact's status changes to Recalled. But Permanent grants survive recall. Caspian still has access. Co-owners keep theirs. Because real co-ownership can't be taken back by a unilateral decision. > Recall is like pulling something off a shared shelf. Casual viewers lose access. Co-owners keep theirs. Because co-ownership that can be revoked isn't co-ownership at all -- it's a lease dressed up in nicer language. The revocation system uses defense in depth. When access is revoked, three things happen: the grant is removed from the ArtifactIndex, the per-artifact encryption key is deleted (rendering any cached ciphertext undecryptable), and a signed RevocationEntry is broadcast to all connected peers. Online peers delete their local copy immediately. Offline peers delete on next sync. A tombstone remains in the audit trail -- proof that the artifact existed, that it was recalled, and when. The content is gone. The record remains. --- ## 🎁 Giving Things Away Transfer is the deepest expression of trust in the system. It says: this thing I made, this thing I own, I'm giving it to you. Not sharing. Not lending. *Giving.* When Ember transfers the final brand assets to Juniper, here's what happens under the surface: 1. Ember's original HomeArtifactEntry changes status to **Transferred**, recording who received it and when. The entry remains in Ember's index as a historical record -- she can see that she once owned this, and where it went. 2. A new HomeArtifactEntry appears in Juniper's ArtifactIndex. It's Active. Juniper is the owner now. 3. Ember automatically receives **Revocable** access back to the artifact. She can still see what she made. But Juniper could revoke even that, if she chose to. The creator becomes a viewer at the new owner's discretion. 4. All **Permanent** grants are inherited. Caspian had Permanent access from Ember. He still has Permanent access under Juniper. Co-ownership travels with the artifact, because co-ownership is a relationship with the *work*, not just with whoever happens to hold the title. 5. The new entry carries full **provenance**: an ArtifactProvenance record listing the original owner, who it was received from, when, and how (in this case, via Transfer). If Juniper later transfers the assets to someone else, the chain extends. Every received artifact carries its history. You can always trace the lineage back to the creator. This provenance system means artifacts have memory. They know where they came from. In a world where digital files are infinitely copyable and endlessly anonymous, this is quietly radical: a file that remembers who made it and every hand it passed through. Think about what Ember experiences. She poured weeks into these brand assets. She's leaving the project, but the work continues. Transfer lets her say: *this is yours now, take care of it* -- and walk away knowing the provenance records her contribution permanently. She didn't just upload a file to a shared drive and hope someone notices the metadata. She performed an act of giving, and the system remembers. --- ## 🪟 Shared Spaces as Shared Views So far we've talked about individual sharing -- one person granting access to another. But groups work together in shared spaces. In Indra's Network, these are **realms**: collaborative spaces where multiple people interact. Here's the crucial insight: shared realms don't store artifacts. They don't contain files. They don't have a "shared folder" where things accumulate. Instead, a realm *queries* each member's Home Realm and shows the intersection -- only artifacts where **every** member has an active grant. The function is called `accessible_by_all`. It takes the list of realm members and the current time, and returns only the artifacts where every single member has a non-expired grant. If Ember shared a file with Caspian and Soren but not Wren, and all four are in the same realm, that file doesn't appear in the realm view. Everyone has to have access for the realm to reflect it. A realm is a **window**, not a container. A view into what everyone agreed to share. The artifacts stay in their owners' Home Realms. The realm just shows what's visible to all. Two sharing patterns make this flexible: 1. **Broadcast**: `share_artifact_with_mode` -- grants the same access mode to every member of the realm. Ember can share a reference image with the whole team at Revocable. Everyone sees it. Everyone can lose it if she recalls. 2. **Granular**: `share_artifact_granular` -- different modes for different people. Ember can share the same artifact into the realm but give Caspian Permanent access and everyone else Revocable. The realm shows the artifact to everyone (because everyone has *some* grant), but the depth of trust varies per person. This means the same shared space can contain different trust relationships simultaneously. Caspian can download the brand guidelines and reshare them. Soren can view but not save. Wren's access will expire on Friday. They're all looking at the same realm, seeing the same artifact -- but their relationship to it is different. The view adapts to the trust topology within it. No shared folder in the history of computing has ever worked this way. Shared folders are containers. Realms are lenses. --- ## 🛟 When You Lose Everything Your phone falls in a river. Your laptop's drive dies. A fire takes your home office. You've lost your device, and with it, your Home Realm. In a centralized system, this is either fine (because the cloud has your data) or catastrophic (because you had no backup). There's no middle ground. Your safety depends entirely on whether you were paying a company to store copies. In Indra's Network, your safety depends on something more interesting: the people you trusted. The sharing model doubles as a distributed backup system. Here's how recovery works: 1. You set up a new device and regenerate your identity. Your Home Realm ID is deterministic -- same identity, same realm -- so your new device knows *where* your data should be, even though it's empty. 2. You send an `ArtifactRecoveryRequest` to your known contacts -- the people you've shared things with, the people who've shared things with you. 3. Each peer checks their local blob store and their grant records. They know what artifacts they hold and what access mode they have. 4. Each peer responds with a `RecoveryManifest` -- a list of everything they can help restore, including the artifact name, size, type, access mode, and original owner. 5. You review the manifests and select what to recover. Your node rebuilds the ArtifactIndex entries from the recovered data and metadata. The quality of recovery depends directly on the access mode: - **Permanent and Transfer** holders are **fully recoverable**. They have download rights, which means they hold the actual blob data locally. Caspian has a complete copy of the brand guidelines. He can send it back whole. - **Revocable and Timed** holders are **best-effort**. They may have viewed the artifact, but they don't necessarily have the blob cached locally. Recovery from these peers is possible but not guaranteed. > Permanent grants serve double duty -- they're not just about sharing, they're about resilience. The more co-owners an artifact has, the more places it exists, the more recoverable it is. Trust makes your data safer. This is the beautiful consequence of the design, and it wasn't bolted on as an afterthought. It's an emergent property of the trust model. When Ember gave Caspian Permanent access to the brand guidelines, she wasn't just trusting him with the work. She was, without thinking about it, creating a backup. If Ember loses everything, Caspian can give it back. If both Ember and Caspian lose everything, whoever Caspian reshared with can help. The trust network *is* the recovery network. Generosity with trust creates a safety net. The people you trusted most are the ones who can help you recover. The wider your circle of deep trust, the more resilient your data becomes. In a system where hoarding is the norm -- where you protect by restricting -- Indra's Network creates an architecture where you protect by *sharing*. --- ## ✦ What Emerges Step back from the mechanisms. Forget the BLAKE3 hashes and the CRDT synchronization and the Rust type system for a moment. Look at what this architecture produces as a human experience. What does it mean when sharing carries weight? When granting someone Permanent access is a meaningful act -- something you think about, something that can't be undone? When the difference between "take a look" and "this is yours" is encoded in the infrastructure itself? What does it mean when digital trust has a gradient? When you can lend without giving, show without surrendering, set a boundary that enforces itself? What does it mean when your files genuinely belong to you? Not hosted on a server you don't control. Not stored in a cloud that could change its terms tomorrow. Living in your Home Realm, derived from your identity, accessible from any of your devices, owned by you in the most literal sense the word can carry? What does it mean when the more trust you extend, the more resilient your data becomes? - 🔒 A filesystem where your files are genuinely yours -- not hosted on someone else's server, not subject to someone else's terms - 🤝 Sharing that preserves the nuance of human trust -- provisional, permanent, bounded, or complete - 📎 No duplication -- the file exists once, sharing is a pointer plus permission - 🛡️ Revocation that actually works -- you can take back what you showed, not just hope they deleted it - 🌐 Recovery through trust -- co-owners are your distributed backup - 🔗 Shared spaces as views, not containers -- realms reflect trust, they don't trap files What emerges from this architecture isn't just a filesystem. It's a **trust fabric**. Every grant, every revocation, every transfer carries social meaning. The network doesn't just store your files -- it encodes your relationships. In the [first article](indras-network-every-node-a-mirror.md), we described a transport layer with no center -- messages bouncing between peers like light between jewels. In the [second](your-network-has-an-immune-system.md), an immune system with no moderator -- communities protecting themselves through local sentiment and emergent response. Now, a filesystem with no cloud -- files that live with their owners, shared through acts of trust rather than acts of copying. The pattern holds: **the participants are the infrastructure.** --- ## 🌅 What Comes Next The shared filesystem described here is built and working. Content-addressed storage with BLAKE3. Four-mode access control -- Revocable, Permanent, Timed, Transfer. CRDT-synchronized artifact index. Realm-level views computed from trust intersections. Peer recovery through grant-based distributed backup. Provenance chains that trace every artifact's lineage. All of it implemented, tested, and running in Rust. What gets built on top -- the economies, the governance, the creative possibilities that emerge when communities own their own storage and their own trust relationships -- is the subject of future articles. --- *What would you share differently if sharing had weight?* 💬 **This is Part 3** of a series on Indra's Network. [Part 1: Every Node a Mirror](indras-network-every-node-a-mirror.md) covers the transport layer. [Part 2: Your Network Has an Immune System](your-network-has-an-immune-system.md) covers the social defense layer. **Subscribe** for future articles on the economic layer -- how groups that own their own infrastructure can build their own economies. ======================================================================== # SOURCE: Article: Nobody Owns the Conversation — Stewardship Over Ownership # https://www.syncengine.earth/articles/nobody-owns-the-conversation.md ======================================================================== # Nobody Owns the Conversation ### *How single stewardship and fractal composition solve the problem that group ownership never could* --- Who owns a conversation you're both having? Sit across a table from Ember at a coffee shop. You're talking about something that matters -- a project, a breakup, an idea for a business. The words hang in the air between you. Nobody owns them. You both carry the memory of what was said, and those memories will diverge -- you'll remember the part about the business differently than she remembers the part about the breakup. That's fine. That's how conversation works. Two people, two experiences, one shared moment that lives differently in each mind. Now open any messaging app. Whose conversation is it? It lives on a server you don't control, in a database you can't inspect, governed by terms of service you didn't read. If the platform goes down, you both lose it. If one person deletes the thread, does the other person lose it too? It depends on the app. It depends on the company. It depends on what day it is and what some product manager decided three years ago. Digital systems force a question that physical life never asks. Every shared thing needs an owner. Every group chat needs an admin. Every document needs a single source of truth. Every repository needs a maintainer with merge rights. The architecture demands it: *someone has to be in charge of this thing.* We built a system where nobody has to be in charge -- because everyone is in charge of their own piece. The architecture is the collaboration. ✦ --- ## 🪑 The Temptation of Group Ownership When you first encounter this problem, the obvious solution is: make it shared. Give the conversation two owners. Give the document a list of stewards. Build a `stewards: Vec` and let everyone on the list have equal authority. It seems right. Collaboration is shared. So stewardship should be shared. Here's what happens the moment you try. **Conflict resolution.** Sage and Orion are co-stewards of a collaborative story. Sage wants to add Lyra's chapter. Orion doesn't think it's ready. Who wins? With a single steward, the answer is clear -- the steward decides. With two stewards, you need a tiebreaker. Do you vote? Who breaks ties in a list of two? Do you add a third steward? Now you need majority rules. Now you have a committee. **Transfer semantics.** Sage wants to step down. She wants to transfer her stewardship to Wren. Does Orion get a say? In a single-steward model, transfer is a clean handoff. In a multi-steward model, adding or removing a steward requires consensus among the existing stewards. You've invented governance overhead for a collaborative project that just wanted to make something together. **Audience control.** The steward decides who can see an artifact. With two stewards, can either one unilaterally change the audience? If yes, one steward can expose the work against the other's wishes. If no, you need consensus for every audience change. You've built a system where sharing requires a vote. **Sync complexity.** In a distributed system, stewards are on different devices, often offline. Multi-steward consensus requires coordination. Coordination requires communication. Communication requires connectivity. You've taken a system designed to work offline and given it a component that requires everyone to be online at the same time to make decisions. > Every committee needs a chair. Multi-steward artifacts don't eliminate the need for a single authority -- they just obscure it behind consensus overhead. The deeper problem is philosophical. Group ownership sounds like collaboration, but it's actually a governance structure. And governance structures are not the same thing as creative collaboration. A band doesn't need three people to own the album. It needs three people to each own their track, and someone to sequence them. --- ## 🌿 What Stewardship Actually Means The word "steward" is deliberate. Not "owner." Not "admin." Not "controller." A steward tends a space. A park steward doesn't own the park -- they care for it. They decide what grows there, who visits, how the paths are maintained. The park belongs to the community, but the steward is the one who shows up every morning to make sure it's a good place to be. In Indra's Network, the steward of an artifact is responsible for three things: **Audience.** Who can see this? The steward sets the audience -- the list of players who have access. This is the `audience: Vec` field on every artifact. The steward curates visibility. **Structure.** What belongs here? For tree artifacts -- stories, galleries, collections, documents -- the steward decides what gets composed into the tree. The `compose()` operation that adds a child reference is steward-only. The steward curates arrangement. **Continuity.** What happens next? If the steward moves on, they can transfer stewardship to someone else via `transfer_stewardship()`. The transfer is recorded. The history is preserved. Someone new picks up the care. That responsibility is singular. One entity is accountable. Not because collaboration isn't valued -- because accountability requires a single point. When something goes wrong with the audience, when something doesn't belong in the tree, when the artifact needs tending -- you know exactly who to talk to. There's no diffusion of responsibility, no bystander effect, no "I thought you were handling it." > Stewardship is care, not control. A steward doesn't own the thing -- they tend it. And tending is a singular act. --- ## 🌀 The Fractal Insight If stewardship is singular, how do people collaborate? Not through shared control. Through **composition**. Think about how a music album works. The album has a producer -- one person who sequences the tracks, decides the order, shapes the arc. Each track has an artist -- one person (or group) who created that piece. The producer doesn't own the tracks. The artists don't control the album. Each stewards their own contribution, and the album is the composition. This is exactly how tree artifacts work in Indra's Network. Caspian is convening a collaborative document -- a community guide to urban food forests. He creates a tree artifact (`TreeType::Document`) and becomes its steward. He controls the structure: what sections appear, in what order, for what audience. Ember writes a chapter on soil preparation. She creates it in her own vault as a tree artifact. She stewards it. She controls its content, its audience, its continuity. Caspian composes Ember's chapter into his document. He adds a reference -- an `ArtifactRef` pointing to her chapter, at position 3, labeled "Soil Preparation." The reference is a pointer, not a copy. Ember's chapter lives in Ember's vault. Caspian's document references it. Now Sage contributes a chapter on companion planting. Orion writes one on water harvesting. Lyra adds a photo gallery of her food forest in its third year. Each person stewards their own piece. Caspian's document tree references all of them. ``` Caspian's Document (steward: Caspian) ├── [0] Introduction (steward: Caspian) ├── [1] Why Food Forests (steward: Caspian) ├── [2] Site Selection (steward: Orion) ├── [3] Soil Preparation (steward: Ember) ├── [4] Companion Planting (steward: Sage) ├── [5] Water Harvesting (steward: Orion) ├── [6] Photo Gallery (steward: Lyra) └── [7] Resources (steward: Caspian) ``` Caspian can reorder the chapters. He can adjust the audience for the whole document. He can add a new contributor's section or remove one that doesn't fit. But he can't edit Ember's chapter -- that's her artifact, in her vault, under her stewardship. If he wants changes, he asks. If she agrees, she makes them. Her sovereignty over her contribution is absolute. This is **fractal**. The same pattern repeats at every scale. Ember's chapter might itself be a tree with sub-sections, each potentially contributed by different people. Lyra's gallery contains individual photos, each a leaf artifact she stewards. The tree goes as deep as the collaboration requires, and at every level, every node has exactly one steward. > Collaboration doesn't require shared control. It requires composition. Each person stewards their own contribution. The tree structure weaves contributions together. Individual sovereignty, collective creation. --- ## 💬 Conversations: The Hardest Case The fractal model works beautifully for documents and galleries. But what about a conversation? In a DM between Ember and Caspian, both players need to append messages. If the conversation has a single steward, and only the steward can compose into the tree, then only one person can add messages. That's not a conversation. That's a lecture. This is where the distributed architecture does something elegant. In Indra's Network, a DM conversation doesn't exist in one place. It exists in two: one copy in Ember's vault, one copy in Caspian's vault. Each copy is a Story artifact with the same deterministic ID -- computed from both player IDs using `dm_story_id()`, which produces the same result regardless of who calls it. Same conversation, same identity, two stewards -- one per copy. Ember's vault holds a Story stewarded by Ember. Caspian's vault holds a Story stewarded by Caspian. Both append messages to their own copy. When their devices sync, the reference lists merge. Messages Ember sent appear in Caspian's copy. Messages Caspian sent appear in Ember's. The "shared conversation" is an emergent view. It exists in both vaults, differently stewarded, converging through sync. Neither person owns the conversation. Both tend their copy of it. Look at what this solves: - **Appending:** Each player composes into their own tree. No permission conflict. No need for multi-steward consensus. - **Deletion:** If Ember deletes a message from her copy, it disappears from her view. Caspian's copy is unaffected. Each steward controls their own experience. - **Availability:** If Ember's device is offline, Caspian can still read and write in his copy. Sync catches up later. - **Sovereignty:** Nobody can unilaterally destroy the conversation. Each player's copy is theirs. Walking away from a conversation means stopping your sync, not deleting someone else's memories. > Nobody owns the conversation. Both tend their copy of it. The "shared conversation" is an emergent view -- it exists in both vaults, differently stewarded, converging through sync. --- ## 🏗️ Scaling Up: The Collaborative Project A two-person conversation is one thing. What about a group creation with a dozen contributors? Indigo is organizing a community zine. Twelve people are contributing -- essays, illustrations, poems, interviews. The zine is a tree artifact in Indigo's vault, stewarded by Indigo. They curate the structure: what appears, in what order, with what framing. Each contributor creates their piece in their own vault. Rune writes a poem. Solene draws an illustration. Theron conducts and records an interview. Each artifact is stewarded by its creator. Indigo composes references to all of them into the zine tree. Six months later, Indigo moves to a new city and doesn't have the bandwidth to maintain the zine. They transfer stewardship of the top-level tree to Cypress, who picks up the curatorial role. What happens to the contributors' work? Nothing. Absolutely nothing. Rune's poem is still Rune's poem, in Rune's vault, under Rune's stewardship. The transfer of the zine's top-level tree doesn't affect any sub-tree. Contributors' sovereignty over their own work is independent of who curates the collection. Cypress can reorder the zine, change the audience, add new pieces. But Rune's poem remains Rune's to edit, share, or withdraw. If Rune decides to pull their poem from the zine, they can revoke the access that lets the zine reference it. The reference in Cypress's tree points to something the audience can no longer see. The zine has a gap. That's the contributor's sovereign choice. The curator can fill the gap or leave it. Neither controls the other. This is how creative collaboration actually works in the physical world. An anthology editor doesn't own the stories. A gallery curator doesn't own the paintings. A festival organizer doesn't own the performances. Each person brings their contribution. Someone arranges them. The whole is greater than any part. And if any contributor walks away, their work is still theirs. --- ## ✦ What Emerges Step back from the data structures. Forget `steward: PlayerId` and `ArtifactRef` and `compose()` for a moment. Look at what this architecture produces as a human experience. A system where collaboration is **additive**, not permissive. You don't ask for write access to someone else's tree. You create your own piece and it gets composed into the whole. Contributing doesn't require surrendering control. It requires creating something worth including. A system where responsibility is **clear**. Every artifact has exactly one steward. If the audience is wrong, the steward fixes it. If the structure needs rearranging, the steward does it. If the steward moves on, stewardship transfers cleanly. No committee meetings. No governance overhead. No diffusion of accountability. A system where leaving is **graceful**. A contributor can withdraw their work without destroying the collection. A curator can transfer stewardship without affecting contributors. A conversation partner can stop syncing without erasing the other person's memories. Every departure is clean because every contribution was sovereign to begin with. A system where the tree **is** the collaboration: - 🌿 Each node in the tree has one steward - 🔗 Composition connects nodes across vaults - 🔄 Sync merges what was created independently - 🌳 The tree structure grows as deep as the collaboration requires - 💎 Every contributor retains sovereignty over their piece What emerges is something that looks like shared ownership but is actually something better: **shared structure with individual sovereignty**. Nobody owns the conversation, the document, the zine, the project. Everybody owns their contribution to it. The structure that holds the contributions together is itself an artifact, stewarded by whoever tends it, transferable when they move on. In the [first article](indras-network-every-node-a-mirror.md), we described a transport layer with no center -- messages bouncing between peers like light between jewels. In the [second](your-network-has-an-immune-system.md), an immune system with no moderator -- communities protecting themselves through local sentiment. In the [third](your-files-live-with-you.md), a filesystem with no cloud -- files that live with their owners, shared through trust. In the [fourth](the-heartbeat-of-community.md), an economy with no bank -- value that emerges from trust relationships. In the [fifth](your-story-is-your-key.md), authentication with no password -- identity rooted in personal narrative. Now, collaboration with no owner. The pattern holds, once more: **the participants are the infrastructure.** Each jewel in Indra's Net reflects every other, but each jewel is its own light. Stewardship is local. Collaboration is emergent. The network doesn't need a single owner because the structure itself *is* the collaboration. --- *What would you create if contributing didn't mean giving up control?* 💬 **This is Part 6** of a series on Indra's Network. [Part 1: Every Node a Mirror](indras-network-every-node-a-mirror.md) covers the transport layer. [Part 2: Your Network Has an Immune System](your-network-has-an-immune-system.md) covers the social defense layer. [Part 3: Your Files Live With You](your-files-live-with-you.md) covers the shared filesystem. [Part 4: The Heartbeat of Community](the-heartbeat-of-community.md) covers the token economy. [Part 5: Your Story Is Your Key](your-story-is-your-key.md) covers authentication. **Subscribe** for future articles on governance, collective decision-making, and the structures that emerge when communities own their own collaboration. ======================================================================== # SOURCE: Article: The Heartbeat of Community — An Economy of Gratitude # https://www.syncengine.earth/articles/the-heartbeat-of-community.md ======================================================================== # The Heartbeat of Community ### *How subjective value, trust chains, and proof of life turn tokens into letters of introduction* --- A token travels from Nairobi to Buenos Aires through three pairs of hands. Cypress earned it by translating a community guide into Swahili -- forty minutes of careful work, witnessed by the people who asked for the help. He blessed it forward to Solene, who carried it across an ocean of network hops to a mutual aid circle in Montevideo. Solene passed it to Theron, who offered it as thanks for a meal shared at a neighborhood asado. What is it worth? If you ask Theron, it carries the warmth of the dinner and the trust he places in Solene, who has never steered him wrong. If you ask Solene, it holds the weight of Cypress's reputation -- a person she's collaborated with for two years across three time zones. If you ask a stranger with no connection to any of them, it is worth precisely nothing. Not because the token is broken. Because value, in this system, is not a number printed on a coin. It is the trust you place in the hands that carried it. Every economy on Earth assumes that a dollar is a dollar regardless of who holds it. We built an economy where that assumption is abandoned on purpose. A token's worth depends on who gave it, who carried it, and how much the person evaluating it trusts each link in the chain. The same token, the same history, valued differently by every observer. This is not a flaw. This is the design. ✦ --- ## 🛡️ The Vulnerability Before we describe the full system, we need to be honest about the problem it exists to solve. Indra's Network has a bounty system called **Tokens of Gratitude**. The original design works like this: someone posts a quest -- a request for help, a task that needs doing, a call for contribution. Another person fulfills the quest and receives attention from the community -- people witness the work, spend time evaluating it, and express gratitude. That attention gets distilled into tokens. The tokens are blessed by the people who witnessed the work, and they can be passed along, spent, or offered as thanks elsewhere in the network. It's a beautiful idea. It's also vulnerable. Here is the attack. It requires no technical sophistication, no exploits, no zero-days. Just patience and a willingness to lie. **Step 1: Create the farm.** An attacker spins up fifty accounts. In the current system, there is nothing stopping this. Each account is a valid participant with a valid identity. **Step 2: Generate synthetic attention.** The fifty fake accounts interact with each other. They post quests. They fulfill quests. They spend time -- or claim to spend time -- evaluating each other's contributions. The system registers attention events: account A watched account B's contribution for three minutes. Account C blessed account D's work. All of it looks, from the protocol's perspective, like genuine community activity. **Step 3: Concentrate the tokens.** The fake accounts bless a single confederate -- a real-looking account controlled by the attacker. Tokens of Gratitude flow inward from fifty sources, each one minted from fabricated attention. The confederate now holds a stack of tokens that appear legitimate. **Step 4: Spend into the real economy.** The confederate enters genuine communities and offers these tokens as payment, as thanks, as social currency. They look real. They have blessing histories. They came from accounts that generated attention and fulfilled quests. The attack works because the original system treats all attention as equal. If any account can generate attention, and attention mints tokens, then anyone who controls enough accounts controls the money supply. This is the sybil farm problem, and it is fatal to any token economy that doesn't address it. > The vulnerability isn't in the cryptography or the transport layer. It's in the assumption that attention is objective. It isn't. Attention from a stranger and attention from a trusted friend are fundamentally different things. --- ## 👁️ Subjective Valuation The fix is not to build a better sybil detector. It is to abandon the premise that tokens have objective value. In the redesigned system, a Token of Gratitude does not carry an intrinsic worth. It carries a *history* -- who created it, who blessed it, who held it, how long they paid attention. The worth of that history is evaluated independently by every observer, using their own trust relationships. The formula is simple: `perceived_value = attention_duration × max(sentiment_toward(blesser), 0.0)` Two variables. The first is verifiable: how long did the blesser actually spend attending to the work? The second is subjective: how much does the *evaluator* trust the person who blessed the token? Only positive sentiment counts. If the evaluator's sentiment toward the blesser is negative or zero -- if they distrust the blesser, or simply don't know them -- the contribution to value is zero. Not negative. Not penalized. Just invisible. The token doesn't become worthless in some global sense. It simply has no weight *in that observer's eyes*. This changes everything about the sybil farm attack. Zephyr receives a token. She looks at its history. It was blessed by Nova -- someone Zephyr has worked with for a year, someone she rates at +1. Nova spent twenty minutes evaluating the contribution. Zephyr's perceived value: `20 × 1.0 = 20`. That token means something to her. The same token crosses paths with Ember. Ember doesn't know Nova. Her sentiment toward Nova is 0 -- the default for strangers. Ember's perceived value: `20 × max(0.0, 0.0) = 0`. The token is invisible to Ember. Not rejected, not flagged -- simply without weight. Now consider the sybil farm. Fifty fake accounts bless a confederate's tokens. Those blessings carry attention durations and account identities. But when a real person evaluates those tokens, they run the formula against their own sentiment graph. Sentiment toward accounts they've never interacted with? Zero. Every blessing from the farm multiplies against zero. The tokens are ghosts. > A sybil farm can mint a million tokens. Every single one of them is worth zero to anyone who doesn't already trust the farm. The attack doesn't fail because it's detected. It fails because it's *irrelevant*. The same token, carried by the same chain of hands, evaluated by different observers through different trust relationships, produces different values. There is no canonical price. There is no exchange rate. There is only the question: *do you trust the people who touched this?* --- ## 🔗 The Steward Chain Tokens don't just carry a single blessing. They accumulate a **chain of custody** -- a steward chain that records every hand the token has passed through. When Cypress earns a token for his translation work, the token's chain begins with him. When he passes it to Solene, her identity is appended. When Solene passes it to Theron, his identity is appended. The chain grows: `Cypress → Solene → Theron`. Every release is a signed operation. The history is immutable. This is not a ledger in the blockchain sense -- there is no global consensus, no mining, no proof of work. It's a provenance record, like the stamps in a passport or the chain of title on a house. Each entry says: *this person held this token and chose to pass it on.* Trust decays with distance. When you evaluate a token, you don't just look at the most recent steward. You evaluate every link in the chain, and trust attenuates with each hop: `trust_weight = sentiment_toward(steward) × 0.7^hops_since` The person who last handed you the token carries full weight. The person before them is discounted to 70%. Two hops back, 49%. Three hops, 34%. By the time you're looking at someone five steps removed, their contribution to the token's perceived value has faded to 17% -- still nonzero if you trust them, but appropriately softened by distance. This makes the token a **letter of introduction**, not a coin. A coin doesn't care who held it before you. A letter of introduction is *defined* by who carried it. When Ember receives a token from Sage, and Sage received it from Nova, Ember is reading a chain of trust: Nova vouched for this value. Sage vouched for Nova's judgment by carrying it forward. Each handoff is a reputation stake. And here's the accountability mechanism: if you pass along garbage -- a token blessed by nobody trustworthy, backed by no real attention -- your name is in the chain. The next person who evaluates it sees your stewardship. If they trust you and the token turns out to be hollow, your reputation absorbs the cost. Not through an explicit punishment mechanism, but through the natural consequence of being associated with bad signal. Pass along garbage, and the people who trusted you learn to trust you a little less. Walk through the math. Ember receives a token from Sage. Sage got it from Nova. Ember's sentiment toward Sage is 0.9 (high trust). Ember's sentiment toward Nova is 0.6 (moderate trust -- she's met Nova but doesn't know her well). - Sage's contribution: `0.9 × 0.7^0 = 0.9` - Nova's contribution: `0.6 × 0.7^1 = 0.42` The token carries weight from both stewards, decayed by distance. If the chain included someone Ember doesn't know at all (sentiment 0), that link contributes nothing. The chain is only as strong as the trust relationships the evaluator has with each steward. > A Token of Gratitude is not a coin. It is a letter of introduction that says: these people, in this order, thought this was worth carrying. Whether you agree depends on whether you trust them. --- ## 🤖 Human and AI Accounts The network has two kinds of accounts, and the distinction matters for the token economy. **Human accounts** can do everything: generate attention, bless tokens, create quests, fulfill quests, and participate in all aspects of the network. Attention -- the scarce resource that backs the entire token economy -- is a fundamentally human act. It takes time. It takes judgment. It takes a person actually looking at someone else's work and deciding it has value. **AI agent accounts** are explicitly marked as non-human. They can fulfill quests -- an AI that translates a document, generates a summary, writes code, or performs analysis is doing real work and can receive tokens for it. They can hold tokens. They can pass tokens along. But they cannot generate attention, and they cannot bless tokens. The thing that mints new value into the economy -- the act of a person witnessing another person's contribution -- is reserved for humans. This is not a technical enforcement. In a decentralized system with no central authority, you cannot build a protocol-level gate that reliably distinguishes human from machine. Any such gate becomes an arms race, and the gate always loses eventually. Instead, the distinction is enforced the same way everything else in this system is enforced: **through subjective evaluation**. When you evaluate a token, you can see whether the attention that backed it came from accounts attested as human or accounts marked as AI. You can see whether the blessings came from humans. You decide what weight to give each. If a community decides that AI-generated attention is worthless, tokens backed by AI attention will carry zero value in that community -- not because the protocol blocks them, but because every member's subjective evaluation discounts them. This keeps the architecture honest. We don't pretend we can solve the human-verification problem at the protocol level. We push the judgment to the edges, where it belongs -- into the hands of the people who are actually deciding whether to trust. > Attention is the scarce human resource that backs the token economy. Machines can work. Only people can witness. --- ## 💓 Proof of Humanness If subjective evaluation of humanness is the enforcement mechanism, the network needs a way for people to make claims about their humanness that others can evaluate. This is the attestation layer. But it is not what you might expect from the phrase "proof of humanness." Most identity verification systems treat humanness as a binary: you prove you're human once, you get a credential, you carry it forever. A CAPTCHA. A biometric scan. A government ID check. One gate, one moment, one stamp. The problem with a one-time credential is that it becomes a commodity. If being "verified human" is a permanent status, the incentive to steal or forge that status is enormous. A sybil farmer who gets past the gate once has a verified human account forever. The credential decays in meaning the moment it's issued, because the issuer has no ongoing relationship with the holder. Indra's Network treats humanness as a **heartbeat**, not a credential. Freshness matters. An attestation from yesterday is worth more than one from last month. An attestation from three months ago is worth almost nothing. The decay function is exponential, with a 7-day grace period: `freshness = e^(-0.1 × max(days_since_attestation - 7, 0))` For the first seven days after an attestation, freshness is 1.0 -- full strength. On day 8, it begins to decay. By day 14, freshness has dropped to about 0.50. By day 21, it's around 0.25. By day 37, it's under 0.05 -- effectively zero. Think of it as a pulse. Each attestation is a heartbeat. Miss too many beats and the system assumes you've flatlined -- not that you're dead, but that your claim to active humanness has gone stale. You don't get banned. You don't lose your account. Your tokens simply carry less weight when evaluated by others, because the freshness multiplier in their assessment trends toward zero. This creates a continuous signal rather than a binary gate. The question is never "is this person human?" but "how recently has this person demonstrated that they're an active, embodied human being?" The answer is always a number between 0 and 1, always decaying, always in need of renewal. > Humanness is not a credential you earn once. It is a pulse that must keep beating. --- ## 🏛️ Temples of Refuge & the Bioregional Delegation Tree Who attests? In a decentralized system, there's no DMV, no passport office, no central authority that stamps your humanness card. Attestation has to emerge from the network itself. Indra's Network uses a fractal delegation structure rooted in geography -- specifically, in the bioregional hierarchy developed by OneEarth. The structure follows the actual ecological organization of the planet: | Level | Count | Example | |-------|-------|---------| | **Temples of Refuge** (root) | 1 | The global root of the delegation tree | | **Realm Temples** | 14 | Neotropical Temple, Palearctic Temple | | **Subrealm Temples** | 52 | Central America Temple, Western Africa Temple | | **Bioregion Temples** | 185 | Greater Antilles Temple, Borneo Lowlands Temple | | **Ecoregion Temples** | 844 | Cuban Moist Forests Temple, Sumatran Peat Forests Temple | | **Individual attesters** | unbounded | People on the land | Each level is the same operation: a **signed delegation**. The root Temples of Refuge delegates authority to 14 Realm Temples. Each Realm Temple delegates to its Subrealm Temples. Each Subrealm delegates to its Bioregion Temples. Each Bioregion delegates to its Ecoregion Temples. Each Ecoregion Temple delegates to individual attesters -- real people, rooted in a specific place, who can vouch for the humanness of people in their community. The delegation is a signed message: *I, the Central America Temple, authorize the Greater Antilles Temple to attest on my behalf.* And then: *I, the Greater Antilles Temple, authorize Kai to attest on my behalf.* And then: *I, Kai, attest that Zephyr is an active human being I interacted with on this date.* When someone evaluates Zephyr's humanness attestation, they see the full chain: `Temples of Refuge → Neotropical → Central America → Greater Antilles → Kai → Zephyr`. Each link is a signed delegation. The evaluator assesses each link through their own sentiment graph. And here is the critical point: **trust in the chain is subjective**. One observer might have high confidence in the Neotropical Temple and the people who run it. Another might distrust that entire branch and place more weight on attestations from the Palearctic delegation tree. A third might ignore the institutional layers entirely and evaluate only based on their direct sentiment toward Kai, the individual attester. The hierarchy provides structure. Subjectivity provides resilience. No single compromised node -- not even a compromised Realm Temple -- can force the rest of the network to accept its attestations. Each observer evaluates each link on its own merits, through their own trust relationships. The delegation tree is a *suggestion* of trust, not a *mandate*. > The bioregional tree is a scaffold for trust, not a chain of command. Every link is evaluated by every observer through their own eyes. --- ## 🎉 Proof of Life Celebrations If humanness requires a heartbeat, where does each beat come from? The most elegant answer: from the act of being alive together. In Indra's Network, **Memories** are shared artifacts created within a realm -- photos, notes, recordings, documents, anything saved to a space where multiple people are present. When you share a Memory into a realm, you are creating a shared artifact that requires the participation of embodied human beings. You were there. Other people were there. Something happened worth remembering. **Creating a shared Memory in any realm automatically refreshes the humanness attestation for all participants.** The protocol records the event: these people, in this place (physical or virtual), created something together on this date. Each participant's freshness counter resets to 1.0. The genius of this design is its friction profile. Traditional proof-of-humanness systems add friction: solve this CAPTCHA, scan your iris, submit your documents. They interrupt what you're doing to prove you're allowed to do it. In Indra's Network, the attestation *is* the activity. You don't pause your life to prove you're human. You live your life, and the proof emerges as a byproduct. A dinner with friends. Someone takes a photo, shares it to the group's realm. Everyone's humanness refreshes. A community meeting. Notes are saved to the shared space. Attestation renewed for all participants. A walk with a neighbor. You pass a blooming jacaranda tree and one of you snaps a picture, drops it in your shared realm. Heartbeat recorded. A co-working session. Kai and Soren are building something together, saving artifacts to their project realm as they go. Every shared save is a mutual attestation: we are here, we are human, we are making something. The protocol doesn't care *what* the Memory is. It cares that multiple humans were involved in creating it. The content is irrelevant to the attestation -- what matters is the act of shared creation. The system incentivizes exactly the thing it's trying to measure: people being alive together. > The token economy doesn't just tolerate community gathering. It incentivizes it. Every celebration, every shared meal, every collaborative session is a proof of life that keeps the economic engine running. --- ## ⚔️ Attack Analysis Now let's walk the attacks against the full system -- the original sybil farm, plus every variation we could think of. ### Sybil farm → tokens are invisible The fifty fake accounts generate attention, bless tokens, and funnel them to a confederate. The confederate walks into a real community and offers the tokens. Every member of the real community evaluates those tokens through their own sentiment graph. Sentiment toward the fifty fake blessers? Zero -- nobody knows them. The perceived value formula: `attention_duration × max(0.0, 0.0) = 0`. Every token from the farm is worth exactly nothing to every member of the community. The attack doesn't fail because it's detected. It fails because it's irrelevant. The sybil farmer spent resources creating accounts and generating activity that produces tokens nobody values. It's the economic equivalent of counterfeiting a currency that only works with people who trust you -- and nobody trusts you. ### Token laundering → steward chain accountability A more sophisticated attacker tries to launder sybil-minted tokens through legitimate intermediaries. They earn real trust with a real person -- Lyra, say -- and then pass her a batch of sybil-backed tokens, hoping she'll carry them further into the network. Lyra receives the tokens and sees the steward chain. The chain shows blessings from accounts she doesn't recognize. Even if she trusts the person handing them to her, the chain's deeper links carry zero weight in her evaluation. She can see the provenance, and the provenance is thin. If Lyra passes them anyway, her name enters the chain. When Soren evaluates those tokens downstream, he sees Lyra's name attached to tokens with thin provenance. His trust in Lyra absorbs some of the cost -- he might value them slightly because he trusts her judgment -- but the 0.7^hops decay means the unknown blessers deep in the chain contribute almost nothing. And if it turns out the tokens are consistently hollow, Soren adjusts his sentiment toward Lyra. She staked her reputation by forwarding them, and reputation is a finite resource. ### Griefing via negative reputation → only positive sentiment counts An attacker tries to destroy someone's token economy by rating them at -1 with many accounts, hoping to poison their ability to bless tokens. This doesn't work because the valuation formula uses `max(sentiment, 0.0)`. Negative sentiment doesn't produce negative token value. It produces zero. The attacker's negative ratings make the target's blessings invisible *to the attacker's trust cluster* -- but they don't reduce the target's value in the eyes of people who actually trust them. Zephyr's +1 sentiment toward Nova means Nova's blessings carry full weight for Zephyr, regardless of what a thousand hostile strangers think. There is no aggregated reputation score to attack. Each observer computes their own view. Griefing is structurally ineffective. ### AI flooding → humanness freshness = 0 An attacker deploys a fleet of AI agents to fulfill quests and accumulate tokens, then uses those tokens as if they were human-generated economic value. AI accounts cannot generate attention and cannot bless tokens. They can earn tokens by doing work, but the tokens they hold still carry blessings from the humans who originally minted them. The AI is a steward, not a source. The deeper problem for the attacker is humanness freshness. AI accounts have no attestation heartbeat. Their freshness is permanently zero unless they can somehow participate in shared Memory creation -- and shared Memories require the mutual presence of attested humans. An AI that hasn't been part of any recent human gathering has a freshness of 0, and evaluators who weight humanness freshness will discount everything the AI touches. Can an AI fake participation in a shared Memory? Only if a real human includes it. And that human's attestation is what's actually being refreshed -- the AI's presence is incidental. The scarce resource remains human attention and human presence. ### Compromised local Temple → the immune system works on institutions too What if an Ecoregion Temple goes rogue? Say the Cuban Moist Forests Temple starts attesting bots as humans, issuing fraudulent humanness attestations to sybil accounts. Every observer evaluates every link in the delegation chain through their own sentiment graph. If people in the network develop negative sentiment toward the Cuban Moist Forests Temple -- because attestations originating from that branch keep being associated with suspicious accounts and hollow tokens -- the entire branch loses weight in their evaluations. The immune system described in [Part 2](your-network-has-an-immune-system.md) works on institutions the same way it works on individuals. Sentiment is local. Response is emergent. A compromised Temple doesn't poison the tree -- it loses trust among the observers who notice, and that loss propagates through the same trust channels that carry everything else. The bioregional hierarchy is a convenience, not a single point of failure. Even if an entire Subrealm Temple is compromised, observers who distrust that branch simply weight it at zero and rely on attestation chains they do trust. The system degrades gracefully because trust was never centralized in the first place. > Every attack fails the same way: by colliding with subjectivity. You can't forge trust. You can't manufacture sentiment. You can't counterfeit a relationship. --- ## 🌱 What Emerges Step back from the mechanisms. Forget the exponential decay functions and the steward chains and the bioregional delegation trees for a moment. Look at what this architecture produces as a human experience. Hard data, soft interpretation. The facts are verifiable: this token was blessed by this person, who spent this many minutes, and the token passed through these hands on these dates. The attestation chain is cryptographically signed, the steward chain is immutable, the attention durations are recorded. All of this is objective, auditable, concrete. But the *meaning* of those facts is evaluated subjectively, by every observer, through the lens of their own relationships. There is no central authority that declares a token's worth. There is no exchange rate. There is no bank. There is only the accumulated trust between people who know each other, applied independently to the same set of verifiable claims. This produces an economy that is: - 🌐 **Sybil-resistant without identity verification** -- fake accounts can mint tokens that nobody values - 🔗 **Accountable without punishment** -- the steward chain makes reputation a natural consequence of behavior - 💓 **Human-centered without gatekeeping** -- humanness is a heartbeat, not a credential - 🏛️ **Structured without hierarchy** -- the bioregional tree provides scaffolding that every observer evaluates independently - 🎉 **Self-renewing through celebration** -- the act of gathering refreshes the economic engine What does it mean when value comes from relationship rather than scarcity? When the worth of a token is not what's printed on it but who carried it to you and whether you trust them? When the most effective way to increase your economic influence is not to accumulate but to deepen your relationships with the people around you? In the [first article](indras-network-every-node-a-mirror.md), we described a transport layer with no center -- messages bouncing between peers like light between jewels. In the [second](your-network-has-an-immune-system.md), an immune system with no moderator -- communities protecting themselves through local sentiment and emergent response. In the [third](your-files-live-with-you.md), a filesystem with no cloud -- files that live with their owners, shared through acts of trust rather than acts of copying. Now, an economy with no bank. Value that lives in the space between people, not in the tokens themselves. An economy where the source of meaning is not abstract scarcity but concrete human connection -- the act of showing up, paying attention, and being alive together. The pattern holds: **the participants are the infrastructure.** The tokens are letters of introduction. The steward chains are webs of accountability. The attestations are heartbeats. And the whole system runs on the one resource that no machine can manufacture and no sybil farm can fake: the trust that accumulates, slowly and irreversibly, between people who show up for each other. --- *What would an economy look like if its currency was trust?* 💬 **This is Part 4** of a series on Indra's Network. [Part 1: Every Node a Mirror](indras-network-every-node-a-mirror.md) covers the transport layer. [Part 2: Your Network Has an Immune System](your-network-has-an-immune-system.md) covers the social defense layer. [Part 3: Your Files Live With You](your-files-live-with-you.md) covers the shared filesystem. **Subscribe** for future articles on governance, collective decision-making, and the structures that emerge when communities own their own economies. ======================================================================== # SOURCE: Article: Your Network Has an Immune System — Moderation Without Moderators # https://www.syncengine.earth/articles/your-network-has-an-immune-system.md ======================================================================== # Your Network Has an Immune System ### *How decentralized sentiment turns a communication mesh into a living, self-protecting organism* --- What if your social network could protect itself the way your body does? Not with a report button that disappears into the void. Not with a "trust and safety" team reviewing screenshots three days after the damage is done. Not with an algorithm that sometimes bans the bully and sometimes bans the victim. Think about the last time a toxic person entered a friend group. A group chat, a Discord server, a neighborhood committee. You felt the shift before anyone named it. Conversations got tense. People went quiet. Some left. By the time anyone with "moderator" power acted -- if they ever did -- the damage was done. We're building something different. ✦ --- ## 🛡️ The Moderator Problem Centralized moderation is the immune equivalent of having one doctor for eight billion people. It does not scale. It *cannot* scale. Major platforms employ thousands of content moderators who review the worst of human behavior for hours a day. Burnout is staggering. Decisions are inconsistent. Context is invisible to someone reviewing a queue of flagged content from communities they've never participated in. And whoever holds the ban hammer shapes the community. Platform employees in San Francisco decide what's acceptable in group chats in Jakarta. A volunteer moderator in a 50,000-person server can silence anyone they dislike. No appeals process, no recourse, no accountability. Small communities get the worst of it. A ten-person group chat has *zero* moderation tools. If someone turns hostile, your options are: mute them (they're still there), leave (you lose the group), or file a report (you're ten people -- nobody cares). > The fundamental error is treating community health as a *content* problem. It isn't. It's a *relationship* problem. And relationships are local. --- ## 🧬 How Your Body Already Solved This Your immune system handles an essentially infinite variety of threats -- bacteria, viruses, parasites, your own cells gone rogue -- without a brain. No central command. No moderator reviewing flagged cells. It works through four principles: **Local detection.** Individual cells notice when something is wrong in their immediate neighborhood. A macrophage doesn't wait for instructions from headquarters. It encounters something foreign, and it acts. The intelligence is at the edge, not the center. **Signal propagation.** When a cell detects a threat, it releases chemical signals -- cytokines -- that tell neighboring cells: *something is wrong here.* Those neighbors relay the signal further. Information spreads outward from the point of contact, like ripples in water. **Graduated response.** Your body doesn't nuke every papercut. The innate immune system handles routine threats with proportional force. Only when something serious gets through does the adaptive system spin up -- slower, more targeted, more powerful. An immune system that overreacts to everything is an autoimmune disease. **Memory.** Once your adaptive immune system has dealt with a specific threat, it remembers. Forever. The next encounter triggers a faster, stronger response. Your body learns. No central authority. No single point of failure. Local cells, local decisions, emergent collective defense. This is exactly how a social network should work. --- ## 🕸️ A Network That Works the Same Way In the [previous article](indras-network-every-node-a-mirror.md), we described Indra's Network's transport layer -- how messages route through a mesh of peers with no central server. Store-and-forward delivery. End-to-end encryption. Every node a full participant. That transport layer is the body. What we're describing now is the immune system that keeps it healthy. Here's how it works. ### Local detection: you rate your own contacts Every person in the network can rate each of their direct contacts on a simple scale: - **+1** — I recommend this person - **0** — Neutral (the default) - **\-1** — I don't recommend this person That's it. No five-star reviews. No detailed reports. Just your honest assessment of the people you actually know. A cell recognizing something in its immediate environment. You know the people around you. The network trusts that knowledge. ### Signal propagation: sentiment travels through trust Here is the key insight -- the thing that makes this system fundamentally different from reputation systems you've seen before: > **You only see ratings from people YOU already trust.** If a thousand strangers rate you negatively, it's invisible. Their opinions don't reach you or anyone in your circle, because nobody in your circle has a trust relationship with those strangers. Sentiment propagates along *existing* trust connections, the same way cytokines travel through tissue -- not through the air to random parts of the body. Your friends-of-friends can relay warnings too. If someone your trusted contact trusts has a negative experience with a person, that signal can reach you -- but attenuated by distance, weaker with each hop. First-degree sentiment hits with full weight. Second-degree is softer. Beyond that, it fades to noise. This is *contact-scoped sentiment*. The network's immune signals travel the same paths as its messages. ### Graduated response: proportional, not nuclear Negative sentiment doesn't immediately exile anyone. The response is graduated, just like biological immunity: **Soft containment.** When several people mark someone as not-recommended, the network makes it harder for that person to be added to *new* shared spaces. They aren't kicked from existing groups -- but the social surface quietly contracts around them. The innate immune response: fast, low-cost, proportional. **Hard isolation.** If someone is actively blocked, that block cascades through every shared space automatically. Every realm, every group, every channel. The adaptive response: slower to trigger, but decisive. **No moderator needed.** Nobody filed a report. Nobody waited for a review. The response emerged from local decisions by the people actually affected. ### Memory: the network learns Blocks and negative ratings persist. If someone leaves and tries to rejoin through a different path, the sentiment data is still there. The network remembers -- not through a central blacklist, but through the distributed memory of every node that was involved. --- ### A scenario Zephyr, Nova, and Sage are in a small group -- a peer-set realm, in the network's terminology. They've been collaborating on a community project for months. Trust is high. All three have mutual +1 ratings. Orion joins, introduced by Sage. At first things are fine. But over the next few weeks, Orion starts being disruptive -- dominating conversations, dismissing others' contributions, creating friction. Nova rates Orion at -1. She doesn't announce this. She doesn't file a report. She just adjusts her local rating. Zephyr notices the same pattern independently and does the same. Now something happens without anyone orchestrating it: when Sage's friend Lyra considers forming a new group that would include everyone, the network quietly surfaces the sentiment data. Through her trust chain via Nova and Zephyr, Lyra can see that Orion carries negative signal. She decides not to include Orion. Orion isn't banned. Orion can still talk to Sage. But Orion's social surface has contracted. The community formed a boundary *around* the problem without any central authority, without any confrontation, without any moderator. If Orion's behavior improves, sentiment can shift. The ratings are continuous, not permanent verdicts. The immune system doesn't just attack -- it also stands down when the threat passes. ![Sentiment gradients shaping network topology — trust clusters forming naturally as positive ratings draw nodes together and negative ratings create distance](asset://localhost/%2FUsers%2Ftruman%2FCode%2FIndrasNetwork%2Farticles%2Fimages%2F06-sentiment-topology.svg) --- ## 🤖 What About Coordinated Attacks? This is always the first question, and it's the right one. What happens when someone tries to game the system? ### The Sybil attack: a thousand fake accounts Someone creates a thousand fake accounts and has all of them rate you at -1. In a centralized reputation system -- Yelp reviews, Reddit karma -- your score would crater. In Indra's Network, nothing happens. Literally nothing. Those thousand accounts have no trust relationships with anyone in your circle. Their ratings propagate along their own trust paths, which connect to... nobody real. The signal never reaches you. > Your immune system only listens to your own cells. A pathogen can scream as loud as it wants -- if it's not inside your body's signaling network, your immune system doesn't hear it. New accounts start with zero social position. No contacts, no sentiment history, no influence. You can't buy trust. You can't manufacture it with bots. Trust is earned one real relationship at a time. ### The brigading attack: a coordinated mob What about real people coordinating to rate someone negatively? Harder, because these are actual humans with actual trust relationships. But contact-scoping still helps. If the mob's members aren't in your trust chain, their ratings are invisible to you. They can damage someone's reputation *within their own cluster*, but they can't project that damage into communities they aren't part of. The attack is contained by the same topology that contains everything else. ### The autoimmune problem: groupthink The most honest concern is this one: what happens when a community collectively turns against someone who doesn't deserve it? This is the autoimmune disease of social networks -- the body attacking its own healthy tissue. This is real, and no system eliminates it entirely. But the continuous gradient helps. Sentiment isn't binary -- banned or not-banned. It's a spectrum. A person receiving mixed signals (-1 from some, +1 from others, 0 from many) isn't cast out. And because ratings are scoped to individual contacts, nobody can see a single aggregated "score" and pile on. You see sentiment from *your* people. Someone else sees sentiment from *theirs*. There's no public number to dogpile. The system is also self-correcting. If people realize the ostracism was unjust, they adjust their ratings. The network remembers, but it can also change its mind. ![Blocking cascade through peer-set realms — when Zephyr blocks Orion, the block propagates through all shared spaces automatically while leaving Orion's separate connections intact](asset://localhost/%2FUsers%2Ftruman%2FCode%2FIndrasNetwork%2Farticles%2Fimages%2F07-blocking-cascade.svg) --- ## ✦ What Emerges Step back from the mechanisms. What you get is a living topology. Communities aren't static containers that someone created and administers. They're dynamic structures shaped by the accumulated sentiment of every participant. Clusters of high mutual trust pull together naturally. Boundaries form where trust drops off. Bad actors drift to the edges -- not because someone decided to punish them, but because hundreds of local decisions produced an emergent immune response. - **Communities self-organize.** Trust shapes access organically. No permissions to configure, no roles to assign. - **Toxicity is contained locally.** A disruptive person in one group doesn't poison the whole network. The response is proportional and bounded. - **Recovery is possible.** Ratings are continuous and mutable. People and communities can heal. - **Nobody has disproportionate power.** No moderator to corrupt, no admin to compromise. Every person's influence is proportional to how much the people around them trust them. This is what a social layer looks like when it's designed as a living system rather than a bureaucracy. --- ## 🌅 The Net That Heals In the [first article](indras-network-every-node-a-mirror.md), we described Indra's Net as a lattice of jewels, each reflecting every other. The transport layer makes that real -- messages bouncing between peers, the whole network present in every point. Now the metaphor deepens. In a living body, the cells don't just exist alongside each other -- they *protect* each other. They communicate. They remember. They respond. Indra's Network isn't just a mesh that connects. It's a mesh that *heals*. The sentiment system doesn't sit on top of the network as an add-on. It *is* the network, the same way your immune system isn't a separate organ -- it's woven through every tissue in your body. > The net doesn't just connect. It heals. ✦ No center to corrupt. No moderator to burn out. No company making decisions about communities it doesn't understand. Just the net itself -- every jewel watching, every thread carrying signal, every point of light contributing to a collective defense that no single point could achieve alone. An immune system for the social internet. We think that's worth building. --- *What would community health look like if the community itself were the immune system?* 💬 **This is Part 2** of a series on Indra's Network. [Part 1: Every Node a Mirror](indras-network-every-node-a-mirror.md) covers the transport layer. **Subscribe** for future articles on the economic layer -- how groups that own their own infrastructure can build their own economies. ======================================================================== # SOURCE: Article: Shared Roots, Different Branches — How Indra's Network and Anytype Diverge from Common Ground # https://www.syncengine.earth/articles/shared-roots-different-branches.md ======================================================================== # Shared Roots, Different Branches: How Indra's Network and Anytype Diverge from Common Ground ### *Two projects built on CRDTs and encryption reached different conclusions about what decentralization is for* --- Most comparisons in decentralized technology are between projects that share a vision but disagree on everything below it. They agree that centralization is bad. They disagree about what to build instead, how to fund it, what security model to adopt, which programming language to write it in. The comparison becomes a list of architectural differences stacked on a thin layer of shared philosophy. The comparison between Anytype and Indra's Network is different, and the difference makes it more interesting. These two projects do not merely share a philosophy. They share a substantial slice of their technical implementation. Both use CRDTs for conflict-free synchronization. Both encrypt data end-to-end so that infrastructure cannot read it. Both are built around local-first, offline-capable design. Both reject mandatory cloud dependency. Both are open-source. Both represent serious, mature engineering — not whitepapers or prototypes. When two projects agree this deeply on the technical substance, their points of divergence become sharper and more revealing. You cannot explain the difference by pointing at one team using a better algorithm or making a more principled choice. The implementations are both principled. The divergence is philosophical — about what decentralization is ultimately for, and about how deep sovereignty needs to go before it actually means something. Anytype launched in 2019, shipped production apps across desktop, iOS, and Android, and has accumulated a genuine user community. It is a polished, working product that thousands of people use every day to organize their notes, projects, and knowledge. That is real. The comparison that follows acknowledges it throughout, because intellectual honesty requires it. But the places where Indra's Network diverges from Anytype's design are not incidental. They reflect a different theory of what it means to remove infrastructure from the equation. --- ## The Shared Foundation Start with what both projects actually agree on, because it is substantial enough that an outside observer could reasonably mistake them for variations on the same theme. Both use **CRDTs** — conflict-free replicated data types — as the synchronization primitive. Anytype implements DAG-based CRDTs in Go as part of the AnySync protocol. Indra's Network uses Automerge in Rust. The specific implementations differ, but the design philosophy is identical: instead of locking data during edits or running a consensus round to resolve conflicts, structure your data such that any two versions can be merged deterministically. Concurrent offline edits do not produce conflicts that need human adjudication. They produce a mathematically defined merge that both parties will reach regardless of the order in which they received changes. Both provide **end-to-end encryption**. Anytype encrypts data with AES using CFB mode and a dual-layer key hierarchy. Indra's Network uses ML-KEM-768 for key encapsulation and ML-DSA-65 for signatures. The details differ — more on that shortly — but the principle is the same: the infrastructure that moves and stores data cannot read it. Anytype's sync nodes, which relay data between devices, see only ciphertext. Indra's Network's relay peers, which forward packets between nodes, hold sealed envelopes they cannot open. Both are **local-first**. Your data lives on your device. Changes happen locally before they go anywhere. The application functions without a network connection. When connectivity returns, sync happens automatically. This is a deliberate inversion of the cloud-first model, where your data lives on a server and your device is a thin client that requests it. Both are **open-source** with documented protocols. Anytype's AnySync protocol is MIT-licensed with 1,540 GitHub stars on its own repository. The TypeScript client has over 7,100 stars. Indra's Network is an open Rust SDK across 25-plus crates. Both projects have made the decision that the protocol layer should be auditable, extensible, and available to anyone who wants to build on it. Both use **rich data models** that go beyond simple documents. Anytype organizes information as Objects with Types and Relations, arranged into Sets and Views — a structured graph that lets users build relational databases, task managers, and wikis in a single unified interface. Indra's Network organizes data as Artifacts living in Realms, accessed through typed Interfaces — a different vocabulary for a similarly graph-structured world. | Dimension | Anytype | Indra's Network | |---|---|---| | Sync primitive | DAG-based CRDTs (Go, AnySync) | Automerge CRDTs (Rust) | | Encryption | AES-CFB, dual-layer key hierarchy | ML-KEM-768 + ML-DSA-65 (post-quantum) | | Architecture | Local-first, offline-capable | Local-first, offline-capable | | Cloud dependency | Optional (self-hostable) | None by design | | Protocol license | MIT (AnySync) | Open Rust SDK | | Data model | Objects / Types / Relations / Sets | Artifacts / Realms / Interfaces | | Primary form | Shipped application | Developer SDK | This overlap is unusual. In a field full of projects that share a slogan and little else, two projects sharing this much implementation philosophy is worth pausing on. It means the comparison is not about one team getting the fundamentals right and the other fumbling them. Both teams got the fundamentals right. The question is what they built on top of those fundamentals — and why. --- ## SDK vs. Product The most visible difference is the simplest to state: Anytype is a finished application. Indra's Network is a toolkit for building applications. Anytype ships native desktop apps for Mac, Windows, and Linux. It ships iOS and Android apps. It has a graph visualization that renders the connections between Objects as an interactive web you can navigate. The UI is polished — the kind of polish that takes years of iteration and real user feedback to achieve. You can download it today, import your Notion export, organize your notes, share a space with a colleague, and have it working within an hour. Seven thousand GitHub stars on the TypeScript client do not accumulate by accident; they represent a real community of people who found the product valuable enough to star the repository. Indra's Network ships a Rust SDK. The chat application, workspace, and dashboard that exist in the ecosystem are examples demonstrating what you can build — they are not the product. The product is the infrastructure: the 25-plus crates that handle transport, CRDT sync, store-and-forward routing, Home Realm storage, liveness attestation, post-quantum identity, and access control. A developer who wants to build a private team collaboration tool, a local-first journal, or a peer-to-peer marketplace picks up the SDK and builds it. They do not fork a finished application; they compose the primitives. This is a meaningful architectural choice with real implications, and it maps onto a distinction the technology industry has navigated many times. Consider WordPress versus HTTP. WordPress built a complete, usable product — you install it, configure a theme, and you have a website. HTTP is the protocol that WordPress, Twitter, Netflix, and every other web application runs on. WordPress captures users who want a website. HTTP captured every developer who ever wanted to build anything on the web. Both are valuable. Both are necessary. They serve fundamentally different roles in the ecosystem. Anytype is closer to WordPress. It solves a specific, well-defined problem — private, sovereign knowledge management and collaboration — and solves it well, for users who have that problem right now. Indra's Network is closer to HTTP. It solves the general problem of peer-to-peer communication with strong identity, sovereignty, and privacy guarantees, so that any specific application can be built on top of it. The question this raises is about where value accumulates in a decentralized ecosystem. Product leverage captures users directly. A well-designed product with a growing community builds network effects that compound over time — more users means more people your friends can share spaces with, which means more reason for new users to join. Anytype is building this. The community is real. Infrastructure leverage captures builders. If the core SDK provides everything a developer needs to build a private, peer-to-peer application, then the SDK is the foundation for an entire category of products — not one product, but the substrate for all of them. The value compounds differently: more builders means more applications, which means more surface area for users to encounter the infrastructure through products they choose independently. These are not competing bets in the sense that one is right and the other wrong. A healthy decentralized ecosystem needs both. But for investors and builders evaluating where to direct attention, the distinction matters enormously. Anytype is a product investment. Indra's Network is an infrastructure investment. The time horizons, the compounding mechanisms, and the eventual form of competitive advantage are different. --- ## How Deep Does Sovereignty Go? The more philosophically interesting divergence is about what data sovereignty actually means once you take it seriously. Both Anytype and Indra's Network claim data sovereignty as a core design goal. Both deliver it, genuinely, relative to the cloud services they are replacing. But sovereignty is not a checkbox. It is a spectrum, and where you land on that spectrum is a function of your architecture. Anytype's architecture requires infrastructure nodes. The AnySync protocol coordinates four types: **sync nodes**, which store spaces and objects and relay changes between devices; **file nodes**, which manage file storage and delivery; **consensus nodes**, which validate changes to the ACL (access control list) that governs who can access a space; and **coordinator nodes**, which handle network configuration. By default, these are operated by Anytype themselves. Self-hosting is supported and documented — the `any-sync-dockercompose` repository (786 GitHub stars, reflecting genuine community demand) provides a Docker Compose setup for running your own infrastructure. If you self-host, your data lives entirely on your own servers. But the default experience routes through Anytype's infrastructure. And even for self-hosters, the architecture requires running servers. You are not eliminating infrastructure; you are taking ownership of it. The distinction is real — owning your infrastructure is meaningfully different from renting someone else's — but it is a different kind of sovereignty than a system where infrastructure is eliminated rather than transferred. Anytype's identity is a BIP-39 seed phrase: 12 words drawn from the standard cryptocurrency wordlist. This is a mature, well-understood approach. The phrase generates your private key; losing the phrase means losing your account; no recovery is possible without it. The encryption derives from this key through a dual-layer hierarchy: a first-layer key that backup nodes hold to group changes by object, and per-object keys that only the user holds. The first-layer key allows infrastructure to organize data efficiently without being able to read content. The backup nodes hold the organizational key but not the content key. Indra's Network's sovereignty is structural rather than operational. There are no sync nodes, file nodes, consensus nodes, or coordinator nodes. The participants are the infrastructure. When two peers form a connection, they relay for each other directly. When a message cannot be delivered immediately, it routes through mutual peers — peers who are neighbors of both sender and recipient — who hold sealed, encrypted packets they cannot read and deliver them when the recipient comes online. The infrastructure is not hosted by anyone; it exists as a property of the network of relationships between participants. Storage follows the same logic. Home Realm derives deterministically from your identity via BLAKE3 — your files live with you, accessible from any of your devices, without requiring an external storage provider. Sharing is not copying data to a server; it is extending a permission that your peer can exercise against your realm. If you grant revocable access, you can withdraw it. If you grant permanent access, you have made an irrevocable commitment — co-ownership, encoded in the protocol. If you grant timed access, it expires automatically. Transfer moves ownership completely. Identity uses a 23-slot autobiographical narrative called a Pass Story. You fill in prompts derived from the hero's journey structure, drawing on actual memories from your own life. These answers run through Argon2id and expand via HKDF into purpose-specific subkeys for ML-KEM-768 key encapsulation and ML-DSA-65 signatures — NIST FIPS 203 and 204, the post-quantum standards that resist Shor's algorithm. Every network message is signed with these quantum-resistant signatures. Relay nodes hold sealed envelopes they cannot decrypt. The secret is not a password you invented or a mnemonic you memorized; it is a story you lived. This is worth naming directly: Anytype represents a genuine and significant step toward data sovereignty relative to Google Docs, Notion, or Slack. Users own their encryption keys. Data lives locally. Self-hosting is possible and documented. The consensus and sync nodes cannot read content. That is real progress, not theater. But there is still infrastructure between you and your data. Sync nodes exist. File nodes exist. Consensus nodes validate ACL changes. If Anytype the company ceased operations tomorrow, users with self-hosted deployments would be fine. Users on Anytype's default infrastructure would need to migrate to self-hosting or find an alternative operator — a non-trivial operational task for a non-technical user. Indra's Network's architecture has no such dependency to migrate away from. If the company building the SDK disappeared, the network would continue to exist as long as peers continued to run. There is no hosted infrastructure to replace, because there was never hosted infrastructure in the first place. The network's existence is coextensive with the existence of its participants. --- ## The Trust Model Gap Access control is where the two projects diverge in the way most relevant to how communities actually function. Anytype uses Access Control Lists. A space owner defines membership. Consensus nodes validate changes to that membership list — additions, removals, permission upgrades. This is familiar, functional, and well-suited to the use case Anytype targets: a team or individual managing their private knowledge base. You are in or you are out. The owner decides. The permission is binary. Indra's Network's trust model is more granular, because it is modeling a more granular social reality. The four access modes — Revocable, Permanent, Timed, Transfer — are not merely different permission bits. They encode different social acts. Revocable access says: I trust you to see this, and I retain the right to withdraw that trust. Permanent access says: this is yours now, as irrevocably as I can make it — a commitment the protocol enforces, not a policy that can be quietly changed. Timed access says: you have this for a bounded period, and the expiration is not subject to renegotiation. Transfer says: this leaves my realm and enters yours completely. None of these have an equivalent in an ACL system, because ACLs do not encode social meaning. They encode permission state. The difference between lending someone a book and giving it to them is not a difference in permission state — it is a difference in the nature of the transaction. Indra's Network encodes that difference in the type system. The liveness model goes further. Every participant has a humanness freshness score between 0.0 and 1.0, measuring how recently they were attested as a living, present human being. The attestation comes from in-person events — shared memories created together, proof-of-life celebrations, gatherings where people document shared presence. Each attestation resets your liveness to 1.0. Then it decays: full freshness for seven days, then exponential decline. By day fourteen you are at roughly half. By day thirty you are at ten percent. The implication is structurally significant: a new account with no in-person attestations has a liveness of zero. Not because the system has judged them untrustworthy, but because they have not yet demonstrated the one thing that cannot be faked at scale — physical presence among other humans. There is no global reputation score, no network-wide average, no aggregate that an attacker could target by creating many fake accounts. Each peer's influence is weighted by their liveness, computed from their own history of showing up. The response to bad actors follows from the physics of decay. A person who stops participating fades naturally — their freshness score declines exponentially and their weight in the network approaches zero. Hard isolation still exists: blocking a contact triggers an automatic cascade, removing the blocker from every shared space containing the blocked peer. But the deeper defense is simpler: you cannot maintain influence without maintaining presence. Sybil attacks fail because fake accounts cannot attend in-person events — no attestations means a liveness of zero, and zero means invisibility. Anytype asks: who has permission? Indra's Network asks: what kind of relationship does this trust carry, and what does this specific sharing act mean? The first question is the right question for document permissions. The second question is the right question for an infrastructure that aspires to model the full range of human social interaction. --- ## Where Anytype Excels Anytype is a serious project, and treating it otherwise would be intellectually dishonest. The product is genuinely polished. The graph visualization — which renders the connections between Objects as a navigable web — is an innovative piece of UX that Anytype has developed and refined with real users over years. The Object/Type/Relation model is expressive enough to build almost anything a knowledge worker needs: a personal database, a project tracker, a wiki, a CRM, a reading list. The cross-platform native apps have the feel of software that was designed carefully rather than assembled. You can feel the iteration. The community is real. 7,100 GitHub stars on the TypeScript client. 786 stars on the Docker Compose self-hosting setup, which tells you something important: the people using Anytype are engaged enough to want operational sovereignty, and they are finding the self-hosting path accessible enough to star the repository and presumably follow it. MCP integration (316 stars), a CLI, and an API reflect an ecosystem building around the product, not just a product sitting alone. The institutional structure is credible. Anytype operates under a Swiss association governance model — a structure with real legal accountability and a track record in the open-source world. The AnySync protocol is MIT-licensed and documented. If you need a private, end-to-end encrypted knowledge management system today, Anytype is arguably the best available option. The polished multi-platform experience, the expressive data model, the genuine offline support, and the growing community all point to a project that has found real product-market fit in a category where most competitors are either not private or not polished. --- ## Infrastructure vs. Application The metaphor that clarifies the relationship between these two projects is architectural rather than competitive. Anytype built the house. It is a good house — well-designed, livable, thoughtfully furnished. You can move in today, bring your notes, your tasks, your team, and find it immediately useful. The floor plan works for how people actually want to organize their information. The construction is solid. Indra's Network built the materials and the tools. The materials — CRDT sync, peer-to-peer transport, post-quantum identity, store-and-forward routing, liveness-based trust, four-mode access control — can build any house. A chat application. A collaborative workspace. A community platform. A peer-to-peer marketplace. A healthcare coordination tool where data sovereignty is not a feature but a legal and ethical requirement. Things nobody has yet imagined but that will become obvious once the infrastructure exists. Both are necessary. The decentralized ecosystem needs products people can use today — not in principle, not eventually, but now. Anytype provides that. The ecosystem also needs infrastructure that lets an ecosystem of products emerge from independent builders who do not have to solve the hard distributed systems problems from scratch. Indra's Network provides that. The question for investors and evaluators is not which approach is correct. It is which kind of leverage they are looking for, and at what point in the development of a decentralized ecosystem that leverage is most valuable. Product leverage compounds through users and community. Infrastructure leverage compounds through builders and the portfolio of applications they create. These are different bets with different time horizons, different risk profiles, and different shapes of eventual return. Anytype is betting that a single excellent product in the knowledge management category, built on sovereign infrastructure, will attract a community large enough to sustain an alternative to the centralized incumbents. Indra's Network is betting that the hard infrastructure problems — identity, trust, routing, storage, access control — are the limiting factor, and that solving them at the SDK level unlocks an entire category of applications that cannot exist today. One framing makes the distinction concrete: Anytype decentralized the product. Indra's Network decentralized the infrastructure that products are built from. --- *Indra's Network SDK is available now. The infrastructure described in this article — store-and-forward transport, Automerge CRDT sync, Home Realm storage, liveness attestation, post-quantum identity, four-mode access control — is built, tested, and running in Rust.* ======================================================================== # SOURCE: Article: Two Paths to Decentralization — Why Indra's Network Chose a Different Road Than Logos # https://www.syncengine.earth/articles/two-paths-to-decentralization.md ======================================================================== # Two Paths to Decentralization: Why Indra's Network Chose a Different Road Than Logos ### *How two projects with the same diagnosis reached opposite conclusions about blockchain, trust, and what it means to ship* --- There is a particular kind of agreement that makes disagreement sharp. When two people start from the same premises and reach opposite conclusions, the divergence is interesting in a way that pure contradiction isn't. You can't dismiss it as ignorance or bad faith. You have to actually think about where the fork is, and why. Logos and Indra's Network share a diagnosis. The internet is structurally broken. Not broken in the way that software has bugs — broken in the way that a house built on a flood plain is broken. The foundation is wrong. Centralized servers create single points of failure and single points of control. Corporate intermediaries extract rent from every interaction. Surveillance is not an abuse of the system; it is the system. The architecture of the modern internet was not designed for human flourishing — it was designed for advertising revenue, and it shows. On this, both projects agree entirely. Logos describes its mission as building "the infrastructure for a new cyber-society," arguing that today's internet has failed to deliver on its promise of openness. Indra's Network was built from the same frustration: that the tools people use to communicate, collaborate, and organize should not be owned by corporations whose interests are structurally opposed to the interests of their users. Same problem. Same urgency. Then the architectures diverge so sharply that the two projects barely share a vocabulary for what they're trying to build. This article is about that fork. It is not an attack on Logos, which is a serious project with serious people behind it. It is an honest account of how two teams looked at the same problem and made fundamentally different bets — about whether blockchain is necessary, about whether trust is global or local, and about what it means to have something working today. --- ## Two Architectures, One Goal At the technical level, both projects are building layered protocol stacks. The layers are where the differences begin. Logos is constructing a three-layer platform. The base layer is Nomos, a blockchain-based consensus network responsible for establishing global agreement and enforcing trustless contracts. The middle layer is Waku, a privacy-preserving peer-to-peer messaging protocol derived from Ethereum's Whisper and built on libp2p. The top layer is Codex, a distributed storage network for durable data availability. These three components are coordinated through a plugin-based runtime and unified by a token economy. The project inherits significant institutional weight from the Status ecosystem — roughly 200 contributors across 265 repositories — and frames itself explicitly as a "social movement" as much as a technology project, with 29 local chapters worldwide. Indra's Network is a Rust SDK of 25-plus crates. The transport layer uses Iroh and QUIC — a modern, connection-oriented protocol with built-in encryption and multiplexing. Synchronization uses CRDTs via Automerge: conflict-free replicated data types that allow concurrent edits across offline devices to merge automatically without a reconciliation step. Routing is store-and-forward with a seven-day retry window, so messages reach recipients who are intermittently connected rather than bouncing with an error. Governance uses liveness — a single scalar derived from in-person attestations that proves humanness and decays over time. Identity uses a 23-slot autobiographical narrative as the cryptographic foundation, derived through Argon2id into ML-KEM-768 and ML-DSA-65 keys. Those algorithms are NIST FIPS 203 and 204: post-quantum standards that resist Shor's algorithm. No blockchain. No token sale. No global consensus protocol. The comparison is easier in a table than in prose: | Dimension | Logos | Indra's Network | |---|---|---| | Transport | libp2p (Waku) | Iroh / QUIC | | History model | Global ledger (Nomos blockchain) | Local shared history (per-interface CRDTs) | | Sync model | Eventual consistency via Waku | CRDTs (Automerge) with mutual peer backup | | Storage | Codex (distributed pool) | Home Realm (files live with owner) | | Consensus | Nomos blockchain | None — CRDTs eliminate it | | Routing | Standard P2P gossip | Store-and-forward via mutual peers, with back-propagation | | Token | Yes (planned) | No | | Governance | On-chain voting | Liveness: in-person attestation with exponential decay | | Identity | Not publicly specified | Pass Story (23-slot narrative) | | Cryptography | Classical | Post-quantum (ML-KEM-768, ML-DSA-65) | | Sybil resistance | Not detailed | Liveness: fake accounts cannot attend in-person events | | Maturity | Testnet design phase | Working SDK, shipping apps | The striking thing about this table is not that Logos has features Indra's Network lacks, or vice versa. It is that the design choices are coherent wholes. Each project's architecture is internally consistent, expressing a particular theory of what decentralization requires. To understand the disagreement, you have to understand the theory. --- ## Blockchain Is Optional The deepest philosophical fork is about consensus. Logos assumes that trustless systems require a chain. This is not an arbitrary assumption — it reflects a serious argument. Blockchains solve a real problem: how do strangers who don't trust each other agree on a shared state without a central authority to enforce it? Bitcoin solved this for money. Ethereum generalized it to arbitrary computation. The Logos stack takes this solution and applies it to the problem of sovereign digital infrastructure. If you want a network that no single entity controls, and you want that guarantee to be cryptographically enforceable rather than dependent on the goodwill of any party, a blockchain is one principled answer. Indra's Network's position is that this answer is correct for a specific class of problems — and unnecessary for many of the problems people actually need to solve. The specific class where blockchain is correct: financial settlement and trustless coordination among strangers. If two people who have never met and have no basis for mutual trust need to execute a contract, and neither is willing to trust a third-party escrow, a blockchain provides a credible neutral ground. The rules are public, the enforcement is automatic, and no party can unilaterally alter the outcome. This is a genuinely valuable property. DeFi applications, token economies, and decentralized governance among anonymous participants all benefit from it. The problem: most human interaction is not in this class. Communication between friends does not require trustless settlement. Collaborative editing among colleagues does not require global consensus. File sharing within a community does not require a distributed ledger. The overhead of a blockchain — consensus latency, validator infrastructure, token economics, the energy of the entire apparatus — is unnecessary weight for these use cases. CRDTs make this argument concrete. A conflict-free replicated data type is a mathematical object with a defined merge function: given any two versions of the object, the merge is deterministic and commutative. You don't need to ask permission to make a change. You don't need to wait for consensus before writing. You make changes locally, and when you reconnect with other nodes, your changes and theirs merge automatically. The merge is not negotiated — it is computed. There is no possibility of conflict, by construction. But CRDTs alone don't explain what replaces blockchain in the architecture. The answer is **mutual peering** — and it is arguably the signature idea of the entire system. In a blockchain, every participant maintains the same global history. Every transaction is visible to every validator. This is powerful, but it is also expensive: the entire network must agree on every state change. Indra's Network inverts this. History is not global. It is scoped to the people who share it. When two or more peers form a shared space — an "interface" in the system's vocabulary — they create a shared CRDT document that belongs only to them. This document holds the member list, the metadata, and an append-only event log. It is the complete history of that relationship, and it exists nowhere else. Nobody outside the interface can see it. Nobody outside the interface needs to validate it. Each peer broadcasts their version of this shared history to the others. Automerge's sync protocol handles the exchange: peers generate compact binary diffs from their local state, send them to each other, and merge incoming diffs automatically. The merge is deterministic — two peers who have seen the same set of changes will always converge to the same document, regardless of the order in which they received them. Changes are identified by content hash in Automerge's internal DAG, so a peer cannot inject forged history without producing invalid hashes. The data structure itself is the accountability mechanism. The peers also back each other up. Every event in the shared history is tracked per-member as "pending" until that member explicitly acknowledges receipt. Events are only pruned from memory once every member has confirmed they hold a copy. If a peer goes offline, their pending events accumulate until they reconnect and sync. When a new member joins an interface, they are immediately backfilled with the entire existing history. The result is that every participant holds a complete copy of the shared history, and every participant knows whether the others are caught up. This is not a minor implementation detail. It is the structural replacement for blockchain's role as a shared ledger. Where a blockchain says "everyone agrees on everything," mutual peering says "the people who need to agree, agree — and they hold each other accountable directly." The scope of agreement matches the scope of the relationship. A conversation between three friends does not need to be validated by a thousand strangers. The routing layer reinforces this model. When a message cannot be delivered directly, the system computes mutual peers — peers who are neighbors of both the sender and the recipient — and routes through them. The mutual peer holds a sealed, encrypted packet it cannot read, and delivers it when the recipient comes online. Delivery confirmations then propagate backward along the relay path, hop by hop, until the original sender receives confirmation. Each relay node must confirm to its predecessor, creating a chain of accountability that mirrors the chain of custody. The network does not trust any single relay; it trusts the structure of mutual relationships. For governance, the same principle applies in a different register. On-chain governance treats every token-holder as an equal participant in every decision. Indra's Network uses liveness — a single scalar that measures how recently someone was attested as a living, present human being. The attestation comes from in-person events: shared memories created together, proof-of-life celebrations, gatherings where people document shared presence. Each attestation resets your liveness to 1.0. Then it decays — exponentially, after a seven-day grace period. Miss too many heartbeats and your claim to active participation fades. You are never banned, never excluded. You simply become quiet. This is not a weakness of the model — it is a feature. Human communities do not operate by anonymous plebiscite. They operate by presence, by showing up, by the continued act of being part of something. A governance mechanism that measures this reality is more accurate than one that ignores it. The argument is not that blockchain is wrong. It is that blockchain is a solution to a specific problem, and importing it into problems it wasn't designed for adds cost without benefit. --- ## Trust Is Local, Not Global Beneath the technical disagreement is a philosophical one about the nature of trust itself. The blockchain worldview is Enlightenment-flavored: trust should be universal, verifiable, and independent of social relationships. Two strangers who have never met should be able to transact with cryptographic certainty, without needing to know or trust each other as people. The consensus protocol substitutes for the social relationship. This is a powerful idea, and it is genuinely useful in contexts where strangers need to coordinate without a trusted intermediary. Indra's Network takes a different starting point. Trust is not universal. Trust is not global. Trust is radically local. It is a property of specific relationships between specific people, and it attenuates with social distance. Consider how trust actually operates in a community. You trust your neighbor's recommendation for a plumber more than you trust a Yelp review, because you know your neighbor and share a context with them. You trust your friend's friend's recommendation more than a stranger's, but less than your friend's. The same information carries different weight depending on where it comes from in your social network. This is not irrationality — it is a reasonable Bayesian prior. People who know you and people who share your context are more likely to have relevant information. Indra's Network encodes this with a single scalar: liveness. Every participant has a humanness freshness score between 0.0 and 1.0, measuring how recently they were attested as a living, present human being. The attestation comes from in-person events — shared memories created together, proof-of-life celebrations, gatherings where people document shared presence. Each attestation resets your liveness to 1.0. Then it decays: full freshness for seven days, then exponential decline. By day fourteen you are at roughly half. By day thirty you are at ten percent. The math is simple. The implication is profound: to remain a full participant in the network, you must keep showing up in the physical world. This is not a reputation score. There is no global ranking to attack. Liveness is binary in its question — are you a human who is present in community? — and continuous in its answer. A new account with no in-person attestations has a liveness of zero. Not because the system has judged them untrustworthy, but because they have not yet demonstrated the one thing that cannot be faked at scale: physical presence among other humans. The network does not collapse all participants into a single democratic average. Each peer's influence is weighted by their liveness, computed from their own history of showing up. A peer who has not been seen in months fades quietly. A peer who gathers regularly with others remains vivid. The architectural consequences flow outward from this premise. **Storage**: Logos's Codex model distributes files across a global storage pool — your data is replicated across nodes operated by strangers, available through cryptographic addressing. This provides strong guarantees about availability and censorship resistance. Indra's Network's Home Realm model inverts this: your files live with you, derived deterministically from your identity, accessible from any of your devices. Sharing is not copying — it is granting access. The file stays in your realm; you extend a permission to another person. Revocable access can be withdrawn. Permanent access constitutes co-ownership. Timed access expires automatically. Transfer moves ownership completely. Each mode is a different social act, not merely a different permission bit. The system encodes the difference between lending and giving, between showing and surrendering. **Identity**: Logos's identity model is not publicly detailed. Indra's Network's Pass Story is a 23-slot autobiographical narrative — you answer prompts derived from the hero's journey structure, filling in real memories from your own life. These answers are concatenated and run through Argon2id to produce a derived key, then expanded via HKDF into purpose-specific subkeys fed into ML-KEM-768 and ML-DSA-65 — quantum-resistant algorithms standardized by NIST. The result is authentication that is simultaneously deeply personal and cryptographically rigorous. The secret is not a password you invented — it is a story you lived. **Access control**: Indra's Network's four-mode access spectrum (Revocable, Permanent, Timed, Transfer) is worth dwelling on, because it does something no other access control system does: it enforces social meaning at the type-system level. A Permanent grant cannot be revoked. This is not a policy — it is a compile-time constraint in Rust. When you grant someone Permanent access, you are making a commitment the code will hold you to. The irrevocability is the gesture. It is the difference between letting someone look at something and actually giving it to them. **Governance**: Where on-chain governance treats all token-holders as equal participants in all decisions, liveness treats influence as earned through presence. A community member who regularly shows up to in-person events — creating shared memories, attending proof-of-life celebrations — maintains full weight in the network. A bad actor who joined yesterday and has never been attested as human has a liveness of zero, and zero liveness means zero influence. This is enforced mathematically, not by policy. The system responds to bad actors through the physics of liveness decay. A person who stops participating fades naturally — their freshness score declines exponentially and their weight in the network approaches zero. Hard isolation still exists: blocking a contact triggers an automatic cascade, with the blocker leaving every shared space containing the blocked peer and severing all shared history simultaneously. But the deeper defense is simpler. You cannot maintain influence without maintaining presence. Sybil attacks — creating many fake accounts to manipulate the system — fail because fake accounts cannot attend in-person events. You can create a hundred identities, but none of them can be in a room with other humans creating shared memories. No attestations means a liveness of zero. A liveness of zero means invisibility. The attack surface is not the protocol; it is the physical world. And physical presence cannot be manufactured at scale. The global trust model is not wrong — it solves real coordination problems. But it describes a subset of human interaction: the subset involving strangers. Most of what people actually do online is not with strangers. They communicate with friends, collaborate with colleagues, organize with community members, share with people they know. For these use cases, a system that models local trust is not a compromise — it is a more accurate representation of social reality. --- ## Ship Today vs. Ship Someday There is a third divergence, less philosophical but equally important: maturity. Indra's Network is a working SDK. The mutual peering model described in this article is not a whitepaper — it is running code. The transport layer uses Iroh/QUIC with store-and-forward routing through computed mutual peers. CRDTs via Automerge handle per-interface shared history with per-member delivery tracking and automatic backfill. Back-propagation of delivery confirmations is implemented hop-by-hop with timeout detection. Liveness freshness tracks in-person attestations with exponential decay, weighting every participant's influence by how recently they were confirmed as a present human being. Blocking triggers automatic cascade departure from all shared realms. Post-quantum cryptography — ML-KEM-768 and ML-DSA-65 under NIST FIPS 203 and 204 — signs every network message with quantum-resistant signatures. The Home Realm filesystem with four-mode access control is built. There are working applications: chat, workspace, dashboard. A delay-tolerant networking layer retries undelivered messages for seven days across multiple routing strategies. This is production-level Rust across 25-plus crates, not a prototype. Logos is, by its own account, still in early stages. The Codex storage layer was paused for a significant architectural redesign. The Nomos blockchain currently uses a centralized sequencer to stand in for the decentralized consensus layer, which is in "early planning." As of early 2026, the public testnet v0.1 has no announced launch date. Documentation is being actively consolidated from across the 265 repositories into a unified developer site. The Waku chat SDK is described as MVP-quality. The logos-docs repository has seven GitHub stars and 87 open issues. Most module repositories have zero to two stars. To be clear about what this comparison is and is not. It is not an argument that Logos is a bad project or that the people building it are not serious. Building a three-layer sovereign internet platform with a novel consensus mechanism, a privacy-preserving messaging network, and a distributed storage layer is genuinely one of the harder things a software team can attempt. The scale of ambition is real and it takes time. Logos is attempting something that has never been built. What it is: a practical observation for anyone deciding where to build today. An application built on Logos today is built on APIs that will change, on a storage layer that was redesigned once already, on a blockchain that uses a centralized sequencer as a placeholder for the eventual decentralized version. The project is transparent about this — these constraints appear in their own documentation. But for a developer or investor evaluating where to commit attention and resources, the question of which project has stable, working infrastructure is not a minor detail. Indra's Network is not easier to build than Logos. It is simply further along in solving the specific problems it set out to solve. The scope is smaller, the architecture is more focused, and the code is running. --- ## Where Logos Excels Intellectual honesty requires this section, and it is not pro forma. Logos has built something that Indra's Network has not: a community. The 29 local chapters, the 143 contributors, the explicit framing as a civil society project — these are not marketing. They reflect a genuine understanding that decentralized infrastructure is a social problem as much as a technical one. You cannot build the infrastructure for a new cyber-society if nobody shows up to live in it. Logos is trying to solve adoption from the beginning, not as an afterthought. The institutional backing from the Status ecosystem brings real resources: funding, brand recognition, and the accumulated knowledge of a team that has shipped privacy-preserving software to millions of users. That history is worth something. The modular plugin-based runtime in the Logos stack is an architecturally elegant choice. Rather than monolithically integrating the three layers, the design allows them to be composed and extended. If the architecture delivers on its promise, this modularity will enable applications that Indra's Network's more focused SDK cannot support — particularly applications in the category where blockchain genuinely adds value: token economies, DeFi, and trustless coordination among anonymous participants. If Logos delivers the full vision, it occupies territory that Indra's Network has deliberately left empty. These are not competing projects for the same users. They are complementary bets on which use cases matter most and which architectural trade-offs are worth making. --- ## Different Bets on the Same Future Both projects want the same thing: a world in which individuals hold sovereignty over their digital lives, communities control their own infrastructure, and corporate gatekeepers have been made structurally irrelevant. The destination is the same. The routes are different. Logos is betting on global consensus: that trustless coordination at scale requires a chain, that a unified platform with a token economy can align incentives across a large and heterogeneous network, and that getting the foundation right now — even if it takes years — is worth the wait. Indra's Network is betting on local trust: that CRDTs make consensus unnecessary for most human-scale use cases, that trust propagated through social relationships is more accurate than trust established through cryptographic proof among strangers, and that shipping working infrastructure today matters more than perfecting the theory. These bets are not obviously compatible, and that is fine. The decentralized internet does not need one winner. It needs multiple serious experiments exploring different corners of the design space. Logos and Indra's Network are exploring different corners. But the reader who has followed this far is presumably asking a practical question: which bet do they believe in? And which one can they build on today? The philosophical difference, distilled: Logos builds for a world of strangers who need trust enforced by mathematics. Indra's Network builds for a world of people who already know each other and need infrastructure that reflects the social reality they already inhabit. --- *Indra's Network SDK is available now. The infrastructure described in this article — store-and-forward transport, CRDT sync, Home Realm storage, liveness attestation, post-quantum identity — is built, tested, and running in Rust.* ======================================================================== # SOURCE: Article: Developer's Guide — Building on Indra's Network # https://www.syncengine.earth/articles/indras-network-developers-guide.md ======================================================================== # The Indras Network Developer's Guide A complete reference for building peer-to-peer applications with `indras-network`. --- ## Table of Contents 1. [Getting Started](#getting-started) 2. [Configuration & Presets](#configuration--presets) 3. [Identity](#identity) 4. [Realms](#realms) 5. [Direct Connect](#direct-connect) 6. [Encounters](#encounters) 7. [Messaging](#messaging) 8. [Documents](#documents) 9. [Members & Presence](#members--presence) 10. [Contacts](#contacts) 11. [Home Realm](#home-realm) 12. [Artifact Sharing](#artifact-sharing) 13. [Access Control](#access-control) 14. [Tree Composition](#tree-composition) 15. [Artifact Sync](#artifact-sync) 16. [Chat Messages](#chat-messages) 17. [Read Tracking](#read-tracking) 18. [Realm Aliases](#realm-aliases) 19. [Encryption](#encryption) 20. [Identity Export & Import](#identity-export--import) 21. [Blocking](#blocking) 22. [World View](#world-view) 23. [Peering](#peering) 24. [Sentiment](#sentiment) 25. [Error Handling](#error-handling) 26. [Escape Hatches](#escape-hatches) 27. [Re-exported Types](#re-exported-types) 28. [The Prelude](#the-prelude) --- ## Getting Started ### Crate Hierarchy Indras Network is organized in layers. As an application developer you almost always want the top-most layer: | Crate | Role | Use when… | |---|---|---| | `indras-sync-engine` | Domain logic (Intentions, Blessings, Tokens) | You need high-level collaboration primitives | | `indras-network` | **SDK — start here** | Building any P2P application | | `indras-node` | Infrastructure (transport, storage, crypto) | Custom node configs or embedding without domain types | | `indras-core` | Shared traits and primitives | Writing crates that extend the stack | Add to your `Cargo.toml`: ```toml [dependencies] indras-network = { path = "..." } ``` ### The Simplest Thing That Works ```rust use indras_network::prelude::*; #[tokio::main] async fn main() -> Result<()> { let network = IndrasNetwork::new("~/.myapp").await?; let realm = network.create_realm("My Project").await?; println!("Invite: {}", realm.invite_code().unwrap()); realm.send("Hello, world!").await?; Ok(()) } ``` `IndrasNetwork::new()` does everything: generates a cryptographic identity, opens local storage, starts the networking stack, connects to relay servers, and begins peer discovery. The path you pass becomes the data directory where keys, documents, and artifacts live on disk. ### Construction Methods There are four ways to create a network instance: **`IndrasNetwork::new(path)`** — The default. Uses `Preset::Default` configuration with the given data directory. Good for prototyping. **`IndrasNetwork::preset(preset)`** — Returns a `NetworkBuilder` pre-configured for a specific use case (Chat, Collaboration, IoT, OfflineFirst). You must call `.data_dir()` and `.build()` on the builder. **`IndrasNetwork::builder()`** — Returns a blank `NetworkBuilder` for full manual configuration. **`IndrasNetwork::with_config(config)`** — Accepts a fully constructed `NetworkConfig` directly. ### Lifecycle After construction, call `start()` to begin networking: ```rust let network = IndrasNetwork::new("~/.myapp").await?; network.start().await?; // ... use the network ... network.stop().await?; ``` `start()` initializes the transport layer, connects to relay servers, and begins listening for peers. `stop()` tears down all interfaces, cancels artifact syncs, and closes connections gracefully. Check state with `is_running()`. ### First Run Detection ```rust if network.is_first_run() { // Show onboarding UI } ``` Returns `true` when the data directory was freshly created (no pre-existing identity). Useful for triggering setup wizards. --- ## Configuration & Presets ### Presets Five presets configure the network for common use cases: | Preset | Max Peers | Max Realms | PQ Crypto | Auto-Reconnect | Notes | |--------|-----------|------------|-----------|-----------------|-------| | `Default` | 64 | 32 | No | Yes | Balanced general use | | `Chat` | 128 | 64 | No | Yes | Higher limits for messaging apps | | `Collaboration` | 32 | 16 | No | Yes | Fewer, deeper connections | | `IoT` | 8 | 4 | No | Yes | Minimal resource use | | `OfflineFirst` | 64 | 32 | No | Yes | Aggressive caching, relaxed timeouts | ```rust let network = IndrasNetwork::preset(Preset::Chat) .data_dir("~/.mychat") .display_name("Alice") .build() .await?; ``` ### NetworkBuilder The builder provides a fluent API for fine-grained control: ```rust let network = IndrasNetwork::builder() .data_dir("~/.myapp") .display_name("Alice") .relay_servers(vec!["relay.example.com".into()]) .enforce_pq_signatures() .passphrase("hunter2") .build() .await?; ``` Builder methods: | Method | Type | Description | |--------|------|-------------| | `.data_dir(path)` | `impl Into` | **Required.** Where to store keys, docs, artifacts | | `.display_name(name)` | `impl Into` | Human-readable name broadcast to peers | | `.relay_servers(urls)` | `Vec` | Custom relay server URLs | | `.enforce_pq_signatures()` | *(none)* | Require ML-DSA-65 post-quantum signatures | | `.passphrase(pass)` | `impl Into` | Encrypt the keystore with Argon2id + ChaCha20-Poly1305 | | `.pass_story(story)` | `PassStory` | Authenticate via a memorable story instead of a passphrase | | `.local_only()` | *(none)* | Disable DNS/pkarr discovery and relay servers | | `.poll_interval(dur)` | `Duration` | How often to poll contacts for peer changes (default 2s) | | `.save_interval(dur)` | `Duration` | How often to save the world view snapshot (default 30s) | ### NetworkConfig The raw config struct that presets and builders produce: ```rust pub struct NetworkConfig { pub preset: Preset, pub data_dir: PathBuf, pub display_name: Option, pub relay_servers: Vec, pub enforce_pq_signatures: bool, pub passphrase: Option, pub pass_story: Option, pub local_only: bool, pub poll_interval: Duration, pub save_interval: Duration, } ``` - `local_only` (default: `true`) — When true, disables DNS/pkarr discovery and relay servers. Peers can only connect via local network gossip. - `poll_interval` (default: 2s) — How often the peering system polls contacts for changes. - `save_interval` (default: 30s) — How often the world view snapshot is saved to disk. ### Authentication Two mutually exclusive authentication modes protect the local keystore: **Passphrase** — A traditional password. The keystore is encrypted with Argon2id key derivation feeding into ChaCha20-Poly1305. **Pass Story** — A memorable narrative used as the key material. Same crypto underneath, but the input is a story rather than a password. See [Your Story Is Your Key](your-story-is-your-key.md). If neither is set, the keystore is unencrypted on disk. For production apps, always set one. --- ## Identity Every network instance has a cryptographic identity — a keypair generated at first run and stored in the data directory. ### MemberId ```rust pub type MemberId = [u8; 32]; ``` The 32-byte public key hash that uniquely identifies a peer across the network. This is the canonical identifier used everywhere — in member lists, access grants, message sender fields, and contact entries. ### Accessing Your Identity ```rust let my_id: MemberId = network.id(); let member: Member = network.identity(); let name: &str = network.display_name(); ``` `id()` returns your `MemberId`. `identity()` returns a full `Member` struct with display name and presence info. `display_name()` returns the human-readable name you set (or a default). ### Setting Display Name ```rust network.set_display_name("Alice").await?; ``` Broadcasts the new name to all connected peers. ### IdentityCode A human-shareable encoding of your `MemberId`: ```rust let code: IdentityCode = network.identity_code(); println!("{}", code); // indra1qyz...k3m (~58 characters) ``` Identity codes use **bech32m** encoding with the `indra` human-readable prefix. They're designed to be copy-pasted, printed on business cards, or embedded in QR codes. The URI format adds a scheme prefix and optional name: ```rust let uri = code.to_uri(); // indra://indra1qyz...k3m // indra://indra1qyz...k3m?name=Alice ``` Parsing back: ```rust let code = IdentityCode::from_str("indra1qyz...k3m")?; let code = IdentityCode::from_uri("indra://indra1qyz...k3m?name=Alice")?; let member_id: MemberId = code.member_id(); let name: Option<&str> = code.display_name(); ``` ### Identity URI A shorthand for the full URI string: ```rust let uri: String = network.identity_uri(); // "indra://indra1qyz...k3m?name=Alice" ``` --- ## Realms A realm is a collaborative space where members communicate, share documents, and exchange artifacts. Under the hood, a realm maps to a gossip topic (an `iroh` interface) where all members publish and subscribe to messages. ### Creating a Realm ```rust let realm = network.create_realm("My Project").await?; ``` This creates a new realm, generates an invite code, and returns a `Realm` handle. The creator is automatically the first member. ### Joining a Realm ```rust let realm = network.join("indra:realm:abc123...").await?; ``` Parses an invite code string and joins the corresponding realm. Returns a `Realm` handle. ### Invite Codes ```rust let invite: Option<&InviteCode> = realm.invite_code(); println!("{}", invite.unwrap()); // indra:realm:kFd8mQ... ``` Invite codes use the URI format `indra:realm:`. The encoded data contains the realm's gossip topic ID and, for artifact-backed realms, the `ArtifactId`. Parsing invite codes: ```rust let invite = InviteCode::from_str("indra:realm:abc123...")?; let topic_id = invite.topic_id(); let artifact_id: Option<&ArtifactId> = invite.artifact_id(); ``` ### Listing Realms ```rust let realms: Vec = network.realms().await; ``` Returns all realms the local node has joined. ### Getting a Realm by ID ```rust let realm_id: RealmId = /* ... */; let realm: Option = network.get_realm_by_id(realm_id).await; ``` `RealmId` is a type alias for the interface identifier (a `[u8; 32]`). ### Peer-Based Realms Two shortcuts create or retrieve a realm for a specific peer: ```rust // Get-or-create a DM realm with a peer let realm: Realm = network.realm(peer_id).await?; // Get an existing peer realm (returns None if not yet created) let realm: Option = network.get_realm(peer_id).await; ``` The realm ID for a peer-based realm is deterministically derived from both members' IDs using BLAKE3, so both sides always agree on the same realm. ### Leaving a Realm ```rust network.leave_realm(realm_id).await?; ``` Removes the realm from local state and stops participating in its gossip topic. ### Realm Properties ```rust let id: RealmId = realm.id(); let name: &str = realm.name(); let artifact_id: Option<&ArtifactId> = realm.artifact_id(); let invite: Option<&InviteCode> = realm.invite_code(); ``` The `artifact_id` links the realm to its corresponding Tree artifact in the domain model. This was added in the unification — a realm IS a Tree artifact. --- ## Direct Connect The direct connect system implements the "Identity IS Connection" pattern. Knowing someone's `MemberId` is sufficient to establish a connection — no server, no IP address, no port number. ### How It Works Every peer has a deterministic **inbox realm** derived from their `MemberId` via BLAKE3: ```rust // Internally: fn inbox_realm_id(member_id: &MemberId) -> [u8; 32] { let mut hasher = blake3::Hasher::new(); hasher.update(b"indras:inbox:"); hasher.update(member_id); *hasher.finalize().as_bytes() } ``` When you want to connect to someone, you send a `ConnectionNotify` message to their inbox. They receive it and can accept the connection. ### Connecting ```rust // Connect by MemberId let realm = network.connect(their_member_id).await?; // Connect by IdentityCode — returns both the DM realm and peer info let (realm, peer_info) = network.connect_by_code("indra1qyz...k3m").await?; ``` Both methods: 1. Derive the peer's inbox realm ID 2. Send a connection notification 3. Wait for the peer to acknowledge 4. Create a shared DM realm 5. Add the peer as a contact 6. Return the `Realm` handle (and `PeerInfo` for `connect_by_code`) ### Key Exchange Post-quantum key exchange happens automatically during connection. The system uses **ML-KEM-768** for key encapsulation: ```rust pub struct PendingKeyExchange { pub peer_id: MemberId, pub our_encapsulation_key: Vec, pub status: KeyExchangeStatus, pub created_at: u64, } pub enum KeyExchangeStatus { Initiated, ResponseReceived { shared_secret: Vec }, Completed, Failed(String), } ``` The `KeyExchangeRegistry` (a CRDT document) tracks all pending and completed exchanges. You typically don't interact with this directly — it's managed automatically by `connect()` and `connect_by_code()`. ### Initiator Determination When two peers connect, one must be the "initiator" (to avoid duplicate realms). This is determined by comparing `MemberId` bytes: ```rust pub fn is_initiator(our_id: &MemberId, their_id: &MemberId) -> bool { our_id > their_id } ``` Deterministic and symmetric — both sides always agree on who initiates. --- ## Encounters Encounters enable in-person peer discovery using short spoken codes. Two people in the same room say "my code is 847293" and they're connected. ### Creating an Encounter ```rust let handle: EncounterHandle = network.create_encounter().await?; println!("Tell them: {}", handle.code()); // "847293" ``` The `EncounterHandle` contains a 6-digit code and the underlying gossip topic. ### Joining an Encounter ```rust let code = "847293"; let handle: EncounterHandle = network.join_encounter(code).await?; ``` Both parties are now on the same gossip topic and can exchange identity information. ### Time Windows Encounter codes are valid for 60-second windows. The current window is derived from the system clock: ```rust fn current_time_window() -> u64 { SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_secs() / 60 } ``` The gossip topic is derived from the code AND the time window via BLAKE3, so the same 6-digit code maps to different topics at different times. This prevents code reuse attacks. ### Exchange Payload When peers discover each other on the encounter topic, they exchange: ```rust pub struct EncounterExchangePayload { pub member_id: MemberId, pub display_name: Option, pub signing_key: Vec, pub kem_key: Vec, } ``` This includes the ML-DSA-65 signing key and ML-KEM-768 encapsulation key for post-quantum secure communication. ### Introduction After an encounter, formalize the connection: ```rust network.introduce(their_member_id).await?; ``` This creates the DM realm, exchanges keys, and adds the peer as a contact. --- ## Messaging ### Sending Messages ```rust // Simple text realm.send("Hello!").await?; // With a content builder realm.send(Content::text("Hello!")).await?; // Images realm.send(Content::image(bytes, "photo.jpg", "image/jpeg")).await?; // Artifacts realm.send(Content::artifact(artifact_id, "report.pdf")).await?; // Reactions realm.react(message_id, "thumbsup").await?; // Replies realm.reply(parent_message_id, "I agree!").await?; ``` ### The Content Enum `Content` has 15 variants covering every type of message payload: | Variant | Description | Construction | |---------|-------------|--------------| | `Text(String)` | Plain text | `Content::text("hello")` | | `Binary { data, mime_type }` | Raw bytes with MIME | `Content::binary(data, "application/pdf")` | | `Artifact { id, name }` | Reference to a shared artifact | `Content::artifact(id, "file.pdf")` | | `Reaction { target, emoji }` | Emoji reaction to a message | `Content::reaction(msg_id, "heart")` | | `System(String)` | System notification | `Content::system("Alice joined")` | | `Extension { type_name, data }` | Custom typed payload | `Content::extension("myapp.poll", data)` | | `Image { data, filename, mime_type }` | Inline image | `Content::image(bytes, "photo.jpg", "image/jpeg")` | | `InlineArtifact { data, filename, mime_type }` | Embedded file | `Content::inline_artifact(bytes, "doc.pdf", "application/pdf")` | | `Gallery { items, caption }` | Multiple images | `Content::gallery(items, Some("Vacation photos"))` | | `ArtifactGranted { artifact_id, artifact_name, access_mode, granter }` | Access grant notification | Constructed internally | | `ArtifactRecalled { artifact_id, artifact_name, recaller }` | Access revoked notification | Constructed internally | | `RecoveryRequest(ArtifactRecoveryRequest)` | Request to recover artifacts | Constructed internally | | `RecoveryManifest(RecoveryManifest)` | Recovery manifest response | Constructed internally | **Extension** is the escape hatch for application-specific messages. The `type_name` is a namespaced string (e.g., `"myapp.poll"`) and `data` is arbitrary bytes. ### Gallery Items ```rust pub struct GalleryItem { pub name: String, pub mime_type: String, pub size: u64, pub thumbnail_data: Option, pub artifact_hash: String, pub dimensions: Option<(u32, u32)>, } ``` ### Receiving Messages ```rust use futures::StreamExt; // Live stream of new messages let mut messages = realm.messages(); while let Some(msg) = messages.next().await { println!("{}: {}", msg.sender_name(), msg.content.as_text().unwrap_or("")); } ``` The `messages()` method returns an async `Stream` of `Message` structs. ### Message Struct ```rust pub struct Message { pub id: MessageId, pub sender: MemberId, pub sender_name: String, pub content: Content, pub timestamp: u64, pub sequence: u64, pub reply_to: Option, pub references: Vec, } ``` Key fields: - `id` — A unique `MessageId` (a `[u8; 32]` hash) - `sequence` — Monotonically increasing per-realm counter, used for read tracking - `reply_to` — Links to parent message for threading - `references` — Additional content references (artifacts, other messages) ### Content Reference ```rust pub struct ContentReference { pub ref_type: String, pub ref_id: Vec, pub display_name: Option, } ``` ### Querying Messages ```rust // All messages (loads from storage) let all: Vec = realm.all_messages().await?; // Messages after a sequence number let recent: Vec = realm.messages_since(sequence_number).await?; // Full-text search let results: Vec = realm.search_messages("budget report").await?; ``` --- ## Documents Documents are CRDT-backed typed data structures that automatically synchronize across all realm members. They're the building block for shared application state. ### DocumentSchema Trait `DocumentSchema` is an explicit trait that controls how documents merge and sync: ```rust pub trait DocumentSchema: Default + Clone + Serialize + DeserializeOwned + Send + Sync + 'static { /// Merge remote state into this document. /// Default: full replacement (last-writer-wins). fn merge(&mut self, remote: Self) { *self = remote; } /// Extract a compact delta between old and new state. /// Returns Some(bytes) for incremental sync, None to send full state. fn extract_delta(_old: &Self, _new: &Self) -> Option> { None } /// Apply a compact delta to this document. /// Returns true if applied successfully. fn apply_delta(&mut self, _delta: &[u8]) -> bool { false } } ``` For types that use the default last-writer-wins behavior, use the convenience macro: ```rust use indras_network::impl_document_schema; #[derive(Default, Clone, Serialize, Deserialize)] struct TodoList { items: Vec, title: String, } #[derive(Clone, Serialize, Deserialize)] struct TodoItem { text: String, done: bool, } impl_document_schema!(TodoList); ``` For types that need custom merge logic (e.g., set-union for chat messages), implement the trait directly and override `merge`. For bandwidth-efficient sync, also implement `extract_delta` and `apply_delta` to send only changed data instead of the full document. ### Getting a Document ```rust let doc: Document = realm.document("todos").await?; ``` The document is identified by name within a realm. If it doesn't exist yet, it's created with the schema's `default_value()`. ### Reading ```rust // Read (acquires lock) let data: TodoList = doc.read().await; // Force refresh from storage doc.refresh().await?; ``` ### Writing ```rust // Simple update doc.update(|todos| { todos.items.push(TodoItem { text: "Buy groceries".into(), done: false, }); }).await?; // Transaction (multiple operations) doc.transaction(|todos| { todos.items.retain(|item| !item.done); todos.title = "Active Items".into(); }).await?; ``` Both `update` and `transaction` serialize the new state and broadcast it to peers. The difference is semantic — use `transaction` when you want to signal that multiple changes are atomic. ### Reactive Changes ```rust use futures::StreamExt; let mut changes = doc.changes(); while let Some(change) = changes.next().await { println!("Document updated (remote={}): {:?}", change.is_remote, change.new_state); if let Some(author) = &change.author { println!(" by: {}", author.name()); } } ``` `DocumentChange` is a struct: ```rust pub struct DocumentChange { pub new_state: T, pub author: Option, pub is_remote: bool, } ``` The `changes()` stream fires whenever the document is updated — either locally or from a remote peer. A background listener watches for `DocumentEnvelope` messages on the realm's gossip topic and deserializes them into the typed value. ### Document Discovery ```rust let names: Vec = realm.document_names().await?; let exists: bool = realm.has_document("todos").await?; ``` --- ## Members & Presence ### Member Struct ```rust pub struct Member { pub id: MemberId, pub display_name: String, pub is_online: bool, pub last_seen: Option, } ``` ### Member Events ```rust use futures::StreamExt; let mut events = realm.member_events(); while let Some(event) = events.next().await { match event { MemberEvent::Joined(member) => println!("{} joined", member.display_name), MemberEvent::Left(member_id) => println!("Someone left"), MemberEvent::Updated(member) => println!("{} updated", member.display_name), MemberEvent::Discovered(member) => println!("Found {}", member.display_name), } } ``` `Discovered` fires when a peer is found on the gossip network but hasn't formally "joined" yet (e.g., they're still syncing). ### Listing Members ```rust // Basic list let members: Vec = realm.member_list().await?; // With cryptographic details let detailed: Vec = realm.member_list_with_info().await?; // Count let count: usize = realm.member_count().await?; ``` ### MemberInfo ```rust pub struct MemberInfo { pub id: MemberId, pub display_name: String, pub signing_key: Option>, // ML-DSA-65 pub kem_key: Option>, // ML-KEM-768 pub is_online: bool, pub last_seen: Option, } ``` The `signing_key` is the post-quantum ML-DSA-65 public key. The `kem_key` is the ML-KEM-768 encapsulation key used for key exchange. ### Presence ```rust let online: Vec = realm.online_members().await?; let is_online: bool = realm.is_member_online(member_id).await?; ``` Presence is tracked via periodic heartbeats on the gossip topic. A member is considered offline if no heartbeat is received within the timeout window. --- ## Contacts The contacts system provides a way to manage relationships with other peers across realms. ### Joining the Contacts Realm ```rust let contacts_realm: ContactsRealm = network.join_contacts_realm().await?; // Or retrieve if already joined let contacts_realm: Option = network.contacts_realm().await; ``` The contacts realm is a special realm where your contact list is stored as a CRDT document. ### Contact Entry ```rust pub struct ContactEntry { pub sentiment: i8, // -1, 0, or 1 pub relayable: bool, // Whether sentiment is relayable to second-degree contacts pub display_name: Option, pub status: ContactStatus, // Pending or Confirmed } ``` ### Contact Status ```rust pub enum ContactStatus { Pending, // Invitation sent, not yet accepted Confirmed, // Both sides acknowledge the contact } ``` ### Sentiment Sentiment is a simple -1/0/1 value: | Value | Meaning | |-------|---------| | `-1` | Negative (blocked, muted) | | `0` | Neutral (default) | | `1` | Positive (trusted, favorited) | ```rust contacts_realm.update_sentiment(&member_id, 1).await?; // Mark as trusted contacts_realm.update_sentiment(&member_id, -1).await?; // Mark as blocked // Query sentiment let sentiment: Option = contacts_realm.get_sentiment(&member_id).await; // Get contacts with sentiment values let with_sentiment: Vec<(MemberId, i8)> = contacts_realm.contacts_with_sentiment().await; // Get only relayable sentiments (for second-degree relay) let relayable: Vec<(MemberId, i8)> = contacts_realm.relayable_sentiments().await; ``` ### Managing Contacts ```rust // Add a contact (default sentiment, no display name) contacts_realm.add_contact(member_id).await?; // Add a contact with a display name contacts_realm.add_contact_with_name(member_id, Some("Alice".into())).await?; // Remove a contact contacts_realm.remove_contact(&member_id).await?; // Check if a member is a contact let is_contact: bool = contacts_realm.is_contact(&member_id).await; // List all contact IDs let contact_ids: Vec = contacts_realm.contacts_list().await; // Get the full entry for a contact let entry: Option = contacts_realm.get_contact_entry(&member_id).await; // Contact count let count: usize = contacts_realm.contact_count().await; // Toggle relayable contacts_realm.set_relayable(&member_id, true).await?; // Confirm a contact (Pending → Confirmed) contacts_realm.confirm_contact(&member_id).await?; // Check status let status: Option = contacts_realm.get_status(&member_id).await; ``` ### ContactsDocument Under the hood, contacts are stored in a `ContactsDocument` — a CRDT document synced within the contacts realm. You typically interact through `ContactsRealm` methods, but the raw document is accessible if needed. --- ## Home Realm The home realm is your personal storage space. It's a deterministic realm derived from your `MemberId` that only you can write to. Other peers can read artifacts you've shared from it. ### Getting the Home Realm ```rust let home: HomeRealm = network.home_realm().await?; // Or get it if it exists let home: Option = network.get_home_realm().await; ``` ### Home Realm ID Derivation The home realm ID is deterministic — derived from your `MemberId` via BLAKE3: ```rust pub fn home_realm_id(member_id: &MemberId) -> [u8; 32] { let mut hasher = blake3::Hasher::new(); hasher.update(b"indras:home:"); hasher.update(member_id); *hasher.finalize().as_bytes() } ``` This means anyone who knows your `MemberId` can derive your home realm ID and request artifacts from it. ### Sharing Artifacts ```rust // Share raw bytes let artifact_id = home.share_artifact( "report.pdf", bytes, "application/pdf", ).await?; // Share a file from disk let artifact_id = home.share_file("/path/to/report.pdf").await?; // Upload with explicit name and mime type let artifact_id = home.upload( "photo.jpg", image_bytes, "image/jpeg", ).await?; ``` All three methods store the artifact, register it in the artifact index, and make it available for P2P sync. ### Retrieving Artifacts ```rust let entry: Option = home.get_artifact(artifact_id).await?; ``` ### HomeArtifactMetadata ```rust pub struct HomeArtifactMetadata { pub id: ArtifactId, pub name: String, pub mime_type: String, pub size: u64, pub created_at: u64, } ``` ### Documents in Home Realm ```rust let doc: Document = home.document("settings").await?; ``` The home realm supports typed documents just like regular realms. ### DM and Realm Artifact Registration ```rust // Ensure a DM story artifact exists for a peer let story_id = home.ensure_dm_story(peer_member_id).await?; // Ensure a realm artifact exists let artifact_id = home.ensure_realm_artifact(realm_id, "Project Alpha").await?; ``` These methods create Tree artifacts that represent conversations and realms in your home artifact tree. --- ## Artifact Sharing ### ArtifactId ```rust pub enum ArtifactId { Blob([u8; 32]), // Content-addressed immutable blob Doc([u8; 32]), // CRDT document identifier } ``` `Blob` variants are hashes of the content. `Doc` variants are deterministically derived identifiers for CRDT documents. ### Deterministic ID Generation Several helpers generate deterministic IDs: ```rust // Generate a random tree ID let tree_id = generate_tree_id(); // Generate a content-addressed leaf ID from payload bytes let leaf_id = leaf_id(payload_bytes); // Generate a DM story ID let dm_id = dm_story_id(&member_a_id, &member_b_id); ``` `dm_story_id` is symmetric — `dm_story_id(A, B) == dm_story_id(B, A)`. ### Sharing in a Realm ```rust // Default sharing (Revocable access) let artifact_id = realm.share_artifact( "report.pdf", bytes, "application/pdf", ).await?; // Share with specific access mode let artifact_id = realm.share_artifact_with_mode( "report.pdf", bytes, "application/pdf", AccessMode::Permanent, ).await?; // Granular sharing to specific members let artifact_id = realm.share_artifact_granular( "report.pdf", bytes, "application/pdf", &[member_a, member_b], AccessMode::Timed(expiry_timestamp), ).await?; ``` ### Viewing Shared Artifacts ```rust let artifacts: Vec = realm.artifacts_view().await?; ``` ### Downloading ```rust let download: ArtifactDownload = realm.download(artifact_id).await?; // Track progress use futures::StreamExt; let mut progress = download.progress(); while let Some(p) = progress.next().await { println!("{}%", p.percent()); } // Wait for completion let file_path: PathBuf = download.finish().await?; // Or cancel download.cancel(); ``` ### DownloadProgress ```rust pub struct DownloadProgress { pub bytes_downloaded: u64, pub total_bytes: u64, } impl DownloadProgress { pub fn percent(&self) -> f32; pub fn is_complete(&self) -> bool; } ``` ### ArtifactDownload Handle The download handle provides: | Method | Returns | Description | |--------|---------|-------------| | `artifact_id()` | `&ArtifactId` | The artifact being downloaded | | `name()` | `&str` | Human-readable name | | `current_progress()` | `DownloadProgress` | Current state snapshot | | `progress()` | `Stream` | Live progress updates | | `finish()` | `Result` | Wait for completion, return file path | | `cancel()` | `()` | Cancel the download | | `is_cancelled()` | `bool` | Check cancellation state | --- ## Access Control Access control governs who can read, modify, and redistribute artifacts. ### AccessMode ```rust pub enum AccessMode { Revocable, // Owner can revoke at any time Permanent, // Cannot be revoked once granted Timed(u64), // Auto-expires at the given Unix timestamp Transfer, // Ownership transfer — grantee becomes new owner } ``` ### Granting Access ```rust home.grant_access(artifact_id, grantee_member_id, AccessMode::Revocable).await?; ``` Grants are stored in the `ArtifactIndex` as part of the `HomeArtifactEntry`. ### Revoking Access ```rust home.revoke_access(artifact_id, grantee_member_id).await?; ``` Only works for `Revocable` and expired `Timed` grants. Attempting to revoke a `Permanent` grant returns `RevokeError`. ### Recalling Artifacts ```rust home.recall(artifact_id).await?; ``` Recall is stronger than revoke — it removes the artifact entirely and notifies all grantees that the artifact has been recalled. This triggers `Content::ArtifactRecalled` messages in the relevant realms. ### Transferring Ownership ```rust home.transfer(artifact_id, new_owner_member_id).await?; ``` Transfers the artifact to a new owner. After transfer, the original owner loses all access and the new owner can manage grants. ### Querying Access ```rust let grantees: Vec<(MemberId, AccessMode)> = home.shared_with(artifact_id).await?; ``` ### Error Types ```rust pub enum GrantError { AlreadyGranted, ArtifactNotFound, NotOwner, InvalidMode(String), } pub enum RevokeError { NotGranted, ArtifactNotFound, NotOwner, PermanentGrant, } pub enum TransferError { ArtifactNotFound, NotOwner, AlreadySelf, } ``` ### ArtifactProvenance Every artifact tracks its origin: ```rust pub struct ArtifactProvenance { pub provenance_type: ProvenanceType, pub original_author: MemberId, pub timestamp: u64, } pub enum ProvenanceType { Original, // Created by the author Received, // Received via sharing Imported, // Imported from external source } ``` ### ArtifactStatus ```rust pub enum ArtifactStatus { Active, Recalled, Expired, Transferred, } ``` --- ## Tree Composition Tree composition lets you organize artifacts into hierarchical structures with inherited access control. ### Attaching Children ```rust // Attach multiple children at once home.attach_children(parent_tree_id, &[child_a_id, child_b_id]).await?; // Attach a single child home.attach_child(parent_tree_id, child_id).await?; ``` When a child is attached to a parent, it inherits the parent's access grants. If the parent is shared with Alice, Alice automatically gets access to all children. ### Detaching ```rust // Detach all children home.detach_all_children(parent_tree_id).await?; // Detach a specific child home.detach_child(parent_tree_id, child_id).await?; ``` Detaching removes the parent-child relationship and revokes inherited access. ### ArtifactIndex Tree Operations The `ArtifactIndex` provides low-level tree operations: ```rust let ancestors: Vec = index.ancestors(artifact_id); let descendants: Vec = index.descendants(artifact_id); let depth: usize = index.depth(artifact_id); let subtree_size: usize = index.subtree_size(artifact_id); ``` ### Inherited Access ```rust let has_access: bool = index.has_access_with_inheritance(artifact_id, member_id); ``` This walks up the tree checking each ancestor's grants. If any ancestor grants access to the member, the function returns `true`. ### Cascade Operations ```rust index.recall_cascade(artifact_id); ``` Recalls an artifact and all its descendants. This is used when a parent Tree is recalled — all children are automatically recalled too. ### HomeArtifactEntry ```rust pub struct HomeArtifactEntry { pub id: ArtifactId, pub name: String, pub mime_type: String, pub size: u64, pub created_at: u64, pub encrypted_key: Option, pub status: ArtifactStatus, pub grants: Vec, pub provenance: ArtifactProvenance, pub parent: Option, } ``` The `parent` field is the link in the tree structure. It points to the parent Tree artifact's ID (if any). --- ## Artifact Sync The `ArtifactSyncRegistry` manages automatic P2P synchronization of artifacts. When you grant access to an artifact, the sync system automatically creates the networking infrastructure (gossip topics, download tasks) needed for the grantee to receive the data. ### How It Works Each artifact gets its own deterministic interface ID and key seed: ```rust pub fn artifact_interface_id(artifact_id: &ArtifactId) -> [u8; 32] { let mut hasher = blake3::Hasher::new(); hasher.update(b"indras:artifact-sync:"); hasher.update(&artifact_id.as_bytes()); *hasher.finalize().as_bytes() } pub fn artifact_key_seed(artifact_id: &ArtifactId) -> [u8; 32] { let mut hasher = blake3::Hasher::new(); hasher.update(b"indras:artifact-key:"); hasher.update(&artifact_id.as_bytes()); *hasher.finalize().as_bytes() } ``` ### Reconciliation ```rust let registry = ArtifactSyncRegistry::new(node.clone()); // Reconcile: ensure sync is running for all granted artifacts registry.reconcile(&artifact_index).await?; ``` `reconcile` compares the current set of active sync interfaces against what the artifact index says should be syncing. It creates new interfaces for new grants and tears down interfaces for revoked grants. ### Ensure and Teardown ```rust // Manually ensure sync for one artifact registry.ensure(artifact_id).await?; // Tear down sync for one artifact registry.teardown(artifact_id).await?; ``` ### Startup Recovery On startup, the sync registry runs `reconcile` to restore any sync sessions that were active before shutdown. This ensures that artifact downloads resume where they left off. ### Store-and-Forward Sync Primitives Under the hood, artifact sync uses three primitives from `indras-sync`: #### ArtifactDocument A per-tree Automerge document wrapping `AutoCommit`. Stores artifact metadata, references, grants, and key-value metadata with CRDT semantics: ```rust use indras_sync::ArtifactDocument; // Create a new document let mut doc = ArtifactDocument::new(&artifact_id, &steward_id, "story", now); // Add references to child artifacts doc.append_ref(&child_id, 0, Some("chapter-1")); // Manage grants doc.add_grant(&grant); doc.remove_grant(&grantee_id); // Arbitrary metadata doc.set_metadata("mime", b"image/png"); // Lifecycle status doc.set_status(&ArtifactStatus::Recalled { recalled_at: now }); // Persistence let bytes = doc.save(); let loaded = ArtifactDocument::load(&bytes)?; ``` For bootstrapping from a received sync payload, use `ArtifactDocument::empty()` — the schema is populated by `load_incremental()`. > **Gotcha**: Never cache Automerge `ObjId`s — they go stale after sync/merge. `ArtifactDocument` re-looks up object IDs on every access. #### HeadTracker Tracks the last-known Automerge `ChangeHash` heads for each `(ArtifactId, peer)` pair. Enables incremental sync: ```rust use indras_sync::HeadTracker; let mut tracker = HeadTracker::new(); // Record what a peer has seen tracker.update(&artifact_id, &peer_id, current_heads); // Query — empty slice means full sync needed let known: &[ChangeHash] = tracker.get(&artifact_id, &peer_id); // Cleanup tracker.remove_peer(&peer_id); tracker.remove_artifact(&artifact_id); // Persistence (postcard) let bytes = tracker.save()?; let loaded = HeadTracker::load(&bytes)?; ``` #### RawSync Stateless functions for producing and consuming sync payloads: ```rust use indras_sync::{RawSync, ArtifactSyncPayload}; // Sender: build a payload for one recipient let payload: ArtifactSyncPayload = RawSync::prepare_payload( &mut doc, &tracker, &artifact_id, &recipient_id, ); // → transport the payload (gossip, relay, store-and-forward) // Receiver: apply the payload RawSync::apply_payload(&mut doc, &mut tracker, payload, &sender_id)?; // Broadcast to all audience members (skips self) let payloads = RawSync::broadcast_payloads( &mut doc, &tracker, &artifact_id, &audience, &self_id, ); ``` `prepare_payload` checks the tracker for what the recipient already has and sends only the delta. `apply_payload` is idempotent — duplicate changes are silently ignored by Automerge. --- ## Chat Messages The chat message system builds on top of Documents to provide editable, versioned messages. ### EditableChatMessage ```rust pub struct EditableChatMessage { pub id: ChatMessageId, pub author: MemberId, pub author_name: String, pub content: EditableMessageType, pub created_at: u64, pub edited_at: Option, pub deleted: bool, pub versions: Vec, pub reply_to: Option, } ``` ### ChatMessageId and Versions ```rust pub type ChatMessageId = String; pub struct ChatMessageVersion { pub content: EditableMessageType, pub timestamp: u64, pub author: MemberId, } ``` Every edit creates a new version. The `versions` vec is the complete edit history. The current content is always the latest version. ### EditableMessageType ```rust pub enum EditableMessageType { Text, ProofSubmitted { quest_id: String, artifact_id: String, }, ProofFolderSubmitted { quest_id: String, folder_id: String, }, BlessingGiven { quest_id: String, claimant: String, }, ArtifactRecalled { artifact_hash: String, shared_at: u64, }, Image { mime_type: String, inline_data: Option, // base64 for small images (<2MB) artifact_hash: Option, // hash ref for large images filename: Option, dimensions: Option<(u32, u32)>, alt_text: Option, }, Gallery { folder_id: String, title: Option, items: Vec, }, } ``` Note: `Text` is a unit variant — the text content is stored in the `EditableChatMessage.current_content` field, not in the enum. The `Image` variant supports both inline base64 data (for small images) and artifact hash references (for large images). `ProofFolderSubmitted` is new — it represents a proof folder artifact submitted for a quest. ### RealmChatDocument ```rust pub struct RealmChatDocument { messages: Vec, } ``` This is a CRDT document that stores all chat messages for a realm. Methods: ```rust let doc: Document = realm.document("chat").await?; doc.update(|chat| { chat.add_message(message); }).await?; doc.update(|chat| { chat.edit_message(message_id, new_content, author, timestamp); }).await?; doc.update(|chat| { chat.delete_message(message_id, author); }).await?; ``` --- ## Read Tracking The read tracker keeps per-member read positions for unread message counting. ### ReadTrackerDocument ```rust pub struct ReadTrackerDocument { // Maps MemberId (hex) -> last read sequence number read_positions: HashMap, } ``` This is a CRDT document with LWW (Last Writer Wins) semantics — each member can only update their own read position. ### Marking as Read ```rust realm.mark_read().await?; ``` Sets your read position to the current latest sequence number. ### Checking Unread Count ```rust let unread: usize = realm.unread_count().await?; let last_read: u64 = realm.last_read_seq().await?; ``` `unread_count` returns the number of messages with sequence numbers higher than your last read position. --- ## Realm Aliases Realm aliases let members give custom nicknames to realms. These are CRDT-synchronized across all members. ### RealmAlias ```rust pub struct RealmAlias { pub realm_id: RealmId, pub alias: String, pub set_by: MemberId, pub set_at: u64, } ``` Aliases are limited to `MAX_ALIAS_LENGTH` (77 characters) and support full Unicode. ### Setting Aliases ```rust realm.set_alias("The Cool Project").await?; ``` ### Getting Aliases ```rust let alias: Option = realm.get_alias().await?; let display: String = realm.alias().await; // Returns alias or realm name ``` `alias()` returns the alias if set, otherwise falls back to the realm name. ### Clearing Aliases ```rust realm.clear_alias().await?; ``` ### RealmAliasDocument The underlying CRDT document that stores aliases for all realms. Members can see each other's aliases but each member controls their own. --- ## Encryption ### Per-Artifact Encryption Every artifact can be encrypted with its own key: ```rust pub const ARTIFACT_KEY_SIZE: usize = 32; pub type ArtifactKey = [u8; ARTIFACT_KEY_SIZE]; ``` ### EncryptedArtifactKey ```rust pub struct EncryptedArtifactKey { pub nonce: Vec, pub ciphertext: Vec, } ``` The artifact key is encrypted with the owner's master key and stored alongside the artifact metadata in the `HomeArtifactEntry`. When granting access, the key is re-encrypted for the grantee's public key. --- ## Identity Export & Import ### Exporting ```rust let backup: IdentityBackup = network.export_identity().await?; // Serialize and save the backup ``` ### Importing ```rust let backup: IdentityBackup = /* deserialize from file */; network.import_identity(backup).await?; ``` `IdentityBackup` contains the cryptographic keypair and enough metadata to reconstruct the identity on a new device. ### Artifact Recovery For recovering artifacts after an identity restore: ```rust pub struct ArtifactRecoveryRequest { pub requesting_member: MemberId, pub artifact_ids: Vec, } pub struct ArtifactRecoveryResponse { pub provider: MemberId, pub artifacts: Vec, } pub struct RecoverableArtifact { pub id: ArtifactId, pub name: String, pub encrypted_key: EncryptedArtifactKey, } pub struct RecoveryManifest { pub artifacts: Vec, pub timestamp: u64, } ``` Recovery works by sending `Content::RecoveryRequest` messages to realm members, who respond with `Content::RecoveryManifest` containing the artifacts they can provide. --- ## Blocking ```rust network.block_contact(member_id).await?; ``` Blocking a contact: 1. Sets their sentiment to `-1` in the contacts document 2. Leaves all shared realms (DM realms with that peer) 3. Prevents future connection attempts from that peer --- ## World View WorldView provides a diagnostic snapshot of the entire network state. ### Building a World View ```rust let world_view: WorldView = network.save_world_view().await?; ``` ### WorldView Structure ```rust pub struct WorldView { pub timestamp: String, pub node: NodeInfo, pub interfaces: Vec, pub peers: Vec, pub transport: TransportInfo, } pub struct NodeInfo { pub display_name: Option, pub iroh_public_key: String, pub member_id: String, pub endpoint_addr: Option, pub data_dir: String, } pub struct InterfaceInfo { pub id: String, pub name: Option, pub event_count: u64, pub member_count: u32, pub encrypted: bool, pub created_at_millis: i64, pub last_activity_millis: i64, pub members: Vec, pub documents: Vec, } pub struct DocumentInfo { pub name: String, pub data_size_bytes: usize, pub chat_message_count: Option, pub recent_message_ids: Option>, } pub struct MemberViewInfo { pub peer_id: String, pub role: String, pub active: bool, pub joined_at_millis: i64, } pub struct PeerViewInfo { pub peer_id: String, pub display_name: Option, pub first_seen_millis: i64, pub last_seen_millis: i64, pub message_count: u64, pub trusted: bool, pub connected: bool, pub has_pq_encapsulation_key: bool, pub has_pq_verifying_key: bool, } pub struct TransportInfo { pub connected_peers: Vec, pub discovered_peers: Vec, pub active_realm_topics: Vec, } ``` ### Saving to File ```rust let world_view = WorldView::build(&network).await; world_view.save(Path::new("/path/to/world_view.json"))?; // Or via the network convenience method: network.save_world_view().await?; ``` The output is JSON, designed to be read by diagnostic tools or the dashboard UI. Comparing world view files from different nodes reveals sync discrepancies — each interface includes per-document data sizes and recent chat message IDs for diffing. --- ## Peering The peering module provides reactive peer tracking, event subscription, and background lifecycle management. It builds on the contacts system to provide a higher-level view of connected peers. ### PeerInfo ```rust pub struct PeerInfo { pub member_id: MemberId, pub display_name: String, pub connected_at: i64, pub sentiment: i8, pub status: ContactStatus, } ``` `PeerInfo` is a snapshot of a connected peer's state, including their current sentiment rating and contact status. ### PeerStatus `PeerStatus` is a re-export of `ContactStatus` for convenience: ```rust pub use ContactStatus as PeerStatus; // Pending — invite sent, waiting for acceptance // Confirmed — bidirectional connection established ``` ### PeerEvent ```rust pub enum PeerEvent { PeerConnected { peer: PeerInfo }, PeerDisconnected { member_id: MemberId }, PeersChanged { peers: Vec }, ConversationOpened { realm_id: RealmId, peer: PeerInfo }, PeerBlocked { member_id: MemberId, left_realms: Vec }, SentimentChanged { member_id: MemberId, sentiment: i8 }, WorldViewSaved, NetworkEvent(GlobalEvent), Warning(String), } ``` | Variant | When it fires | |---------|---------------| | `PeerConnected` | A new peer appeared in the contacts list | | `PeerDisconnected` | A peer was removed from the contacts list | | `PeersChanged` | The full peer list changed (emitted on every poll diff) | | `ConversationOpened` | A new DM conversation was opened via `connect` / `connect_by_code` | | `PeerBlocked` | A contact was blocked and all shared realms were left | | `SentimentChanged` | Sentiment toward a peer was updated | | `WorldViewSaved` | The world view was saved to disk | | `NetworkEvent` | A raw `GlobalEvent` forwarded from the network event stream | | `Warning` | A non-fatal warning (e.g., failed world view save) | ### Subscribing to Peer Events ```rust // Subscribe to peer events (broadcast channel) let mut rx = network.peer_events(); // Subscribe and get the current peer list as a snapshot let (mut rx, current_peers) = network.peer_events_with_snapshot(); // Watch the current peer list (always has the latest value) let peers_rx = network.peers(); let current: Vec = peers_rx.borrow().clone(); ``` `peer_events()` returns a broadcast receiver. `peer_events_with_snapshot()` also returns the current peer list at subscription time, avoiding a race between subscribing and the first `PeersChanged` event. `peers()` returns a watch channel that always holds the latest peer list. ### Background Tasks The peering system spawns three background tasks when the network starts: - **Contact poller** — Polls the contacts realm every `poll_interval` (default 2s), diffs against the previous peer set, and emits `PeerConnected` / `PeerDisconnected` / `PeersChanged` events. - **Event forwarder** — Forwards raw `GlobalEvent`s from the network event stream into the `PeerEvent` broadcast channel. - **Periodic saver** — Saves the world view to disk every `save_interval` (default 30s) and emits `WorldViewSaved` events. All background tasks are cancelled when `stop()` is called. --- ## Sentiment The sentiment module implements second-degree trust signal propagation. Each peer publishes their relayable sentiment ratings, and contacts can read these to get signals about people they don't directly know. ### RelayedSentiment ```rust pub struct RelayedSentiment { pub about: MemberId, pub sentiment: i8, pub relay_source: MemberId, pub degree: u8, } ``` A sentiment signal relayed through a contact. `degree` indicates separation: 1 = direct contact's opinion, 2 = relayed through a contact's contact. ### SentimentView ```rust pub struct SentimentView { pub direct: Vec<(MemberId, i8)>, pub relayed: Vec, } ``` Aggregated sentiment about a specific member, combining direct signals (from your own contacts) with relayed signals (from contacts' contacts). Key methods: ```rust // Compute a weighted score (direct signals full weight, relayed attenuated) let score: Option = view.weighted_score(DEFAULT_RELAY_ATTENUATION); // Count of unique signal sources let count: usize = view.signal_count(); // Threshold checks let bad: bool = view.is_negative(0.0, DEFAULT_RELAY_ATTENUATION); let good: bool = view.is_positive(0.0, DEFAULT_RELAY_ATTENUATION); ``` ### SentimentRelayDocument ```rust pub struct SentimentRelayDocument { pub sentiments: BTreeMap, } ``` A CRDT document published by each peer containing their relayable sentiment ratings. Only sentiments where the contact has `relayable = true` are included. Synced within the contacts realm so contacts can read each other's ratings. ### Relay Attenuation ```rust pub const DEFAULT_RELAY_ATTENUATION: f64 = 0.3; ``` Relayed signals are weighted at 30% of direct signals by default. This prevents distant opinions from dominating the aggregate score while still providing useful second-degree information. ### How Sentiment Relay Works 1. You rate contacts with sentiment (-1, 0, or +1) via `contacts_realm.update_sentiment()` 2. Contacts with `relayable = true` have their sentiment included in your `SentimentRelayDocument` 3. Your contacts can read your relay document to learn your opinions about mutual connections 4. When computing a `SentimentView` about someone, direct ratings have full weight and relayed ratings are attenuated by `DEFAULT_RELAY_ATTENUATION` The system is scoped: you only see sentiment from your own contacts and their contacts. There are no global reputation scores. --- ## Error Handling All fallible operations return `Result`. ### IndraError ```rust pub enum IndraError { // Invite errors InvalidInvite { reason: String }, InviteExpired, // Realm errors RealmFull, RemovedFromRealm, RealmNotFound { id: String }, // Document errors DocumentNotFound { name: String }, // Connection errors NotConnected, NotStarted, AlreadyStarted, Timeout, // Permission errors NotMember, InvalidOperation(String), // Infrastructure errors Network(String), Storage(StorageError), Sync(String), Crypto(String), Serialization(String), Io(std::io::Error), Config(String), Schema(String), // Artifact errors Artifact(String), // Authentication errors StoryAuth { reason: String }, // Peer/contact errors NoPeerInRealm, ContactsRealmNotJoined, AlreadyShutDown, } ``` Note: Several variants use struct syntax (e.g., `InvalidInvite { reason }`, `RealmNotFound { id }`, `StoryAuth { reason }`) rather than tuple syntax. `Timeout` has no payload. `Storage` wraps a `StorageError` from the storage layer. ### The Result Type ```rust pub type Result = std::result::Result; ``` Imported via the prelude: ```rust use indras_network::prelude::*; async fn do_stuff() -> Result<()> { // ... Ok(()) } ``` --- ## Escape Hatches For advanced users who need direct access to the underlying infrastructure: ```rust use indras_network::escape::*; ``` ### Available Re-exports | Module | Types | Description | |--------|-------|-------------| | `indras_core` | `NodeId`, `InterfaceId`, `PeerId` | Core identifiers | | `indras_node` | `Node`, `NodeConfig`, `NodeEvent` | The P2P node | | `indras_sync` | `SyncEngine`, `SyncConfig`, `SyncEvent` | CRDT sync engine | | `indras_transport` | `Transport`, `Connection` | Network transport layer | | `indras_storage` | `Storage`, `StorageConfig` | Persistent storage | | `indras_crypto` | `Keypair`, `PublicKey`, `Signature` | Cryptographic primitives | | `indras_messaging` | `MessageBroker`, `Subscription` | Message routing | ### From IndrasNetwork ```rust let node = network.node(); // Arc let storage = network.storage(); // Arc let config = network.config(); // &NetworkConfig ``` ### From Realm ```rust let node = realm.node(); // &Node let node_arc = realm.node_arc(); // Arc ``` ### Additional Types The escape module also re-exports: - `RealmConfig` — Low-level realm configuration - `Encryption` — Encryption primitives - `OfflineDelivery` — Offline message queuing --- ## Re-exported Types `indras-network` re-exports the entire `indras-artifacts` crate for ergonomic imports: ```rust // Blanket re-export pub use indras_artifacts; // Specific type re-exports for convenience pub use indras_artifacts::{ Artifact, ArtifactRef, PayloadRef, BlessingRecord, StewardshipRecord, AttentionLog, AttentionSwitchEvent, AttentionValue, DwellWindow, compute_heat, extract_dwell_windows, PeerEntry, PeerRegistry, MutualPeering, ArtifactStore, PayloadStore, AttentionStore, InMemoryArtifactStore, InMemoryAttentionStore, InMemoryPayloadStore, IntegrityResult, Vault, Story, Exchange, Request, Intention, VaultError, compute_token_value, }; ``` This means consumers only need one dependency — `indras-network` — to access both the high-level SDK and the full artifact domain model. ### Domain Types | Type | Description | |------|-------------| | `Artifact` | Union type for all artifacts | | `ArtifactRef` | Lightweight reference to an artifact | | `PayloadRef` | Reference to artifact payload data | | `LeafType` | Enum: Note, File, Image, Intention, Proof, etc. | | `TreeType` | Enum: Vault, Story, Exchange, Request, etc. | ### Vault Types | Type | Description | |------|-------------| | `Vault` | A personal vault (top-level container) | | `Story` | A narrative thread of artifacts | | `Exchange` | A trade or gift between peers | | `Request` | A request for artifacts or actions | | `Intention` | A goal with proofs, attention tokens, and pledges | | `VaultError` | Error type for vault operations | ### Attention Economy | Type | Description | |------|-------------| | `AttentionLog` | Record of attention given to artifacts | | `AttentionSwitchEvent` | Individual focus change event | | `AttentionValue` | Computed value of attention | | `DwellWindow` | Time window of focused attention | | `compute_heat` | Calculate artifact "heat" from attention | | `extract_dwell_windows` | Extract dwell windows from attention events | | `compute_token_value` | Derive token value from attention data | ### Peer Registry | Type | Description | |------|-------------| | `PeerEntry` | A peer's information | | `PeerRegistry` | Collection of known peers | | `MutualPeering` | Bidirectional peer relationship | ### Stores | Type | Description | |------|-------------| | `ArtifactStore` | Trait for artifact persistence | | `PayloadStore` | Trait for payload (binary content) persistence | | `AttentionStore` | Trait for attention data persistence | | `InMemoryArtifactStore` | In-memory implementation | | `InMemoryPayloadStore` | In-memory implementation | | `InMemoryAttentionStore` | In-memory implementation | ### Integrity | Type | Description | |------|-------------| | `IntegrityResult` | Result of artifact integrity verification | | `BlessingRecord` | Record of a blessing given to an artifact | | `StewardshipRecord` | Record of stewardship responsibility | ### Additional Exports These types are re-exported from `indras-network` for convenience: | Type | Description | |------|-------------| | `ChatAck` | Acknowledgement for a chat message | | `ChatAckDocument` | CRDT document tracking chat acknowledgements | | `ChatDelta` | Compact delta for incremental chat sync | | `DeliveryStatus` | Delivery tracking status for chat messages | | `SystemEvent` | System event type for realm notifications | | `GeoLocation` | Geographic coordinates for artifact metadata | | `DocumentRegistryDocument` | CRDT document for document discovery within a realm | --- ## The Prelude Import everything commonly needed with one line: ```rust use indras_network::prelude::*; ``` The prelude includes: ```rust pub use crate::{ ArtifactDownload, ArtifactIndex, GeoLocation, HomeArtifactEntry, Content, Document, DocumentSchema, EditableChatMessage, GlobalEvent, HomeRealm, IdentityBackup, IdentityCode, IndraError, IndrasNetwork, InviteCode, Member, MemberEvent, MemberInfo, Message, PeerEvent, PeerInfo, Preset, Realm, RealmAlias, RealmAliasDocument, RealmChatDocument, RealmId, Result, }; pub use futures::StreamExt; ``` Note that `futures::StreamExt` is included so you can iterate async streams without a separate import. `PeerEvent`, `PeerInfo`, and `GeoLocation` were added to support the peering and artifact location systems. --- ## Global Events `GlobalEvent` is a struct that tags a raw `ReceivedEvent` with the realm it came from: ```rust pub struct GlobalEvent { /// The realm this event originated from. pub realm_id: RealmId, /// The underlying event. pub event: ReceivedEvent, } ``` Subscribe to the network-wide event stream: ```rust let mut events = network.events(); while let Some(ge) = events.next().await { println!("Event from realm {:?}: {:?}", ge.realm_id, ge.event); } ``` For higher-level peer lifecycle events (peer connected/disconnected, sentiment changes, etc.), use the [Peering](#peering) event system instead. --- ## Putting It All Together Here's a complete example of a chat application: ```rust use indras_network::prelude::*; #[tokio::main] async fn main() -> Result<()> { // Initialize with chat preset let network = IndrasNetwork::preset(Preset::Chat) .data_dir("~/.mychat") .display_name("Alice") .build() .await?; network.start().await?; // Create a realm let realm = network.create_realm("Book Club").await?; println!("Share this invite: {}", realm.invite_code().unwrap()); // Set a friendly alias realm.set_alias("Book Club (2026)").await?; // Share a document let home = network.home_realm().await?; let artifact_id = home.share_file("/path/to/reading-list.pdf").await?; // Share the artifact in the realm realm.send(Content::artifact(artifact_id, "reading-list.pdf")).await?; // Listen for messages and member events concurrently let realm_clone = realm.clone(); tokio::spawn(async move { let mut members = realm_clone.member_events(); while let Some(event) = members.next().await { match event { MemberEvent::Joined(m) => println!("{} joined!", m.display_name), MemberEvent::Left(id) => println!("Member left: {:?}", id), _ => {} } } }); let mut messages = realm.messages(); while let Some(msg) = messages.next().await { match &msg.content { Content::Text(text) => { println!("{}: {}", msg.sender_name, text); } Content::Image { filename, .. } => { println!("{} sent an image: {}", msg.sender_name, filename); } Content::Artifact { name, .. } => { println!("{} shared: {}", msg.sender_name, name); } _ => {} } } network.stop().await?; Ok(()) } ``` --- *This guide covers every public module, type, and method in `indras-network` v0.1. The crate is the single import surface for building on Indra's Network — it re-exports the full `indras-artifacts` domain model so you never need to depend on lower-level crates directly.*