Matrix logo

Chronos API

The centralized agent scheduler: agent DID authentication plus create, list, get, and cancel alarms that wake an agent at a scheduled time.

Chronos (chronosd) is the centralized agent scheduler and wake-up system. Agents authenticate with their DID, then create alarms that fire a wake at a scheduled time. Chronos uses two-layer auth: a shared transport bearer (CHRONOS_TOKEN) proves the caller is a legitimate Matrix daemon, and an ed25519 agent-DID principal token (X-Chronos-Agent) proves which owner is calling.

Routes

MethodPathPurpose
GET/healthzUnauthenticated liveness (pings database)
GET/Service root: name, version, health link
POST/v1/agent/auth/challengeRequest a nonce for the agent DID
POST/v1/agent/auth/verifyVerify the signed nonce, mint a session token
POST/v1/alarmsCreate an alarm
GET/v1/alarmsList the agent's alarms
GET/v1/alarms/{id}Get one alarm
DELETE/v1/alarms/{id}Cancel an alarm

Authentication

Two-layer auth on all /v1/* paths:

  1. Transport bearer -- Authorization: Bearer <CHRONOS_TOKEN> proves the caller is a Matrix daemon.
  2. Principal token -- X-Chronos-Agent: <token> proves which agent/owner. Minted via the challenge/verify handshake below.

See the shared agent DID handshake.

Challenge

POST /v1/agent/auth/challenge

didstringrequired

The agent DID (did:matrix:<owner_user_id>:<key_fingerprint>).

Returns a nonce and the exact message to sign. The nonce is single-use and expires after the configured TTL.

Verify

POST /v1/agent/auth/verify

didstringrequired

The agent DID.

public_keystringrequired

Hex-encoded ed25519 public key (must match the DID fingerprint).

noncestringrequired

The nonce from the challenge response.

signaturestringrequired

Hex-encoded ed25519 signature over matrix-chronos-auth:<did>:<nonce>.

Returns a short-lived HMAC principal token and the owner user ID.

Create an alarm

POST /v1/alarms requires the X-Chronos-Agent principal token.

kindstringrequired

once or cron.

wake_messagestringrequired

The contextful turn delivered to the agent on wake.

delay_secondsinteger

For once: seconds from now until fire.

fire_atstring (ISO 8601)

For once: absolute fire time.

cron_exprstring

For cron: a standard cron expression (5-field).

timezonestring

For cron: IANA timezone (default UTC).

labelstring

Human-readable label for the alarm.

conversation_idstring

Conversation to resume on wake.

payloadobject

Opaque data delivered to the agent on wake.

idempotency_keystring

Deduplicates retries; same key + owner returns the existing alarm.

max_failuresinteger

Max consecutive failures before terminal fail (default 5).

curl -X POST https://chronos.example/v1/alarms \
  -H "Authorization: Bearer $CHRONOS_TOKEN" \
  -H "X-Chronos-Agent: $PRINCIPAL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "once",
    "delay_seconds": 3600,
    "wake_message": "Time for your daily digest.",
    "label": "daily-digest"
  }'
idstringrequired

The alarm identifier (used for get/cancel).

next_fire_atstring

ISO 8601 timestamp of the next scheduled fire.

statusstring

active, fired, cancelled, or failed.

List alarms

GET /v1/alarms?limit=100 returns the caller's alarms, most-recent first. The limit query parameter defaults to 100 (max 500).

Get an alarm

GET /v1/alarms/{id} returns a single alarm by ID, owner-checked.

Cancel an alarm

DELETE /v1/alarms/{id} marks an active alarm as cancelled. Already-fired or already-cancelled alarms return success without modification.

Alarm lifecycle

StatusMeaning
activeScheduled and waiting to fire
firedSuccessfully delivered (once alarms are terminal)
cancelledManually cancelled by the owner
failedRetries exhausted (once alarms are terminal; cron alarms skip and advance)

Cron alarms automatically reschedule after each successful fire. Failed cron fires use a bounded backoff ladder: retry, then skip-and-advance so one bad fire does not wedge the series.

All alarm operations are idempotent on the idempotency_key. Concurrent dispatchers use FOR UPDATE SKIP LOCKED to avoid double-claiming.