Contributing
Thanks for your interest in contributing to Optio! This guide covers the development setup, project structure, workflow, and conventions.
Development Setup
Prerequisites
- Node.js 22+
- pnpm 10+ (
npm install -g pnpm) - Docker Desktop with Kubernetes enabled
- Helm 3+ and kubectl
Quick Start
terminal
git clone https://github.com/jonwiggins/optio.git
cd optio
pnpm install
# Start Kubernetes infrastructure
./scripts/setup-local.sh
# Start dev servers (API + Web) with hot reload
pnpm devThe API runs on http://localhost:4000 and the web UI on http://localhost:3000.
Building the Agent Image
terminal
docker build -t optio-agent:latest -f Dockerfile.agent .
# Load into K8s containerd (Docker Desktop)
docker save optio-agent:latest | \
docker exec -i desktop-control-plane \
ctr -n k8s.io image import --digests -Project Structure
apps/api/ Fastify API server + BullMQ workers
apps/web/ Next.js web UI
packages/ Shared libraries (types, runtime, adapters, providers)
helm/ Production Helm charts
images/ Agent container Dockerfiles
k8s/ Local dev K8s manifestsKey Directories
| Path | Contents |
|---|---|
| apps/api/src/routes/ | API route handlers (tasks, repos, secrets, auth, etc.) |
| apps/api/src/services/ | Business logic (task-service, repo-pool, review, etc.) |
| apps/api/src/workers/ | BullMQ workers (task, PR watcher, cleanup, sync) |
| apps/api/src/db/ | Drizzle schema (~26 tables) and migrations (~28) |
| apps/web/src/app/ | Next.js App Router pages |
| apps/web/src/components/ | React components (task-card, log-viewer, etc.) |
| packages/shared/ | Types, state machine, prompt renderer, error classifier |
| packages/container-runtime/ | Kubernetes container runtime interface |
| packages/agent-adapters/ | Claude Code and Codex agent adapters |
| packages/ticket-providers/ | GitHub Issues and Linear ticket providers |
Commands
terminal
# Development
pnpm dev # Start API + Web with hot reload
pnpm dev:api # Fastify API on :4000
pnpm dev:web # Next.js on :3100
# Quality checks (same as CI + pre-commit hooks)
pnpm format:check # Check formatting (Prettier)
pnpm format # Auto-fix formatting
pnpm lint # Lint with ESLint
pnpm turbo typecheck # Typecheck all 6 packages
pnpm turbo test # Run tests (Vitest)
# Build
cd apps/web && npx next build # Verify production web build
./images/build.sh # Build all agent image presets
# Database
cd apps/api && npx drizzle-kit generate # Generate migration
cd apps/api && npx drizzle-kit migrate # Apply migration
# Helm
helm lint helm/optio --set encryption.key=test
helm upgrade optio helm/optio -n optio --reuse-valuesDevelopment Workflow
Database Changes
The database schema is defined with Drizzle ORM. After editing the schema, generate and apply a migration:
terminal
# 1. Edit the schema
# apps/api/src/db/schema.ts
# 2. Generate a migration
cd apps/api && npx drizzle-kit generate
# 3. Apply (migrations also auto-run on API startup)
cd apps/api && npx drizzle-kit migrateAdding a New API Route
- Create the route handler in
apps/api/src/routes/ - Register it in
apps/api/src/server.ts - Add the API client method in
apps/web/src/lib/api-client.ts
Conventions
Code Style
- TypeScript with strict mode everywhere
- ESM modules — use
.jsextensions in imports (TypeScript resolves them to.ts) - Prettier for formatting (runs on commit via Husky)
- Tailwind CSS v4 —
@import "tailwindcss"+@themeblock in CSS, notailwind.configfile - Zustand for client state — use
useStore.getState()in callbacks/effects, not hook selectors - Zod for API request validation
- Drizzle ORM for database access
Important Patterns
- State transitions — always go through
taskService.transitionTask()which validates, updates DB, records an event, and publishes to WebSocket - Secrets — never log or return secret values. Only names and scopes are exposed via API. Encrypted at rest with AES-256-GCM
- Cost tracking — stored as string (
costUsd) to avoid floating-point precision issues - Error handling — use the error classifier (
@optio/shared) for user-facing messages, raw errors in logs - WebSocket events — published to Redis pub/sub channels, relayed to browser clients
- Next.js webpack config —
extensionAliasinnext.config.tsresolves.jsto.tsfor workspace packages
Commit Conventions
Optio uses Conventional Commits, enforced by commitlint via a Husky commit-msg hook.
| Prefix | Usage |
|---|---|
| feat: | A new feature |
| fix: | A bug fix |
| docs: | Documentation changes |
| style: | Formatting, no code change |
| refactor: | Code change that neither fixes nor adds |
| perf: | Performance improvement |
| test: | Add or update tests |
| build: | Build system or dependencies |
| ci: | CI configuration |
| chore: | Maintenance |
Pre-Commit Hooks
Husky runs the following checks before each commit, mirroring CI:
- lint-staged — runs ESLint + Prettier on staged files
pnpm format:check— verifies formatting across the entire projectpnpm turbo typecheck— typechecks all packages
Tip
Run
pnpm format to auto-fix formatting issues before committing. This saves time when the pre-commit hook catches formatting problems.Pull Requests
- Fork the repo and create a feature branch
- Make your changes with tests
- Ensure
pnpm turbo typecheckandpnpm turbo testpass - Submit a PR using the template
- Wait for CI to pass and a maintainer review
CI Checks
GitHub Actions runs the following on every PR:
- Format check (Prettier)
- Typecheck all packages
- Run tests (Vitest)
- Build web app (Next.js production build)
- Build agent image
License
Optio is MIT licensed. See the LICENSE file for details.