Thank you for your interest in contributing! Decision OS is an open-source decision intelligence platform, and we welcome contributions of all kinds — code, documentation, bug reports, feature requests, and ideas.
- Getting Started
- Development Workflow
- Code Style Guide
- Commit Message Format
- Pull Request Requirements
- Adding a New Decision Algorithm
- Adding a New UI Component
- Testing
- Documentation
- Node.js 22+ (LTS)
- Git
- A code editor (we recommend VS Code with our recommended extensions)
# 1. Fork the repository on GitHub
# 2. Clone your fork
git clone https://github.com/YOUR_USERNAME/decision-os.git
cd decision-os
# 3. Install dependencies
npm install
# 4. Start the development server
npm run devOpen http://localhost:3000 — a demo decision loads instantly.
npm run lint # ESLint (must pass with zero warnings)
npm run typecheck # TypeScript strict mode check
npm run test # Run unit tests
npm run build # Production buildAll four commands must pass before you submit a PR.
git checkout -b feat/your-feature-name
# or: fix/bug-description, docs/what-changed, test/what-tested- Write code following our style guide
- Add tests for new logic
- Update docs if behavior changes
npm run lint # Zero warnings
npm run typecheck # No type errors
npm run test # All tests pass
npm run build # Build succeedsgit commit -m "feat: add Monte Carlo sensitivity analysis"git push origin feat/your-feature-nameThen open a Pull Request on GitHub. The PR template will guide you.
Our CI pipeline runs: lint, typecheck, test (with coverage), build, bundle analysis, accessibility audit, E2E tests, and Lighthouse. All must pass.
Once approved and all checks pass, the PR auto-merges via squash merge.
- Strict mode — no
anytypes unless justified with a comment - Explicit return types on exported functions
- Interface over type for object shapes (unless union/intersection needed)
- Readonly where possible
- No non-null assertions (
!) — use proper type narrowing
- Functional components only (no class components except ErrorBoundary)
- Named exports — no default exports
- Props interfaces — define and export
ComponentNameProps - Memoization — use
React.memofor expensive components,useMemo/useCallbackfor expensive computations - Accessibility first — every interactive element needs keyboard support and ARIA labels
src/
├── app/ # Next.js pages — minimal logic, compose components
├── components/ # React components — UI rendering + event handling
├── hooks/ # Custom React hooks — reusable stateful logic
└── lib/ # Pure functions — no React, fully testable
├── types.ts # All TypeScript types/interfaces
├── scoring.ts # Decision algorithms (MUST be deterministic)
└── ...
| Entity | Convention | Example |
|---|---|---|
| Components | PascalCase | DecisionBuilder.tsx |
| Hooks | camelCase with use prefix |
useValidation.ts |
| Utilities | camelCase | formatRelativeTime |
| Types | PascalCase | Decision, OptionResult |
| Constants | UPPER_SNAKE_CASE | MAX_OPTIONS |
| Files | PascalCase (components), camelCase (lib) | ResultsView.tsx, scoring.ts |
We use Conventional Commits:
type(scope): description
[optional body]
[optional footer]
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
style |
Formatting, no code change |
refactor |
Code change that neither fixes nor adds |
perf |
Performance improvement |
test |
Adding or updating tests |
build |
Build system or dependencies |
ci |
CI/CD changes |
chore |
Other changes (configs, scripts) |
revert |
Revert a previous commit |
feat: add TOPSIS algorithm implementation
fix(scoring): correct weight normalization for zero-weight edge case
docs: update architecture diagram with new components
test: add edge case tests for Monte Carlo simulation
chore(deps): update vitest to v4.1.0
feat!: change score matrix format (BREAKING CHANGE)
Add ! after the type or include BREAKING CHANGE: in the footer:
feat!: change score matrix from nested to flat format
BREAKING CHANGE: ScoreMatrix type changed from Record<string, number> to flat array.
Every PR must:
- Title: Follow conventional commit format
- Description: Fill out the PR template completely
- Tests: New logic must have tests; existing tests must pass
- Types:
npm run typecheckpasses - Lint:
npm run lintpasses with zero warnings - Build:
npm run buildsucceeds - Docs: Updated if behavior changed
- Size: Keep PRs focused — prefer small, reviewable changes
- Scoring engine: Changes to
src/lib/scoring.tsmust updatedocs/SCORING_MODEL.md
-
Create the implementation in
src/lib/:// src/lib/topsis.ts export function computeTOPSIS(decision: Decision): DecisionResults { // Pure function — no side effects, deterministic }
-
Write comprehensive tests in
src/__tests__/:// src/__tests__/topsis.test.ts describe("TOPSIS", () => { it("should rank options correctly for known example", () => { // Use a worked example from academic literature }); });
-
Document the algorithm in
docs/DECISION_FRAMEWORKS.md:- Mathematical notation (LaTeX)
- When to use it
- Academic references
-
Add types to
src/lib/types.tsif needed -
Create an ADR in
docs/DECISIONS/explaining why this algorithm was added
-
Create the component in
src/components/:// src/components/MyComponent.tsx export interface MyComponentProps { // Define props } export function MyComponent({ ...props }: MyComponentProps) { return (/* JSX */); }
-
Ensure accessibility:
- Keyboard navigable
- ARIA labels on interactive elements
- Proper semantic HTML
- Sufficient color contrast
-
Write tests in
src/__tests__/components/:// src/__tests__/components/MyComponent.test.tsx import { renderWithProviders } from "../test-utils";
-
Style with Tailwind CSS — no custom CSS unless absolutely necessary
npm run test # All unit tests
npm run test:watch # Watch mode
npm run test:coverage # With coverage report
npm run test:e2e # Playwright E2E tests- Pure functions: Test inputs → outputs with known-answer tests
- Components: Test user-visible behavior, not implementation details
- Edge cases: Empty inputs, maximum values, zero weights, single option/criterion
- Determinism: Same inputs MUST produce same outputs, always
- Statements: ≥ 80%
- Branches: ≥ 75%
- Functions: ≥ 80%
- Lines: ≥ 80%
- New feature → Update README features list
- Algorithm change → Update
docs/SCORING_MODEL.mdanddocs/DECISION_FRAMEWORKS.md - Architecture change → Update
docs/ARCHITECTURE.md - New component → Auto-indexed by CI, but add JSDoc
- Concise: Say it in fewer words
- Examples: Include code samples and worked examples
- Accurate: Keep docs in sync with code (CI helps)
- Open a Discussion
- Check existing Issues
- Read the Architecture and Governance docs