Getting started
This page takes you from zero to a passing run in a few minutes: install the CLI, run the bundled example end-to-end, then build your own first collection.
Prerequisite: Node ≥ 22. TruSpec uses the platform
fetchand modern streaming APIs.
Install
The CLI ships as the truspec package.
npm i -g truspec # global `truspec` command
truspec --helpPrefer not to install globally? Every command works through npx:
npx truspec --helpOther package managers:
pnpm add -g truspec
yarn global add truspecHacking on TruSpec itself? Run from source instead:
git clone https://github.com/code-with-rashid/truspec && cd truspec, thenpnpm install && pnpm build. After that,node packages/cli/dist/index.jsis thetruspecbinary.
Run the example loop (60 seconds, fully offline)
The repository ships ready-made collections plus an OpenAPI spec so you can see the whole loop — run, mock, drift, coverage, contract — without writing anything. These commands are copy-paste-safe.
git clone https://github.com/code-with-rashid/truspec
cd truspec
truspec mock --spec examples/blog/openapi.yaml > /tmp/truspec-mock.log 2>&1 & # mock on :4000
truspec run examples/blog --env local # run requests + assertions
truspec drift examples/blog --spec examples/blog/openapi.yaml
truspec coverage examples/blog --spec examples/blog/openapi.yaml
truspec contract examples/blog --spec examples/blog/openapi.yaml --env localYou should see:
runreport 3 passing requests against the mock,driftflagGET /users/{id}as untracked (it's in the spec but no request references it yet),coverageshow 75% (3/4) operations tested,contractconfirm all 3 tested responses conform to the spec's schemas.
Two examples ship in examples/: a small petstore and a fuller blog.
When you're done, stop the mock server (it was started with &):
kill %1Your first collection
A collection is a folder of plain-text YAML files. Here's a minimal one you can create by hand.
1. The request — api/get-pet.tspec.yaml (one request per file):
name: Get pet by id
method: GET
url: "{{baseUrl}}/pets/{{petId}}"
assertions:
- { type: status, equals: 200 }
- { type: jsonpath, path: "$.id", exists: true }2. An environment — api/environments/local.env.yaml (provides the {{variables}}):
name: local
variables:
baseUrl: "http://localhost:4000"
petId: "1"3. Give it something to call. The request targets {{baseUrl}} → http://localhost:4000, so something has to be listening there. The repo ships a petstore spec that serves /pets/{id}, so mock it on port 4000 (run from the cloned repo root):
truspec mock --spec examples/petstore/openapi.yaml > /tmp/truspec-mock.log 2>&1 & # mock on :4000The > /tmp/truspec-mock.log 2>&1 keeps the server's startup banner out of your prompt so the background job doesn't look like it hijacked the terminal — your shell is ready for the next command immediately. If the run below ever reports fetch failed, check that log to see whether the mock came up.
Pointing at a real API instead? Skip this step and set
baseUrlto that API's URL inlocal.env.yaml.
4. Run it:
truspec run ./api --env local✓ PASS Get pet by id (api/get-pet.tspec.yaml) 200 41ms
1 passed, 0 failed, 1 totalWhen you're done, stop the mock (it was started with &):
kill %1That's the whole flow: a request file, an environment that fills its variables, and a run that checks the assertions and exits non-zero if anything fails — which is exactly what makes it CI-ready.
This hand-written request mirrors
examples/petstore/get-pet.tspec.yaml. Generate a mock from any OpenAPI spec the same way —truspec mock --spec openapi.yaml(see the mock server guide).
Recommended project layout
TruSpec discovers everything by convention. A typical repo looks like this:
your-repo/
├─ openapi.yaml # your API spec (the source of truth)
└─ api/ # your collection (the "workspace")
├─ folder.tspec.yaml # shared baseUrl / headers / auth
├─ environments/
│ ├─ local.env.yaml
│ └─ staging.env.yaml
├─ auth/
│ └─ 01-login.tspec.yaml # order: 1 — captures a token
└─ pets/
├─ list-pets.tspec.yaml
└─ get-pet.tspec.yaml- One request per file (
*.tspec.yaml) keeps Git diffs clean. folder.tspec.yamlholds config inherited by every request in that folder and below (base URL, shared headers, auth).environments/<name>.env.yamlholds per-environment variables; secrets are referenced by name and resolved from the OS/.env, never stored in the file.
See Core concepts for how discovery, inheritance, and variable resolution work, and the File format reference for every field.
Where to go next
- Core concepts — understand the moving parts before you scale up.
- File format — the full schema: assertions, bodies, auth, capture.
- Spec sync — the reason TruSpec exists: keep code and spec honest.
- CI/CD integration — make
truspeca build gate. - AI agents (MCP) — let Claude Code author and run your collection.