Nodes
A node is one process, one identity, and one or more local indexes. It is the only thing in Gnarl that holds data.
Anatomy
| Component | Responsibility |
|---|---|
| Identity | An ed25519 keypair. The public key is the node ID. |
| Store | The local index. Lives beside the data, never leaves the host. |
| Manifest | The signed summary the node is willing to advertise. |
| Policy | Who may ask, what they may ask about, and how often. |
| Peer table | Manifests learned from other nodes, with freshness and health. |
What a node stores
- Its own index, derived from data it can already read.
- Manifests for peers it has heard from.
- Health and latency statistics used for planning.
What a node never stores
- Another node's documents.
- Another node's index segments.
- A copy of the network's state that must be kept in sync.
This is the property that makes the model work: nodes are cheap to add and cheap to lose, because losing one removes exactly one node's answers.
Roles
Any node can play any of these at the same time. They are not deployment types.
Serving node — holds an index and answers queries. The default.
Entry node — receives queries from applications and coordinates fan-out. Any serving node does this; some operators run entry nodes with no local index at all as a query gateway.
gnarl node up --no-index --entry-only
Relay — forwards manifests and queries across a network boundary where nodes cannot reach each other directly. A relay sees ciphertext queries and results; it cannot read them.
gnarl node up --relay --listen 0.0.0.0:7420
Peer classes
A peer is not a machine class. The same node, the same protocol, and the same identity model run everywhere — what changes is how much the peer takes on.
| Class | Platforms | Typical role |
|---|---|---|
| Cloud / server | Linux, Windows Server, Kubernetes | Heavy corpora, widest fan-out participation |
| Desktop | macOS, Windows, Linux | Local archives, always-on workstation peers |
| Laptop | macOS, Windows, Linux | Answers offline, reconciles its manifest on reconnect |
| Mobile | iOS, Android | Collects and answers at the edge, on battery |
There is no privileged tier. A phone's manifest is planned against exactly like a rack's; it simply advertises less and is asked less often.
Mobile and laptop peers add power and connectivity constraints:
node:
power:
index_while: charging # or: always
answer_on: [wifi, ethernet] # skip metered links
max_concurrent_queries: 4
A peer that declines to answer because it is on battery is not an error — the coordinator records it as unanswered and the response reports the coverage.
Sizing
Index size is dominated by the fields you index, not the size of the source documents.
| Corpus | Typical index | Memory |
|---|---|---|
| 10 GB text | 2.5–4 GB | 2 GB |
| 1 TB text | 250–400 GB | 16 GB |
| 100 TB imagery metadata | 3–6 TB | 32 GB |
A node answers from disk with a hot cache; there is no requirement to hold the index in memory.
Lifecycle
gnarl node up # start, index, serve
gnarl node status # health, peers, query stats
gnarl node drain # stop accepting new queries, finish in-flight
gnarl node down # stop
Draining is graceful: the manifest is withdrawn first, so peers stop planning around you before you stop answering.