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.
Table of Contents
Section titled “Table of Contents”- Getting Started
- Development Setup
- Creating a Plugin
- Code Style
- Testing
- Submitting Changes
- Plugin Guidelines
Getting Started
Section titled “Getting Started”Prerequisites
Section titled “Prerequisites”- Bun v1.0 or higher
- PostgreSQL 14 or higher
- Node.js 20+ (for some tooling)
- Git
Fork and Clone
Section titled “Fork and Clone”# Fork the repository on GitHub# Then clone your forkgit clone https://github.com/YOUR_USERNAME/checkstack.gitcd checkstackInstall Dependencies
Section titled “Install Dependencies”bun installSynchronize Configurations
Section titled “Synchronize Configurations”Ensure your project follows the shared standards for TypeScript and package scripts:
bun run core/scripts/src/sync.tsSet Up Database
Section titled “Set Up Database”# Create a PostgreSQL databasecreatedb checkstack_dev
# Set environment variablescp .env.example .env# Edit .env and set DATABASE_URLRun Development Server
Section titled “Run Development Server”# Start backend and frontendbun run devThe application will be available at:
- Frontend: http://localhost:5173
- Backend: http://localhost:3000
Development Setup
Section titled “Development Setup”Project Structure
Section titled “Project Structure”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 scriptsAvailable Scripts
Section titled “Available Scripts”# Developmentbun run dev # Start dev serversbun run dev:backend # Backend onlybun run dev:frontend # Frontend only
# Buildingbun run build # Build all packagesbun run build:backend # Backend onlybun run build:frontend # Frontend only
# Testingbun test # Run all testsbun test:watch # Watch mode
# Tooling (Standardized via @checkstack/scripts)bun run sync # Synchronize project configurationsbun run lint # Run all lintersbun 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.jsonbun run typecheck:references:check # Dry-run; CI runs this to detect driftbun run typecheck:clean # Wipe `.tsbuild/` + tsbuildinfo
# Databasebun run db:generate # Generate migrationsbun run db:migrate # Run migrationsbun run db:studio # Open Drizzle StudioCreating a Plugin
Section titled “Creating a Plugin”1. Choose Plugin Type
Section titled “1. Choose Plugin Type”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.
2. Create Plugin Structure
Section titled “2. Create Plugin Structure”# Create directoriesmkdir -p plugins/myplugin-backend/srcmkdir -p plugins/myplugin-frontend/srcmkdir -p plugins/myplugin-common/src3. Initialize Packages
Section titled “3. Initialize Packages”Create package.json for each package. Then run the sync tool to apply shared configurations:
bun run syncSee:
4. Implement Plugin
Section titled “4. Implement Plugin”Follow the guides above to implement your plugin.
5. Test Your Plugin
Section titled “5. Test Your Plugin”Write tests for your plugin:
# Unit testsbun test plugins/myplugin-backend/src/**/*.test.ts
# Integration testsbun test plugins/myplugin-backend/src/**/*.integration.test.ts6. Document Your Plugin
Section titled “6. Document Your Plugin”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.Code Style
Section titled “Code Style”TypeScript
Section titled “TypeScript”- Use TypeScript for all code
- Extend shared configurations from
@checkstack/tsconfig - Enable strict mode
- Avoid
anytypes (useunknownif 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:
| Script | When to run |
|---|---|
bun run typecheck | Always. The default. Runs :references:check first (~150ms) then tsgo -b. Reads cached .tsbuild/ for incremental work. |
bun run typecheck:references:generate | After 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:check | Dry-run; runs automatically as part of typecheck. Run standalone if you just want the validation without the actual typecheck. |
bun run typecheck:clean | Almost 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.
Naming Conventions
Section titled “Naming Conventions”- Files: kebab-case (
my-service.ts) - Classes: PascalCase (
MyService) - Functions: camelCase (
myFunction) - Constants: UPPER_SNAKE_CASE (
MY_CONSTANT) - Interfaces: PascalCase (
MyInterface) - Types: PascalCase (
MyType)
Code Organization
Section titled “Code Organization”// 1. Imports (grouped)import { z } from "zod";import { createBackendPlugin } from "@checkstack/backend-api";
// 2. Types and interfacesinterface MyData { id: string; name: string;}
// 3. Constantsconst DEFAULT_TIMEOUT = 5000;
// 4. Implementationexport class MyService { // ...}Comments
Section titled “Comments”- 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) => { // ... });}Testing
Section titled “Testing”Unit Tests
Section titled “Unit Tests”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"); });});Integration Tests
Section titled “Integration Tests”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(); });});E2E Tests (Frontend)
Section titled “E2E Tests (Frontend)”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();});Test Coverage
Section titled “Test Coverage”Aim for:
- 80%+ coverage for business logic
- 100% coverage for critical paths
- Test error cases and edge cases
Submitting Changes
Section titled “Submitting Changes”1. Create a Branch
Section titled “1. Create a Branch”git checkout -b feature/my-new-pluginUse prefixes:
feature/- New featuresfix/- Bug fixesdocs/- Documentationrefactor/- Code refactoringtest/- Test additions
2. Make Changes
Section titled “2. Make Changes”- Follow code style guidelines
- Write tests
- Update documentation
- Run standardized linters
- Ensure configurations are synchronized
bun run syncbun run lintbun run typecheckbun test3. Commit Changes
Section titled “3. Commit Changes”Use conventional commits:
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 featurefix- Bug fixdocs- Documentationrefactor- Code refactoringtest- Testschore- Maintenance
4. Push and Create PR
Section titled “4. Push and Create PR”git push origin feature/my-new-pluginThen create a Pull Request on GitHub.
PR Guidelines
Section titled “PR Guidelines”- 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

## Breaking Changes
NonePlugin Guidelines
Section titled “Plugin Guidelines”Backend Plugins
Section titled “Backend Plugins”- ✅ 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
Frontend Plugins
Section titled “Frontend Plugins”- ✅ 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
Common Plugins
Section titled “Common Plugins”- ✅ 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
Documentation
Section titled “Documentation”- ✅ Document all public APIs
- ✅ Include usage examples
- ✅ Explain configuration options
- ✅ Document breaking changes
- ❌ Don’t assume prior knowledge
- ❌ Don’t skip edge cases
Architecture Rules
Section titled “Architecture Rules”Dependency Rules
Section titled “Dependency Rules”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.
Database Isolation
Section titled “Database Isolation”- Each plugin gets its own schema
- Don’t use
pgSchema()in table definitions - Migrations are automatic
See Drizzle Schema Isolation for details.
Versioned Configs
Section titled “Versioned Configs”- Use versioned configs for extension points
- Provide migrations for schema changes
- Test migrations thoroughly
See Versioned Data System for details.
Getting Help
Section titled “Getting Help”Documentation
Section titled “Documentation”- Plugin Architecture
- Monorepo Tooling
- Backend Plugins
- Frontend Plugins
- Extension Points
- Versioned Configs
Community
Section titled “Community”- GitHub Issues: Report bugs or request features
- GitHub Discussions: Ask questions or share ideas
- Pull Requests: Submit code contributions
Code Review
Section titled “Code Review”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.
License
Section titled “License”By contributing to Checkstack, you agree that your contributions will be licensed under the same license as the project.
Thank You!
Section titled “Thank You!”Thank you for contributing to Checkstack! Your contributions help make this project better for everyone.