Qualify a workload
You will prove that a workload you changed boots through its production entrypoint, reaches readiness with the workloads it runs with, and answers real requests — with one command and one verdict, and no hand-written smoke test. The same verdict works on your machine before a pull request and against a deployment after it ships.
putnami lint,test,build,validate proves a change statically. putnami qualify proves it by running it. Keep both: the gate is static evidence, the verdict is execution evidence.
Steps
1) Declare what the workload runs with
A workload that calls another workload names it in runsWith, in its putnami.json (or under putnami.runsWith in a TypeScript package.json):
{
"name": "@example/go-items-consumer",
"runsWith": ["/services/items-api"]
}Each entry resolves by project name, then by project id. That list, followed transitively, is the whole composition. Putnami never infers a runtime dependency from the build graph: compiling against a generated client does not mean you run the provider.
2) Develop against the composition with compose
For the daily loop, serve the workload together with everything it runs with:
putnami compose @example/go-items-consumerEvery member binds an ephemeral port behind a local proxy whose URL stays stable across restarts. The provider's URL reaches the consumer through its clients configuration, and each datasource declared in infra/requirements.json gets its own database for the length of the run. Dependencies run production-mode; the target watches your edits. Ctrl-C stops every process and drops every database.
3) Qualify on your machine before a pull request
When the change is ready, run the local proof:
putnami qualify @example/go-items-consumer --target localOne invocation composes the workload production-mode, waits for each member's typed ready event, sends the smoke contract, and tears everything down, whatever happened. The contract is derived from the workload's route inventory: every exact, public GET or HEAD route except the platform endpoints, each expected to answer below 500. Print it without running anything:
putnami qualify @example/go-items-consumer --print-contractA TypeScript workload without a committed route inventory needs a build first, which produces one:
putnami build --projects @example/web
putnami qualify @example/web --target localWithout it the verdict is unsupported, never passed.
4) Read the verdict
Human output prints one line per phase and a final line naming the tree it proved. With --output=json, the verdict is the result's data. Three members answer everything:
| Member | What to check |
|---|---|
state |
passed is the only pass and the only state that exits 0. failed, unsupported, timed_out, composition_failed, digest_mismatch and the others exit 1, and the failing phase carries the diagnostic. |
binding |
{kind: "tree", fingerprint, dirty, headSHA} names the exact worktree, uncommitted changes included. It is the same digest a gate session records as tree.fingerprint, so a verdict and a gate prove the same tree when the two are equal. A file that changes during the run makes the verdict digest_mismatch. |
cleanup |
state: "clean" means every process, proxy and database was released; partial lists leftovers, and the verdict is never passed. |
5) Qualify a deployment after it ships
The runner is the same against any URL. A URL target must name the build it expects, which the workload reports on /version:
putnami qualify @example/go-items-consumer --target https://staging.example.com --expect-sha "$(git rev-parse HEAD)" --output=jsonA different or missing sha is digest_mismatch: a green verdict on a stale deployment proves nothing. A CI system qualifies a pull request preview the same way, with the preview URL and the pull request head sha.
When qualification does not apply
Qualify every workload your change reaches: a workload you changed, or one whose runsWith closure includes a project you changed. A library-only or docs-only change that reaches no workload has no execution proof to run. Report it as NOT APPLICABLE, with the reason, instead of claiming a pass.
You now have one command that proves a changed workload runs with its real composition, a verdict that names the exact tree or build it proved, and the same proof for your machine, a pull request preview, and a deployed environment.