Thanks for your interest in contributing to Overstory! This guide covers everything you need to get started.
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/<your-username>/overstory.git cd overstory
- Install dependencies:
bun install
- Link the CLI for local development:
bun link
- Create a branch for your work:
git checkout -b fix/description-of-change
Use descriptive branch names with a category prefix:
fix/-- Bug fixesfeat/-- New featuresdocs/-- Documentation changesrefactor/-- Code refactoringtest/-- Test additions or fixes
bun test # Run all tests
bun test src/config.test.ts # Run a single test file
biome check . # Lint + format check
biome check --write . # Auto-fix lint + format issues
tsc --noEmit # Type check
bun test && biome check . && tsc --noEmit # All quality gatesAlways run all three quality gates before submitting a PR.
Overstory is a strict TypeScript project that runs directly on Bun (no build step).
noUncheckedIndexedAccessis enabled -- always handle possibleundefinedfrom indexingnoExplicitAnyis an error -- useunknownand narrow, or define proper typesuseConstis enforced -- useconstunless reassignment is needednoNonNullAssertionis a warning -- avoid!postfix, check for null/undefined instead
This is a hard rule. Use only Bun built-in APIs:
bun:sqlitefor databasesBun.spawnfor subprocessesBun.filefor file I/OBun.writefor writes
External tools (bd, mulch, git, tmux) are invoked as subprocesses via Bun.spawn, never as npm imports.
- All shared types and interfaces go in
src/types.ts - All error types go in
src/errors.tsand must extendOverstoryError - Each CLI command gets its own file in
src/commands/ - Each subsystem gets its own directory under
src/
- Tab indentation (enforced by Biome)
- 100 character line width (enforced by Biome)
- Biome handles import organization automatically
- No mocks unless absolutely necessary. Tests use real filesystems, real SQLite, and real git repos.
- Create temp directories with
mkdtempfor file I/O tests - Use
:memory:or temp file databases for SQLite tests - Use real git repos in temp directories for worktree/merge tests
- Clean up in
afterEach - Tests are colocated with source files:
src/config.test.tsalongsidesrc/config.ts
Only mock when the real thing has unacceptable side effects (tmux sessions, external AI services, network requests). When mocking is necessary, document WHY in a comment at the top of the test file.
Example test structure:
import { mkdtemp, rm } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { afterEach, beforeEach, describe, it, expect } from "bun:test";
describe("my-feature", () => {
let testDir: string;
beforeEach(async () => {
testDir = await mkdtemp(join(tmpdir(), "overstory-test-"));
});
afterEach(async () => {
await rm(testDir, { recursive: true });
});
it("does the thing", async () => {
// Write real files, run real code, assert real results
});
});Shared test utilities are available in src/test-helpers.ts:
createTempGitRepo()-- Initialize a real git repo in a temp dir with initial commitcleanupTempDir()-- Remove temp directoriescommitFile()-- Add and commit a file to a test repo
- Create
src/commands/<name>.ts - Register the command in
src/index.ts - Add tests in
src/commands/<name>.test.ts - Update the CLI Reference table in
README.md
Use concise, descriptive commit messages:
fix: resolve merge conflict detection for renamed files
feat: add dashboard live-refresh interval option
docs: update CLI reference with new nudge flags
Prefix with fix:, feat:, or docs: when the category is clear. Plain descriptive messages are also fine.
- One concern per PR. Keep changes focused -- a bug fix, a feature, a refactor. Not all three.
- Tests required. New features and bug fixes should include tests. See the testing conventions above.
- Passing CI. All PRs must pass CI checks (lint + typecheck + test) before merge.
- Description. Briefly explain what the PR does and why. Link to any relevant issues.
Use GitHub Issues for bug reports and feature requests. For security vulnerabilities, see SECURITY.md.
By contributing, you agree that your contributions will be licensed under the MIT License.