Thank you for your interest in contributing to Checkstack! This guide will help you get started with contributing plugins or code to the project.
# Fork the repository on GitHub
# Then clone your fork
git clone https://github.com/YOUR_USERNAME/checkstack.git
cd checkstack
bun install
Ensure your project follows the shared standards for TypeScript and package scripts:
bun run core/scripts/src/sync.ts
# Create a PostgreSQL database
createdb checkstack_dev
# Set environment variables
cp .env.example .env
# Edit .env and set DATABASE_URL
# 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
# 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
# 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:
Most plugins will have all three.
# 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:
bun run sync
See:
Follow the guides above to implement your plugin.
Write tests for your plugin:
# 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.
@checkstack/tsconfigany types (use unknown if needed)my-service.ts)MyService)myFunction)MY_CONSTANT)MyInterface)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 {
// ...
}
/**
* 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:
git checkout -b feature/my-new-plugin
Use prefixes:
feature/ - New featuresfix/ - Bug fixesdocs/ - Documentationrefactor/ - Code refactoringtest/ - Test additionsbun run sync
bun run lint
bun run typecheck
bun test
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 - Maintenancegit push origin feature/my-new-plugin
Then create a Pull Request on GitHub.
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
None
pgSchema() in DrizzleThese are automatically enforced by the linter:
See dependency-linter.md for details.
pgSchema() in table definitionsSee drizzle-schema-isolation.md for details.
See versioned-configs.md for details.
All contributions go through code review. Reviewers will check:
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.