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
ReferenceReview and records

ToolsReview and records

Acceptances

Some changes can break someone else, such as removing a field clients read. jadpo check fails on them until a person accepts them. An acceptance is one file per decision, listing every change it allows, with the reason in a /// line. This one allows removing the priority field from what API main sends as a TodoView:

acceptances/20261020T1400_remove_todo_priority.jadpo:

example
/// Priority was never shown by any client; the mobile app stopped sending it in 3.2.acceptance {    changes: {        main.TodoView.priority: ApiChange.output_field_removed    }}

acceptance, changes: and ApiChange are built in. The rest of the entry comes from the compiler: each entry is subject: Kind.change, with the subject and the change copied from its message. A subject is a dotted name, or, for a route, its API, method and path in quotes, since a route has no name. You don't need to type one, since jadpo acceptance new drafts the file (below).

  • It counts only in the change that adds it. Acceptances already on the before side are history, and editing one is an error (acceptance.edited). check fails when a change needs a person and no added acceptance lists it (acceptance.missing), when a listed entry matches nothing (acceptance.unmatched), or when the reason is missing (acceptance.no_reason). A file that isn't one acceptance with its changes: is acceptance.invalid. A quoted key anywhere else is a syntax error.
  • Drafting is a command. jadpo acceptance new <purpose> writes a file listing every change not yet accepted, with no reason. An agent may run it, then stops: the missing reason keeps check failing until a person writes one.
  • The git host is the gate. acceptances/, api/, access.jadpo_record and network.jadpo_record are owned in CODEOWNERS, so the owner's approval of the pull request is what lets a decision in, and the host records who gave it (Review and sign-off). jadpo new writes a CODEOWNERS listing them, for the project to name its owners.
Needs a person Kind Where it is described
A route removed, a required input field added, a rule tightened, an output field removed or retyped, a body sent as another media type, a failure code changed ApiChange The public API record
An event removed, or an event's field removed, retyped, newly required or its rule tightened ApiChange The event record
A column or table dropped, an entity removed, an entity moved to another store DataChange Removing data
Any widening of who can do what, however it arises PolicyChange Policy
A sign-in setting loosened past its limit PolicyChange Magic links
Any change to how a role must be signed in to, tighter or looser, or a role's line added or removed PolicyChange Roles that need a way in
A git location added to, or widened in, packages:'s own_sources: PolicyChange Installing safely
A domain created or renamed DomainChange Domains
A risky package change (Package upgrades) PackageChange External services
A package's service: a new or changed container image, before it runs PackageChange External services
Installing a third party's package from git rather than the registry (an unverified publisher) PackageChange External services
A connection that receives personal data but can't erase it, with the reason the data stays ErasureNotPossible External services, Erasure
A threshold raised or removed ThresholdChange Monitoring
Declining an error the compiler's catalogue marks as a security rule, such as policy.call_ungranted PolicyChange Writing a decline
A new outside host the app can send data to: a provider's host, a connection's host:, an outbound: grant or an email relay NetworkChange External services

Changes that only add need no acceptance: a new route, even one anyone may call, a new optional input field, a new output field, tightened policy, listing a query, a new entity that belongs to a tenant. The diff still shows them.

Each change the compiler reports, and the subject it names:

Change Subject When
ApiChange.route_removed "main GET /todos/{todo_id: Uuid}" A route's entry in the API record is gone
ApiChange.input_field_required main.CreateTodo.due A field clients must send is new on a type they send, or on an event
ApiChange.rule_tightened main.CreateTodo.title A field clients send allows fewer values: a bound raised or lowered, a rule added, a type changed, none no longer allowed, or a field that could be left out no longer can; an enum variant gone from what clients send
ApiChange.output_field_removed main.TodoView.priority A field clients read is gone, from its type or from the type a route now answers with
ApiChange.output_field_retyped main.TodoView.priority A field clients read allows more or other values
ApiChange.media_type_changed "main GET /deeds/{deed_ref: Text}" A route's sends line in the API record is new, gone or names another media type (Sending raw bytes)
ApiChange.failure_changed main.todo_locked A failure code is gone, or its status changed
ApiChange.event_removed planning.TodoCompleted An event is gone from its domain's event record
PolicyChange.route_public "main GET /books" A route that needed a signed-in caller is open to anyone
PolicyChange.confirmation_removed "main POST /payouts/{payout_id: Uuid}/send" A route that needed the person's passkey no longer asks for it (Confirm one request with a passkey)
PolicyChange.widened library.Book.read, library.Book.cost.read, lending.borrow A caller is added to an entity's or a field's grant, or to a listed action's or query's line; or a field's own list now follows its record's
PolicyChange.restriction_removed library.Book.cost A field's own row, or its server_only, is gone
PolicyChange.tenancy_loosened library.Book, or tenant An entity that belonged to the tenant is shared by every tenant, or the app's tenant is gone
PolicyChange.shared_entity_added library.Genre A new entity shared by every tenant
PolicyChange.listing_added lending.borrow An action is newly listed under actions:, which replaces its entities' grants
PolicyChange.listing_removed catalogue.staff_books An action's or a query's line under actions: is gone
PolicyChange.call_ungranted_declined lending.borrow A new decline policy.call_ungranted:, on the declaration it sits above
PolicyChange.sign_in_loosened magic_link.expires_after A setting past its limit and looser than before
PolicyChange.role_requirements_changed desk.StaffRole.admin A role's requires: line changed, tighter or looser, or a role's line added or removed
PolicyChange.own_source_added "github.com/acme/" An entry in packages:'s own_sources: that wasn't there, or one that now covers more; not one below an entry already there, which lets nothing new in
DomainChange.created billing A folder under domains/ that wasn't there
NetworkChange.host_added couriers A connection reaches a host it didn't, a new connection's included; one entry covers every new host of the connection
PackageChange.git_source AcmeCouriers.v1 A package locked from git that wasn't, or locked from another repository than it was, from a repository under none of packages:'s own_sources:
DataChange.column_dropped Todo.legacy_flag A migration this change adds drops a retired column, by the field's born name, as changes.jadpo names it
DataChange.table_dropped Todo A migration this change adds drops a retired table, by its entity's born name
DataChange.entity_removed Todo A migration this change adds retires an entity's table, since the entity is gone
DataChange.entity_moved Todo A migration this change adds gives an entity a table in another store, leaving its records behind
PackageChange.operation_removed AcmeCouriers.bookings.get An operation, action or library function the app used is gone (Package upgrades)
PackageChange.declaration_removed Postcodes.UkPostcode A type, failure or message the app wrote is gone
PackageChange.operation_changed AcmeCouriers.bookings.get A used operation's request, input, output or what it changes, or a used function's or action's signature, is different
PackageChange.field_removed AcmeCouriers.Booking.driver_phone A field or enum variant of a type the app uses is gone
PackageChange.field_retyped AcmeCouriers.Booking.weight, or Postcodes.UkPostcode A field of a type the app uses has another type or rules; or a used refined type's base or rules, or a used failure's code or kind, changed
PackageChange.failure_added AcmeCouriers.bookings.create.address_unverifiable A used operation, action or function can fail in a new way, named by the failure's code
PackageChange.host_changed AcmeCouriers.host A connected provider package's hosts: changed; one entry covers them all
PackageChange.credential_changed AcmeCouriers.credential A connected provider package's credential scheme changed
ErasureNotPossible.data_stays couriers A connection receives personal data and can't erase it (Erasure at providers), with no acceptance on the before side listing it
ThresholdChange.raised planning.todo_list.p95, planning.todo_list.within A threshold's limit is higher than the same-named threshold's on the before side, or its within: longer
ThresholdChange.removed planning.todo_list.p95, or planning.todo_list A limit is gone from a threshold; or the threshold is gone, or watches something else
ThresholdChange.lowered uploads.free_space_floor A disk store's free_space_floor: is lower than it was

Two records give these checks a before side, and put what changed in front of the reviewer: access.jadpo_record, who can do what, from the permissions report, and network.jadpo_record, every outside host the app can reach, from the network report. jadpo check keeps them at the root beside api/, as it keeps the API record, and jadpo records update writes them. A project with nothing for one to hold has no such file, except that an app with a connections: block keeps network.jadpo_record, its header alone while it reaches no host.

text
// Generated by Jadpo from who can do what; update it with `jadpo records update`, never by hand.record access 1tenant Companyentity work.Project    create CompanyRole.editor    read CompanyRole.editor    read CompanyRole.viewer    tenant company_idfield work.Project.budget    read CompanyRole.editoraction todos.transfer_todo    who Todo.owner_iddecline policy.call_ungranted lending.borrowsign_in magic_link    code_attempts: 5    expires_after: 15m    failed_codes_per_day: 20
text
// Generated by Jadpo from the hosts the app can reach; update it with `jadpo records update`, never by hand.record network 1connection couriers    for AcmeCouriers.v1    host https://api.acme-couriers.example    host https://sandbox.acme-couriers.exampleconnection main    for database    host config.database_url

A field's own list that lets nobody in is written read nobody, so it reads apart from a field that follows its record's list. A route made public is read from the API record, whose route entry says authentication none.

Markdown for agents: /docs/acceptances.md.Built from Jadpo main at aee2e8f.