Bruno
punkaze's Claude Code agent skills collection (plugin marketplace). Ships the bruno skill: author/generate/run Bruno .bru API collections.
npx -y skills add punkaze/skills --skill brunoAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Bruno, the Git-friendly API client, and its CLI (bru). Use when authoring or editing .bru requests/collections, generating a collection from an OpenAPI spec or a codebase's routes, writing Bruno tests or scripts, managing environments and secrets, or running collections with `bru run` (local or CI).
SKILL.md
6.5 KB, as published. Nobody here has run it
Bruno — Author, Generate, and Run .bru Collections
Requires the Bruno CLI: npm install -g @usebruno/cli. Everything below is
verified against bru 3.5.0 (bru --version).
Generating a collection — two paths
Path A — an OpenAPI/Swagger spec exists (preferred). Look for one first:
openapi.yaml, swagger.json, a framework's swagger endpoint (Elysia,
NestJS @nestjs/swagger, etc.). Then:
bru import openapi -s <spec.yaml|url> -o <out-dir> -n "My API" --collection-format bru -g path
--collection-format bru is required — the CLI default (opencollection)
emits .yml files, not a .bru collection. -g picks folder grouping: path
(by URL structure, usually what you want) or tags (by OpenAPI tags, the CLI
default). Done when <out-dir> contains bruno.json and .bru files; an
opencollection.yml there means the format flag was dropped.
Path B — no spec. Read the codebase and write a routes manifest (shape below), then run the bundled generator:
node "${CLAUDE_PLUGIN_ROOT}/skills/bruno/scripts/generate-bruno.mjs" --manifest routes.json --out ./api-collection
Flags: --force (overwrite existing files), --dry-run (preview, write
nothing). Extract routes by reading the code — do not write a
per-framework regex route scanner. Done when the generator reports
wrote N file(s) and, with the API running, bru run . -r --env <env> from
the output dir executes every request.
Routes manifest
Schema: ${CLAUDE_PLUGIN_ROOT}/skills/bruno/references/routes.schema.json —
full example: ${CLAUDE_PLUGIN_ROOT}/skills/bruno/references/sample-manifest.json.
{
"name": "My API",
"baseUrl": "http://localhost:3000",
"auth": { "type": "bearer" },
"environments": [{ "name": "dev", "baseUrl": "http://localhost:3000", "secretVars": ["authToken"] }],
"routes": [
{ "method": "POST", "path": "/auth/login", "name": "Login", "body": {"email":"","password":""},
"auth": false, "script": "token-capture", "tests": ["status-2xx"] },
{ "method": "GET", "path": "/users/:id", "name": "Get User", "auth": true, "tests": ["status-200"] }
]
}
- Manifest-level
auth.typebecomes collection-level auth incollection.bru; routes withauth: trueinherit it. - Route
auth:true→auth: inherit,false→none, or an explicit"bearer"|"basic"|"inherit"|"none"per-request override. - Use
:paraminpathfor path params. script: "token-capture"adds a post-response script that capturesres.body.tokeninto the runtime variableauthToken.testsacceptsstatus-200,status-201,status-2xx.
.bru syntax (verified against Bruno 3.5.0)
meta {
name: Get User
type: http
seq: 1
tags: [smoke]
}
get {
url: {{baseUrl}}/users/:id
body: none
auth: inherit
}
params:path {
id: 1
}
params:query {
expand: profile
}
headers {
Accept: application/json
}
body:json {
{
"name": "John"
}
}
script:post-response {
if (res.status >= 200 && res.status < 300 && res.body && res.body.token) {
bru.setVar("authToken", res.body.token);
}
}
tests {
test("status is 200", function() {
expect(res.status).to.equal(200);
});
}
docs {
Retrieve a single user by id.
}
Critical syntax rules (these were wrong in other community skills):
- Query params use
params:query { }— NOT legacyquery { }. - Path params: keep
:paramin the URL and add aparams:path { }block — do NOT substitute{{param}}. - Child requests should use
auth: inheritto reuse collection/folder auth; only emitauth:bearer { token }/auth:basic { ... }for an explicit per-request override.
Collection-level auth — collection.bru
auth: inherit resolves against collection.bru at the collection root (or a
folder's folder.bru). Without it, "inherited" requests send no auth at all:
meta {
name: My API
}
auth {
mode: bearer
}
auth:bearer {
token: {{authToken}}
}
Environments
vars {
baseUrl: http://localhost:3000
}
vars:secret [
authToken
]
Secret variable names go in vars:secret [ ]; their values are never
written to disk — set them at runtime or via the GUI. Bruno also supports typed
vars (@number, @boolean, @object) and multiline values with '''…'''.
Variables in scripts
bru.setVar(key, val)/bru.getVar(key)— runtime/in-memory, scoped to a single run, never written to disk. Use this for chaining secrets like auth tokens between requests.bru.setEnvVar(key, val)/bru.getEnvVar(key)— environment variable. The Bruno GUI can save environment edits into the environment file — a secret set this way can end up committed to Git. UsesetEnvVaronly for non-secret config; prefersetVarfor tokens.- Response:
res.status,res.body,res.responseTime.
Running with bru run (CLI 3.5.0)
Run from the collection root (the directory containing bruno.json) —
anywhere else fails with "You can run only at the root of a collection".
bru run . -r --env dev # run the whole collection recursively
bru run folder -r --env dev # run a folder recursively
bru run request.bru --env-file env.bru # explicit env file
bru run . -r --env dev --env-var token=$TOK # override one var from shell (no secret in history)
bru run . -r --reporter-junit results.xml --reporter-html report.html
bru run . -r --bail --tests-only # CI: stop on first failure, only requests with tests
bru run . -r --csv-file-path data.csv --parallel # data-driven, parallel iterations
bru run . -r --tags smoke --exclude-tags wip # filter by meta tags
Sandbox (v3 default changed): the CLI defaults to --sandbox safe — no
filesystem access, no require() of external npm packages. Only pass
--sandbox developer when you trust the collection and genuinely need fs/exec/
npm in scripts; it is dangerous with untrusted collections.
Secrets: prefer --env-file or --env-var KEY=$SHELL_VAR; never paste a live
secret literal on the command line (it leaks into shell history).