Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 5 Nov 2026. What's built · Install 0.3.0
jadpo
ReferenceHTTP

APIsHTTP

The public API record

On this page

Each API has a committed, readable record of its routes, fields and failure codes: api/main.jadpo_record for main. jadpo check fails while the record disagrees with the source, and jadpo api update rewrites it. So every change to the API is a diff of one file, and a breaking change is caught at review, not by a client in production.

The record is written in the record format. Its first line says what generated it and which command updates it. A hand edit is record.edited, and a record out of date is record.out_of_date.

Here is a whole route group, with what it runs, and the record jadpo api update writes for it:

example
use planning/entities { Todo }use planning/types { TodoView }use planning/actions { CreateTodo, create_todo }use planning/queries { find_todo }/// Todos: making one and reading one back.routes Todos {    prefix: /todos    /// Creates a todo.    POST / {        authentication: RouteAuthentication.none        input: CreateTodo        output: TodoView        status: SuccessStatus.created        run: create_todo(input)    }    /// One todo.    GET /{todo_id: Todo.id} {        authentication: RouteAuthentication.none        output: TodoView        run: find_todo(todo_id)    }}
example
// Generated by Jadpo from the routes of API main; update it with `jadpo api update`, never by hand.record api 1GET /openapi.json    generated openapi    authentication none    status 200POST /todos    authentication none    input CreateTodo (body)    output TodoView    status 201GET /todos/{todo_id: Uuid}    authentication none    output TodoView    status 200    fails todo_not_foundinput CreateTodo    title: Text { min_length: 1, max_length: 200 }output TodoView    done: Bool    id: Uuid    title: Text { min_length: 1, max_length: 200 }failure todo_not_found    status 404    message "Todo not found."    todo_id: Uuid

What the record holds

  • The wire contract. A field shows what a client sends or reads. Objects and enums have an entry of their own, and each failure code has an entry with its status, message and client fields.
  • How clients sign in. An API that signs clients in says how in an api main entry, one line per method (authentication browser_session). A route for one kind of caller says which (caller user). So switching an API from bearer tokens to cookies is a diff of the record.
  • A fixed order. Everything is sorted: routes by path, then method; types, fields and variants by name; failures by code. Reordering the source changes nothing.
  • No version. Two branches that both changed the API would always conflict on one. The OpenAPI document's version is the first 12 hex digits of the record's SHA-256, computed at build and never stored.

Breaking changes

A change that can break a client also needs an acceptance written by a person: a route removed, a required input field added, an output field removed, a body sent as another media type, or a failure code changed. An acceptance is a file in acceptances/ saying a person accepts the change (Acceptances). Every change that needs one uses the same form, such as a database drop, a policy weakening or a new domain: one file per decision, listing the changes it allows, counted only in the change that adds it.

jadpo check compares each API's record with the record on the default branch at its merge base, and names each break with the entry an acceptance lists: "main GET /todos/{todo_id: Uuid}": ApiChange.route_removed, main.CreateTodo.due: ApiChange.input_field_required, main.CreateTodo.title: ApiChange.rule_tightened (a bound raised or lowered, a rule added, a type changed, none no longer allowed, an enum variant gone), main.TodoView.priority: ApiChange.output_field_removed or .output_field_retyped, and main.todo_locked: ApiChange.failure_changed (the code gone or its status changed). A route that now takes or answers with another type is compared field by field with the one it had. A route that now sends another media type, or starts or stops sending raw bytes, is "main GET /deeds/{deed_ref: Text}": ApiChange.media_type_changed (Sending raw bytes). A route made open to anyone is PolicyChange.route_public (Protecting policy).

acceptances/ and api/ are owned in CODEOWNERS, the file a code host reads to know who must approve changes to a path, so the host's review shows who approved it. jadpo new writes one listing them.

Markdown for agents: /docs/the-public-api-record.md.Built from Jadpo main at aee2e8f.