Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 3 Nov 2026. What's built · Install 0.2.0
jadpo
Reference: External services

External services

The verifier

The verifier is jadpo package verify, the same tool authors run, in a container image published with each Jadpo release. A package's tests and examples are code from anyone, so the verifier is built around where that code runs and what can come back from it.

  • jadpo package verify <folder> --previous <folder> --json runs the publishing bar and writes everything a release shows: the bar's rows, surface, facts, change record, the fingerprints of every public function and declaration, the previous release's examples and tests run against the new code, and the Jadpo release it was checked with.
  • --serve answers the registry, reached over HTTPS with a credential the registry holds. Each request names a repository, a commit and the previous release's digest. It fetches over git with network to the git host only, then verifies in a process with no network at all.
  • It is reached from the registry as an ordinary connection to a provider package, so the registry needs no feature an app doesn't have. Verifying takes longer than a call may, so a verification is started and asked after.
Request Answers
GET /health { "status": "ok" }, the only answer with no credential
POST /v1/resolve Given repository and tag, the commit it points at, for a tag being published and to tell when one moved
POST /v1/verifications Given repository, commit and previous_digest (null for a first release), starts one and answers 202 with its id. The same three name the same one
GET /v1/verifications/{id} Its state (verifying, checked, could_not_check), its result once checked and its failure's code and message if it couldn't be
GET /v1/verifications/{id}/source For a release that passed, what a model reads to write its account: files, each with its path and text, and truncated
GET /v1/verifications/{id}/diff For a release that passed, what a model reads for what the facts can't show: diff, as git diff writes it against the previous release, null for a first release, and truncated

result has every field, null or empty where it has no value: passed, package, version, bar, problems, surface, facts, change_record, fingerprints, previous, jadpo, checked_with, left_out, and for a release that passed its digest and archive: the tar archive of GET archives/{digest}, in base64, which is how the registry comes to hold a release's files. A release whose whole answer wouldn't fit that 10 MiB fails too, rather than pass and never arrive. The source and the diff are asked for on their own, since neither would fit beside the archive; each is at most 8 MiB of its answer, past which truncated says some was left out. They are what the package's author wrote, so a model reads them as data. could_not_check says nothing of the release and can be asked for again: repository_refused, commit_not_fetched, previous_not_found, previous_digest_mismatch or verifier_failed. Its other failures, in the failure envelope, are unauthorized (401), repository_refused, commit_refused, tag_refused, digest_refused and invalid_body (422), tag_not_found and verification_not_found (404), repository_unreachable (502) and verifier_busy (503, when 16 are waiting).

What a commit may hold is decided from its tree's listing, before any of it is written anywhere. A release holds .jadpo source, .jadpo_record records, GUIDE.md and CHANGELOG.md at its root, .json files under a recordings/ folder and a jadpo.lock in a folder such as sample/, all of them text, whose archive comes to at most 7 MB and 10,000 files, since the registry, a Jadpo application, receives it in base64 in an answer of at most 10 MiB. Any other file, a symbolic link or a submodule refuses the commit (publish.file_not_allowed, publish.too_large). What a repository needs for itself, hidden files and folders and a root README, LICENSE, LICENCE or COPYING, is left out instead: it isn't in the archive or the digest, and left_out lists it. jadpo package verify <folder> has the same files row, so a local pass is a pass here.

Where its code runs. Each pass runs in a sandbox of its own, sharing nothing with another pass or another verification:

Network None: a network namespace of its own
The machine Nothing but the system's programs, read-only, and the release's folders, read-only
Its own files A temporary folder of at most 512 MB, in memory, gone when it ends
The verifier None of its variables, the credential included, and no sight of its process
Limits 300 seconds of CPU, 600 seconds, 3 GB of memory, 256 MB in one file, 4,096 processes, 1,024 open files, 32 MB of output

One verification runs at a time, so one package can't take another's time or memory. A run stopped at a limit fails the release with the bar's limits row.

What it can't choose. jadpo package verify runs twice: first with --no-run, which runs none of the package's code and gives the surface, facts, fingerprints, version and the change record from its source; then whole, for what running shows, the examples, tests, recipes, decoders and the previous release's. A row the first decided is taken from the first, and if the second says anything else about what the first decided, the release fails with the bar's agreement row, so code that took over its own process still can't change what the release shows. The digest and archive are the verifier's own work, from the commit's files.

Reaching a repository. A repository is an https:// address at a host name, on the default port, with no credential. Every address the host has must be public: this machine, private networks, Fly.io's own and a cloud's metadata service are refused, and git is handed the address that was checked, so a name that changes afterwards reaches nothing else. It follows no redirect and runs no hook, filter or submodule, and a commit is read from the object store, never checked out. A previous release comes from the registry's GET archives/{digest} and is used only once its files have that digest.

Which Jadpo. It checks with the release its image carries, which is the newest once deployed. When the package's jadpo: names another line, it also runs the bar with that line's newest release, fetched and checked as a project's own jadpo is, as the bar's declared jadpo row and an entry in checked_with. A release too old to have verify can't say, and the row says so. What a release shows always comes from the newest.

Running it. jadpo package verify --serve [--listen <address>] [--registry <url>] needs the credential in JADPO_VERIFIER_TOKEN, of at least 32 characters, and serves only on Linux with bubblewrap; it confirms a program in its sandbox has no network before it listens, and otherwise refuses with cli.verifier_start_failed. It speaks HTTP on 127.0.0.1:8080 unless told otherwise: HTTPS is what stands in front of it, Fly.io's edge in deploy/verifier/fly.toml.

Markdown for agents: /docs/the-verifier.md.Built from Jadpo main at ed7572b.