Configuration
Gnarl reads ./gnarl.yaml unless --config says otherwise. Every value has a
default; an empty file is a valid config.
Full example
gnarl.yaml
node:
name: gnarl-ops-1
listen: 0.0.0.0:7420
advertise: gnarl-a.acme.internal:7420
home: ~/.gnarl
network:
name: acme-internal
bootstrap:
- gnarl-b.acme.internal:7420
- gnarl-c.acme.internal:7420
psk_file: ./acme.psk
index:
name: imagery
source:
path: ./corpus/imagery
include: ["**/*.json"]
exclude: ["**/drafts/**"]
fields:
- {name: title, type: text, analyzer: standard}
- {name: captured_at, type: datetime}
- {name: footprint, type: geo_shape}
- {name: sensor, type: keyword}
expose:
fields: [title, captured_at, sensor]
summary: [doc_count, time_range, bbox]
routing:
gossip_interval: 5s
manifest_ttl: 15m
candidate_cap: 128
bloom_bits_per_doc: 10
policy:
default: deny
allow:
- networks: [acme-internal]
indexes: [imagery]
rate_limit: 200/s
require_signed_queries: true
storage:
path: /var/lib/gnarl
cache_mb: 2048
fsync: on_commit
telemetry:
metrics_listen: 127.0.0.1:9420
log_format: json
node
| Key | Default | Description |
|---|---|---|
name | hostname | Human label. Not the identity. |
listen | 0.0.0.0:7420 | Bind address for peers and the HTTP API |
advertise | derived | Address peers should use to reach you |
home | ~/.gnarl | Identity, peer table, local state |
network
| Key | Default | Description |
|---|---|---|
name | none | Network to join. Nothing is announced without it. |
bootstrap | [] | Peers to contact on start |
psk_file | none | Pre-shared key for a private network |
index
Repeatable — use a YAML list for multiple indexes on one node.
| Key | Description |
|---|---|
source.path | Directory to index, opened read-only |
source.include / exclude | Glob filters |
fields[] | Field name, type, and analyzer |
expose.fields | Fields named in the manifest |
expose.summary | Summaries published: doc_count, time_range, bbox, terms |
Field types: text, keyword, int, float, datetime, geo_point,
geo_shape, vector, bool.
routing
| Key | Default | Description |
|---|---|---|
gossip_interval | 5s | Manifest push cadence |
manifest_ttl | 15m | When a peer's manifest goes stale |
candidate_cap | 128 | Hard fan-out ceiling per query |
latency_window | 5m | History used to rank candidates |
bloom_bits_per_doc | 10 | Term-summary precision vs. manifest size |
policy
| Key | Default | Description |
|---|---|---|
default | deny | allow or deny when no rule matches |
allow[].nodes | — | Node IDs this rule applies to |
allow[].networks | — | Networks this rule applies to |
allow[].indexes | all | Indexes exposed by this rule |
allow[].fields | manifest | Fields returnable by this rule |
allow[].rate_limit | unlimited | e.g. 40/s, 10000/h |
redact[] | — | Fields stripped from results |
storage
| Key | Default | Description |
|---|---|---|
path | <home>/store | Index location |
cache_mb | 1024 | Block cache size |
fsync | on_commit | on_commit, interval, or never |
Environment overrides
Any key can be set with an environment variable. Uppercase, underscore-separated,
prefixed GNARL_:
GNARL_NODE_LISTEN=0.0.0.0:8000 \
GNARL_NETWORK_NAME=acme-internal \
gnarl node up
Precedence is: flags → environment → config file → defaults.