Skip to main content

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

System requirements:
  • 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).
1

Clone the repository

2

Configure environment variables

Edit .env and set the required values:
3

Build and start all services

4

Build the devserver image

This image is required for user project containers:
5

Run database migrations and seed data

6

Access the application

Project Structure

Adding a New API Router

1

Create the router file

Create a new file in orchestrator/app/routers/. Follow the naming convention of existing routers.
2

Create Pydantic schemas

Add schemas in orchestrator/app/schemas.py (or a new schemas_*.py file):
3

Register in main.py

Open orchestrator/app/main.py and add:
4

Add database models (if needed)

Add models to orchestrator/app/models.py, then generate a migration.
5

Write tests

Create tests in orchestrator/tests/routers/test_your_feature.py:

Adding Agent Tools

1

Create the tool module

Create a new directory under orchestrator/app/agent/tools/:
2

Implement the executor function

The executor function receives params (tool parameters) and context (execution context with user_id, project_id, etc.):
3

Register the tool

Add a registration function and wire it into the registry:
Then edit orchestrator/app/agent/tools/registry.py to import and call your registration function in _register_all_tools().
4

Test the tool

Write unit tests with mocked dependencies:

Database Migrations with Alembic

1

Make model changes

Edit orchestrator/app/models.py (or models_auth.py / models_kanban.py).
2

Generate migration

3

Review the generated migration

Check the new file in orchestrator/alembic/versions/. Verify:
  • Correct column types and nullable settings
  • Proper index and constraint names
  • No unintended data loss
4

Apply migration

5

Test rollback

Alembic autogenerate cannot detect column renames (it sees delete + add). For renames, create a manual migration with alembic revision -m "rename_column" and use op.alter_column().

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 HTTPException with appropriate status codes; log errors with context.
  • Non-blocking: Use BackgroundTasks for 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.ts client.
  • State management: Use React Context for global state; local state for component-specific data.

Running Tests

Common Development Tasks

Pull Request Process

1

Create a feature branch

2

Make your changes

Follow the code style and patterns described above. Write tests for new functionality.
3

Run tests locally

Ensure all existing and new tests pass.
4

Commit with descriptive messages

Keep commits focused on a single logical change.
5

Push and open a pull request

Include a description of what changed and why. Reference any related issues.
6

Address review feedback

Update the PR based on reviewer comments. Keep the conversation focused on code quality and correctness.