Configuration¶
Duckton is configured through a layered, validated system. You almost never
need to touch a file — zero-config defaults are safe and frictionless, and most
tuning is a per-call override or a one-line CALL.
Precedence (lowest → highest)¶
1. built-in defaults (compiled into the binary — GridConfig::default())
2. config file (P2P_CONFIG=/path/to/p2p.toml, or P2P_CONFIG_DIR)
3. environment variables (P2P_* — e.g. P2P_REPLICAS, P2P_BIND_ADDR)
4. SQL / runtime setters (p2p_economics, p2p_selection, p2p_set, …)
5. per-call SQL parameters (replicas =>, prefer =>, nodes =>, …)
Layer 4 (SQL setters) is persisted to a sparse runtime-overrides file
(default <config-dir>/runtime.toml, override with P2P_RUNTIME_CONFIG) so it
survives restart. Your hand-edited base file is never rewritten, and secrets
are kept out (in separate 0600 files). Unknown keys are a hard error
(deny_unknown_fields) — typos fail fast.
The example config¶
A fully-documented example lives at
config/p2p.example.toml.
Copy it, set P2P_CONFIG=/path/to/p2p.toml, and uncomment only what you need.
Key sections¶
| Section | What it controls |
|---|---|
[protocol] |
Advertised/min protocol version; optional engine-version matching for quorum determinism. |
[network] |
QUIC bind/advertised address, timeouts, flow-control windows, chunk sizes. |
[transport.quic] / [transport.result] / [transport.compression] |
GSO/GRO, congestion control, 0-RTT, parallel result streaming, wire compression, result-size caps. See transport tuning. |
[identity] |
Key path, pinning mode (tofu/allowlist), peer allowlist. |
[security] |
mode = public / private (closed grid). See Private mode. |
[discovery] |
Bootstrap seeds, candidate_sample_size (bounded fan-out). |
[scheduler] |
replicas, quorum, verify_mode, re-dispatch/backoff, require_staked_hosts. |
[budget] |
Host resource donation: memory, threads, max jobs, per-job caps, spill caps. |
[planner] |
Local-first vs prefer = remote; local_execution hard gate; spill tolerance. |
[trust] |
min_trust, min_attestation. |
[membership] |
Networks, groups (+ token issuers), region (+ region trust tier). |
[storage] |
Object-store providers, enable_remote_access, credential mode (presigned / scoped-secret / sealed), Parquet encryption keys. |
[sandbox] |
OS isolation backend (noop default; process_per_job opt-in), egress allow-list. |
[antiabuse] |
Deny-list/auto-block, free-job rate limit, cost gate, fault attribution. |
[economics] |
On/off, network (testnet/mainnet + confirm guard), fees, pricing, bidding, slashing, per-network wallet/contracts. |
[metadata] |
Signed system-profile capture interval (routing hint only). |
Common knobs¶
[scheduler]
replicas = 3
quorum = 2
[discovery]
candidate_sample_size = 16 # set to 1 to contact a single node (see node targeting)
[planner]
prefer = "auto" # "local" | "remote" | "auto"
local_execution = true # false = hard remote-only (thin clients)
Equivalent env / SQL:
CALL p2p_selection(replicas => 3, quorum => 2);
CALL p2p_planner(prefer => 'remote', local_execution => false);
CALL p2p_set('discovery.candidate_sample_size', 1); -- generic escape hatch
Secrets¶
Wallet mnemonics and API keys are never stored in the config file or echoed.
Pass file references (mnemonic_file / api_key_file) pointing outside the
repo; inline secrets are moved to a 0600 file under the config dir's
secrets/ and only the path is persisted. p2p_config() redacts them
everywhere. See Security.