Documentation Configuration

Three files, all TOML. nuthatch.toml is written by init and yours to edit; semantic.toml is covered in The semantic layer; roost.toml mounts many nests. A nest declaring a schema_version newer than the binary understands is rejected on load - the guard that makes init --from and nest load safe.

nuthatch.toml

[nest]
name = "usdc"                 # nest name (also the roost mount name)
chain = "mainnet"             # mainnet | arbitrum-one | base
chain_id = 1
rpc_urls = ["https://…"]      # tried in order, with failover
schema_version = 1            # managed by nuthatch

[[contracts]]                 # one or more
alias = "usdc"                # table prefix → usdc__transfer, usdc__approval, …
address = "0xA0b8…eB48"
start_block = 6082465         # optional; deployment block (init detects it)
abi = "abis/usdc.json"        # vendored ABI path, relative to the nest dir
events = ["Transfer"]         # optional allowlist; omit to decode every ABI event

The per-contract events allowlist is how a nest indexing e.g. GraphToken keeps only Transfer instead of millions of irrelevant rows. A name the ABI doesn’t define is a config error, caught at registry build.

Factories (RFC-0009)

[[templates]]
name = "pool"                 # shared table prefix for all discovered children
abi = "abis/pool.json"
filter = "topic0"             # optional: force the topic0-only backfill strategy

[[factories]]
watch = "factory"             # the *alias* of the watched contract (or a template, for nesting)
event = "PoolCreated"         # the announcing event
child_param = "pool"          # the event param holding the child's address
template = "pool"             # which [[templates]] the child uses
start = 12369621              # optional: ignore discoveries before this block

All children of one template share tables ({template}__{event}), distinguished by the implicit address column. filter = "topic0" is a strategy override for templates known to have many children; omit it for the automatic address-list → topic0 flip (around ~500 children). See Factories.

Screening, flags, alerts (RFC-0008)

[screening]
lists = ["<list-hash>"]           # snapshot hashes from `nuthatch lists fetch`

[flags]                           # amounts are token BASE UNITS as decimal strings (i128)
threshold = "1000000000000"       # flag any single transfer ≥ this
velocity_amount = "5000000000000" # flag an address whose windowed outbound volume ≥ this
velocity_window = 7200            # window in BLOCKS (default 7200 ≈ 24h of 12s mainnet blocks)

[[alerts]]                        # route annotations to webhook sinks
kinds = ["sanction_hit", "threshold_flag"]
url = "https://…"

All three are opt-in: absent means no screening, no flags, no alerts, zero cost. Alert delivery is at-least-once via a durable outbox; a stalled sink never blocks indexing. Note velocity_window is a block count, not wall-clock - an honest approximation, since the chain has no clock.

Webhooks (RFC-0010)

[[webhooks]]
name = "large-transfers"
table = "usdc__transfer"
where = "value_dec > 1000000"     # optional SQL predicate (note the key is `where`)
url = "https://…"
batch_max = 100                   # optional rows-per-POST cap
finality = "sealed"               # "sealed" (default, and the only mode today); "tip" is planned
since = "registration"            # "registration" (default) | "genesis" | a block number
secret = "…"                      # optional; adds X-Nuthatch-Signature: sha256=<hex> (HMAC)

since = "registration" means a --seal-direct backfill won’t fire history at your endpoint. See Webhooks.

roost.toml

[roost]
name = "my-roost"
chain = "mainnet"
chain_id = 1
rpc_urls = ["https://…"]
nests = ["usdc", "weth"]      # subdirectories under nests/ to mount
max_rss_mb = 2048             # optional per-cursor RAM ceiling (default 2048)

See Run a roost for the multichain [[chains]] shape (RFC-0021).

A note on nest.star

An earlier Starlark front-end (nest.star, RFC-0018 §2) could compute a nest’s config. It is retired: author nests in plain nuthatch.toml. The loader still evaluates a legacy nest.star hermetically for backward compatibility, but don’t write new ones.