Repository navigation
Releases
v0.24.0
-
Leave a step out of one run:
run --skip. The step that deletes what you want to look at, a slowsleep, a step against a service that is down today: skip it for this run, and the file stays as it is, so a step never stays out by mistake in CI. A step is named as with--to, by its number asinspectlists it or by its name, and the option can be repeated (spec 0021).tinyprobe run tinyprobe/workflows/users.yaml -e tinyprobe/env.local.yaml --skip 11 --skip "Deleted user is gone"✓ Patch the user PATCH 200 397µs /api/users/56 – Delete the user skipped (--skip) – Deleted user is gone skipped (--skip) steps...............: 10/10 passed 2 skippedSkipped steps are not counted: the run passes when the steps that ran passed. A later step that needs a value only a skipped step saves fails and says why:
Variable 'userId' is not defined: step 7 (Create a user), which saves it, was skipped.With--to, skipped steps after the target are ignored.--skiptakes one workflow file. -
For tools.
run_startedlists the skipped steps inskippedand the summary counts them inskipped_steps(new keys, protocol 1); in the JUnit report they are<skipped message="Skipped with --skip"/>. The MCPruntool takesskip, so an agent can explore a flow without the step that would delete what it looks at. tinyprobe-app uses it for ⊘ Skip on the steps of a workflow.
Update: tinyprobe update, or run the install command again.
What's Changed
- Spec 0021: skip steps in a run (--skip) by @kikutano in #41
- Add run --skip: leave steps out of one run (spec 0021) by @kikutano in #42
Full Changelog: v0.23.0...v0.24.0
v0.23.0
-
A sequence once per item:
for_eachonuse. A case made of several steps (create, read back, delete) is a sequence; give itsuseafor_each, a written list or a data file, and the sequence runs once per item. Each item's keys are params of the sequence, checked likewith, and each item saves and reads its own values (spec 0020).- use: ../sequences/user-lifecycle.yaml for_each: - { firstName: Ada, city: Bari } - { firstName: Grace, city: Lecce }
✓ User lifecycle [1/2] › Create POST 201 1.08ms /api/users ✓ User lifecycle [1/2] › Read it … GET 200 554µs /api/users/35 ✓ User lifecycle [1/2] › Delete DELETE 204 665µs /api/users/35 ✓ User lifecycle [2/2] › Create POST 201 674µs /api/users ...The workflow stops at the first failing step. A variable as the items (
for_each: ${users}) is not supported on ause: it stays for call steps.inspect --jsongives each step'ssequenceitsitemanditems. -
Faster
inspectandcall. The YAML of a workflow is parsed once instead of twice, and the default names of steps no longer recompute their endpoint's placeholders:inspectof 2000 steps went from 443 to 321 ms, of 8000 from 1917 to 1235 ms. The VS Code extension and tinyprobe-app runinspecton every save, so editors get faster too. -
The README is rewritten around what makes tinyprobe different; the command-line reference moved to docs/cli.md, and docs/comparison.md compares tinyprobe with Postman, Bruno and Hurl.
Update: tinyprobe update, or run the install command again.
What's Changed
- Parse a workflow once in inspect and call by @kikutano in #37
- Rewrite the README around what makes tinyprobe different by @kikutano in #38
- A comparison with Postman, Bruno and Hurl by @kikutano in #39
- for_each over a sequence: a use step runs it once per item by @kikutano in #40
Full Changelog: v0.22.0...v0.23.0
v0.22.0
-
A call shows its status, not a verdict.
tinyprobe callchecks nothing, so its line no longer starts with a green ✓ for any response, a 401 or a 500 included. It starts with→(>without Unicode) and the colored status; a ✗ now means only that no response arrived.tinyprobe run, the exit codes and the ndjson events don't change (spec 0019).$ tinyprobe call docs/example/api/testserver.yaml status --with code=404 -e docs/environment.yaml → status code=404 GET 404 64.41ms /api/status/404 HTTP 404 Not Found -
License: GPL-3.0. From this version tinyprobe is licensed under the GNU General Public License, version 3 (GPL-3.0-only): it stays free and open source, and a changed version can be shared only under the same license, with its source code. Releases up to 0.21.0 stay under the MIT License.
Update: tinyprobe update, or run the install command again.
What's Changed
Full Changelog: v0.21.0...v0.22.0
v0.21.0
The file as written, for editors.
tinyprobe inspect tinyprobe/api/shop.yaml --json --sourceadds two keys to the inspect --json document:
source: the file as written, as JSON — keys in order, scalars typed as YAML reads them, placeholders unresolved. The headers written in an endpoint, its auth set, the auth sets, checks as operator and value,usesteps,import,variables.blocks: where every top-level key, auth set, endpoint and step starts and ends, so an editor rewrites one block and keeps the rest of the file, comments included.
{ "kind": "endpoint", "name": "login", "start": { "line": 7, "column": 3 }, "end": { "line": 10, "column": 57 } }Without --source nothing changes, the MCP tool inspect included. The protocol stays 1: new keys only (docs/protocol.md).
tinyprobe-app 0.3.0 builds its visual editor on it: endpoints, auth sets, workflows and their steps edited with forms, and tinyprobe checks every change before it is kept.
What's Changed
Full Changelog: v0.20.1...v0.21.0
v0.20.1
tinyprobe mcp is now listed in the official MCP Registry as io.github.kikutano/tinyprobe, with the Docker image ghcr.io/kikutano/tinyprobe as its package: clients that read the registry can add the tinyprobe tools (guide, inspect, call, run) from there. Each stable release updates the listing.
The image has the label the registry checks (io.modelcontextprotocol.server.name). Nothing else changes: the binary is the same as 0.20.0.
Full Changelog: v0.20.0...v0.20.1
v0.20.0
Two new operators for expect and until: regular expressions, and JSON Schema. No breaking change.
matches: a regular expression
On a body value, a header or a cookie. It searches the value, like JavaScript's RegExp.test; anchor it with ^...$ for the whole value, (?i) ignores case. Numbers and booleans are matched as their JSON text. Placeholders work: '^${prefix}-'.
expect:
headers:
Location: { matches: '^/api/orders/[0-9]+$' }
cookies:
sid: { matches: '^[0-9a-f]{32}$' }
body:
$.id: { matches: '^ORD-[0-9]{8}-[0-9]{4}$' }
$.email: { matches: '(?i)@example\.com$' }An invalid pattern is an error before any request, with the reason. A pattern that takes more than 1 s on a value fails the step instead of hanging the run.
schema: check a value against a JSON Schema
The whole body ($) or a part of it, against a JSON or YAML schema file, a schema inside your OpenAPI document (after #, a JSON Pointer), or a schema written in the step:
expect:
body:
$: { schema: ../openapi/openapi.yaml#/components/schemas/User }
$.address: { schema: ../schemas/address.json }
$.id: { schema: { type: integer, minimum: 1 } } ✗ $.nickname schema required actual (missing)
✗ $.id schema type "string" actual 1
- JSON Schema drafts 4 to 2020-12 and the schemas of OpenAPI 3.0 and 3.1 (
nullable, booleanexclusiveMinimum),$refwithin a document and to other files, and the common formats (date-time,date,time,email,uuid,uri,ipv4,ipv6). - Schemas are read and checked when the workflow is loaded: a missing file, a pointer that leads nowhere, a misspelled keyword (
requird) or an unsupported one is an error with its location, before any request. - One failed check per problem, at the path of the value, at most 20, then a count.
The guide for coding agents (tinyprobe guide) maps Postman's jsonSchema, tv4.validate and .to.be.a("string"), and Bruno's type checks, to schema, and tells agents that start from an OpenAPI document to point at components/schemas instead of copying them.
Also
docs/exampleuses both operators, so CI and the test server image exercise them.- Strings in the report keep characters such as
+as they are, instead of+. - The binary is 165 KB larger (9.3 MB) and starts in the same 5 ms.
What's Changed
- matches: regular expressions on body values, headers and cookies (spec 0015) by @kikutano in #33
- schema: check a body value against a JSON Schema (spec 0016) by @kikutano in #34
Full Changelog: v0.19.0...v0.20.0
v0.19.0
Examples anyone can run: the test server as a Docker image, and a guided tour of every feature.
Highlights
The test server in Docker
The complete example project, docs/example, runs against a small test server: bearer and API-key auth, Basic, OAuth2, cookie sessions, forms and uploads, slow responses and async jobs. It used to need the .NET SDK. It is now an image:
docker run --rm -p 127.0.0.1:5122:5122 ghcr.io/kikutano/tinyprobe-testserver:0.19.0
tinyprobe run docs/example/workflows -e docs/environment.yamlThe server accepts fixed credentials and fake tokens on purpose: keep the 127.0.0.1: in -p so only your machine reaches it. Images for linux/amd64 and linux/arm64, tagged like the tinyprobe image (0.19.0, 0.19, latest).
A guided tour of docs/example
docs/example/README.md walks through the format one workflow at a time: what each one shows, and the commands to try (call, --to, --junit, inspect, a validation error on purpose, init), and the Postman and OpenAPI files to try a migration with your agent.
The suite now covers the whole format. A new workflow, jobs.yaml, starts a report and waits for it with until, with generated values and workflow variables:
variables:
reportName: "report-${$uuid}" # resolved once per run: every step sees the same name
requestedAt: ${$now}
steps:
- call: start_report
with: { name: "${reportName}", requestedAt: "${requestedAt}" }
save: { reportId: $.id }
- call: get_report
with: { id: "${reportId}" }
until:
body: { $.status: done }
every: 100ms
timeout: 10scatalog.yaml adds AND and OR (any) checks.
Also
- No change in the format, the CLI or the protocol: the tinyprobe binary does what 0.18.0 did.
- The VS Code extension 0.8.0 follows, with sequence files, go to definition and the items of
for_eachsteps.
No breaking changes.
What's Changed
Full Changelog: v0.18.0...v0.19.0
v0.18.0
Cookies, Basic and OAuth2, tables of cases, shared steps, named imports, and run to here.
Highlights
Cookies
Every workflow run keeps the cookies the server sets, redirects included, and sends them with the next requests. Each workflow starts with none; tinyprobe call keeps none between calls. Cookies can be checked, and saved for a CSRF header:
- call: login
expect:
cookies:
sid: { exists: true }
save:
csrf: { cookie: XSRF-TOKEN }The recorded request (ndjson, the VS Code extension) now shows the Cookie header as sent.
Basic auth and OAuth2 client credentials
Two keys of an auth set, next to its headers:
auth:
admin:
basic: { username: ${username}, password: ${password} }
service:
oauth2:
token_url: ${authUrl}/oauth/token
client_id: ${clientId}
client_secret: ${clientSecret}
scope: [orders:read]- tinyprobe computes the Basic header.
- It gets the OAuth2 token on first use and reuses it for the run until it expires, so
tinyprobe callworks on protected endpoints with only the environment file.
for_each: tables of cases
One step, one call per item. Each item's keys are arguments, and in a for_each step the expected status can come from the item. The list is written in the workflow, held by a variable, or read from a CSV or JSON file, which is how Postman data files translate.
- name: Invalid users are rejected
call: create_user
for_each:
- { email: "", error: email_required }
- { email: not-an-email, error: email_invalid }
expect:
status: 422
body: { $.code: ${error} }Every item runs, even after a failing one, and the console and JUnit show one line per item.
Sequences: steps shared by several workflows
A login written once, in tinyprobe/sequences/, and run with use. Its params are local to it; what it saves is visible after it.
steps:
- use: ../sequences/log-in.yaml
with: { password: "${adminPassword}" }
- call: list_ordersNamed imports
Two services with the same endpoint names can be imported together:
import:
- ../api/shop.yaml
- billing: ../api/billing.yaml # billing.login, billing.create_invoiceRun to here
tinyprobe run tinyprobe/workflows/orders.yaml --to 4 -vThis runs a workflow up to a step, given by its number or its name, and stops. The steps after it are not counted, so the run exits 0 when everything up to it passed. The MCP run tool takes to as well. The VS Code extension's ▶ Run to here follows in its next release.
Also
- Protocol 1, new keys only:
basic_auth,oauth2,for_each,source_location,sequence,import_name,imports,kind: sequence;iterationsonstep_completed;toandstopped_afteron the run events.
- Guide:
tinyprobe guidenow translates Postman, Insomnia and Bruno cookies, Basic, OAuth2 client credentials and data files, and the same from OpenAPI, HAR and curl. - Size and speed budgets in CI: the binary is 9.2 MB, starts in under 10 ms, and runs 500 requests with their checks in about 300 ms against a local server.
tinyprobe initalso createstinyprobe/sequences/.
No breaking changes.
What's Changed
- Cookies: a jar per workflow, expect.cookies, save from a cookie by @kikutano in #25
- Basic auth and OAuth2 client credentials in auth sets by @kikutano in #26
- for_each: repeat a step over a list of items by @kikutano in #27
- Sequences: steps shared by several workflows, run with use by @kikutano in #28
- Performance guard in CI: size and speed budgets by @kikutano in #29
- Named imports: call billing.login by @kikutano in #30
- run --to: run a workflow up to a step by @kikutano in #31
Full Changelog: v0.17.0...v0.18.0
v0.17.0
Form and multipart bodies, with file uploads.
Highlights
form: urlencoded bodies, encoded for you
An endpoint can send application/x-www-form-urlencoded with form. Names and values are encoded after placeholders are resolved, so a password with &, + or = is sent as written. A list repeats the field.
endpoints:
token:
method: POST
path: /oauth/token
params: { client_id:, client_secret: }
form:
grant_type: client_credentials
client_id: ${client_id}
client_secret: ${client_secret}multipart: text fields and file uploads
multipart sends multipart/form-data: text fields, files (file, with optional filename and content_type), and lists, in the order written.
endpoints:
upload_avatar:
method: PUT
path: /api/users/${id}/avatar
auth: bearer
params: { id:, avatar: }
multipart:
description: Profile picture
avatar:
file: ${avatar}
tags: [profile, public]steps:
- call: upload_avatar
with:
id: ${userId}
avatar: ../fixtures/avatar.png
expect:
status: 204- A relative
filepath is relative to the file tinyprobe was given: the workflow forrun, the API file forcall. A workflow runs the same from any directory. Content-Typeis set by tinyprobe. AContent-Typein the endpoint's own headers is an error, reported with its location.- Recorded requests (
-v, ndjson, the VS Code extension) show each file as one line,(file ../fixtures/avatar.png, 79 B), instead of its bytes. - Under
tinyprobe mcp, files must be inside the server's working directory. inspect --jsonhasformandmultipartfor each endpoint (new keys, protocol 1).tinyprobe schemadescribes the new keys, so the extension completes them with no update.
Imports by your AI
tinyprobe guide now translates Postman formdata and urlencoded, OpenAPI multipart/form-data and form bodies, Insomnia, Bruno, HAR form parameters, and curl -F and --data-urlencode, where it used to list them as not translated. Files go in tinyprobe/fixtures/. In the OpenAPI bench, Sonnet converted 11 operations of 11, the avatar upload included.
No breaking changes.
What's Changed
Full Changelog: v0.16.0...v0.17.0
v0.16.0
Docker image
docker run --rm -v "$PWD:/work" ghcr.io/kikutano/tinyprobe:0.16.0 run tinyprobe/workflows -e tinyprobe/env.local.yamlghcr.io/kikutano/tinyprobe, for linux/amd64 and linux/arm64, tagged 0.16.0, 0.16 and latest: the Alpine binary of this release on Microsoft's .NET runtime-deps Alpine base, about 20 MB. It has a shell, so GitLab CI and other CIs that run jobs in a container can use it as the job image:
api-tests:
image:
name: ghcr.io/kikutano/tinyprobe:0.16.0
entrypoint: [""]
script:
- tinyprobe run tinyprobe/workflows -e tinyprobe/env.ci.yaml --junit reports/tinyprobe.xml
artifacts:
when: always
reports:
junit: reports/tinyprobe.xmlAlpine binaries
New release assets: tinyprobe-linux-musl-x64.tar.gz and tinyprobe-linux-musl-arm64.tar.gz. install.sh picks them on Alpine and other musl systems. tinyprobe update keeps an Alpine install on the Alpine build.
What's Changed
Full Changelog: v0.15.0...v0.16.0