Config System
Chronos loads configuration from the environment with an optional chronos.config.kvx overlay. Environment variables always win over kvx values, which always win over defaults.
Chronos loads configuration from the environment with an optional chronos.config.kvx overlay. Environment variables always win over kvx values, which always win over defaults.
Source files: internal/config/config.go, internal/config/kvx.go.
Config struct
type Config struct {
Port int // box-local listen port (default 9096)
PostgresURI string // shared matrix DB DSN (required)
MigrationsDir string // forward-only SQL migrations (default "migrations")
TransportToken string // shared bearer for MCP proxy (CHRONOS_TOKEN)
AgentAuthSecret string // keys agent-DID nonces + principal tokens (HMAC)
ChallengeTTL time.Duration // nonce validity (default 120s)
TokenTTL time.Duration // principal token validity (default 24h)
RouterWakeURL string // router internal wake endpoint
WakeToken string // shared secret matching router's ROUTER_WAKE_TOKEN
Tick time.Duration // dispatch worker poll interval (default 1s)
MaxFailures int // default wake-delivery retry ceiling (default 5)
ClaimLease time.Duration // alarm claim lease before reclaim (default 2min)
ClaimBatch int // max alarms claimed per tick (default 100)
Dev bool // relaxes prod fail-closed secret checks
}
Environment variables
| Variable | Config field | Required | Default |
|---|---|---|---|
CHRONOS_PORT | Port | No | 9096 |
CHRONOS_POSTGRES_URI | PostgresURI | Yes | (none) |
CHRONOS_MIGRATIONS_DIR | MigrationsDir | No | migrations |
CHRONOS_TOKEN | TransportToken | Yes (prod) | (none) |
CHRONOS_AGENT_AUTH_SECRET | AgentAuthSecret | Yes (prod) | (none) |
CHRONOS_ROUTER_WAKE_URL | RouterWakeURL | No | http://127.0.0.1:8088/internal/wake |
CHRONOS_WAKE_TOKEN | WakeToken | Yes (prod) | (none) |
CHRONOS_TICK_MS | Tick | No | 1000 (1s) |
CHRONOS_MAX_FAILURES | MaxFailures | No | 5 |
CHRONOS_DEV | Dev | No | false |
CHRONOS_CONFIG | (kvx path) | No | chronos.config.kvx |
.kvx overlay
The .kvx format is a sectioned key/value document shared with tachyon/uwac config loaders:
# comment
[server]
port = 9096
dev = "0"
[store]
postgres_uri = "${CHRONOS_POSTGRES_URI}"
migrations_dir = "migrations"
[auth]
transport_token = "${CHRONOS_TOKEN}"
agent_secret = "${CHRONOS_AGENT_AUTH_SECRET}"
challenge_ttl_seconds = 120
token_ttl_seconds = 86400
[wake]
router_url = "http://127.0.0.1:8088/internal/wake"
token = "${CHRONOS_WAKE_TOKEN}"
[dispatch]
tick_ms = 1000
max_failures = 5
claim_lease_seconds = 120
claim_batch = 100
Key properties:
| Property | Description |
|---|---|
| Comments | Lines starting with # (outside quoted strings) |
| Sections | [section] headers |
| Subsections | [section.sub] for nested paths |
| Strings | Double-quoted: "value" |
| Numbers/bools | Bare: 9096, true |
| Env interpolation | "${ENV_VAR}" is replaced from the process environment |
| Missing file | Not an error; returns an empty document |
Resolution order
The pick function implements the three-tier precedence:
func pick(envKey, kvxVal, def string) string {
if v := os.Getenv(envKey); v != "" {
return v // 1. Environment variable (always wins)
}
if kvxVal != "" {
return kvxVal // 2. kvx file value
}
return def // 3. Hardcoded default
}
Numeric values use pickUint with the same precedence.
Production requirements
In production (when CHRONOS_DEV is not "1"), these secrets are required and the service refuses to start without them:
| Secret | Env var | Purpose |
|---|---|---|
| Transport token | CHRONOS_TOKEN | Shared bearer for the MCP proxy |
| Agent auth secret | CHRONOS_AGENT_AUTH_SECRET | Keys the HMAC principal tokens |
| Wake token | CHRONOS_WAKE_TOKEN | Shared secret with the router |
In dev mode, missing secrets fall back to defaults (e.g., AgentAuthSecret defaults to "chronos-dev-agent-secret-do-not-use-in-prod").
Defaults summary
| Parameter | Default | Env override |
|---|---|---|
| Port | 9096 | CHRONOS_PORT |
| Challenge TTL | 120 seconds | kvx challenge_ttl_seconds |
| Token TTL | 24 hours | kvx token_ttl_seconds |
| Tick | 1 second | CHRONOS_TICK_MS |
| Max failures | 5 | CHRONOS_MAX_FAILURES |
| Claim lease | 2 minutes | kvx claim_lease_seconds |
| Claim batch | 100 | kvx claim_batch |
| Router wake URL | http://127.0.0.1:8088/internal/wake | CHRONOS_ROUTER_WAKE_URL |
| Migrations dir | migrations | CHRONOS_MIGRATIONS_DIR |
