Overview
This guide walks you through setting up a local development environment, understanding the codebase structure, and contributing changes to OpenSail. Whether you want to add a new API endpoint, extend the AI agent with a new tool, or fix a bug, this page covers the full workflow.Prerequisites
- 8 GB RAM minimum (16 GB recommended)
- 20 GB free disk space
- Docker Desktop running with WSL 2 (Windows) or native (macOS/Linux)
Local Development Setup
You have two options: Docker Compose (recommended for getting started quickly) or native development (recommended for debugging with breakpoints).- Docker Compose (Quick Start)
- Native Development (Without Docker)
Clone the repository
Configure environment variables
.env and set the required values:Build and start all services
Build the devserver image
Run database migrations and seed data
Access the application
Project Structure
Adding a New API Router
Create the router file
orchestrator/app/routers/. Follow the naming convention of existing routers.Create Pydantic schemas
orchestrator/app/schemas.py (or a new schemas_*.py file):Register in main.py
orchestrator/app/main.py and add:Add database models (if needed)
orchestrator/app/models.py, then generate a migration.Write tests
orchestrator/tests/routers/test_your_feature.py:Adding Agent Tools
Create the tool module
orchestrator/app/agent/tools/:Implement the executor function
params (tool parameters) and context (execution context with user_id, project_id, etc.):Register the tool
orchestrator/app/agent/tools/registry.py to import and call your registration function in _register_all_tools().Test the tool
Database Migrations with Alembic
Make model changes
orchestrator/app/models.py (or models_auth.py / models_kanban.py).Generate migration
Review the generated migration
orchestrator/alembic/versions/. Verify:- Correct column types and nullable settings
- Proper index and constraint names
- No unintended data loss
Apply migration
Test rollback
Running Migrations in Production
Code Style and Patterns
Backend (Python)
- Async everywhere: All I/O operations must use
async/await. - Dependency injection: Receive database sessions and config as function parameters; never create sessions inside services.
- Factory pattern: Use
get_orchestrator()for container operations. - Error handling: Use
HTTPExceptionwith appropriate status codes; log errors with context. - Non-blocking: Use
BackgroundTasksfor long-running operations.
Frontend (TypeScript)
- Functional components: Use React hooks, not class components.
- Type safety: Define interfaces for all props and API responses.
- API calls: Use the centralized
api.tsclient. - State management: Use React Context for global state; local state for component-specific data.
Running Tests
Common Development Tasks
Reset the database
Reset the database
Access the database shell
Access the database shell
Rebuild a Docker image with no cache
Rebuild a Docker image with no cache
View backend logs
View backend logs
Pull Request Process
Create a feature branch
Make your changes
Run tests locally
Commit with descriptive messages
Push and open a pull request
Address review feedback