Contributing to Kubb
September 1, 2026 · View on GitHub
We welcome contributions that help improve Kubb. A few ways to get involved:
- Found a bug? File it in the issue tracker.
- Have an idea to improve Kubb? Open an issue to share it.
- Need help? Ask the community on Discord.
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 iscorepack enableand 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
| Tool | Purpose |
|---|---|
| TypeScript | Primary language (strict, ESM only) |
| pnpm | Package manager with workspaces |
| Turborepo | Monorepo task runner |
| tsdown | Bundler and .d.ts generation |
| Vitest | Testing |
| oxlint | Linter |
| oxfmt | Formatter |
| Changesets | Versioning and changelogs |
| GitHub Actions | CI/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
- Create a branch from
main. - Make your change, with tests for new behavior.
- Build and verify locally with
pnpm build && pnpm typecheck && pnpm test. - Fix style with
pnpm format && pnpm lint:fix.
Opening a pull request
-
Run the full check locally first:
pnpm format && pnpm lint:fix pnpm typecheck pnpm test -
Add a changeset for any change that affects a published package (see below).
-
Commit with Conventional Commits:
feat:,fix:,docs:,chore:,refactor:,test:,perf:. -
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:
- A maintainer with npm publish access and 2FA runs
npm stage approve(or approves on npmjs.com) for each staged package. - The same maintainer approves the
promotejob's environment review in the Actions tab. promoteverifies 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.