The contract
The endpoint contract
One host, one wire. Every surface — chat, workflows, code, the CLI, an external agent — is a client of the same governed planes; this page is the public record of that wire.
Conifer is a host you stand up and call. The desktop studio, the CLI, and a third-party agent all speak to the same HTTP surface, with the same shapes, the same headers, and the same receipts — there is no private wire. The contract is published so a client written against it keeps working: the surface only grows, it never breaks.
Served planes
| Plane | Wire | Specified by |
|---|---|---|
/v1 | OpenAI-compatible chat completions and model listing | OpenAI's API, served verbatim |
/v1/messages | Anthropic-compatible messages and count_tokens | Anthropic's Messages API, served verbatim |
/api, /infill | Ollama-compatible chat, generate, and infill | Ollama's API, served verbatim |
/agent/v1 | Agent tasks, approvals, workflows, sessions — 25 routes | The frozen OpenAPI document |
/lab/v1 | The kernel lab as an API — 12 routes | The frozen OpenAPI document |
/host/v1 | Host identity, health, telemetry — 8 routes | The frozen OpenAPI document |
/observe/v1 | The queryable observability surface, read-only by construction — 4 routes | The frozen OpenAPI document |
/canopy/v1 | The metaharness read slice — instances, tasks, task events, placement dry-run — 5 routes | The frozen OpenAPI document |
/recorder/v1 | Flight Recorder write/control — per-rack grants, write-token ingest, purge — 4 routes | The frozen OpenAPI document |
Contract version 1.4.0. The governed planes are specified by the machine-readable document below; the compatible facades are specified upstream and served verbatim. Conifer semantics ride only in the x-conifer-* header family, never in bespoke body fields.
Additive-only evolution
That rule, quoted verbatim from the canonical contract, governs every plane above. Fields that were present stay present, with the same type and the same name; new endpoints, new fields, and new enum values are the only non-breaking change. Fixtures are normative: when code and contract disagree, the code is wrong. A client may therefore ignore anything it does not recognize — an unknown field, header, or code is never an error.
The routing slot
Routing is part of the wire, not a private feature of any surface. A client submits an ask; the host executes within it; a receipt discloses what actually ran.
The ask
| Model field | Meaning |
|---|---|
<concrete-id> | Serve exactly this model, or refuse with a typed error. A named model is never silently substituted. |
auto | Delegate the choice to this door's decider; the receipt discloses the pick. |
Ids beginning conifer or auto are reserved, including the auto/<pool> grammar and the constraint-header family — reserved names grow additively like everything else. The advisory x-conifer-request-type request header steers auto, never auth or billing. Credit-spending calls carry a client-minted idempotency-key header, stable per turn, so a retry never bills twice.
The receipt
Response headers on a settled completion disclose the execution:
| Header | Meaning |
|---|---|
x-conifer-requested-model | The ask, verbatim. |
x-conifer-effective-model | The model that executed. |
x-conifer-route-reason | Why, as a code from the vocabulary below. |
x-conifer-endpoint | The venue that served it, e.g. credits or byok:<provider>. |
x-conifer-cost-nanousd | Settled cost in nano-USD when the call was metered. Absent when unmetered — absent is never zero. |
A hop that decides emits its own receipt; a hop that relays forwards the upstream receipt unchanged. The header family versions add-only: a v2 may add headers, never remove or rename them.
Reason codes
The x-conifer-route-reason vocabulary is owned by a versioned artifact (route-reasons.json, version 7) and grows additively. The codes:
| Code |
|---|
privacy_local_only |
offline |
capability_unavailable |
context_overflow |
needs_vision |
needs_audio |
needs_tools |
local_confident |
low_confidence |
predicted_low_local_quality |
not_entitled |
as_requested |
type_routed |
tier_substitution |
budget_downgrade |
budget_floor |
sticky_promotion |
content_unsupported |
cloud_not_permitted |
airgap |
out_of_budget |
endpoint_down |
capability_unmet |
tainted |
no_cloud_lane |
resident |
pinned |
unknown_local_model |
local_unavailable |
cloud_masked |
cloud_unavailable |
tool_capability_unmet |
tool_stream_unsupported |
cache_unsupported |
thinking_unsupported |
vision_unsupported |
native_fallback |
strategy_routed |
health_routed |
provider_failover |
Codes are opaque to clients: a newer host may emit a code an older client has never seen, and the client treats it as an unknown string, never as an error.
Changelog
| Version | Date | Change |
|---|---|---|
1.4.0 | 2026-07-09 | Flight Recorder Phase 1: the /recorder/v1 write/control family mounts — arm/disarm a rack's recording grant (PUT /recorder/v1/racks/{rack_id}), review grants (GET /recorder/v1/racks), write-token-gated capture ingest (POST /recorder/v1/ingest), and purge with crypto-shred (DELETE /recorder/v1/racks/{rack_id}/history) — every response the one RecorderEnvelope, bearer required even on loopback. Recorder reads mount no new noun; they ride /observe/v1 as surface transcript. The same window mounted the /canopy/v1 read slice (instances, tasks, task events, placement dry-run) additively, consuming no version slot of its own. |
1.3.0 | 2026-07-09 | Team Pulse: the /observe/v1 plane lands — the queryable observability surface. Four read-only routes (GET /observe/v1/surfaces, GET /observe/v1/surfaces/{surface}/schema, POST /observe/v1/query, POST /observe/v1/questions/{name}) over the ObserveEnvelope schema; bearer required even on loopback; the async query door stays reserved, not mounted. |
1.2.0 | 2026-07-06 | Session state adds cancelled and waiting; suspend_kind and wrapper_cycle; run inputs and verified retry provenance (retried_from); external session registration (POST /agent/v1/sessions, heartbeat, end) and the session work receipt (GET /agent/v1/sessions/{id}/receipt); pause, resume, and run-now on runs; task journaling (GET /agent/v1/tasks/{id}); SubstrateInfo adds contract_version, the capability probe. |
1.1.0 | 2026-07-05 | One host: the OpenAI and Ollama facades and the observation plane ride the managed endpoint. Session adds waiting_on, cwd, tokens, and route; GET /agent/v1/runs/{id}; the bearer security scheme for non-loopback binds. |
1.0.0 | 2026-06-13 | The native-plane document freezes (x-status: final), reconciled with the host's route table in both directions: every documented path is mounted, every mounted native path is documented. |
Every entry is additive. No version has removed, renamed, or retyped a member.
Machine-readable
The normative artifact is the OpenAPI 3.1 document the native planes are generated from: openapi-native-planes.yaml. The copy served here is byte-identical to the contract this site is built against; a drift test fails the test suite when they diverge. Its canonical home is the platform’s contracts directory, alongside the golden fixtures (turn events, run events, host identity, session states) that pin the wire byte-for-byte across repos.
A live host discloses its own contract version at GET /host/v1/info (contract_version), so a client can probe capability before relying on it.