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
| Placement | Who may hold a replica | Who may read it |
|---|---|---|
local | nobody — it never leaves this node | nobody remote |
mesh | peers of your own mesh | the same peers |
public | any peer, including strangers | anyone |
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.
--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.
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
- Trust and verification — identity, signing, and what a mesh name does and does not prove
- Agent memory — the private corpus this exists for
- Join the network — creating a mesh and naming its peers