The jadpo command
You work with Jadpo through one command, jadpo, and a short list of
subcommands. Run them anywhere inside your project: each finds the project
by walking up from the current folder to app.jadpo, so you only give a
path to work on another project. Every subcommand takes --json, for
output an agent reads instead of prose, except the interactive modes,
which need a terminal. Every --json document says how long the command
took, in durationMs.
A report keeps what an agent reads short: what it repeats points back at
the first, and what says nothing is left out. Every subcommand takes
--full, which shows everything, on the screen or under --json.
Without it, a diagnostic or a failed test that repeats an earlier one keeps
its headline and its place, and its reason points back at the first
(sameAs under --json). Long output from another program is cut to the
line that says why. --json leaves out null and empty lists and objects,
counts the tests that passed, and jadpo check counts its files.
Commands have plain synonyms where people reach for either word, such as
fmt and format, and an unknown command suggests the nearest. Tab
completes commands, flags and your project's own names, and a command
missing an argument asks for it from a searchable list.
The commands you use every day:
| Command | Does |
|---|---|
jadpo new <name> |
Starts a project |
jadpo check |
Checks everything and writes the derived files in build/ |
jadpo fmt |
Formats your code |
jadpo test |
Runs your tests |
jadpo build [<deployable>] |
Builds the programs you deploy, into build/target/ |
jadpo dev |
Runs the app locally, rebuilding it on every save |
| Command | What it does |
|---|---|
jadpo new | Start a project. |
jadpo check | Check the project for errors. |
jadpo fmt | Format source files. |
jadpo test | Run tests. |
jadpo build | Build the app to deploy. |
jadpo dev | Run the app and reload on every save. |
jadpo new
jadpo new <name> starts a project in a folder that doesn't exist yet or
is empty, and the project passes jadpo check, jadpo fmt --check and
jadpo test as soon as it is written. It writes the fixed root
(The root) and one small
domain, hello:
todo-app/ app.jadpo application { jadpo: "X.Y" } and the project token config.jadpo config {}, with no settings yet policy.jadpo who may run greet: Access.public access.jadpo_record as jadpo records update writes it CODEOWNERS the paths a person approves, for the project's owners api/ main.jadpo_record as jadpo api update writes it domains/ hello/ types/ visitor.jadpo greeting.jadpo actions/ greet.jadpo routes/ hello.jadpo hello.test.jadpo database/ empty tests/ empty AGENTS.md .gitignore .gitattributes
app.jadponames the release line of thejadpothat rannew, sojadpo newfrom X.Y.Z writesjadpo: "X.Y"(Which jadpo runs). It also holds the project'ssuggestions { project_token: }, 32 random hex digits from the operating system's generator (Sharing with Jadpo HQ); when the generator fails it leaves the block out, andsharewrites it later.- The
hellodomain is one route,POST /hello, withauthentication: RouteAuthentication.none. It takes aVisitorand runsgreet, which returns aGreeting. Becausegreetreaches no entity, root policy grants it withhello.greet: [Access.public]. The route's test, beside it, posts a visitor and checks the status and the greeting. The API record is written by the codejadpo api updateruns, from these routes, andaccess.jadpo_record, who may rungreet, by the codejadpo records updateruns. AGENTS.mdsays what Jadpo is, the release lineapp.jadponames, where the docs are (the primer, the index and the error pages on the site), and which commands to run after a change. It gives an agent a working method: one concern at a time,jadpo checkafter each connected change (a declaration and the first thing that uses it, since a supporting type alone islayout.unused_declaration), one topic read rather than a whole page, a feature declared and checked before it is designed around,jadpo help <rule>for an error, andjadpo acceptance newthen a stop for a change that needs a person (Acceptances). It ends with the closest teaching example for each feature, linked at thisjadpo's own release, and what isn't built yet, area by area, both written from the docs, so they can't drift from them..gitignoreholdsbuild/, and.gitattributesholds the lines that keep records readable in a diff (Review and records). There are no hidden folders.
The project is named after the folder: the last part of <name>, or the
folder it runs in for jadpo new .. A folder that holds anything, hidden
files included, is refused with toolchain.scaffold_destination_not_empty
and left as it was; a file of that name is
toolchain.scaffold_destination_exists, and a <name> that ends in no
folder's name, such as .., is toolchain.scaffold_name_invalid. If a
write fails partway, jadpo new removes what it wrote and reports
toolchain.scaffold_write_failed.
The screen is one status line, then the command to run next:
Created todo-app jadpo X.Y route POST /hello files 14 writtennext: cd todo-app && jadpo dev serves it on http://localhost:3000
With --json, data holds the path as typed, the root, the jadpo
line, the routes and the files it wrote.
jadpo check
jadpo check checks the whole project and writes the files derived from
it: build/manifest.json and the catalogues in build/catalogue/
(The build/ folder). In a git repository it
compares the change with the default branch at its merge base, and fails
on each change that needs a person's acceptance and has none
(Review and sign-off); --before <branch or commit> compares with another. With --json, data holds the layout,
the root, the fileCount and the errors, and any notice_list,
providers, per_instance and before; --full lists the files and what it
wrote to build. What a first commit holds that nothing can compare, such as a
new project's public write or personal data anyone may read, passes and is said as a notice for a person, in
notice_list
(What a first record holds).
jadpo fmt
jadpo fmt formats every file. It fixes each file's imports first, then
lays the file out, writing each file's declarations before their use, the
primary declaration last. --check only reports what it would change, and
--layout also makes promotion moves (Formatting).
jadpo test
jadpo test runs every test. It runs pure and action tests in the
interpreter, route tests, and schedule tests (--kind schedule). It also
reads each recording of the app's own integrations through its
operation's decoders (--kind recording), and each recorded answer to a
prompt through each type the prompt is asked for as. A recording made from
an older version of the prompt is an alert on the report and in
data.alerts (Kinds of test).
To run fewer tests:
jadpo test <file>runs one test file, and<file>:<line>the test at that line. A folder runs the tests under it.--name <text>runs the tests whose names match,--kind routeone kind of test, and--failedthe last run's failures.--seed <n>reruns the tests in the order a given seed sets.
jadpo test --watch reruns the affected tests on every save. Each save
reruns the tests that reach something whose digest, a hash of its code,
changed since the last run, within the path, name and kind you gave. While
the build is broken it shows the errors and runs nothing. With --json it
writes one envelope per line. Ctrl-c quits.
--keep-failed keeps a failed test's database and names it in the report.
When the tests need a database and none can be had, no test runs and the
one error is test.database_unavailable,
marked (human) (The test database).
jadpo build
jadpo build writes the runnable app into build/target/, with each
API's <api>.failures.<locale>.json beside its OpenAPI document
(Failures for client apps). It takes
--json. It first checks as jadpo check does, writing the same files,
and stops at the errors.
- An app that declares no deployables builds its one deployable,
app, natively: the binarybuild/target/app/app, andbuild/target/app/openapi/with each API's document and failure files. It is built with the toolchain and lock this Jadpo pins (A native deployable). - An app that declares deployables builds every one, or the one you name,
each into
build/target/<deployable>/beside only its own APIs' documents (Declared deployables). - A deployable built for
Target.wasmis a WebAssembly module with Jadpo's module shim and a Wrangler file, and the screen gives the module's size (A Workers deployable).
jadpo dev
jadpo dev runs your app locally and keeps it up to date as you edit. It
runs the app in the interpreter at http://localhost:3000 (--port
changes it) and prints one line per request with its request id.
Each save that checks cleanly serves the next request. While a save has
errors, the last good version keeps serving. --no-run only checks on
every save and writes build/, and --json writes one envelope per line.
An editor that saves a file in place first empties it, then writes its
text. So a save that leaves a file empty that had text isn't taken as
finished yet: the reload waits up to 2 seconds for the file's text. An
empty routes file checks cleanly, with no routes, so this keeps a
half-saved file from replacing the version serving. A file still empty
after that reloads as saved. jadpo test --watch waits the same way.
Settings. The settings config.jadpo declares are read from the
environment, then .env.local, and checked before the app starts. A
missing or invalid value stops it starting, and the screen names the
setting and its variable, never the value. A save of .env.local is
checked like a save of source, so the last good version keeps serving.
Databases. Each database opens at the address its connection's url:
setting holds, or the one --url names. A store whose address no
variable gives gets a disposable PostgreSQL for the session. Jadpo starts
that from PostgreSQL's own programs (initdb, pg_ctl and postgres), so
PostgreSQL has to be installed on your machine; you don't create a
database or set a password. Pending migrations are applied as they appear.
While it runs, the address of each database it started is in
build/dev/stores.json, for jadpo schedules and jadpo why.
External tokens. An app that signs in with external_token gets a
local issuer in place of the configured one, and jadpo dev token <user-id> prints a bearer token for that user from it
(External tokens in tests and jadpo dev).
The ready screen says so on its tokens line. The token is printed alone,
so it goes straight into a header, and signs in for an hour:
curl -H "Authorization: Bearer $(jadpo dev token <user-id>)" localhost:3000/staff/meWith --json it gives the token, its subject and expiresAt. It needs
a running jadpo dev in the project, whose key it signs with: the key is
made for the session, kept in build/dev/issuer.json, readable only by
you, while it runs, and removed when it stops.
Sign-in providers. An app that signs in through a provider
(Providers) gets the local issuer in each
provider's place, so none of the provider's settings is needed. Its start
route sends the browser to the local issuer's account-chooser page, on
its own port beside the app, which the ready screen gives on its
sign-in line (signIn with --json). There you choose a test account
or add one (subject, email, whether it is verified, name) and come back
signed in, or cancel and come back refused
(In jadpo dev). The accounts are kept in
build/dev/accounts.json for the next session.
Background work. Each schedule run and each skipped tick (a paused
schedule's, once) gets a line with its trace's id, its outcome, what it
emitted or its failure, and its time. Each alert gets a line when it
starts. Each step reached by an action with several changing calls is a
line under its request's line. A delivery whose action reached steps gets
a line of its own, with jadpo deliveries show <id> when it needs an
operator (Background work).
Provider calls. Every call to an outside provider is faked by default,
so you need no credential. A connection's development: { sandbox: }
lets calls through to the provider's sandbox, never to its live service.
--fake <connection> and --sandbox <operation> change which for one
session only. Each request's line lists its calls, and each call is logged
for jadpo calls (Provider calls in
development).
Stopping. Ctrl-c or SIGTERM stops it cleanly: the server finishes the requests it has, its background work gives back what it holds, and it exits 0. A second signal ends it at once (Running background work).
Not built yet:
jadpo test --affected, which runs the tests a change reaches, measured against the merge-base withmain.jadpo test --interactive, a keyboard view of every test: search, move between tests, run a file, one test or all, rerun failures and turn watching on and off (Testing). The flag saystoolchain.not_built_yet.- The trace
--keep-failedkeeps, which comes with Debugging. jadpo devstarting the services the app's connections declare (External services).
Markdown for agents: /docs/the-jadpo-command.md.Built from Jadpo main at aee2e8f.