Configuration Reference
Wippy reads runtime configuration from .wippy.yaml files.
Use the repeatable wippy run --set section.path=value option to override the configuration fields below at launch. To override individual registry entries rather than configuration sections, use the override: section or -o; see Overriding Entries.
Config Composition
--config is repeatable; files compose left to right using the same schema:
wippy run --config .wippy.yaml --config .wippy.local.yaml
- Later files override matching values and keep everything else.
- Every explicitly named file must exist. Without
--config, the default.wippy.yamlis optional. - The first file anchors the directory used to resolve relative paths.
- Filenames carry no reserved meaning; nothing besides the default is auto-discovered.
Configuration applies in this order: composed files, selected --profile overlays, and then --set overrides. For applications run from packs, packed runtime defaults have lower precedence than all three; see Publishing Runtime Defaults.
Profiles
A configuration file may declare named overlays under profiles:. Each profile body mirrors the standard configuration sections. Selecting it with --profile <name> applies those values over the merged base configuration:
version: "1.0"
vars:
port: 8085
override:
app:db:kind: db.sql.sqlite
disable:
namespaces: ["legacy.**"]
profiles:
pg:
vars:
port: 18085
override:
app:db:kind: db.sql.postgres
disable:
namespaces.add: ["experimental.**"]
wippy run --profile pg
--profileis repeatable; profiles compose left to right, after file composition and before--set. An unknown name is an error.- Values merge per leaf (last writer wins). The
profiles:section itself is stripped from the resolved config. - The
disablesection supports list operations inside profiles —namespaces.add,namespaces.remove,entries.add,entries.remove— so a profile can adjust the base list instead of replacing it. ${name}references interpolate from the mergedvars:section. OS environment references are not allowed inside profile vars; use${env:NAME}in the base config, resolved at file load.
wippy run, test, and pack accept --profile; run list, install, update, lint, and registry accept it as well for workspace profiles (together with --set). Applications can ship profiles inside packs — see Publishing Profiles.
Logger
Controls the zap logger encoder. CLI flags (-v, -c, -s) override the level and output; encoding is the only YAML-configured option.
| Field | Type | Default | Description |
|---|---|---|---|
encoding |
string | console | Encoder: console (humanized) or json (structured) |
logger:
encoding: json
Log Manager
Controls runtime log routing. Console output is configured via CLI flags (-v, -c, -s).
| Field | Type | Default | Description |
|---|---|---|---|
propagate_downstream |
bool | true | Send logs to console/file output |
stream_to_events |
bool | false | Publish logs to event bus for programmatic access |
min_level |
int | 0 (-1 with -v) |
Minimum level: -1=debug, 0=info, 1=warn, 2=error. The CLI writes this key from its flags after the file is read, so a file value is ignored; change it with --set logmanager.min_level=<n> |
logmanager:
propagate_downstream: true
stream_to_events: false
See: Logger Module
Profiler
Go pprof HTTP server for CPU/memory profiling. Enable with -p flag or config.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false | Start profiler server |
address |
string | localhost:6060 | Listen address |
read_timeout |
duration | 15s | HTTP read timeout |
write_timeout |
duration | 15s | HTTP write timeout |
idle_timeout |
duration | 60s | Keep-alive timeout |
profiler:
enabled: true
address: "localhost:6060"
When enabled with the default address, the profiler is available at http://localhost:6060/debug/pprof/.
Security
Global security behavior. Individual policies are defined as security.policy entries.
| Field | Type | Default | Description |
|---|---|---|---|
strict_mode |
bool | true | Deny access when the security context is incomplete |
security:
strict_mode: false
See: Security System, Security Module
Registry
Entry storage and version history. The registry holds all configuration entries.
| Field | Type | Default | Description |
|---|---|---|---|
enable_history |
bool | true | Track entry versions |
history_type |
string | memory | Storage: memory, sqlite, postgres, nil |
history_path |
string | .wippy/registry.db | SQLite file path (used when history_type: sqlite) |
history_dsn |
string | Postgres DSN (used when history_type: postgres) |
|
history_schema |
string | Postgres schema name (used when history_type: postgres) |
|
event_wait_timeout |
duration | 30s | Per-operation wait for listener acknowledgement during a registry apply |
dispatch_internal_kinds |
string[] | [registry.entry, ns.dependency, ns.requirement, ns.definition] |
Entry kinds handled internally instead of dispatched to component listeners |
dependency_resolve_timeout |
duration | 0 (none) | Bound on dependency resolution |
dependency_download_timeout |
duration | 0 (none) | Bound on each module download and download-URL request |
dependency_lock_path |
string | discovered wippy.lock |
Lock file the dependency handler reads and writes |
dependency_vendor_dir |
string | <lock dir>/<directories.modules>/vendor |
Directory holding downloaded module packs |
registry:
history_type: sqlite
history_path: /var/lib/wippy/registry.db
registry:
history_type: postgres
history_dsn: ${env:WIPPY_REGISTRY_HISTORY_DSN}
history_schema: wippy_registry
See: Registry Concept, Registry Module
Artifact
Output root for materialized build-time artifacts.
| Field | Type | Default | Description |
|---|---|---|---|
materialization_root |
string | parent of the dependency vendor directory | Application-owned root under which each artifact format writes its own subtree |
artifact:
materialization_root: build/wippy
See: Build-time artifacts
Workspace
Local module replacements, keyed by org/module. Values are directories; relative paths resolve against the first --config file's directory, and null disables a replacement inherited from an earlier config layer or profile.
workspace:
replacements:
acme/http: ../local-http
acme/sql: null
Replacements are never written to wippy.lock. See Local Development with Replacements.
Relay
Message routing between processes across nodes.
| Field | Type | Default | Description |
|---|---|---|---|
node_name |
string | derived per-instance ID | Identifier for this relay node (default: UUIDv5 of machine-id/hostname + working dir; overridable via WIPPY_NODE_ID / WIPPY_RELAY_NODE_NAME) |
relay:
node_name: worker-1
See: Process Model
Supervisor
Service lifecycle management. Controls the supervisor's internal control mailbox used to dispatch lifecycle events.
| Field | Type | Default | Description |
|---|---|---|---|
host.buffer_size |
int | 1024 | Internal control mailbox capacity |
host.worker_count |
int | 16 | Concurrent dispatcher workers |
supervisor:
host:
buffer_size: 2048
worker_count: 32
See: Supervision Guide
Lua Runtime
Lua VM caching and expression evaluation.
| Field | Type | Default | Description |
|---|---|---|---|
cache.enabled |
bool | type_system.enabled |
Persist compiled bytecode/typecheck cache to disk; follows type_system.enabled unless set explicitly |
cache.dir |
string | .wippy/cache/lua |
Cache directory path (relative to the config/working directory) |
cache.mode |
string | readwrite |
Cache mode: readwrite (default), readonly, off; unknown values fall back to readwrite |
cache.compile.enabled |
bool | true | Persist compiled bytecode (when cache.enabled) |
cache.typecheck.enabled |
bool | true | Persist typecheck results (when cache.enabled) |
cache.max_bytes |
int | 1073741824 | On-disk cache size ceiling in bytes |
cache.max_entries |
int | 20000 | Maximum cached entries |
cache.prune_interval |
int | 256 | Writes between cache prune passes |
type_system.enabled |
bool | false | Enable static type checking |
type_system.strict |
bool | false | Treat type warnings as errors |
invalidation_wait_timeout |
duration | registry.event_wait_timeout (30s) |
Wait for code invalidation to be acknowledged after an entry changes |
eval.max_steps |
int | 10000 | Default scheduler-step budget for an eval run; negative values are rejected |
eval.cache_size |
int | 256 | Compiled-program cache entries for evaluated source |
eval.cache_ttl |
duration | 0 (no expiry) | Lifetime of a cached compiled program |
lua:
cache:
enabled: true
dir: .cache/lua
type_system:
enabled: true
See: Lua Overview
Scheduler
Core partitioning for the WASM runtime. When enabled, reserved_cores CPUs are set aside for WASM execution and the rest serve the actor scheduler; an invalid split (for example more reserved cores than available) is logged and ignored.
| Field | Type | Default | Description |
|---|---|---|---|
wasm_isolation.enabled |
bool | false | Partition cores between WASM and actor work |
wasm_isolation.reserved_cores |
int | 1 | Cores reserved for WASM execution |
scheduler:
wasm_isolation:
enabled: true
reserved_cores: 2
Finder
Registry search caching. Used internally for entry lookups.
| Field | Type | Default | Description |
|---|---|---|---|
query_cache_size |
int | 1000 | Cached query results |
regex_cache_size |
int | 100 | Compiled regex patterns |
finder:
query_cache_size: 2000
OpenTelemetry
Distributed tracing and metrics export via OTLP.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false | Enable OTEL |
endpoint |
string | localhost:4318 | OTLP endpoint |
protocol |
string | http/protobuf | Protocol: grpc, http/protobuf |
service_name |
string | wippy-runtime | Service identifier |
service_version |
string | Service version tag | |
insecure |
bool | true | Allow plaintext OTLP connection |
sample_rate |
float | 1.0 | Trace sampling (0.0-1.0) |
propagators |
string[] | [tracecontext, baggage] |
Context propagators |
traces_enabled |
bool | true | Export traces |
metrics_enabled |
bool | false | Export metrics |
http.enabled |
bool | true | Trace HTTP requests |
http.extract_headers |
bool | true | Extract trace context from inbound headers |
http.inject_headers |
bool | true | Inject trace context into the HTTP response |
process.enabled |
bool | true | Trace process lifecycle |
process.trace_lifecycle |
bool | true | Emit spans for spawn/terminate |
interceptor.enabled |
bool | true | Trace function calls |
interceptor.order |
int | 100 | Decoded compatibility field; runtime v0.3.32a registers the interceptor at order 100 regardless of this value |
queue.enabled |
bool | true | Trace queue publish/consume |
temporal.enabled |
bool | false | Trace Temporal workflows |
otel:
enabled: true
endpoint: "http://jaeger:4318"
traces_enabled: true
process:
trace_lifecycle: true
Standard OTEL environment variables (OTEL_SDK_DISABLED, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_INSECURE, OTEL_SERVICE_NAME, OTEL_SERVICE_VERSION, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, OTEL_PROPAGATORS) override the matching fields.
See: Observability Guide
Shutdown
Graceful shutdown behavior.
| Field | Type | Default | Description |
|---|---|---|---|
timeout |
duration | 30s | Max wait for components to stop |
shutdown:
timeout: 60s
Metrics
Internal metrics collection buffer.
| Field | Type | Default | Description |
|---|---|---|---|
buffer.size |
int | 10000 | Metrics buffer capacity |
interceptor.enabled |
bool | true | Auto-track function calls |
metrics:
buffer:
size: 20000
interceptor:
enabled: true
See: Metrics Module, Observability Guide
Prometheus
Prometheus metrics endpoint.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false | Start metrics server |
address |
string | Listen address; must be set explicitly when enabled: true, otherwise the metrics server does not start |
|
max_cardinality |
int | 1024 | Distinct label sets retained per metric (LRU); 0 or less uses the default |
prometheus:
enabled: true
address: "0.0.0.0:9090"
Exposes /metrics endpoint for Prometheus scraping, plus /livez.
See: Observability Guide
Cluster
Multi-node clustering: gossip membership plus a bounded Raft consensus core. See the Cluster Guide for the architecture and operational model; this section is the config-key reference.
Top-level
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false | Enable clustering |
name |
string | hostname | Node name; must be unique across the cluster |
failure_domain |
string | Zone/rack label; advertised in gossip so voters spread across domains | |
kv_crdt_tombstone_retention |
duration | 0 | Age after which store.kv.crdt delete tombstones are reclaimed; 0 disables age-based GC |
kv_crdt_tombstone_gc_alive_peers |
bool | false | Use the current alive membership as the tombstone acknowledgement set |
Membership (gossip)
SWIM gossip via memberlist. Used for node discovery, failure detection, and metadata dissemination.
| Field | Type | Default | Description |
|---|---|---|---|
membership.bind_addr |
string | 0.0.0.0 | Gossip bind address |
membership.bind_port |
int | 7946 | Gossip bind port (TCP+UDP) |
membership.advertise_addr |
string | Address peers use to reach this node (NAT/k8s) | |
membership.join_addrs |
string | Comma-separated seed host:port pairs |
|
membership.secret_key |
string | Base64-encoded gossip encryption key (inline) | |
membership.secret_file |
string | Path to file holding the gossip encryption key | |
membership.gossip_interval |
duration | 500ms | Gossip dissemination period |
membership.push_pull_interval |
duration | 5s | Full state sync period |
membership.dead_node_reclaim_time |
duration | 30s | When a dead node's name/address can be reclaimed |
membership.probe_interval |
duration | 1s | Failure-detection probe cycle |
membership.probe_timeout |
duration | 200ms | Ack wait per probe |
membership.tcp_timeout |
duration | 1s | TCP fallback probe timeout |
membership.suspicion_mult |
int | 3 | Suspicion timeout multiplier |
A gossip secret is required. Set membership.secret_key or membership.secret_file (the file wins if both are given); with neither, the cluster component fails to start. The value is base64-encoded.
The four probe keys inherit memberlist's local-network defaults when unset; raise them for high-latency links (e.g. probe_interval: 2s, probe_timeout: 500ms, suspicion_mult: 5).
Internode (transport)
TCP mesh carrying the relay and Raft traffic between nodes. Raft rides this mesh over internode request/reply; there is no separate Raft port.
| Field | Type | Default | Description |
|---|---|---|---|
internode.bind_addr |
string | 0.0.0.0 | Mesh bind address |
internode.bind_port |
int | 0 | Mesh port (0 = auto: 7950-7959, then ephemeral) |
internode.auto_port |
bool | true | Discover the actual port at boot, pin it, and advertise it in gossip |
internode.advertise_addr |
string | Additional relay endpoint (IP or DNS name) published for upgraded peers — for NAT or load-balanced reachability | |
internode.advertise_port |
int | 0 | Port for advertise_addr (0 = bind port; requires advertise_addr) |
internode.identity_key |
string | Base64-encoded ed25519 private key identifying this node (inline) | |
internode.identity_key_file |
string | Path to a file holding that key | |
internode.trusted_peer_keys |
map | Base64-encoded ed25519 public key per node name, including this node | |
internode.tls.enabled |
bool | false | Enable mutual TLS on the internode TCP mesh |
internode.tls.cert_file |
string | PEM node certificate; required with TLS | |
internode.tls.key_file |
string | Matching private key; required with TLS | |
internode.tls.ca_file |
string | PEM CA bundle for client and server verification; required with TLS |
advertise_addr/advertise_port publish an additive endpoint in node metadata while the bind endpoint stays advertised unchanged, so mixed-version clusters keep connecting during a rolling upgrade.
Internode identity is mandatory whenever clustering is enabled. identity_key and identity_key_file are mutually exclusive and one of them must be present; the value decodes (standard or raw base64) to either a 32-byte ed25519 seed or a 64-byte ed25519 private key. trusted_peer_keys maps each node name to that node's 32-byte ed25519 public key, and must contain an entry for the local cluster.name whose value matches the local identity — otherwise startup fails. See the Cluster Guide.
TLS requires all three credential paths and TLS 1.2 or later. Unknown settings, invalid values, unreadable or invalid credentials, and credential paths supplied while TLS is disabled fail startup. The ed25519 identity configuration remains required. See Internode TLS for an example.
Raft (consensus)
The bounded Raft core stores durable state under raft.data_dir by default (~/.wippy/store). A restarted node rejoins quorum from its peers. store.kv.raft entries replicate through this core, and gossip coordinates bootstrap using a bootstrap_expect model.
| Field | Type | Default | Description |
|---|---|---|---|
raft.data_dir |
string | ~/.wippy/store |
Directory for fs-durable Raft state and durable CRDT snapshots (under <data_dir>/_sys/). Diskless only when no path resolves (no home dir and none set) |
raft.enabled |
bool | true | Run a Raft node; false makes this a gossip-only client |
raft.role |
string | server | server runs a Raft node; client is gossip-only |
raft.eligible |
bool | true | Whether this node may be selected as a voter or standby; false keeps it outside Raft as a client |
raft.priority |
int | 100 | Voter selection priority (lower is preferred) |
raft.bootstrap_expect |
int | 1 | Initial quorum size: 0=join existing, 1=single-node, N=wait for N eligible nodes including the local node, then form quorum |
raft.max_voters |
int | 5 | Voter ceiling (must be odd); up to max_standbys additional eligible nodes become standbys, and the rest remain clients |
raft.max_standbys |
int | 4 | Non-voting members kept warm for promotion; nodes beyond voters+standbys are not Raft members |
raft.reconcile_debounce |
duration | 2s | Coalesce window after a gossip event before the voter reconciler runs |
raft.reconcile_timeout |
duration | 2s | Bound per reconcile pass |
raft.heartbeat_timeout |
duration | 3s | Follower idle wait before starting an election |
raft.election_timeout |
duration | 3s | Candidate election timeout (clamped to >= heartbeat) |
raft.commit_timeout |
duration | 500ms | Idle leader heartbeat cadence |
raft.snapshot_threshold |
uint64 | 8192 | Log entries since last snapshot before a new one |
raft.snapshot_interval |
duration | 2m | Snapshot check interval |
raft.snapshot_retain |
int | 3 | Snapshots retained |
raft.trailing_logs |
uint64 | 10240 | Log entries retained after a snapshot |
raft.max_append_entries |
int | 16 | Max entries per AppendEntries RPC |
raft.leader_probe_interval |
duration | 3s | Global-registry leader-reachability probe cadence |
raft.leader_probe_grace |
int | 3 | Consecutive probe failures before leader is declared unreachable |
raft.registry_backend |
string | kv | Cluster name-registry implementation: kv (shared kv keyspace) or fsm (dedicated Raft FSM) |
raft.global_dissem_tombstone_retention |
duration | 0 | How long the global-name dissemination cache keeps delete tombstones |
Single-node (development) — clustering on, bootstraps itself immediately:
cluster:
enabled: true
name: dev
membership:
secret_key: "d2lwcHktZG9jcy1nb3NzaXAtc2VjcmV0LTMyYnl0ZXM="
internode:
identity_key: "d2lwcHktZG9jcy1kZXYtbm9kZS1leGFtcGxlc2VlZCE="
trusted_peer_keys:
dev: "rNqImcjOzef28dzvma80mSrCW1px5LBAc5TbaYqAgm0="
raft:
bootstrap_expect: 1
Three-node voting cluster — each node lists the others as seeds and waits for all three before forming quorum. Every node carries the same trusted_peer_keys map and its own private key:
cluster:
enabled: true
name: node-1
failure_domain: us-east-1a
membership:
bind_port: 7946
join_addrs: "node-2:7946,node-3:7946"
secret_file: /etc/wippy/cluster.key
internode:
identity_key_file: /etc/wippy/node-1.key
trusted_peer_keys:
node-1: "okmamN3PKkMpPwPBurknHy2Wi3dwp/rz+uTM2fF9aD0="
node-2: "PWX+oOYrFdtjUxbgmTkXCFI0KEvG++ZM52HOWfDkqP8="
node-3: "QfP0fgllbj4s95VAztTORhy3bv9mst1l0lwuUNvO/hE="
raft:
bootstrap_expect: 3
max_voters: 5
Gossip-only client — joins the cluster for naming/messaging but never runs Raft. It still needs its own identity and must appear in every node's trusted map:
cluster:
enabled: true
name: edge-7
membership:
join_addrs: "node-1:7946,node-2:7946"
secret_file: /etc/wippy/cluster.key
internode:
identity_key_file: /etc/wippy/edge-7.key
trusted_peer_keys:
node-1: "okmamN3PKkMpPwPBurknHy2Wi3dwp/rz+uTM2fF9aD0="
node-2: "PWX+oOYrFdtjUxbgmTkXCFI0KEvG++ZM52HOWfDkqP8="
node-3: "QfP0fgllbj4s95VAztTORhy3bv9mst1l0lwuUNvO/hE="
edge-7: "7lzP4jBAkC3P+0jq4vtMsC45571BlVXk3mSlOD/Z0SA="
raft:
role: client
LSP
Language Server Protocol server for editor integrations.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false | Enable the LSP service and TCP server; the HTTP transport also requires this |
address |
string | :7777 | TCP listen address |
http_enabled |
bool | false | Enable the HTTP transport |
http_address |
string | :7778 | HTTP listen address |
http_path |
string | /lsp | HTTP endpoint path |
http_allow_origin |
string | * | CORS allowed origin |
max_message_bytes |
int | 8388608 | Max incoming message size |
lsp:
enabled: true
address: ":7777"
http_enabled: true
See: LSP Guide
Network Service
Overlay network manager (SOCKS5, I2P, Tailscale drivers).
| Field | Type | Default | Description |
|---|---|---|---|
state_dir |
string | .wippy/net | Driver state storage directory |
default_network |
string | Default network ID applied when entries omit network |
network_service:
state_dir: /var/lib/wippy/net
default_network: app:tailscale
See: Network Overlays
HTTP Dispatcher
Tuning for the shared HTTP client pool used by HTTP-dispatched functions and outbound requests.
| Field | Type | Default | Description |
|---|---|---|---|
dispatcher.http.timeout |
duration | 0 (none) | Per-request timeout |
dispatcher.http.max_idle_conns |
int | 0 (stdlib) | Max idle connections across all hosts |
dispatcher.http.max_idle_per_host |
int | 0 (stdlib) | Max idle connections per host |
dispatcher.http.idle_conn_timeout |
duration | 0 (stdlib) | Idle connection timeout |
dispatcher.http.max_clients |
int | 0 (unbounded) | Max distinct pooled clients |
dispatcher:
http:
timeout: 30s
max_idle_per_host: 32
Modules
Module registry client used by wippy install/update.
| Field | Type | Default | Description |
|---|---|---|---|
registry_url |
string | https://hub.wippy.ai | Registry endpoint |
modules:
registry_url: https://internal-registry.example.com
Extensions
Native Go plugin extensions loaded at boot (Unix only).
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true | Load extensions |
paths |
string[] | Plugin file paths (relative to config dir) |
extensions:
enabled: true
paths:
- ./extensions/myplugin.so
Environment Variables
| Variable | Description |
|---|---|
GOMEMLIMIT |
Memory limit fallback when --memory-limit flag is not set (precedence: --memory-limit flag > GOMEMLIMIT > 1G default) |
See Also
- CLI Reference — Command-line options
- Cluster Guide — Clustering architecture and operations
- Entry Kinds — Entry types and fields
- Observability Guide — Logging, metrics, and tracing