17 KiB

This repository contains the code for OpenHands, an automated AI software engineer. It has a Python backend (in the openhands directory) and React frontend (in the frontend directory).

General Setup:

To set up the entire repo, including frontend and backend, run make build. You don't need to do this unless the user asks you to, or if you're trying to run the entire application.

Running OpenHands with OpenHands:

To run the full application to debug issues:

export INSTALL_DOCKER=0
export RUNTIME=local
make build && make run FRONTEND_PORT=12000 FRONTEND_HOST=0.0.0.0 BACKEND_HOST=0.0.0.0 &> /tmp/openhands-log.txt &

IMPORTANT: Before making any changes to the codebase, ALWAYS run make install-pre-commit-hooks to ensure pre-commit hooks are properly installed.

Before pushing any changes, you MUST ensure that any lint errors or simple test errors have been fixed.

  • If you've made changes to the backend, you should run pre-commit run --config ./dev_config/python/.pre-commit-config.yaml (this will run on staged files).
  • If you've made changes to the frontend, you should run cd frontend && npm run lint:fix && npm run build ; cd ..
  • If you've made changes to the VSCode extension, you should run cd openhands/integrations/vscode && npm run lint:fix && npm run compile ; cd ../../..

The pre-commit hooks MUST pass successfully before pushing any changes to the repository. This is a mandatory requirement to maintain code quality and consistency.

If either command fails, it may have automatically fixed some issues. You should fix any issues that weren't automatically fixed, then re-run the command to ensure it passes. Common issues include:

  • Mypy type errors
  • Ruff formatting issues
  • Trailing whitespace
  • Missing newlines at end of files

Git Best Practices

  • Prefer specific git add <filename> instead of git add . to avoid accidentally staging unintended files
  • Be especially careful with git reset --hard after staging files, as it will remove accidentally staged files
  • When remote has new changes, use git fetch upstream && git rebase upstream/<branch> on the same branch

Repository Structure

Backend:

  • Located in the openhands directory
  • Testing:
    • All tests are in tests/unit/test_*.py
    • To test new code, run poetry run pytest tests/unit/test_xxx.py where xxx is the appropriate file for the current functionality
    • Write all tests with pytest

Frontend:

  • Located in the frontend directory
  • Prerequisites: A recent version of NodeJS / NPM
  • Setup: Run npm install in the frontend directory
  • Testing:
    • Run tests: npm run test
    • To run specific tests: npm run test -- -t "TestName"
    • Our test framework is vitest
  • Building:
    • Build for production: npm run build
  • Environment Variables:
    • Set in frontend/.env or as environment variables
    • Available variables: VITE_BACKEND_HOST, VITE_USE_TLS, VITE_INSECURE_SKIP_VERIFY, VITE_FRONTEND_PORT
  • Internationalization:
    • Generate i18n declaration file: npm run make-i18n
  • Data Fetching & Cache Management:
    • We use TanStack Query (fka React Query) for data fetching and cache management
    • Data Access Layer: API client methods are located in frontend/src/api and should never be called directly from UI components - they must always be wrapped with TanStack Query
    • Custom hooks are located in frontend/src/hooks/query/ and frontend/src/hooks/mutation/
    • Query hooks should follow the pattern use[Resource] (e.g., useConversationSkills)
    • Mutation hooks should follow the pattern use[Action] (e.g., useDeleteConversation)
    • Architecture rule: UI components → TanStack Query hooks → Data Access Layer (frontend/src/api) → API endpoints

VSCode Extension:

  • Located in the openhands/integrations/vscode directory
  • Setup: Run npm install in the extension directory
  • Linting:
    • Run linting with fixes: npm run lint:fix
    • Check only: npm run lint
    • Type checking: npm run typecheck
  • Building:
    • Compile TypeScript: npm run compile
    • Package extension: npm run package-vsix
  • Testing:
    • Run tests: npm run test
  • Development Best Practices:
    • Use vscode.window.createOutputChannel() for debug logging instead of showErrorMessage() popups
    • Pre-commit process runs both frontend and backend checks when committing extension changes

Enterprise Directory

The enterprise/ directory contains additional functionality that extends the open-source OpenHands codebase. This includes:

  • Authentication and user management (Keycloak integration)
  • Database migrations (Alembic)
  • Integration services (GitHub, GitLab, Jira, Linear, Slack)
  • Billing and subscription management (Stripe)
  • Telemetry and analytics (PostHog, custom metrics framework)

Enterprise Development Setup

Prerequisites:

  • Python 3.12
  • Poetry (for dependency management)
  • Node.js 22.x (for frontend)
  • Docker (optional)

Setup Steps:

  1. First, build the main OpenHands project: make build
  2. Then install enterprise dependencies: cd enterprise && poetry install --with dev,test (This can take a very long time. Be patient.)
  3. Set up enterprise pre-commit hooks: poetry run pre-commit install --config ./dev_config/python/.pre-commit-config.yaml

Running Enterprise Tests:

# Enterprise unit tests (full suite)
PYTHONPATH=".:$PYTHONPATH" poetry run --project=enterprise pytest --forked -n auto -s -p no:ddtrace -p no:ddtrace.pytest_bdd -p no:ddtrace.pytest_benchmark ./enterprise/tests/unit --cov=enterprise --cov-branch

# Test specific modules (faster for development)
cd enterprise
PYTHONPATH=".:$PYTHONPATH" poetry run pytest tests/unit/telemetry/ --confcutdir=tests/unit/telemetry

# Enterprise linting (IMPORTANT: use --show-diff-on-failure to match GitHub CI)
poetry run pre-commit run --all-files --show-diff-on-failure --config ./dev_config/python/.pre-commit-config.yaml

Running Enterprise Server:

cd enterprise
make start-backend  # Development mode with hot reload
# or
make run  # Full application (backend + frontend)

Key Configuration Files:

  • enterprise/pyproject.toml - Enterprise-specific dependencies
  • enterprise/Makefile - Enterprise build and run commands
  • enterprise/dev_config/python/ - Linting and type checking configuration
  • enterprise/migrations/ - Database migration files

Database Migrations: Enterprise uses Alembic for database migrations. When making schema changes:

  1. Create migration files in enterprise/migrations/versions/
  2. Test migrations thoroughly
  3. The CI will check for migration conflicts on PRs

Integration Development: The enterprise codebase includes integrations for:

  • GitHub - PR management, webhooks, app installations
  • GitLab - Similar to GitHub but for GitLab instances
  • Jira - Issue tracking and project management
  • Linear - Modern issue tracking
  • Slack - Team communication and notifications

Each integration follows a consistent pattern with service classes, storage models, and API endpoints.

Important Notes:

  • Enterprise code is licensed under Polyform Free Trial License (30-day limit)
  • The enterprise server extends the OSS server through dynamic imports
  • Database changes require careful migration planning in enterprise/migrations/
  • Always test changes in both OSS and enterprise contexts
  • Use the enterprise-specific Makefile commands for development

Enterprise Testing Best Practices:

Database Testing:

  • Use SQLite in-memory databases (sqlite:///:memory:) for unit tests instead of real PostgreSQL
  • Create module-specific conftest.py files with database fixtures
  • Mock external database connections in unit tests to avoid dependency on running services
  • Use real database connections only for integration tests

Import Patterns:

  • Use relative imports without enterprise. prefix in enterprise code
  • Example: from storage.database import session_maker not from enterprise.storage.database import session_maker
  • This ensures code works in both OSS and enterprise contexts

Test Structure:

  • Place tests in enterprise/tests/unit/ following the same structure as the source code
  • Use --confcutdir=tests/unit/[module] when testing specific modules
  • Create comprehensive fixtures for complex objects (databases, external services)
  • Write platform-agnostic tests (avoid hardcoded OS-specific assertions)

Mocking Strategy:

  • Use AsyncMock for async operations and MagicMock for complex objects
  • Mock all external dependencies (databases, APIs, file systems) in unit tests
  • Use patch with correct import paths (e.g., telemetry.registry.logger not enterprise.telemetry.registry.logger)
  • Test both success and failure scenarios with proper error handling

Coverage Goals:

  • Aim for 90%+ test coverage on new enterprise modules
  • Focus on critical business logic and error handling paths
  • Use --cov-report=term-missing to identify uncovered lines

Troubleshooting:

  • If tests fail, ensure all dependencies are installed: poetry install --with dev,test
  • For database issues, check migration status and run migrations if needed
  • For frontend issues, ensure the main OpenHands frontend is built: make build
  • Check logs in the logs/ directory for runtime issues
  • If tests fail with import errors, verify PYTHONPATH=".:$PYTHONPATH" is set
  • If GitHub CI fails but local linting passes: Always use --show-diff-on-failure flag to match CI behavior exactly

Template for Github Pull Request

If you are starting a pull request (PR), please follow the template in .github/pull_request_template.md.

Implementation Details

These details may or may not be useful for your current task.

Microagents

Microagents are specialized prompts that enhance OpenHands with domain-specific knowledge and task-specific workflows. They are Markdown files that can include frontmatter for configuration.

Types:

  • Public Microagents: Located in microagents/, available to all users
  • Repository Microagents: Located in .openhands/microagents/, specific to this repository

Loading Behavior:

  • Without frontmatter: Always loaded into LLM context
  • With triggers in frontmatter: Only loaded when user's message matches the specified trigger keywords

Structure:

---
triggers:
- keyword1
- keyword2
---
# Microagent Content
Your specialized knowledge and instructions here...

Frontend

Action Handling:

  • Actions are defined in frontend/src/types/action-type.ts
  • The HANDLED_ACTIONS array in frontend/src/state/chat-slice.ts determines which actions are displayed as collapsible UI elements
  • To add a new action type to the UI:
    1. Add the action type to the HANDLED_ACTIONS array
    2. Implement the action handling in addAssistantAction function in chat-slice.ts
    3. Add a translation key in the format ACTION_MESSAGE$ACTION_NAME to the i18n files
  • Actions with thought property are displayed in the UI based on their action type:
    • Regular actions (like "run", "edit") display the thought as a separate message
    • Special actions (like "think") are displayed as collapsible elements only

Adding User Settings:

  • To add a new user setting to OpenHands, follow these steps:
    1. Add the setting to the frontend:
      • Add the setting to the Settings type in frontend/src/types/settings.ts
      • Add the setting to the ApiSettings type in the same file
      • Add the setting with an appropriate default value to DEFAULT_SETTINGS in frontend/src/services/settings.ts
      • Update the useSettings hook in frontend/src/hooks/query/use-settings.ts to map the API response
      • Update the useSaveSettings hook in frontend/src/hooks/mutation/use-save-settings.ts to include the setting in API requests
      • Add UI components (like toggle switches) in the appropriate settings screen (e.g., frontend/src/routes/app-settings.tsx)
      • Add i18n translations for the setting name and any tooltips in frontend/src/i18n/translation.json
      • Add the translation key to frontend/src/i18n/declaration.ts
    2. Add the setting to the backend:
      • Add the setting to the Settings model in openhands/storage/data_models/settings.py
      • Update any relevant backend code to apply the setting (e.g., in session creation)

Settings UI Patterns:

There are two main patterns for saving settings in the OpenHands frontend:

Pattern 1: Entity-based Resources (Immediate Save)

  • Used for: API Keys, Secrets, MCP Servers
  • Behavior: Changes are saved immediately when user performs actions (add/edit/delete)
  • Implementation:
    • No "Save Changes" button
    • No local state management or isDirty tracking
    • Uses dedicated mutation hooks for each operation (e.g., use-add-mcp-server.ts, use-delete-mcp-server.ts)
    • Each mutation triggers immediate API call with query invalidation for UI updates
    • Example: MCP settings, API Keys & Secrets tabs
  • Benefits: Simpler UX, no risk of losing changes, consistent with modern web app patterns

Pattern 2: Form-based Settings (Manual Save)

  • Used for: Application settings, LLM configuration
  • Behavior: Changes are accumulated locally and saved when user clicks "Save Changes"
  • Implementation:
    • Has "Save Changes" button that becomes enabled when changes are detected
    • Uses local state management with isDirty tracking
    • Uses useSaveSettings hook to save all changes at once
    • Example: LLM tab, Application tab
  • Benefits: Allows bulk changes, explicit save action, can validate all fields before saving

When to use each pattern:

  • Use Pattern 1 (Immediate Save) for entity management where each item is independent
  • Use Pattern 2 (Manual Save) for configuration forms where settings are interdependent or need validation

Adding New LLM Models

To add a new LLM model to OpenHands, you need to update multiple files across both frontend and backend:

Model Configuration Procedure:

  1. Frontend Model Arrays (frontend/src/utils/verified-models.ts):

    • Add the model to VERIFIED_MODELS array (main list of all verified models)
    • Add to provider-specific arrays based on the model's provider:
      • VERIFIED_OPENAI_MODELS for OpenAI models
      • VERIFIED_ANTHROPIC_MODELS for Anthropic models
      • VERIFIED_MISTRAL_MODELS for Mistral models
      • VERIFIED_OPENHANDS_MODELS for models available through OpenHands provider
  2. Backend CLI Integration (openhands/cli/utils.py):

    • Add the model to the appropriate VERIFIED_*_MODELS arrays
    • This ensures the model appears in CLI model selection
  3. Backend Model List (openhands/utils/llm.py):

    • CRITICAL: Add the model to the openhands_models list (lines 57-66) if using OpenHands provider
    • This is required for the model to appear in the frontend model selector
    • Format: 'openhands/model-name' (e.g., 'openhands/o3')
  4. Backend LLM Configuration (openhands/llm/llm.py):

    • Add to feature-specific arrays based on model capabilities:
      • FUNCTION_CALLING_SUPPORTED_MODELS if the model supports function calling
      • REASONING_EFFORT_SUPPORTED_MODELS if the model supports reasoning effort parameters
      • CACHE_PROMPT_SUPPORTED_MODELS if the model supports prompt caching
      • MODELS_WITHOUT_STOP_WORDS if the model doesn't support stop words
  5. Validation:

    • Run backend linting: pre-commit run --config ./dev_config/python/.pre-commit-config.yaml
    • Run frontend linting: cd frontend && npm run lint:fix
    • Run frontend build: cd frontend && npm run build

Model Verification Arrays:

  • VERIFIED_MODELS: Main array of all verified models shown in the UI
  • VERIFIED_OPENAI_MODELS: OpenAI models (LiteLLM doesn't return provider prefix)
  • VERIFIED_ANTHROPIC_MODELS: Anthropic models (LiteLLM doesn't return provider prefix)
  • VERIFIED_MISTRAL_MODELS: Mistral models (LiteLLM doesn't return provider prefix)
  • VERIFIED_OPENHANDS_MODELS: Models available through OpenHands managed provider

Model Feature Support Arrays:

  • FUNCTION_CALLING_SUPPORTED_MODELS: Models that support structured function calling
  • REASONING_EFFORT_SUPPORTED_MODELS: Models that support reasoning effort parameters (like o1, o3)
  • CACHE_PROMPT_SUPPORTED_MODELS: Models that support prompt caching for efficiency
  • MODELS_WITHOUT_STOP_WORDS: Models that don't support stop word parameters

Frontend Model Integration:

  • Models are automatically available in the model selector UI once added to verified arrays
  • The extractModelAndProvider utility automatically detects provider from model arrays
  • Provider-specific models are grouped and prioritized in the UI selection

CLI Model Integration:

  • Models appear in CLI provider selection based on the verified arrays
  • The organize_models_and_providers function groups models by provider
  • Default model selection prioritizes verified models for each provider