Skip to main content

Overview

Kuzenbo is built as a Bun workspace monorepo with strict package boundaries enforced via Turborepo tags. This architecture ensures clean separation between UI packages, build tooling, and internal dependencies.

Repository layout

The monorepo follows a clear structure with apps and packages:
kuzenbo/
├── apps/
│   └── website/          # Next.js 16 docs and playground
├── packages/
│   ├── core/             # @kuzenbo/core - UI components
│   ├── charts/           # @kuzenbo/charts - Chart components
│   ├── theme/            # @kuzenbo/theme - Theme runtime
│   ├── styles/           # @kuzenbo/styles - Baseline CSS
│   ├── hooks/            # @kuzenbo/hooks - React hooks
│   ├── notifications/    # @kuzenbo/notifications - Toast/notifications
│   ├── date/             # @kuzenbo/date - Calendar/date pickers
│   ├── ai/               # @kuzenbo/ai - AI UI components
│   ├── code/             # @kuzenbo/code - Code editor/syntax
│   ├── datatable/        # @kuzenbo/datatable - Data tables
│   ├── tiptap/           # @kuzenbo/tiptap - Rich text editor
│   ├── storybook/        # @kuzenbo/storybook - Shared config
│   ├── cli/              # @kuzenbo/cli - CLI tooling
│   └── mcp/              # @kuzenbo/mcp - MCP integration
├── turbo.json            # Monorepo task orchestration
└── package.json          # Workspace root

Package categories

Kuzenbo packages fall into three categories:

UI packages

User-facing component libraries:

@kuzenbo/core

Primary UI component library with buttons, inputs, dialogs, and layouts.

@kuzenbo/charts

13 production-ready chart components built on Recharts.

@kuzenbo/notifications

Toast and notification system with multiple viewport positions.

@kuzenbo/date

Calendar, date picker, and date range components.

@kuzenbo/ai

AI-specific UI components for chat, completions, and tool outputs.

@kuzenbo/code

Code editor, syntax highlighting, and code snippet primitives.

@kuzenbo/datatable

Advanced data table with sorting, filtering, and pagination.

@kuzenbo/tiptap

Rich text editor built on Tiptap with markdown support.

Platform packages

Foundational runtime and tooling:

@kuzenbo/theme

Theme runtime, semantic tokens, and 75+ prebuilt color themes.

@kuzenbo/styles

Optional baseline global styles for focus rings and scrollbars.

@kuzenbo/hooks

Standalone React hooks with no UI dependencies.

@kuzenbo/storybook

Shared Storybook configuration (internal only).

Experimental packages

Future-focused tooling (not yet published):

@kuzenbo/cli

CLI for scaffolding and code generation.

@kuzenbo/mcp

Model Context Protocol integration.

Package boundaries

Kuzenbo enforces strict boundaries to maintain clean architecture:

Core boundary rules

1

@kuzenbo/hooks is standalone

Must not import @kuzenbo/core or any UI packages. Keeps hooks lightweight and framework-local.
// ❌ Not allowed in @kuzenbo/hooks
import { Button } from "@kuzenbo/core";

// ✅ Allowed in @kuzenbo/hooks
import { useState, useEffect } from "react";
2

@kuzenbo/core depends on hooks

Can import from @kuzenbo/hooks through normal semver dependencies.
// ✅ Allowed in @kuzenbo/core
import { useMediaQuery } from "@kuzenbo/hooks";
3

One-way code dependency

@kuzenbo/code can depend on @kuzenbo/core, but the reverse is denied.
// ✅ Allowed in @kuzenbo/code
import { Button } from "@kuzenbo/core";

// ❌ Not allowed in @kuzenbo/core
import { CodeEditor } from "@kuzenbo/code";
4

Extracted packages depend on core

Charts, notifications, date, datatable, and tiptap can import from @kuzenbo/core for shared utilities.
// ✅ Allowed in @kuzenbo/charts
import { useComponentSize } from "@kuzenbo/core/provider";

Boundary enforcement

Boundaries are verified via Turborepo tags:
bun run boundaries
This command checks that:
  • Package imports respect tag boundaries
  • No circular dependencies exist
  • Internal packages aren’t imported by external code

Build architecture

Build tooling

Kuzenbo uses modern ESM-only builds:
Builder
tsdown
TypeScript bundler for all package workspaces.
Module format
ESM-only
No CommonJS output. Targets modern bundlers and runtimes.
Type generation
tsdown
Declaration files (.d.ts) generated automatically.

Multi-entry packages

Some packages export multiple entry points:
package.json
{
  "exports": {
    ".": "./dist/index.js",
    "./provider": "./dist/provider.js",
    "./ui/button": "./dist/ui/button.js",
    "./styles.css": "./dist/styles.css"
  }
}
Examples:
  • @kuzenbo/core: Multiple UI component subpaths
  • @kuzenbo/charts: Per-chart subpaths (ui/line-chart, ui/bar-chart)
  • @kuzenbo/theme: Theme provider and CSS exports

CSS asset handling

CSS files are copied during build:
tsdown.config.ts
export default {
  entry: ["src/index.ts"],
  format: "esm",
  dts: true,
  onSuccess: async () => {
    // Copy CSS from src to dist
    await copyFile("src/default.css", "dist/default.css");
    await copyDir("src/prebuilt/", "dist/prebuilt/");
  },
};

Release architecture

Kuzenbo uses lockstep versioning with manual releases:

Version management

1

Changesets for versioning

All packages share the same version number. Use Changesets to track changes:
bun run release:changeset
2

Version bump

Update all package versions atomically:
bun run changeset:version
3

Generate release notes

Create changelog entries:
bun run release:notes
4

Publish via GitHub Actions

Publishing runs only in CI with Trusted Publishing:
# Trigger via workflow dispatch
gh workflow run release.yml -f version=0.0.8 -f channel=stable

Release channels

Kuzenbo supports two release channels:
stable
channel
Production releases from main branch. Used for final versions.
next
channel
Pre-release versions from main branch. For testing before stable.

Publishable packages

Only an allowlist of packages is published: Published:
  • @kuzenbo/core
  • @kuzenbo/charts
  • @kuzenbo/theme
  • @kuzenbo/styles
  • @kuzenbo/hooks
  • @kuzenbo/notifications
Not published:
  • @kuzenbo/storybook (internal)
  • @kuzenbo/website (internal)
  • @kuzenbo/ai (blocked until promoted)
  • @kuzenbo/code (blocked until promoted)
  • @kuzenbo/datatable (blocked until promoted)
  • @kuzenbo/date (blocked until promoted)
  • @kuzenbo/tiptap (blocked until promoted)
  • @kuzenbo/cli (placeholder)
  • @kuzenbo/mcp (placeholder)

Trusted Publishing

Releases require GitHub Actions with id-token: write:
.github/workflows/release.yml
permissions:
  contents: read
  id-token: write

steps:
  - name: Publish packages
    run: npm publish --provenance

Documentation runtime

The docs site runs on Next.js 16 App Router:

File-based routing

apps/website/app/(docs)/docs/
├── page.tsx                    # /docs
├── quickstart/
│   └── page.tsx                # /docs/quickstart
└── foundations/
    ├── theme-runtime/
    │   └── page.tsx            # /docs/foundations/theme-runtime
    └── architecture/
        └── page.tsx            # /docs/foundations/architecture

Documentation manifest

Navigation and metadata live in docs-manifest.ts:
docs-manifest.ts
export const docsManifest = [
  {
    title: "Foundations",
    pages: [
      { title: "Theme runtime", href: "/docs/foundations/theme-runtime" },
      { title: "Architecture", href: "/docs/foundations/architecture" },
    ],
  },
];

MDX content

Docs are authored as MDX with route-local content.mdx files:
content.mdx
---
title: "Architecture"
description: "Monorepo structure and package boundaries"
---

# Architecture

Content goes here...

Development workflow

Run the monorepo locally:

Install dependencies

bun install

Start dev server

Run the docs site with HMR for all packages:
bun run dev
Package edits flow automatically via HMR—no watch scripts needed.

Run Storybook

bun run storybook

Quality gates

Run all checks before committing:
# Format code
bun run format

# Lint codebase
bun run lint

# Type check all packages
bun run typecheck

# Run tests
bun run test

# Verify boundaries
bun run boundaries

Scoped tasks

Run tasks for specific packages:
# Build only @kuzenbo/core
bun turbo run build --filter=@kuzenbo/core

# Test only @kuzenbo/hooks
bun turbo run test --filter=@kuzenbo/hooks

Toolchain

Kuzenbo uses modern tooling:

Bun

Runtime, package manager, and test runner. Version 1.3.9.

Turborepo

Monorepo orchestration and caching. Version 2.8.7.

React

UI framework. Version 19.2.4.

Next.js

App framework for docs site. Version 16.1.6.

TypeScript

Type system. Version 5.9.3 with tsgo compiler.

Ultracite

Linter and formatter using oxlint and oxfmt.

Design policies

Kuzenbo follows strict conventions:

Component structure

One component per file in packages/*/src/ui/<component>/:
packages/core/src/ui/
├── button/
│   ├── button.tsx           # Component
│   ├── button.test.tsx      # Tests
│   └── button.stories.tsx   # Storybook
└── dialog/
    ├── dialog.tsx
    ├── dialog.test.tsx
    └── dialog.stories.tsx

Export contracts

Exported components must have matching props types:
// ✅ Correct: Exported with props type
export function Button(props: ButtonProps) { ... }
export type ButtonProps = { ... };

// ❌ Incorrect: Missing props export
export function Button(props: ButtonProps) { ... }
type ButtonProps = { ... }; // Not exported

Import style

Use direct named imports:
// ✅ Correct
import { useState, useEffect } from "react";
import type { ReactNode } from "react";

// ❌ Avoid namespace imports
import React from "react";
const node: React.ReactNode = ...;

Color primitives

Use semantic tokens, not raw Tailwind classes:
// ✅ Correct: Semantic tokens
<div className="bg-background text-foreground" />

// ❌ Avoid: Raw palette classes
<div className="bg-white text-gray-900" />

Cursor primitives

Use cursor-clickable token:
// ✅ Correct: Token-based cursor
<button className="cursor-clickable" />

// ❌ Avoid: Raw cursor values
<button className="cursor-pointer" />

Testing strategy

Kuzenbo uses Bun’s native test runner:

Test files

Place tests alongside source:
packages/hooks/src/
├── use-media-query/
│   ├── use-media-query.ts
│   └── use-media-query.test.ts
└── use-clipboard/
    ├── use-clipboard.ts
    └── use-clipboard.test.ts

Naming convention

*.test.tsx    # UI component tests
*.test.ts     # Logic/utility tests
Never use:
  • *.spec.ts
  • *.spec.tsx
  • tests/ directories
  • __tests__/ directories

Running tests

# All tests
bun run test

# Watch mode
bun test --watch

# Single package
bun turbo run test --filter=@kuzenbo/hooks

Best practices

Never import across boundary violations. Run bun run boundaries to verify compliance.
Reference local packages with workspace:* in package.json:
{
  "dependencies": {
    "@kuzenbo/hooks": "workspace:*"
  }
}
Only export what consumers need. Internal utilities should not be exported from package index.
Use Changesets to document breaking changes:
bun run release:changeset
# Select "major" for breaking changes

Theme runtime

Learn about the theme package architecture.

Charts

Understand chart package internals.

Build docs developers (and LLMs) love