This document defines the technical interface between the ratelord daemon (ratelord-d) and its clients (agents, TUI, CLI). It specifies the transport mechanism, request/response schemas, and error handling protocols.
The daemon exposes a JSON-over-HTTP interface on localhost.
- Ubiquity: HTTP is natively supported by every language (Python, Node, Go, Rust, Curl).
- Simplicity: JSON payloads are human-readable and easy to debug.
- Zero-Ops: No complex binary protocols or custom drivers required for basic integration.
- Local-First: Bound strictly to
127.0.0.1(or a Unix Domain Socket in future strict modes).
- Default Port:
8090(configurable via envRATELORD_PORT) - Bind Address:
127.0.0.1 - Content-Type:
application/jsonrequired for all POST bodies.
The core "Ask-Wait-Act" primitive. This endpoint blocks until a decision is reached or the request times out.
POST /v1/intent
{
"agent_id": "string", // Who is asking? (e.g., "crawler-01")
"identity_id": "string", // Credentials (e.g., "pat:rmax")
"workload_id": "string", // Abstract task (e.g., "repo_scan")
"scope_id": "string", // Target boundary (e.g., "repo:owner/name")
"urgency": "string", // "high" | "normal" | "background"
"expected_cost": number, // Optional: Estimated consumption units
"duration_hint": number, // Optional: Expected runtime in seconds
"debug": boolean, // Optional: Enable detailed tracing logs
"client_context": object // Optional: arbitrary metadata for logs
}{
"intent_id": "string", // Unique ID assigned by daemon
"decision": "string", // "approve" | "approve_with_modifications" | "deny_with_reason"
"modifications": {
"wait_seconds": number, // If > 0, client MUST sleep before acting
"identity_switch": "string" // Optional: Alternate identity to use
},
"reason": "string", // Present if denied (human-readable)
"trace": [ // Present if debug=true or configured
{
"policy_id": "string",
"rule_index": number,
"condition": "string",
"result": boolean,
"reason": "string"
}
],
"evaluation": {
"as_of_ts": "string", // ISO8601 timestamp of decision
"risk_summary": "string" // Why this decision was made
}
}200 OK: Decision reached (Approve OR Deny). Note: A Deny is a successful HTTP 200 response withdecision: "deny_with_reason".400 Bad Request: Invalid schema (missing mandatory fields).503 Service Unavailable: Daemon is initializing or overloaded.
GET /v1/health
Returns the operational status of the daemon.
{
"status": "ok", // "ok" | "degraded" | "initializing"
"version": "string", // Daemon version
"uptime_seconds": number,
"db_checkpoint_lag": number // Optional: Health metric
}POST /v1/identities
Registers a new identity (actor) in the system. This emits an identity_registered event.
{
"identity_id": "string", // Unique ID (e.g., "pat:rmax")
"kind": "string", // "user" | "service" | "bot"
"metadata": object // Optional: Display names, email, etc.
}{
"identity_id": "string",
"status": "registered",
"event_id": "string" // The event ID created
}DELETE /v1/identities/{id}
Permanently removes an identity and scrubs associated data from the event log (GDPR compliance).
204 No Content: Success.404 Not Found: If the identity doesn't exist.
Note: This action is irreversible.
GET /v1/events
Stream recent events for real-time visualization (TUI live tail).
limit: Number of past events to return (default 50).stream:trueto enable Server-Sent Events (SSE).
Array of Event objects (see DATA_MODEL.md).
Line-delimited JSON events.
data: {"event_id": "...", "type": "intent_submitted", ...}
data: {"event_id": "...", "type": "usage_observed", ...}
GET /v1/cluster/nodes
Returns the current topology of the cluster (Leader and known Followers).
{
"leader_id": "string", // The current leader identity
"self_id": "string", // ID of the node serving this request
"nodes": [
{
"node_id": "string", // Follower ID
"last_seen": "string", // ISO8601 timestamp of last grant/heartbeat
"status": "string", // "active" | "offline"
"metadata": object // Optional: { "version": "...", "uptime": "..." }
}
]
}POST /v1/federation/grant
Follower daemons use this endpoint to request token grants from the leader.
{
"follower_id": "string", // ID of the requesting daemon
"provider_id": "string",
"pool_id": "string", // The constraint pool (e.g., "github:core")
"amount": number, // Tokens requested
"metadata": object
}{
"granted": number, // Tokens actually granted (may be less than requested)
"valid_until": "string", // ISO8601 timestamp when this grant expires
"remaining_global": number // Optional: Hint of global state
}All endpoints enforce strict JSON Schema validation.
- Timestamps: ISO 8601 strings (
2024-01-01T12:00:00Z). - IDs: String, case-sensitive. Recommended format:
type:value(e.g.,scope:repo:rmax-ai/ratelord). - Enums:
urgency:["high", "normal", "background"]decision:["approve", "approve_with_modifications", "deny_with_reason"]
Standardized error format for 4xx/5xx responses.
{
"error": {
"code": "string", // Machine-readable (e.g., "invalid_scope")
"message": "string", // Human-readable detail
"request_id": "string" // For correlation
}
}Since ratelord is a local-first daemon (Phase 1), security relies on process isolation and localhost binding.
- Binding: The daemon MUST listen only on
127.0.0.1(IPv4) or::1(IPv6). It MUST NOT bind to0.0.0.0by default. - Agent Identity: The
agent_idin theIntentpayload is trusted. (In Phase 2/3, we may add mTLS or process-owner verification if needed). - Secrets: The API MUST NOT accept or return raw credentials (PATs, keys) in payloads. Identity is referenced by ID (
identity_id), not by value.
Clients MUST set a read timeout on the /v1/intent call.
- Recommended: 5000ms.
- Fallback: If timeout occurs, assume DENY (Fail Safe).
- 503 Unavailable: Retry with exponential backoff.
- 429 Too Many Requests (from Daemon): Retry after
Retry-Afterheader. - 400 Bad Request: Do not retry; fix the payload.
Clients engaging in long-running streaming usage should periodically submit new intents (e.g., every 60s) to re-confirm budget availability.
- Unix Domain Sockets: For lower latency and file-permission based security on Linux/macOS.
- Batch Intents:
POST /v1/intents/batchfor high-throughput agents requesting multiple slots. - Webhooks: Daemon pushing alerts to a registered URL (e.g., for desktop notifications).