Contributing to Kubb

September 1, 2026 · View on GitHub

We welcome contributions that help improve Kubb. A few ways to get involved:

Please read and follow our Code of Conduct. Be respectful and open-minded, search the issue tracker before opening a PR, and for opinion-driven changes open an issue first.

Prerequisites

  • Node.js 22 or newer
  • pnpm 11 or newer. The repo pins a version in packageManager, so the easiest way to match it is corepack enable and let Corepack pick the right pnpm
  • Git

Getting started

Fork the repo, then clone your fork and install:

gh repo fork kubb-labs/kubb --clone   # or: git clone https://github.com/kubb-labs/kubb.git
cd kubb
pnpm install
pnpm build

pnpm build compiles every package with tsdown. Run it once after install so local packages resolve each other, and again after you change package source.

The Kubb ecosystem

Kubb spans a few repositories. Knowing where code lives saves time:

  • kubb-labs/kubb (this repo) is the core. It holds the engine that runs the plugin system, the OpenAPI adapter, the AST and JSX renderer, the CLI, and the MCP server. Work here on generation internals, plugin APIs, the command line, or the MCP integration.
  • kubb-labs/plugins holds the official plugins (TypeScript, client, React Query, Vue Query, SWR, Zod, Faker, MSW, Cypress, ReDoc, MCP) and a runnable example per plugin. Work here on a specific generator or to add a new plugin.

What is inside this repo

kubb/
├── packages/                # Published npm packages and core modules
│   ├── core/                # Plugin system and code generation orchestration
│   ├── kit/                 # Authoring toolkit re-exported through kubb/kit (definePlugin, ast, factories)
│   ├── ast/                 # Spec-agnostic AST layer (nodes, visitors, factories)
│   ├── adapter-oas/         # OpenAPI/Swagger adapter (OAS to AST)
│   ├── parser-ts/           # TypeScript parser for AST manipulation
│   ├── parser-md/           # Markdown parser (AST to .md source, YAML frontmatter)
│   ├── renderer-jsx/        # JSX renderer for component-based output
│   ├── plugin-barrel/       # Barrel export generation (enforce: 'post' plugin)
│   ├── unplugin-kubb/       # Bundler integration (Vite, Nuxt, Astro, webpack)
│   ├── cli/                 # Command-line interface (kubb init, kubb generate)
│   ├── mcp/                 # Model Context Protocol server for AI assistants
│   └── kubb/                # Main package, re-exports the public APIs
├── internals/               # Non-published helpers (changelog, shared logic, utils)
├── configs/                 # Shared build and test configuration
└── .agents/skills/          # Cross-provider agent skills

Tech stack

ToolPurpose
TypeScriptPrimary language (strict, ESM only)
pnpmPackage manager with workspaces
TurborepoMonorepo task runner
tsdownBundler and .d.ts generation
VitestTesting
oxlintLinter
oxfmtFormatter
ChangesetsVersioning and changelogs
GitHub ActionsCI/CD

Commands

pnpm build          # Build all packages with tsdown
pnpm clean          # Remove build artifacts
pnpm test           # Run tests once
pnpm test:watch     # Run tests in watch mode
pnpm test:bench     # Run performance benchmarks
pnpm typecheck      # Type-check all packages
pnpm lint           # Lint with oxlint
pnpm lint:fix       # Lint and auto-fix
pnpm format         # Format with oxfmt
pnpm changeset      # Create a changeset
pnpm upgrade        # Bump dependencies with taze

To run a single package's tests, point Vitest at its folder:

pnpm vitest run --config ./configs/vitest.config.ts packages/core
pnpm vitest run --config ./configs/vitest.config.ts -u packages/core   # update snapshots

Development workflow

  1. Create a branch from main.
  2. Make your change, with tests for new behavior.
  3. Build and verify locally with pnpm build && pnpm typecheck && pnpm test.
  4. Fix style with pnpm format && pnpm lint:fix.

Opening a pull request

  1. Run the full check locally first:

    pnpm format && pnpm lint:fix
    pnpm typecheck
    pnpm test
    
  2. Add a changeset for any change that affects a published package (see below).

  3. Commit with Conventional Commits: feat:, fix:, docs:, chore:, refactor:, test:, perf:.

  4. Push your branch and open a PR against main, then fill out the template.

Changesets

Changesets drive versioning and the changelog. When your change affects a published package, run:

pnpm changeset

Pick the packages you changed, choose the bump (patch for fixes, minor for features, major for breaking changes), and write a short summary aimed at users. Commit the generated file under .changeset/. Docs-only or internal changes that touch no published package do not need one.

The Claude Code plugin under tools/claude/ (commands, agents, skills, hooks) is versioned the same way as "@kubb/claude-plugin", a private workspace package that sits in the same fixed group as every other @kubb/* package. Add a changeset when you change its content; release syncs the bumped version into tools/claude/.claude-plugin/plugin.json automatically, so never edit that file's version field by hand.

Releasing

Maintainers only, once a changeset merges. Merging a changeset queues or updates the automatic "Version Packages" PR. Merging that PR runs the release job, which stages every changed package with pnpm stage publish (npm's staged publishing). Nothing is installable until a maintainer approves it.

To approve a release:

  1. A maintainer with npm publish access and 2FA runs npm stage approve (or approves on npmjs.com) for each staged package.
  2. The same maintainer approves the promote job's environment review in the Actions tab.
  3. promote verifies the versions are live on npm, tags them, creates a GitHub Release, then triggers the Discord announcement and the changelog sync to kubb-labs/docs.

To reject a bad version instead, run npm stage reject. Nothing downstream fires.

Every package here shares one version (the fixed group in .changeset/config.json), so a release is one combined GitHub Release tagged with kubb's own tag. The release and promote steps come from the shared kubb-labs/config actions (.github/actions/release and .github/actions/promote). kubb-labs/plugins uses the same promote action but versions independently and releases per package instead, switched by the release-mode input.

Manage promote's environment reviewers under the repo's Settings > Environments > npm-release-approval on GitHub, separate from npm's own settings.

Canary is the exception: every push to main publishes a 0.0.0-canary-<timestamp> under the canary tag directly, unstaged, so canary installs stay automatic.