Skip to main content

Where your data goes

A node can hold two very different things at once: a private memory corpus that is nobody else's business, and a public index it contributes to the commons.

Mesh scope is a property of the node. Placement is a property of the index. That distinction is what lets one node do both.

The three settings​

PlacementWho may hold a replicaWho may read it
localnobody — it never leaves this nodenobody remote
meshpeers of your own meshthe same peers
publicany peer, including strangersanyone

mesh is the default. Every index you create gets it without asking.

gnarl index policy notes # show
gnarl index policy notes --placement local # never leaves this machine
gnarl index policy crawl --placement public --replicas 6

Only the node that created an index may change where its data goes. Any other node answers 403. A peer that could widen someone else's index could pull that owner's private data onto the public fabric.

What mesh means on a public node​

This is the part worth reading twice.

On the public fabric, admission is open by design. Anyone may join, so membership proves nothing. There, mesh means only the peers you named in your admission allowlist, and nobody else. If you have named nobody, mesh on a public node means nobody — an empty allowlist is read as "no one", not "everyone", because deciding who may talk to you and deciding who may hold your data are different questions, and the second one fails closed.

An allowlist is not accepted on a public node yet

--admit-peer is refused on any scope but private, so on a public-scope node the allowlist is necessarily empty and mesh placement resolves to this node only. Nothing leaks; it simply does not replicate. Serving the public fabric and replicating to your own devices from the same node is not supported today — to have memory follow you across your devices, run a private mesh.

On a LAN or a named private mesh, "your own mesh peers" means whoever the discovery gate admitted.

A private mesh with an empty allowlist admits anyone who knows the name

At private scope the allowlist is not consulted for placement, and discovery admits any node presenting the mesh name. A mesh created with gnarl mesh setup --mesh-name my-brain and no --admit-peer will therefore replicate a mesh index — agent memory included — to a stranger who learns or guesses that name. Name the node IDs you actually own with --admit-peer before putting anything private on a mesh, or set the index to local.

Three gates, not one​

Placement is enforced in three places, because any one of them alone leaks.

Replicas are chosen by the index's origin. It simply does not offer the claim to a peer that may not hold it. Narrowing an index also drops replicas already placed — revoking reach that leaves the data where it is revokes nothing.

Reads are refused for peers that may not hold it. Keeping data off a stranger's disk while serving them every document on request protects nothing, so the same policy governs both. That covers documents, term statistics, the write-ahead log, graph traversal, manifests, raw segment bytes, whole-node fanout queries, and storage-proof challenges — a proof returns a slice of the segment, so it is a read wearing different clothes and passes the same gate.

These gates are on the peer-to-peer interface. They are not a substitute for not exposing your node's user-facing API: on a public-scope node /v1 has no authentication by design, so bind it to localhost or put it behind your own authentication if the machine is reachable. On a private mesh, enable RBAC.

Advertisements are withheld. A peer that may not read an index is not told it exists — otherwise the read gate spends its time refusing requests the advertisement invited, and the shape of your private index is public anyway.

The claim-routing plane is a known exception still being closed: claim and manifest identifiers are gossiped to peers without a placement filter, so a peer can learn that some index exists and how large it is without being able to read a byte of it. Names and content are withheld; the existence of claims is not yet.

A local index is advertised to nobody at all. It has no replicas anywhere, so no peer has a reason to know it is there.

Replication factor​

Set per index, defaulting to the node's own setting.

gnarl index policy crawl --replicas 6

Private memory wants one or two copies across your own devices. Public-internet content needs many more to survive churn. One node-wide number cannot serve both.

Each node caps what it will adopt from someone else's declaration. An unbounded factor would let one index conscript storage across the whole fabric, so the ceiling is a local decision every node makes for itself.

What this does not do​

It is not encryption. Placement decides who may obtain the bytes. It does not make the bytes unreadable to a peer legitimately holding them. Indexed terms are stored as plaintext by design, so a peer allowed to hold your index can read its contents — that is what "allowed to hold" means.

It is not a substitute for naming your peers. On a public node the allowlist is what mesh resolves to. If it is empty, private indexes replicate nowhere, which is safe but also means no redundancy.

Tombstones always propagate. A delete has to converge mesh-wide or the name never frees up. A tombstone carries no schema and no live claims, so there is nothing in it to protect.

Next​