{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://hermes.bstein.dev/contracts/hux/v1/common.schema.json", "title": "HUX shared definitions", "description": "Cross-surface primitives reused by every HUX contract. Identity, time, provenance, sensitivity and evidence are defined once here so Chat, Worker, Telegram, voice and future clients agree on them.", "$defs": { "id": { "type": "string", "description": "Opaque, prefix-typed identifier. Prefix names the record kind (evt, mem, prj, conv, art, pol, apr, rcpt, src, psg, cit, nb, sug, rel).", "pattern": "^[a-z]{2,6}_[A-Za-z0-9._-]{4,80}$" }, "user_ref": { "type": "string", "description": "Hashed Keycloak subject as already used by the chat router. Never a raw subject, email, or Telegram id.", "pattern": "^usr_[0-9a-f]{16,64}$" }, "timestamp": { "type": "string", "description": "RFC 3339 UTC timestamp with a trailing Z.", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,6})?Z$" }, "sha256": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, "surface": { "type": "string", "enum": [ "chat", "worker", "telegram", "voice", "api" ] }, "provider": { "type": "string", "description": "Provider class, never a vendor model name. Switchyard resolves the class to a concrete target.", "enum": [ "codex", "claude", "local" ] }, "effort": { "type": "string", "enum": [ "low", "medium", "high", "xhigh" ] }, "sensitivity": { "type": "string", "description": "public: safe to show anywhere; personal: user-owned but not sensitive; sensitive: health/finance/legal/relationships; restricted: credentials, minors, biometric, location traces.", "enum": [ "public", "personal", "sensitive", "restricted" ] }, "redaction": { "type": "object", "additionalProperties": false, "required": [ "level" ], "properties": { "level": { "type": "string", "enum": [ "none", "partial", "full" ] }, "reason": { "type": "string", "maxLength": 200 } } }, "actor": { "type": "object", "additionalProperties": false, "required": [ "type", "id" ], "properties": { "type": { "type": "string", "enum": [ "user", "assistant", "tool", "system", "operator" ] }, "id": { "type": "string", "minLength": 1, "maxLength": 120 }, "display": { "type": "string", "maxLength": 120 } } }, "route": { "type": "object", "description": "What was asked of Switchyard and what it resolved. requested is a friendly mode or a route id; resolved_target is the Switchyard target name.", "additionalProperties": false, "required": [ "requested" ], "properties": { "requested": { "type": "string", "minLength": 1, "maxLength": 120 }, "resolved_target": { "type": "string", "maxLength": 120 }, "provider": { "$ref": "#/$defs/provider" }, "effort": { "$ref": "#/$defs/effort" } } }, "build": { "type": "object", "additionalProperties": false, "properties": { "commit": { "type": "string", "pattern": "^[0-9a-f]{40}$" }, "image_digest": { "$ref": "#/$defs/sha256" } } }, "provenance": { "type": "object", "description": "Who produced a record, on which surface, under which session/run, through which route, from which build.", "additionalProperties": false, "required": [ "surface", "actor", "recorded_at" ], "properties": { "surface": { "$ref": "#/$defs/surface" }, "actor": { "$ref": "#/$defs/actor" }, "recorded_at": { "$ref": "#/$defs/timestamp" }, "session_id": { "type": "string", "maxLength": 120 }, "conversation_id": { "$ref": "#/$defs/id" }, "message_id": { "type": "string", "maxLength": 120 }, "run_id": { "type": "string", "maxLength": 120 }, "route": { "$ref": "#/$defs/route" }, "build": { "$ref": "#/$defs/build" } } }, "evidence_ref": { "type": "object", "description": "Pointer to the thing that justifies a record. Never inline the payload here; the UI expands it through the owning API.", "additionalProperties": false, "required": [ "kind", "id" ], "properties": { "kind": { "type": "string", "enum": [ "message", "tool_call", "tool_result", "artifact_version", "source", "passage", "memory", "approval", "run", "url", "file", "build", "flux", "pod", "receipt" ] }, "id": { "type": "string", "minLength": 1, "maxLength": 200 }, "uri": { "type": "string", "maxLength": 2000 }, "hash": { "$ref": "#/$defs/sha256" } } }, "tags": { "type": "array", "maxItems": 32, "uniqueItems": true, "items": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,39}$" } }, "tenant_slot": { "type": "string", "description": "Router-assigned tenant process slot.", "pattern": "^slot-[0-9]{1,3}$" }, "trust": { "type": "string", "description": "How identity was asserted: router, relay, worker, or the loopback-only release evidence producer.", "enum": [ "router", "relay", "worker", "evidence" ] }, "identity": { "type": "object", "description": "Resolved caller identity. Every record path and authorization check derives from tenant_slot + subject.", "additionalProperties": false, "required": [ "tenant_slot", "subject", "surface", "trust" ], "properties": { "tenant_slot": { "$ref": "#/$defs/tenant_slot" }, "subject": { "$ref": "#/$defs/user_ref" }, "surface": { "$ref": "#/$defs/surface" }, "trust": { "$ref": "#/$defs/trust" } } }, "revision": { "type": "integer", "description": "Optimistic concurrency counter. Mutations send If-Match: ; a mismatch is 409.", "minimum": 1 }, "idempotency_key": { "type": "string", "description": "Client-chosen key; a repeat with the same key returns the original record instead of creating a duplicate.", "pattern": "^[A-Za-z0-9._:-]{8,120}$" }, "contract_version": { "type": "string", "pattern": "^1\\.[0-9]+\\.[0-9]+$" }, "audit_outcome": { "type": "object", "description": "Result of an authorization decision, written for every read and mutation.", "additionalProperties": false, "required": [ "at", "identity", "action", "resource", "outcome" ], "properties": { "at": { "$ref": "#/$defs/timestamp" }, "identity": { "$ref": "#/$defs/identity" }, "action": { "type": "string", "pattern": "^[a-z_]+\\.[a-z_]+$" }, "resource": { "type": "string", "maxLength": 200 }, "outcome": { "type": "string", "enum": [ "allow", "deny", "not_found", "conflict", "flag_off" ] }, "reason": { "type": "string", "maxLength": 200 } } } } }