Token导航 LogoToken导航

Agent Skill · 研究检索

bruno-collection-generator(布鲁诺集合生成器)

bruno-collection-generator 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

bruno-collection-generator 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 19,245。

总安装 5,696周安装 235GitHub Stars 33下载 1,861核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:bruno-collection-generator(布鲁诺集合生成器)
来源仓库:https://github.com/patricio0312rev/skills
仓库路径:skills/bruno-collection-generator
安装命令:
npx skills add https://github.com/patricio0312rev/skills --skill bruno-collection-generator
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/patricio0312rev/skills --skill bruno-collection-generator

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

bruno-collection-generator 用于生成 Bruno API 客户端集合文件,支持 Git 友好格式。适合在 Codex、Claude、Cursor、Gemini CLI 中扫描路由并自动生成 .bru 文件。创建 bruno.json 清单并组织环境配置,支持开发和生产环境分离。

使用前需确认 API 路由定义,注意仅限 Bruno 客户端生成用途。建议结合原始 README 和仓库文档进一步核验具体使用方法和限制条件。

来源仓库内路径:skills/bruno-collection-generator

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/patricio0312rev/skills --skill bruno-collectio…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

bruno-collection-generator 怎么安装?

在终端执行 npx skills add https://github.com/patricio0312rev/skills --skill bruno-collection-generato…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

bruno-collection-generator 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

bruno-collection-generator 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

bruno-collection-generator 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

bruno-collection-generator 用的人多吗?

公开数据是累计安装 5,696 次,近一周安装 235 次,下载 1,861 次,GitHub 33 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

bruno-collection-generator 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
bruno-collection-generator

布鲁诺集合生成器 · 本页

5,69633需要联网MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Bruno Collection Generator

Generate Bruno collection files for the open-source, Git-friendly API client.

Core Workflow

  1. Scan routes: Find all API route definitions
  2. Extract metadata: Methods, paths, params, bodies
  3. Create collection: Initialize bruno.json manifest
  4. Generate.bru files: One file per request
  5. Organize folders: Group by resource
  6. Add environments: Dev, staging, production

Bruno Collection Structure

collection/
├── bruno.json              # Collection manifest
├── environments/
│   ├── Development.bru
│   ├── Staging.bru
│   └── Production.bru
├── users/
│   ├── folder.bru
│   ├── get-users.bru
│   ├── get-user.bru
│   ├── create-user.bru
│   ├── update-user.bru
│   └── delete-user.bru
├── auth/
│   ├── folder.bru
│   ├── login.bru
│   ├── register.bru
│   └── logout.bru
└── products/
    ├── folder.bru
    └── ...

bruno.json Manifest

{
  "version": "1",
  "name": "My API",
  "type": "collection",
  "ignore": ["node_modules", ".git"]
}

.bru File Syntax

meta {
  name: Get Users
  type: http
  seq: 1
}

get {
  url: {{baseUrl}}/users
  body: none
  auth: bearer
}

auth:bearer {
  token: {{authToken}}
}

query {
  page: 1
  limit: 10
}

headers {
  Accept: application/json
}

docs {
  Retrieve a paginated list of users.
}

Generator Script

// scripts/generate-bruno.ts
import * as fs from "fs";
import * as path from "path";

interface RouteInfo {
  method: string;
  path: string;
  name: string;
  description?: string;
  body?: object;
  queryParams?: { name: string; value: string }[];
  auth?: boolean;
}

interface BrunoOptions {
  collectionName: string;
  outputDir: string;
  baseUrl: string;
  authType?: "bearer" | "basic" | "apikey";
}

function generateBrunoCollection(
  routes: RouteInfo[],
  options: BrunoOptions
): void {
  const { outputDir, collectionName } = options;

  // Create output directory
  if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
  }

  // Create bruno.json
  const manifest = {
    version: "1",
    name: collectionName,
    type: "collection",
    ignore: ["node_modules", ".git"],
  };
  fs.writeFileSync(
    path.join(outputDir, "bruno.json"),
    JSON.stringify(manifest, null, 2)
  );

  // Create environments
  generateEnvironments(outputDir, options);

  // Group routes by resource
  const groupedRoutes = groupRoutesByResource(routes);

  for (const [resource, resourceRoutes] of Object.entries(groupedRoutes)) {
    const folderPath = path.join(outputDir, resource);

    if (!fs.existsSync(folderPath)) {
      fs.mkdirSync(folderPath, { recursive: true });
    }

    // Create folder.bru
    const folderBru = `meta {\n  name: ${capitalize(resource)}\n}\n`;
    fs.writeFileSync(path.join(folderPath, "folder.bru"), folderBru);

    // Create request files
    let seq = 1;
    for (const route of resourceRoutes) {
      const fileName = generateFileName(route);
      const content = generateBruFile(route, seq++, options);
      fs.writeFileSync(path.join(folderPath, `${fileName}.bru`), content);
    }
  }
}

function generateBruFile(
  route: RouteInfo,
  seq: number,
  options: BrunoOptions
): string {
  const lines: string[] = [];

  // Meta section
  lines.push("meta {");
  lines.push(`  name: ${route.name}`);
  lines.push("  type: http");
  lines.push(`  seq: ${seq}`);
  lines.push("}");
  lines.push("");

  // Request section
  const method = route.method.toLowerCase();
  const urlPath = route.path.replace(/:(\w+)/g, "{{$1}}");

  lines.push(`${method} {`);
  lines.push(`  url: {{baseUrl}}${urlPath}`);

  if (["post", "put", "patch"].includes(method) && route.body) {
    lines.push("  body: json");
  } else {
    lines.push("  body: none");
  }

  if (route.auth && options.authType) {
    lines.push(`  auth: ${options.authType}`);
  } else {
    lines.push("  auth: none");
  }

  lines.push("}");
  lines.push("");

  // Auth section
  if (route.auth && options.authType === "bearer") {
    lines.push("auth:bearer {");
    lines.push("  token: {{authToken}}");
    lines.push("}");
    lines.push("");
  } else if (route.auth && options.authType === "basic") {
    lines.push("auth:basic {");
    lines.push("  username: {{username}}");
    lines.push("  password: {{password}}");
    lines.push("}");
    lines.push("");
  }

  // Query params
  if (route.queryParams?.length) {
    lines.push("query {");
    for (const param of route.queryParams) {
      lines.push(`  ${param.name}: ${param.value}`);
    }
    lines.push("}");
    lines.push("");
  }

  // Headers
  lines.push("headers {");
  lines.push("  Accept: application/json");
  if (["post", "put", "patch"].includes(method)) {
    lines.push("  Content-Type: application/json");
  }
  lines.push("}");
  lines.push("");

  // Body
  if (["post", "put", "patch"].includes(method) && route.body) {
    lines.push("body:json {");
    lines.push(JSON.stringify(route.body, null, 2));
    lines.push("}");
    lines.push("");
  }

  // Docs
  if (route.description) {
    lines.push("docs {");
    lines.push(`  ${route.description}`);
    lines.push("}");
  }

  return lines.join("\n");
}

function generateEnvironments(outputDir: string, options: BrunoOptions): void {
  const envsDir = path.join(outputDir, "environments");

  if (!fs.existsSync(envsDir)) {
    fs.mkdirSync(envsDir, { recursive: true });
  }

  const environments = [
    { name: "Development", baseUrl: "http://localhost:3000/api" },
    { name: "Staging", baseUrl: "https://staging-api.example.com" },
    { name: "Production", baseUrl: "https://api.example.com" },
  ];

  for (const env of environments) {
    const content = `vars {
  baseUrl: ${env.baseUrl}
  authToken:
}

vars:secret [
  authToken
]
`;
    fs.writeFileSync(path.join(envsDir, `${env.name}.bru`), content);
  }
}

function generateFileName(route: RouteInfo): string {
  return route.name.toLowerCase().replace(/\s+/g, "-");
}

function groupRoutesByResource(
  routes: RouteInfo[]
): Record<string, RouteInfo[]> {
  const groups: Record<string, RouteInfo[]> = {};

  for (const route of routes) {
    const parts = route.path.split("/").filter(Boolean);
    const resource = parts[0] || "api";

    if (!groups[resource]) {
      groups[resource] = [];
    }
    groups[resource].push(route);
  }

  return groups;
}

function capitalize(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

Complete Example Files

bruno.json

{
  "version": "1",
  "name": "My API",
  "type": "collection",
  "ignore": ["node_modules", ".git"]
}

environments/Development.bru

vars {
  baseUrl: http://localhost:3000/api
  authToken:
  userId: 1
}

vars:secret [
  authToken
]

environments/Production.bru

vars {
  baseUrl: https://api.example.com
  authToken:
  userId:
}

vars:secret [
  authToken
]

users/folder.bru

meta {
  name: Users
}

users/get-users.bru

meta {
  name: Get Users
  type: http
  seq: 1
}

get {
  url: {{baseUrl}}/users
  body: none
  auth: bearer
}

auth:bearer {
  token: {{authToken}}
}

query {
  page: 1
  limit: 10
}

headers {
  Accept: application/json
}

docs {
  Retrieve a paginated list of users.

  ## Query Parameters
  - page: Page number (default: 1)
  - limit: Items per page (default: 10, max: 100)

  ## Response
  Returns paginated user list with metadata.
}

users/get-user.bru

meta {
  name: Get User by ID
  type: http
  seq: 2
}

get {
  url: {{baseUrl}}/users/{{userId}}
  body: none
  auth: bearer
}

auth:bearer {
  token: {{authToken}}
}

headers {
  Accept: application/json
}

docs {
  Retrieve a single user by their ID.
}

users/create-user.bru

meta {
  name: Create User
  type: http
  seq: 3
}

post {
  url: {{baseUrl}}/users
  body: json
  auth: bearer
}

auth:bearer {
  token: {{authToken}}
}

headers {
  Accept: application/json
  Content-Type: application/json
}

body:json {
  {
    "name": "John Doe",
    "email": "john@example.com",
    "role": "user"
  }
}

docs {
  Create a new user account.

  ## Request Body
  - name: User's full name (required)
  - email: User's email address (required, unique)
  - role: User role (optional, default: "user")
}

users/update-user.bru

meta {
  name: Update User
  type: http
  seq: 4
}

put {
  url: {{baseUrl}}/users/{{userId}}
  body: json
  auth: bearer
}

auth:bearer {
  token: {{authToken}}
}

headers {
  Accept: application/json
  Content-Type: application/json
}

body:json {
  {
    "name": "John Updated",
    "email": "john.updated@example.com"
  }
}

docs {
  Update an existing user.
}

users/delete-user.bru

meta {
  name: Delete User
  type: http
  seq: 5
}

delete {
  url: {{baseUrl}}/users/{{userId}}
  body: none
  auth: bearer
}

auth:bearer {
  token: {{authToken}}
}

headers {
  Accept: application/json
}

docs {
  Delete a user account.
}

auth/login.bru

meta {
  name: Login
  type: http
  seq: 1
}

post {
  url: {{baseUrl}}/auth/login
  body: json
  auth: none
}

headers {
  Accept: application/json
  Content-Type: application/json
}

body:json {
  {
    "email": "user@example.com",
    "password": "password123"
  }
}

script:post-response {
  if (res.body.token) {
    bru.setEnvVar("authToken", res.body.token);
  }
}

docs {
  Authenticate user and receive access token.

  On successful login, the token is automatically saved
  to the authToken environment variable.
}

Pre/Post Request Scripts

script:pre-request {
  // Set dynamic values before request
  const timestamp = Date.now();
  bru.setVar("requestId", `req-${timestamp}`);
}

script:post-response {
  // Extract values from response
  if (res.body.token) {
    bru.setEnvVar("authToken", res.body.token);
  }

  if (res.body.id) {
    bru.setEnvVar("userId", res.body.id);
  }

  // Log response info
  console.log(`Status: ${res.status}`);
  console.log(`Response time: ${res.responseTime}ms`);
}

Tests in Bruno

tests {
  test("should return 200", function() {
    expect(res.status).to.equal(200);
  });

  test("should return array of users", function() {
    expect(res.body.data).to.be.an("array");
  });

  test("should include pagination", function() {
    expect(res.body.meta).to.have.property("page");
    expect(res.body.meta).to.have.property("total");
  });
}

CLI Script

#!/usr/bin/env node
// scripts/bruno-gen.ts
import * as fs from "fs";
import { program } from "commander";

program
  .name("bruno-gen")
  .description("Generate Bruno collection from API routes")
  .option("-f, --framework <type>", "Framework type", "express")
  .option("-s, --source <path>", "Source directory", "./src")
  .option("-o, --output <path>", "Output directory", "./bruno-collection")
  .option("-n, --name <name>", "Collection name", "My API")
  .option("-b, --base-url <url>", "Base URL", "http://localhost:3000/api")
  .option("-a, --auth <type>", "Auth type (bearer|basic|apikey)")
  .parse();

const options = program.opts();

async function main() {
  const routes = await scanRoutes(options.framework, options.source);

  generateBrunoCollection(routes, {
    collectionName: options.name,
    outputDir: options.output,
    baseUrl: options.baseUrl,
    authType: options.auth,
  });

  console.log(`Generated Bruno collection in ${options.output}`);
  console.log(`Open with: bruno run ${options.output}`);
}

main();

Best Practices

  1. Git-friendly: Bruno stores everything as plain text files
  2. Use environments: Store URLs and tokens in environment files
  3. Secret variables: Mark sensitive vars with vars:secret
  4. Add docs: Document each request with the docs block
  5. Pre/post scripts: Automate token extraction and setup
  6. Add tests: Include assertions in test blocks
  7. Organize folders: Group related requests together
  8. Sequence numbers: Order requests logically with seq

Output Checklist

  • bruno.json manifest created
  • Environment files for dev/staging/prod
  • Folder structure by resource
  • folder.bru for each folder
  • Request.bru files with proper syntax
  • Path parameters use {{param}} syntax
  • Query parameters in query block
  • Request bodies in body:json block
  • Authentication configured
  • Documentation in docs block
  • Pre/post scripts for token handling

平台分布

Antigravity

29.85%
按下载量换算556

Claude Code

22.53%
按下载量换算419

OpenCode

15.88%
按下载量换算296

github-copilot

11.82%
按下载量换算220

Codex

8.03%
按下载量换算149

Cursor

3.45%
按下载量换算64

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills