Configuration Reference
Complete specification of all TOML configuration options.
ztick is configured via a TOML file passed with the -c / --config flag. All sections and keys are optional; omitted values use the defaults below.
zig build run -- -c /path/to/config.tomlSections
[log]
Logging configuration.
| Key | Type | Default | Description |
|---|---|---|---|
level | string | "info" | Log verbosity threshold: off, error, warn, info, debug, trace. Messages at or above this level are written to stderr; messages below are suppressed. |
Levels (ordered from least to most verbose):
off— All log output suppressed, including startup messageserror— Errors only (e.g. controller start failures)warn— Warnings and above (e.g. database load failures)info— Startup info (config path, log level, listen address, loaded job/rule counts), client connect/disconnect, and above (recommended for production)debug— Instruction receipt, execution outcomes, and abovetrace— Maximum verbosity (maps to debug internally)
[controller]
TCP server configuration.
| Key | Type | Default | Description |
|---|---|---|---|
listen | string | "127.0.0.1:5678" | TCP address and port for the protocol server |
auth_file | string (path) | null | Path to TOML auth token file. When set, all connections require AUTH command before accepting other commands. When unset (default), authentication is disabled and connections are accepted immediately. |
tls_cert | string (path) | null | Path to PEM-encoded TLS certificate file (requires tls_key to be set) |
tls_key | string (path) | null | Path to PEM-encoded TLS private key file (requires tls_cert to be set) |
Address Format: <host>:<port> where host is IPv4 or IPv6
127.0.0.1:5678— Localhost only0.0.0.0:5678— All interfaces (IPv4)[::1]:5678— Localhost only (IPv6)
Authentication Configuration Notes:
- When
auth_fileis set, the server requires all clients to authenticate before issuing commands - The auth file uses TOML format with
[token.<name>]sections containingsecretandnamespacekeys - Secrets are matched using constant-time comparison to prevent timing attacks
- Tokens are loaded once at startup; changes require a server restart
- Omit
auth_fileto disable authentication (default for backward compatibility) - See Configuring Authentication for setup instructions and examples
TLS Configuration Notes:
- Both
tls_certandtls_keymust be set together to enable TLS - If only one is set, ztick exits with
ConfigError.InvalidValueat startup - Omit both to run in plaintext mode (default)
- By convention, use port
5678for plaintext and port5679for TLS to avoid confusion between encrypted and unencrypted endpoints - Important: When using authentication, TLS is strongly recommended to prevent tokens from being transmitted in plaintext
- Requires
libssl-dev(Debian/Ubuntu) or equivalent on the build machine - See README TLS section for certificate generation instructions
[http]
HTTP REST API server configuration. This section is optional; omit it to disable the HTTP API.
| Key | Type | Default | Description |
|---|---|---|---|
listen | string | null | HTTP address and port. When set, enables the HTTP server on the specified address. When omitted or null, the HTTP API is disabled. |
Address Format: Same as [controller] — <host>:<port> where host is IPv4 or IPv6
127.0.0.1:5680— Localhost only0.0.0.0:5680— All interfaces (IPv4)[::1]:5680— Localhost only (IPv6)
HTTP Server Notes:
- The HTTP API is optional and disabled by default. To enable it, add an
[http]section with alistenaddress. - The HTTP server handles multiple concurrent requests by spawning a dedicated thread per connection (thread-per-connection model, F022)
- All HTTP endpoints require Bearer token authentication (same tokens as TCP protocol via
auth_file) - Public endpoints
/healthand/openapi.jsondo not require authentication - The HTTP server shares the same scheduler and storage as the TCP server—both protocols interact with the same data
- Connection handling includes a 5-second graceful shutdown timeout; in-flight requests have up to 5 seconds to complete before server exit
- By convention, use port
5680for HTTP and port5681for HTTPS (if TLS support is added in the future)
Concurrency: The HTTP server is designed for concurrent request handling. Multiple clients can send requests simultaneously without blocking each other. This enables higher throughput under concurrent load compared to a sequential accept loop.
Configuration Examples:
# Disable HTTP API (default)
# [http] section omitted
# Enable HTTP API on localhost only
[http]
listen = "127.0.0.1:5680"
# Enable HTTP API on all interfaces
[http]
listen = "0.0.0.0:5680"[shell]
Shell execution configuration. Controls which shell binary and arguments are used when executing shell runner jobs.
| Key | Type | Default | Description |
|---|---|---|---|
path | string | "/bin/sh" | Absolute path to the shell binary used for shell runner execution. Validated at startup — if the path does not exist, ztick exits with ConfigError.InvalidValue. |
args | array of strings | ["-c"] | Arguments passed to the shell binary before the command string. The job command is appended as the final argument. |
Startup Validation:
- The shell
pathmust exist on disk at startup. If it does not, ztick exits immediately with a configuration error. - The path is validated once at startup and not re-checked at job execution time.
Configuration Examples:
# Default (equivalent to omitting [shell] entirely)
[shell]
path = "/bin/sh"
args = ["-c"]
# Use bash instead of sh
[shell]
path = "/bin/bash"
args = ["-c"]
# Use dash with errexit for stricter error handling
[shell]
path = "/bin/dash"
args = ["-e", "-c"]
# Use echo for dry-run testing (executes /bin/echo <command>)
[shell]
path = "/bin/echo"
args = []Direct Execution Mode:
In addition to configurable shell execution, ztick supports a direct runner type that bypasses the shell entirely. Direct runner rules are created via the protocol:
RULE SET <id> <pattern> direct <executable> [args...]The first token after direct is the executable path; remaining tokens are passed as literal argv elements. No shell interpretation occurs, eliminating shell injection risks. This mode uses execve directly — shell metacharacters like ;, |, and $() are passed as literal strings, not interpreted.
[database]
Persistence and scheduling configuration.
| Key | Type | Default | Description |
|---|---|---|---|
persistence | string | "logfile" | Persistence backend: "logfile" (disk-backed, persistent) or "memory" (ephemeral, no disk I/O) |
logfile_path | string | "logfile" | Path to the append-only persistence logfile (ignored when persistence = "memory") |
fsync_on_persist | bool | true | Call fsync after each persistence write (safer, slower; ignored when persistence = "memory") |
framerate | integer | 512 | Scheduler tick rate in Hz (valid range: 1-65535) |
compression_interval | integer (seconds) | 3600 | Interval between background compression cycles in seconds; set to 0 to disable compression (logfile backend only; ignored for memory backend) |
[telemetry]
Observability and monitoring configuration via OpenTelemetry.
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable telemetry export to an OTLP collector. When disabled (default), no observability data is exported and telemetry instrumentation has zero overhead. |
endpoint | string | (required if enabled) | HTTP endpoint of the OpenTelemetry collector (e.g., "http://localhost:4318"). The collector must accept OTLP/HTTP JSON at /v1/metrics, /v1/traces, and /v1/logs paths. |
service_name | string | "ztick" | Logical name for this service in observability backends (appears as service.name resource attribute). |
flush_interval_ms | integer (milliseconds) | 5000 | Batch export interval in milliseconds. Accumulated metrics, traces, and logs are sent to the collector at this interval. |
Telemetry Features:
- Metrics: Job throughput (
ztick.jobs.scheduled,ztick.jobs.executed,ztick.jobs.removed), execution latency (ztick.execution.duration_ms), connection counts (ztick.connections.active), rule counts (ztick.rules.active), and compression events (ztick.persistence.compactions). - Traces:
ztick.requestspan (kind: server) covering TCP request lifecycle (receive → parse → dispatch → response), with attributesztick.command,ztick.request.id, andztick.success. - Structured Logs: Log records at warn level and above, correlated with traces via shared trace IDs.
- Resource Attributes: All signals include
service.nameandservice.versionresource attributes. - Resilience: Export failures do not impact scheduler operation; ztick continues processing jobs normally when the collector is unreachable.
Configuration Examples:
# Telemetry disabled (default — zero overhead)
[telemetry]
enabled = false
# Telemetry enabled with local collector
[telemetry]
enabled = true
endpoint = "http://localhost:4318"
service_name = "my-ztick-instance"
flush_interval_ms = 5000
# Telemetry enabled with remote collector (Datadog, Grafana Agent, etc.)
[telemetry]
enabled = true
endpoint = "http://otel-collector.observability.svc.cluster.local:4318"
service_name = "ztick-prod"
flush_interval_ms = 10000Collector Compatibility:
- Tested with OpenTelemetry Collector (
otelcontribcol) - Compatible with any OTLP/HTTP JSON receiver (Datadog Agent, Grafana Agent, New Relic, etc.)
- Metrics and traces are exported via OTLP/HTTP protobuf to
POST /v1/metricsandPOST /v1/tracesrespectively - Requires the collector to be reachable and healthy for export; unavailable collectors do not cause scheduler failures
Persistence Modes:
"logfile"— (default) Store jobs and rules in an append-only binary logfile. Data persists across restarts. Use for production deployments where durability is critical."memory"— Store jobs and rules only in memory. No disk I/O occurs. Data is lost on shutdown. Useful for ephemeral deployments, CI environments, and testing where durability is not required.
Compression Interval:
0— Disable automatic compression entirely3600— Default, compress once per hour60— Compress every minute (high-mutation workloads)
Compression runs in a background thread and does not block the scheduler tick loop. When the persistence backend is "memory", compression is completely inactive regardless of this setting. If a leftover .to_compress file exists at startup (from a previously interrupted compression), it is compressed before the periodic timer begins. If a compression cycle is still running when the next interval triggers, the cycle is skipped.
Framerate:
1— Evaluate once per second (low CPU, long latency)512— Default, evaluate 512 times per second (~2ms latency)1000— Evaluate 1000 times per second (~1ms latency)
Full Example
[log]
level = "debug"
[controller]
listen = "0.0.0.0:5679"
tls_cert = "/etc/ztick/cert.pem"
tls_key = "/etc/ztick/key.pem"
[shell]
path = "/bin/bash"
args = ["-c"]
[database]
persistence = "logfile"
logfile_path = "data/ztick.log"
fsync_on_persist = false
framerate = 100
compression_interval = 1800
[telemetry]
enabled = true
endpoint = "http://otel-collector:4318"
service_name = "ztick-prod"
flush_interval_ms = 10000Errors
| Error | Cause |
|---|---|
InvalidLogLevel | level is not one of the valid values |
FramerateOutOfRange | framerate is 0 or exceeds 65535 |
UnknownSection | Section name is not log, controller, shell, database, or telemetry |
UnknownKey | Key is not recognized within its section |
InvalidValue | Value cannot be parsed (e.g. non-boolean for fsync_on_persist), or only one of tls_cert/tls_key is set, or persistence is not "logfile" or "memory", or telemetry.enabled = true but endpoint is missing/malformed, or flush_interval_ms is not a valid u32, or shell.path does not exist on disk, or shell.args is not a valid array of quoted strings |
MissingSecret | Auth file: a [token.*] section is missing the secret key |
EmptyNamespace | Auth file: a [token.*] section has an empty namespace or is missing it |
DuplicateSecret | Auth file: two or more tokens share the same secret value |