Skip to content

Contributing to Checkstack

Thank you for your interest in contributing to Checkstack! This guide will help you get started with contributing plugins or code to the project.

  • Bun v1.0 or higher
  • PostgreSQL 14 or higher
  • Node.js 20+ (for some tooling)
  • Git
Terminal window
# Fork the repository on GitHub
# Then clone your fork
git clone https://github.com/YOUR_USERNAME/checkstack.git
cd checkstack
Terminal window
bun install

Ensure your project follows the shared standards for TypeScript and package scripts:

Terminal window
bun run core/scripts/src/sync.ts
Terminal window
# Create a PostgreSQL database
createdb checkstack_dev
# Set environment variables
cp .env.example .env
# Edit .env and set DATABASE_URL
Terminal window
# Start backend and frontend
bun run dev

The application will be available at:

checkstack/
├── core/ # Core packages
│ ├── backend/ # Backend core
│ ├── frontend/ # Frontend core
│ ├── backend-api/ # Backend plugin API
│ ├── frontend-api/ # Frontend plugin API
│ ├── common/ # Shared types
│ ├── ui/ # UI components
│ ├── tsconfig/ # Shared TypeScript configurations
│ └── scripts/ # Shared monorepo scripts
├── plugins/ # Plugin packages
│ ├── catalog-backend/
│ ├── catalog-frontend/
│ ├── catalog-common/
│ └── ...
├── docs/ # Documentation
└── scripts/ # Build and utility scripts
Terminal window
# Development
bun run dev # Start dev servers
bun run dev:backend # Backend only
bun run dev:frontend # Frontend only
# Building
bun run build # Build all packages
bun run build:backend # Backend only
bun run build:frontend # Frontend only
# Testing
bun test # Run all tests
bun test:watch # Watch mode
# Tooling (Standardized via @checkstack/scripts)
bun run sync # Synchronize project configurations
bun run lint # Run all linters
bun run typecheck # TypeScript type checking — single `tsgo -b`
# across the whole repo via project references.
# Cold ~12s, warm/incremental ~0.3s.
# Typecheck maintenance (rarely needed; see "TypeScript setup" below)
bun run typecheck:references:generate # Refresh references after editing
# workspace deps in package.json
bun run typecheck:references:check # Dry-run; CI runs this to detect drift
bun run typecheck:clean # Wipe `.tsbuild/` + tsbuildinfo
# Database
bun run db:generate # Generate migrations
bun run db:migrate # Run migrations
bun run db:studio # Open Drizzle Studio

Decide what type of plugin you’re creating:

  • Backend: REST APIs, business logic, database
  • Frontend: UI components, pages, routing
  • Common: Shared types, access rules, constants

Most plugins will have all three.

Terminal window
# Create directories
mkdir -p plugins/myplugin-backend/src
mkdir -p plugins/myplugin-frontend/src
mkdir -p plugins/myplugin-common/src

Create package.json for each package. Then run the sync tool to apply shared configurations:

Terminal window
bun run sync

See:

Follow the guides above to implement your plugin.

Write tests for your plugin:

Terminal window
# Unit tests
bun test plugins/myplugin-backend/src/**/*.test.ts
# Integration tests
bun test plugins/myplugin-backend/src/**/*.integration.test.ts

Create a README in your plugin directory:

# My Plugin
## Description
What does this plugin do?
## Configuration
How to configure this plugin.
## Usage
How to use this plugin.
## API
API endpoints or components provided.
  • Use TypeScript for all code
  • Extend shared configurations from @checkstack/tsconfig
  • Enable strict mode
  • Avoid any types (use unknown if needed)
  • Use type inference where possible

TypeScript setup (project references + tsgo)

Section titled “TypeScript setup (project references + tsgo)”

Typechecking uses tsgo (the TypeScript 7 native port, in preview) with project references between every workspace package. A single bun run typecheck from the repo root walks the dependency graph: cold ~12s, warm/incremental ~0.3s.

The references graph is generated from package.json deps — you don’t hand-edit references arrays. Helper scripts:

ScriptWhen to run
bun run typecheckAlways. The default. Runs :references:check first (~150ms) then tsgo -b. Reads cached .tsbuild/ for incremental work.
bun run typecheck:references:generateAfter adding or removing a @checkstack/* workspace dep in any package.json, adding a new package to the workspace, or removing a package. bun run create runs this for you when scaffolding a new package. If you forget, the next bun run typecheck will tell you.
bun run typecheck:references:checkDry-run; runs automatically as part of typecheck. Run standalone if you just want the validation without the actual typecheck.
bun run typecheck:cleanAlmost never. Wipes .tsbuild/ and tsconfig.tsbuildinfo files. Useful when diagnosing a stale cache, after major dep upgrades, or when switching between branches with very different type graphs. Don’t run this routinely — it forces a 12s cold rebuild on the next typecheck.

bun run typecheck does not auto-run the generator (would mutate tsconfig files without explicit intent) or the cleaner (would defeat the warm cache). It does run :references:check so you find out about stale references with a clear error message — not a cryptic tsgo failure.

.tsbuild/ and tsconfig.tsbuildinfo are gitignored. Bun runs source TypeScript directly at runtime, so emitted .d.ts files exist purely to satisfy the project-references contract.

  • Files: kebab-case (my-service.ts)
  • Classes: PascalCase (MyService)
  • Functions: camelCase (myFunction)
  • Constants: UPPER_SNAKE_CASE (MY_CONSTANT)
  • Interfaces: PascalCase (MyInterface)
  • Types: PascalCase (MyType)
// 1. Imports (grouped)
import { z } from "zod";
import { createBackendPlugin } from "@checkstack/backend-api";
// 2. Types and interfaces
interface MyData {
id: string;
name: string;
}
// 3. Constants
const DEFAULT_TIMEOUT = 5000;
// 4. Implementation
export class MyService {
// ...
}
  • Use JSDoc for public APIs
  • Explain why, not what
  • Keep comments up to date
/**
* Fetches items from the database.
* @param filter - Optional filter criteria
* @returns Array of items matching the filter
*/
async getItems(filter?: ItemFilter): Promise<Item[]> {
// Use a transaction to ensure consistency
return await db.transaction(async (tx) => {
// ...
});
}

Test individual functions and classes:

import { describe, expect, test } from "bun:test";
import { MyService } from "./my-service";
describe("MyService", () => {
test("creates item", async () => {
const service = new MyService(mockDb);
const item = await service.createItem({ name: "Test" });
expect(item.name).toBe("Test");
});
});

Test plugin integration with the core:

import { describe, expect, test } from "bun:test";
import plugin from "./index";
describe("MyPlugin Integration", () => {
test("registers correctly", () => {
expect(plugin.pluginId).toBe("myplugin");
expect(plugin.register).toBeFunction();
});
});

Use Playwright for end-to-end tests:

import { test, expect } from "@playwright/test";
test("user can create item", async ({ page }) => {
await page.goto("/items");
await page.click("text=Create Item");
await page.fill("#name", "New Item");
await page.click("text=Save");
await expect(page.locator("text=New Item")).toBeVisible();
});

Aim for:

  • 80%+ coverage for business logic
  • 100% coverage for critical paths
  • Test error cases and edge cases
Terminal window
git checkout -b feature/my-new-plugin

Use prefixes:

  • feature/ - New features
  • fix/ - Bug fixes
  • docs/ - Documentation
  • refactor/ - Code refactoring
  • test/ - Test additions
  • Follow code style guidelines
  • Write tests
  • Update documentation
  • Run standardized linters
  • Ensure configurations are synchronized
Terminal window
bun run sync
bun run lint
bun run typecheck
bun test

Use conventional commits:

Terminal window
git commit -m "feat(myplugin): add new feature"
git commit -m "fix(catalog): resolve bug in entity service"
git commit -m "docs: update plugin architecture guide"

Prefixes:

  • feat - New feature
  • fix - Bug fix
  • docs - Documentation
  • refactor - Code refactoring
  • test - Tests
  • chore - Maintenance
Terminal window
git push origin feature/my-new-plugin

Then create a Pull Request on GitHub.

  • Title: Clear and descriptive
  • Description: Explain what and why
  • Tests: Include test results
  • Screenshots: For UI changes
  • Breaking Changes: Clearly marked

Example PR description:

## Description
Adds a new HTTP health check plugin that supports custom headers and retry logic.
## Changes
- Created `healthcheck-http-backend` plugin
- Added support for custom headers
- Implemented retry logic with exponential backoff
- Added comprehensive tests
## Testing
- [x] Unit tests pass
- [x] Integration tests pass
- [x] Manual testing completed
## Screenshots
![Health check configuration](./assets/screenshots/config.png)
## Breaking Changes
None
  • ✅ Use Hono for routing
  • ✅ Use Drizzle for database
  • ✅ Use Zod for validation
  • ✅ Implement access checks
  • ✅ Write comprehensive tests
  • ✅ Document all endpoints
  • ❌ Don’t use pgSchema() in Drizzle
  • ❌ Don’t hardcode URLs or ports
  • ❌ Don’t skip validation
  • ✅ Use React hooks
  • ✅ Use ShadCN components
  • ✅ Implement access checks
  • ✅ Handle loading states
  • ✅ Handle error states
  • ✅ Use TypeScript
  • ❌ Don’t use inline styles
  • ❌ Don’t hardcode API URLs
  • ❌ Don’t skip accessibility
  • ✅ Export access rules
  • ✅ Export shared types
  • ✅ Use Zod for schemas
  • ✅ Keep dependencies minimal
  • ❌ Don’t import backend packages
  • ❌ Don’t import frontend packages
  • ❌ Don’t include runtime-specific code
  • ✅ Document all public APIs
  • ✅ Include usage examples
  • ✅ Explain configuration options
  • ✅ Document breaking changes
  • ❌ Don’t assume prior knowledge
  • ❌ Don’t skip edge cases

These are automatically enforced by the linter:

  • Common plugins → Common only
  • Frontend plugins → Frontend or Common
  • Backend plugins → Backend or Common

See dependency-linter.md for details.

  • Each plugin gets its own schema
  • Don’t use pgSchema() in table definitions
  • Migrations are automatic

See Drizzle Schema Isolation for details.

  • Use versioned configs for extension points
  • Provide migrations for schema changes
  • Test migrations thoroughly

See Versioned Data System for details.

  • GitHub Issues: Report bugs or request features
  • GitHub Discussions: Ask questions or share ideas
  • Pull Requests: Submit code contributions

All contributions go through code review. Reviewers will check:

  • Code quality and style
  • Test coverage
  • Documentation
  • Architecture compliance
  • Security considerations

Be responsive to feedback and iterate on your PR.

By contributing to Checkstack, you agree that your contributions will be licensed under the same license as the project.

Thank you for contributing to Checkstack! Your contributions help make this project better for everyone.