# ADR-0001: freeze the hux.v1 contract at 1.0.0 Status: accepted, 2026-08-24. Owners: Claude (backend), Codex (integration). ## Decision `services/hermes/contracts/hux/` is frozen as contract version `1.0.0` (`VERSION`, `flags.json.contract_version`). It is the only shape any HUX surface (Chat, Worker, Telegram, voice) codes against. The Python reference implementation lives in `dockerfiles/hermes-hux-foundation/hux/`: `contracts.py` validates records, `rules.py` holds the governance rules the schemas cannot express. Records carry their own version in `schema` (`hux.event.v1`). Wire fixtures under `services/hermes/contracts/hux/examples/` are validated by `testing/tests/test_hermes_hux_contract_schemas.py` and are the exchange format with Codex: a change to a fixture is a change to the contract. ## What 1.0.0 covers | Requirement | Where | |---|---| | Tenant and surface identity | `common.identity` (tenant_slot, hashed subject, surface, trust: router/relay/worker) — carried on every stored record that a caller can create | | Capability negotiation, default-off flags | `identity.capabilities` (`GET /hux/v1/capabilities`), `flags.json`; a card is enabled only when its dependency chain is enabled (`rules.flag_enabled`) | | Redacted activity events | `event`: `seq` (monotonic per conversation), `turn`, `correlation_id`, `idempotency_key`, replay by `after_seq`, kinds for decisions, delegation, failure/completion, cancellation, budget and side-effect gates; `detail` is allowlisted per kind and scrubbed | | Memory | `memory`: provenance, `source`, `reason`, `sensitivity`, `topic`, `ttl`, `approval_mode` incl. `no_store`, `status` incl. `no_store`, edit via `supersedes`, delete via `forgotten`, retrieval removal via `retrievable=false`, revisioned | | Projects, lineage, artifacts, versions, diffs, authorization | `project`, `conversation.branch`, `artifact.versions[]` immutable with `content_ref` hash, `diff_from`, `lineage`, `promotion`, `access`, `revision` | | Autonomy | `permission.policy` (levels, grants, budgets: tokens/tool calls/wall clock/spend/subagents/delegations/scope), `approval` with `request.external`, `cancellation_receipt`, `budget_state` | | Research | `citation.source/passage/citation/notebook` with classification, support verdict, notes, assumptions, unresolved questions, `dedupe_key` | | Additive migrations, rollback readers | `identity.manifest` (`data_layout_version`, `min_reader_contract_version`); rules in "Compatibility" below | ## Wire conventions - Identity is asserted by the trusted hop, never by the client body: the chat router sets `X-Hermes-Tenant-Identity: slot-N`, `X-Hux-Subject: usr_`, `X-Hux-Surface: chat`; the Telegram relay adds the relay key and `trust: relay`; the Worker uses `trust: worker`. Requests without a complete, well-formed identity are `401 unauthorized`. The service must only be reachable from those hops (NetworkPolicy is Codex's to enforce). - Mutations of revisioned records send `If-Match: `; a mismatch is `409 conflict` with `hux.error.v1`. Creates accept `Idempotency-Key`; a repeat returns the original record with `200` instead of a duplicate. - Lists return `{"items": [...], "next": }`. Event pages use `after_seq`; the SSE stream sets `id:` to `seq` so `Last-Event-ID` resumes exactly. - Errors are always `hux.error.v1`. A disabled card answers `404 flag_off` so an old client and a flag-off server look identical. - Every read and mutation writes a `common.audit_outcome`. ## Compatibility rules 1. Within `1.x`: only add optional fields, enum values or new record kinds. Never rename, remove, change a type, or make an optional field required. 2. Readers ignore unknown fields and unknown enum values they do not need; a reader that needs a new enum value must check `contract_version`. 3. On-disk data is append-only per family; `data_layout_version` bumps only for additive layout changes, and `min_reader_contract_version` says the oldest service that can still read it. Rolling the service back to any version ≥ `min_reader_contract_version` leaves data readable. 4. Anything outside 1–3 is `hux.v2`, served beside v1 until every surface has moved. ## Revision 1.1.0 (2026-08-24, additive) Raised after the three Wave A lanes reported. Adds `receipt` to `evidence_ref.kind`, `unprocessable` (422) to error codes, optional `revision` on source/passage/citation, optional `audit_stale` on the privacy policy, and per-route body caps (artifact uploads up to 25 MiB content). The argument hash a `once` approval is released against travels as `request.evidence[] = {kind: "tool_call", id, hash}`; the agent hook must send it or the gate can never release. Memory rules skip content-free statuses (`no_store`, `forgotten`, `rejected`). Review follow-up (same revision, still additive): `cancellation_receipt` gains optional `revision`. Stored documents in every revisioned family carry the store's `revision`, and a `failed_to_cancel` receipt is the one non-terminal outcome: a later stop that the gateway (worker trust) confirms supersedes it with a revision bump; an identical repeat replays. Only a human actor (router/relay trust on chat, telegram or voice) may write a policy or hold an `allow` grant; `trust: worker` reaches only the routes in `hux.flags.WORKER_ROUTES` (SO-08). External side effects release only against an approval for the same run and argument hash. Cards HUX-06, HUX-09 and HUX-12 declare no routes until they ship. ## Consequences - Codex codes UI against the fixtures, not against the running service. - Claude's implementation cards (HUX-01/02/03/04/05/08/10/11) may add optional fields but must ship the fixture change in the same commit. - If Codex needs a shared-interface change, it lands as a `1.(x+1).0` revision of the schemas and fixtures here, never as an informal edit.