Configuration reference
Halro uses a strict YAML configuration. Unknown fields, invalid enums, and illegal combinations are rejected. The authoritative field inventory is the configs/config.example.yaml file at the pinned source revision above.
Runtime file versus example
Section titled “Runtime file versus example”| File | Purpose | Edit directly? |
|---|---|---|
config.yaml | The file passed to the current instance with --config | Yes; back it up and validate every change |
configs/config.example.yaml | Version-matched reference template | Copy for a new managed deployment; never overwrite a live configuration during upgrade |
Relative paths resolve from the process working directory. Managed deployments should use explicit absolute paths. Choose the usage IANA timezone before initialization; changing accounting boundaries later requires operational review.
One deliberate difference is easy to miss: the repository template uses Asia/Shanghai for usage.timezone, while the config.yaml created by the first halro start uses UTC. Both are valid; choose the real accounting timezone before initialization.
Safe change procedure
Section titled “Safe change procedure”cp ./config.yaml ./config.yaml.bak$EDITOR ./config.yaml./halro config check --config ./config.yaml# restart through the deployment managercurl -fsS http://127.0.0.1:8080/health/readyConfiguration is not a general live-reload contract. Validate first, then restart exactly one writer.
Activation and reload behavior
Section titled “Activation and reload behavior”Except for the items below, every configuration change requires a Halro restart.
Reloadable with SIGHUP on Linux/macOS | Behavior |
|---|---|
logging.level | Halro rereads the configuration; the entire file must still validate |
Files referenced by tls.certificates | File contents are reread at the same paths; path or list changes require restart |
Files referenced by metrics.tls | Certificate, key, and client CA reload as one set; path changes require restart |
| Log file handles | Supports the external “rename, then signal” rotation pattern |
Use systemctl reload halro or kill -HUP <PID>. For other changes, use the deployment manager—for example sudo systemctl restart halro. Windows does not deliver SIGHUP, so restart for every change. Listener addresses, timeouts, proxy trust, admin.external_origin, storage, and Master Key settings always require restart.
Top-level version
Section titled “Top-level version”| Parameter | Example | Meaning |
|---|---|---|
version | 1 | Configuration schema version; it must currently be 1 and is not the Halro release version |
Server: listeners and HTTP limits
Section titled “Server: listeners and HTTP limits”| Parameter | Example | Purpose and constraints |
|---|---|---|
server.gateway_listen | 127.0.0.1:8080 | Model request entry point; prefer TLS termination at a reverse proxy in production |
server.admin_listen | 127.0.0.1:8081 | Admin API and console; do not expose directly to the public Internet |
server.metrics_listen | 127.0.0.1:9090 | Prometheus Metrics and audit-anchor pull listener |
server.read_header_timeout | 5s | Maximum time to read all request headers; must be positive |
server.read_body_timeout | 15s | Maximum time to read the request body; must be positive |
server.shutdown_timeout | 120s | Graceful shutdown budget; must be positive and no shorter than gateway.route_total_timeout |
server.max_header_bytes | 32768 | Maximum request-header bytes; minimum 1024 |
server.max_request_bytes | 10485760 | Maximum non-streaming request size; must be positive; example is 10 MiB |
All enabled listener addresses must differ. Non-loopback listeners trigger additional TLS and authentication validation.
TLS: Gateway and Admin inbound encryption
Section titled “TLS: Gateway and Admin inbound encryption”When other machines can reach Gateway or Admin, production traffic must use HTTPS. The recommended deployment terminates TLS at Caddy, nginx, or Traefik and keeps Halro on a protected loopback or container network with tls.enabled: false. Enable Halro TLS only when clients connect to it directly.
| Parameter | Example | Purpose and constraints |
|---|---|---|
tls.enabled | false | Enables inbound TLS for Gateway and Admin |
tls.certificates | [] | Certificate list; one to sixteen entries when enabled |
tls.certificates[].cert_file | — | PEM certificate-chain path; no duplicates |
tls.certificates[].key_file | — | Matching PEM private-key path |
tls: enabled: true certificates: - cert_file: /etc/halro/tls/fullchain.pem key_file: /etc/halro/tls/privkey.pemThe first certificate serves clients without SNI; the others are selected by hostname. The certificate list must be empty while TLS is disabled.
Storage: data and Master Key
Section titled “Storage: data and Master Key”| Parameter | Example | Purpose and constraints |
|---|---|---|
storage.data_dir | ./data | Root for database, Ledger, Audit, and Usage data; relative to the process working directory |
storage.metadata_file | halro.db | Metadata filename only; directories are not allowed |
storage.master_key.mode | file | Master Key source; normal single-node deployments use a local file, advanced deployments use external key slots |
storage.master_key.file | ./master.key | Master Key path in file mode; relative to the process working directory |
Mount the data directory and Master Key on separate persistent volumes. Design key_slots mode around the real KMS provider, region, account, key ID, algorithm, and startup timeout; do not trial-and-error a live migration from file mode.
Admin: sessions and management features
Section titled “Admin: sessions and management features”| Parameter | Example | Purpose and constraints |
|---|---|---|
admin.session_ttl | 8h | Maximum Admin session lifetime; must be positive |
admin.idle_timeout | 30m | Idle-session expiry; positive and no longer than session_ttl |
admin.login_rpm | 5 | Login attempts per minute; minimum 1 |
admin.mfa_policy | optional | Instance policy: optional or required |
admin.developer_workbench | enabled | Real Gateway debugging on the Admin listener: enabled or disabled |
admin.reauth_elevation_window | 10m | How long reauthentication authorizes sensitive actions; 0s means every action |
admin.external_origin | "" | Canonical browser origin, for example https://admin.example.com; no path, query, or fragment |
admin.setup_token_file | "" | Absolute path to a production-mounted one-time setup token; ignored after an administrator exists. Available since v0.8.3 |
admin.setup_token_ttl | 30m | Generated-token lifetime or maximum remaining lifetime accepted from a file; positive, at most 24h, and never renewed by restart. Available since v0.8.3 |
Disable the developer workbench when Admin is not loopback-only. external_origin must exactly match the user-facing scheme, host, and port. A non-empty value requires a one-time setup token for the first administrator.
Starting in v0.8.3, production serve does not generate a Token that operators cannot retrieve safely. A remote zero-administrator instance must configure an absolute setup_token_file or create the administrator offline with admin bootstrap. A missing, malformed, expired, or over-long-remaining-TTL file blocks startup with no log fallback. The file is read once at process start; after rotating the Secret, stop the old Pod and start one that loads the new version. Halro stops reading after an administrator exists, but the orchestrator must still remove mandatory mount dependencies before rescheduling without the Secret.
See Production Admin bootstrap and secret lifecycle for generation, mounting, automated Jobs, Audit verification, and compromise recovery. Releases up to and including v0.8.2 does not contain these fields; do not give the updated configuration to that older binary.
MFA policy
Section titled “MFA policy”| Policy | No authenticator | Authenticator exists | Intended use |
|---|---|---|---|
optional | Console access is allowed; the user may enroll | Existing MFA remains required and is not removed or bypassed | Loopback-only development or personal instances |
required | Only MFA setup is available after password login | Every login requires password and TOTP; the final authenticator cannot be removed | Any remotely reachable Admin, especially production |
Remote Admin should use required together with HTTPS, network access control, and accurate time synchronization. Policy changes require restart. To recover after losing every authenticator and recovery code, stop Halro and run:
./halro admin reset-mfa --config ./config.yaml --username adminThe command deletes that account’s authenticators and recovery codes, invalidates sessions and pending challenges, and writes an Audit record. With required, the next password login is limited to MFA reenrollment.
Model capability detection
Section titled “Model capability detection”Capability detection runs only after explicit administrator confirmation and can issue billable Provider calls.
| Parameter | Example | Purpose and constraints |
|---|---|---|
admin.model_capability_detection.fresh_ttl | 24h | Time a result remains fresh; must be positive |
admin.model_capability_detection.retention | 720h | Record retention; no shorter than fresh_ttl |
admin.model_capability_detection.refresh_cooldown | 5m | Minimum interval between manual refreshes of one model |
admin.model_capability_detection.total_timeout | 90s | Task timeout; positive and no more than 2m |
admin.model_capability_detection.global_concurrency | 4 | Instance-wide detection concurrency; minimum 1 |
admin.model_capability_detection.provider_concurrency | 1 | Per-Provider concurrency; minimum 1 and no greater than global concurrency |
admin.model_capability_detection.max_provider_calls | 10 | Maximum billable calls in one detection |
admin.model_capability_detection.create_rpm | 6 | New tasks per administrator per minute; 1–60 |
Usage: persistence and export
Section titled “Usage: persistence and export”| Parameter | Example | Purpose and constraints |
|---|---|---|
usage.durability | balanced | balanced favors throughput and latency; strict strengthens durability at higher write cost |
usage.timezone | Asia/Shanghai | Accounting timezone used only at first initialization; change an initialized instance in Admin settings |
usage.wal_queue_capacity | 4096 | Usage records waiting for the WAL; minimum 1 |
usage.wal_max_batch | 128 | Records per WAL batch; minimum 1, no greater than queue capacity |
usage.wal_flush_interval | 2ms | Maximum time an incomplete batch waits; must be positive |
usage.analytics_queue_capacity | 4096 | Records waiting for analytics processing; minimum 1 |
usage.checkpoint_interval | 1m | Persistent-checkpoint cadence; must be positive |
usage.parquet_interval | 1h | Analytics-partition write cadence; must be positive |
usage.retention_days | 90 | Local analytics retention; minimum 1 day |
usage.console_window_days | 30 | Initial in-memory console window for Attempts and failures; runtime value lives in instance settings and cannot exceed retention |
usage.export_format | parquet | New partition format: parquet or ndjson; existing partitions are not rewritten |
Changing usage.timezone after initialization does not change the active accounting timezone; halro doctor reports the mismatch.
Ledger: sealing
Section titled “Ledger: sealing”| Parameter | Example | Purpose and constraints |
|---|---|---|
ledger.seal.enabled | false | Seals a complete active Accounting WAL generation at the threshold |
ledger.seal.max_active_bytes | 8589934592 | Active WAL threshold; minimum 16 MiB |
ledger.seal.compress | true | Replaces a sealed generation with a verified gzip copy after export and checkpoint boundaries are safe |
Sealing does not delete accounting history. Replay continues from sealed segments into the active WAL. Treat it as a recovery design choice, not ordinary log rotation.
Gateway: request budgets, attempts, and limits
Section titled “Gateway: request budgets, attempts, and limits”| Parameter | Example | Purpose and constraints |
|---|---|---|
gateway.route_total_timeout | 120s | Total request budget across every Attempt |
gateway.pricing_clock_rollback_tolerance | 2s | Permitted clock rollback when selecting prices; not below the safety floor |
gateway.pricing_clock_forward_tolerance | 30s | Permitted price timestamp lead; nonnegative |
gateway.pricing_unknown_policy | reject | reject or allow_without_cost_governance |
gateway.attempt_connect_timeout | 5s | Per-Attempt upstream connection timeout |
gateway.attempt_response_header_timeout | 60s | Per-Attempt wait for upstream headers |
gateway.downstream_write_timeout | 15s | Timeout for one downstream response write |
gateway.stream_max_duration | 10m | Maximum streaming request duration |
gateway.max_total_attempts | 3 | Request-wide Attempt limit across all targets; minimum 1 |
gateway.deferred_response_workers | 4 | Instance-wide deferred-response workers |
gateway.health_probe_interval | 30s | Background Deployment health-probe interval |
gateway.source_rate_limit.requests_per_minute | 600 | Pre-authentication per-source budget; 0 disables it |
gateway.source_rate_limit.max_tracked_sources | 16384 | Distinct tracked sources before overflow shares one budget |
Increasing an Attempt timeout does not increase the total budget. Review gateway.route_total_timeout and server.shutdown_timeout together.
Failed-request diagnostic capture
Section titled “Failed-request diagnostic capture”| Parameter | Example | Purpose and constraints |
|---|---|---|
gateway.failure_capture.enabled | false | Stores bounded, redacted final-failure diagnostics |
gateway.failure_capture.max_bytes | 65536 | Maximum stored bytes per record |
gateway.failure_capture.max_records_per_day | 1000 | Maximum records per accounting day |
gateway.failure_capture.retain | 24h | Diagnostic retention |
It never stores Provider credentials and is not a request-body archive. Enable it only after reviewing disk and privacy boundaries.
Retry and Circuit Breaker
Section titled “Retry and Circuit Breaker”| Parameter | Example | Purpose and constraints |
|---|---|---|
retry.max_attempts_per_target | 2 | Attempts on one upstream target; minimum 1 |
retry.base_delay | 100ms | Initial retry backoff; positive |
retry.max_delay | 2s | Backoff cap; no shorter than base_delay |
retry.jitter | true | Randomizes backoff to prevent synchronized retries |
circuit_breaker.consecutive_failures | 5 | Consecutive failures before opening; minimum 1 |
circuit_breaker.open_duration | 30s | Time open before half-open; positive |
circuit_breaker.half_open_max_requests | 1 | Concurrent half-open probes; minimum 1 |
The effective boundary combines the per-target limit, the request-wide gateway.max_total_attempts, and available route targets.
Alerts
Section titled “Alerts”| Parameter | Example | Purpose and constraints |
|---|---|---|
alerts.queue_capacity | 1024 | Pending alert-delivery queue; minimum 1 |
alerts.workers | 2 | Parallel delivery workers; minimum 1 |
alerts.timeout | 5s | Per-delivery timeout; positive |
alerts.max_attempts | 3 | Delivery attempts per alert; minimum 1 |
alerts.base_delay | 250ms | Initial alert retry backoff; positive |
alerts.max_delay | 5s | Alert retry cap; no shorter than base delay |
alerts.dedup_cooldown | 1m | Cooldown before the same alert may be delivered again |
Security: private access and proxy trust
Section titled “Security: private access and proxy trust”| Parameter | Example | Purpose and constraints |
|---|---|---|
security.allow_private_provider_endpoints | false | Allows Provider endpoints to resolve or connect to private addresses; expands SSRF reachability |
security.allow_private_webhooks | false | Allows Webhook targets on private addresses |
security.trust_proxy_headers | false | Trusts forwarded client-address headers |
security.trusted_proxy_cidrs | [] | Proxy CIDRs allowed to supply trusted headers |
Enable proxy trust only behind a controlled reverse proxy and restrict CIDRs to real proxy networks.
security: trust_proxy_headers: true trusted_proxy_cidrs: - "10.42.0.0/16"Metrics: Prometheus and independent mTLS
Section titled “Metrics: Prometheus and independent mTLS”| Parameter | Example | Purpose and constraints |
|---|---|---|
metrics.enabled | true | Enables the Metrics service |
metrics.require_auth | true | Requires an independent bearer credential |
metrics.credential_file | "" | Metrics credential file; requires require_auth: true |
metrics.max_concurrent_scrapes | 2 | Concurrent scrapes, 1–32 |
metrics.write_timeout | 5s | Response-write timeout; positive and at most 30s |
metrics.tls.enabled | false | Enables independent TLS and client-certificate authentication |
metrics.tls.cert_file | "" | Metrics server certificate chain |
metrics.tls.key_file | "" | Metrics server private key |
metrics.tls.client_ca_file | "" | CA used to authenticate scrape clients |
For loopback-only Metrics, an empty credential file derives a default token from the Master Key; read it with halro metrics token --config ./config.yaml. Production should use a separately rotatable credential file. A non-loopback Metrics listener requires that independent credential and complete mTLS configuration.
Audit Anchor: external audit anchors
Section titled “Audit Anchor: external audit anchors”| Parameter | Example | Purpose and constraints |
|---|---|---|
audit.anchor.enabled | false | Publishes audit-chain summaries without event bodies |
audit.anchor.sink | dead_man_pull | Only implemented sink; other names are reserved |
audit.anchor.interval | 5m | Maximum interval between anchors; positive and at most 1h |
audit.anchor.record_delta | 500 | New records required to trigger an anchor; minimum 1 |
audit.anchor.credential_file | "" | Independent dead-man pull credential |
External anchoring requires Metrics mTLS and an anchor credential different from metrics.credential_file.
Model Catalog: signed model catalog
Section titled “Model Catalog: signed model catalog”| Parameter | Example | Purpose and constraints |
|---|---|---|
model_catalog.enabled | false | Refreshes a signed model catalog in the background; Gateway requests never download it |
model_catalog.refresh_interval | 6h | Refresh interval, 5m–168h |
model_catalog.pinned_revision | "" | Optional sha256: revision followed by 64 hex digits |
model_catalog.max_download_bytes | 1048576 | Compressed response cap, 4 KiB–16 MiB |
model_catalog.max_decoded_bytes | 4194304 | Decoded cap; at least download cap and no more than 64 MiB |
model_catalog.max_compression_ratio | 20 | Maximum expansion ratio, 1–100 |
model_catalog.max_entries | 10000 | Verified manifest entry cap, 1–100000 |
Providers: v0.8.1 configuration compatibility
Section titled “Providers: v0.8.1 configuration compatibility”v0.8.2 no longer uses global providers.bedrock.region. A Bedrock Mantle Credential saved in Admin determines its Region and binds to that Region’s endpoint. For in-place upgrades, Halro still accepts and validates this legacy block:
providers: bedrock: region: us-east-1The value must still be a valid AWS Region name, but it no longer changes saved Credentials or Providers. Remove it after confirming the Admin Credential is bound to the intended regional endpoint.
Logging: output and rotation
Section titled “Logging: output and rotation”| Parameter | Example | Purpose and constraints |
|---|---|---|
logging.level | info | debug, info, warn, or error; the only semantic field reloadable by SIGHUP |
logging.format | json | json for collectors or text for terminals; both are redacted |
logging.output | stderr | stderr, file, or both |
logging.file | "" | Empty uses <data_dir>/logs/halro.log; used only for file output |
logging.max_size_mb | 64 | File size cap, 1–4096 MiB |
logging.max_files | 5 | Files retained including active file, 1–100 |
logging.error_file is an independent ERROR-level diagnostic file:
| Parameter | Example | Purpose and constraints |
|---|---|---|
logging.error_file.enabled | false | Enables the independent ERROR log |
logging.error_file.file | "" | Empty uses the default path under the data directory |
logging.error_file.max_size_mb | 32 | Per-file cap |
logging.error_file.max_files | 10 | Retained error-log files |
systemd, Docker, and Kubernetes normally send stderr to platform collection. Without a collector, use file or both and size the data volume accordingly.
Common adjustment scenarios
Section titled “Common adjustment scenarios”| Goal | Review together |
|---|---|
| Expose Admin through a reverse proxy | server.admin_listen, admin.external_origin, proxy trust, and proxy TLS/access control |
| Extend long or streaming responses | gateway.stream_max_duration, gateway.route_total_timeout, server.shutdown_timeout, and outer-proxy timeouts |
| Increase request size | server.max_request_bytes and proxy/Ingress body-size limits |
| Expose Metrics to another host | server.metrics_listen, metrics.credential_file, and complete Metrics mTLS |
| Increase retries | Both retry limits, total timeout, non-idempotent behavior, and Provider cost |
| Rate-limit by real client IP | Trust only controlled proxy CIDRs before enabling forwarded headers |
| Change accounting timezone | Set usage.timezone before new-instance initialization; use Admin instance settings afterward |
| Change console history window | Change the runtime instance setting and review retention |
| Increase deferred-response throughput | Workers, Project queue, Project/Deployment concurrency, and total timeout |
| Enable failure diagnostics | Capture settings, data volume, retention, and privacy policy |
Run Governance parameters outside config.yaml
Section titled “Run Governance parameters outside config.yaml”Run Governance is Project policy configured in the Admin Console, not instance YAML.
| Project parameter | Purpose and constraints |
|---|---|
run_governance.enabled | Enables Work Unit/Run APIs and request attribution; cannot be disabled while a Run is active |
default_run_budget_micros_usd | Default budget when Run creation omits one |
max_run_budget_micros_usd | Maximum lifetime budget a Run may declare |
default_run_ttl_seconds | Default TTL when Run creation omits one |
max_run_ttl_seconds | Maximum Run TTL, no more than 30 days |
max_active_runs | Active Runs per Project, maximum 1000 |
max_open_work_units | Open Work Units per Project, maximum 1000 |
The console displays budgets in USD and TTLs in hours; the Run API uses micros USD and seconds. See Integrate Run Governance.
For certificate, permission, disk, and runtime-data checks, stop Halro and run:
./halro doctor --config ./config.yamlconfig check validates structure, ranges, and combinations. doctor also inspects deployment conditions and requires exclusive access to the data directory. Start only after both checks pass, then verify /health/ready and logs.