Skip to main content

Documentation Index

Fetch the complete documentation index at: https://allhandsai-promote-sdk-public-exports-2444.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

The reference workflow is available here!
Scan your codebase for TODO comments and let the OpenHands Agent implement them, creating a pull request for each TODO and picking relevant reviewers based on code changes and file ownership

Quick Start

1

Copy workflow to your repository

cp examples/03_github_workflows/03_todo_management/workflow.yml .github/workflows/todo-management.yml
2

Configure secrets in GitHub Settings → Secrets

Go to GitHub Settings → Secrets and add LLM_API_KEY (get from https://docs.openhands.dev/openhands/usage/llms/openhands-llms).
3

Configure GitHub Actions permissions

Go to Settings → Actions → General → Workflow permissions and enable:
  • Read and write permissions
  • Allow GitHub Actions to create and approve pull requests
4

Add TODO comments to your code

Trigger the agent by adding TODO comments into your code.Example: # TODO(openhands): Add input validation for user email
The workflow is configurable and any identifier can be used in place of TODO(openhands)

Features

  • Scanning - Finds matching TODO comments with configurable identifiers and extracts the TODO description.
  • Implementation - Sends the TODO description to the OpenHands Agent that automatically implements it
  • PR Management - Creates feature branches, pull requests and picks most relevant reviewers

Best Practices

  • Start Small - Begin with MAX_TODOS: 1 to test the workflow
  • Clear Descriptions - Write descriptive TODO comments
  • Review PRs - Always review the generated PRs before merging

Reference Workflow

This example is available on GitHub: examples/03_github_workflows/03_todo_management/
examples/03_github_workflows/03_todo_management/workflow.yml
---
# Automated TODO Management Workflow
# Make sure to replace <YOUR_LLM_MODEL> and <YOUR_LLM_BASE_URL> with
# appropriate values for your LLM setup.
#
# This workflow automatically scans for TODO(openhands) comments and creates
# pull requests to implement them using the OpenHands agent.
#
# Setup:
#  1. Add LLM_API_KEY to repository secrets
#  2. Ensure GITHUB_TOKEN has appropriate permissions
#  3. Make sure Github Actions are allowed to create and review PRs
#  4. Commit this file to .github/workflows/ in your repository
#  5. Configure the schedule or trigger manually

name: Automated TODO Management

on:
  # Manual trigger
    workflow_dispatch:
        inputs:
            max_todos:
                description: Maximum number of TODOs to process in this run
                required: false
                default: '3'
                type: string
            todo_identifier:
                description: TODO identifier to search for (e.g., TODO(openhands))
                required: false
                default: TODO(openhands)
                type: string

  # Trigger when 'automatic-todo' label is added to a PR
    pull_request:
        types: [labeled]

  # Scheduled trigger (disabled by default, uncomment and customize as needed)
  # schedule:
  # # Run every Monday at 9 AM UTC
  # - cron: "0 9 * * 1"

permissions:
    contents: write
    pull-requests: write
    issues: write

jobs:
    scan-todos:
        runs-on: ubuntu-latest
    # Only run if triggered manually or if 'automatic-todo' label was added
        if: >
            github.event_name == 'workflow_dispatch' ||
            (github.event_name == 'pull_request' &&
             github.event.label.name == 'automatic-todo')
        outputs:
            todos: ${{ steps.scan.outputs.todos }}
            todo-count: ${{ steps.scan.outputs.todo-count }}
        steps:
            - name: Checkout repository
              uses: actions/checkout@v4
              with:
                  fetch-depth: 0 # Full history for better context

            - name: Set up Python
              uses: actions/setup-python@v5
              with:
                  python-version: '3.13'

            - name: Copy TODO scanner
              run: |
                  cp examples/03_github_workflows/03_todo_management/scanner.py /tmp/scanner.py
                  chmod +x /tmp/scanner.py

            - name: Scan for TODOs
              id: scan
              run: |
                  echo "Scanning for TODO comments..."

                  # Run the scanner and capture output
                  TODO_IDENTIFIER="${{ github.event.inputs.todo_identifier || 'TODO(openhands)' }}"
                  python /tmp/scanner.py . --identifier "$TODO_IDENTIFIER" > todos.json

                  # Count TODOs
                  TODO_COUNT=$(python -c \
                    "import json; data=json.load(open('todos.json')); print(len(data))")
                  echo "Found $TODO_COUNT $TODO_IDENTIFIER items"

                  # Limit the number of TODOs to process
                  MAX_TODOS="${{ github.event.inputs.max_todos || '3' }}"
                  if [ "$TODO_COUNT" -gt "$MAX_TODOS" ]; then
                    echo "Limiting to first $MAX_TODOS TODOs"
                    python -c "
                  import json
                  data = json.load(open('todos.json'))
                  limited = data[:$MAX_TODOS]
                  json.dump(limited, open('todos.json', 'w'), indent=2)
                  "
                    TODO_COUNT=$MAX_TODOS
                  fi

                  # Set outputs
                  echo "todos=$(cat todos.json | jq -c .)" >> $GITHUB_OUTPUT
                  echo "todo-count=$TODO_COUNT" >> $GITHUB_OUTPUT

                  # Display found TODOs
                  echo "## 📋 Found TODOs" >> $GITHUB_STEP_SUMMARY
                  if [ "$TODO_COUNT" -eq 0 ]; then
                    echo "No TODO(openhands) comments found." >> $GITHUB_STEP_SUMMARY
                  else
                    echo "Found $TODO_COUNT TODO(openhands) items:" \
                      >> $GITHUB_STEP_SUMMARY
                    echo "" >> $GITHUB_STEP_SUMMARY
                    python -c "
                  import json
                  data = json.load(open('todos.json'))
                  for i, todo in enumerate(data, 1):
                      print(f'{i}. **{todo[\"file\"]}:{todo[\"line\"]}** - ' +
                            f'{todo[\"description\"]}')
                  " >> $GITHUB_STEP_SUMMARY
                  fi

    process-todos:
        needs: scan-todos
        if: needs.scan-todos.outputs.todo-count > 0
        runs-on: ubuntu-latest
        strategy:
            matrix:
                todo: ${{ fromJson(needs.scan-todos.outputs.todos) }}
            max-parallel: 1 # Process one TODO at a time to avoid conflicts
        steps:
            - name: Checkout repository
              uses: actions/checkout@v4
              with:
                  fetch-depth: 0
                  token: ${{ secrets.GITHUB_TOKEN }}

            - name: Switch to feature branch with TODO management files
              run: |
                  git checkout openhands/todo-management-example
                  git pull origin openhands/todo-management-example

            - name: Set up Python
              uses: actions/setup-python@v5
              with:
                  python-version: '3.13'

            - name: Install uv
              uses: astral-sh/setup-uv@v6
              with:
                  enable-cache: true

            - name: Install OpenHands dependencies
              run: |
                  # Install OpenHands SDK and tools from git repository
                  uv pip install --system "openhands-sdk @ git+https://github.com/OpenHands/agent-sdk.git@main#subdirectory=openhands-sdk"
                  uv pip install --system "openhands-tools @ git+https://github.com/OpenHands/agent-sdk.git@main#subdirectory=openhands-tools"

            - name: Copy agent files
              run: |
                  cp examples/03_github_workflows/03_todo_management/agent_script.py agent.py
                  cp examples/03_github_workflows/03_todo_management/prompt.py prompt.py
                  chmod +x agent.py

            - name: Configure Git
              run: |
                  git config --global user.name "openhands-bot"
                  git config --global user.email \
                    "openhands-bot@users.noreply.github.com"

            - name: Process TODO
              env:
                  LLM_MODEL: <YOUR_LLM_MODEL>
                  LLM_BASE_URL: <YOUR_LLM_BASE_URL>
                  LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                  GITHUB_REPOSITORY: ${{ github.repository }}
                  TODO_FILE: ${{ matrix.todo.file }}
                  TODO_LINE: ${{ matrix.todo.line }}
                  TODO_DESCRIPTION: ${{ matrix.todo.description }}
                  PYTHONPATH: ''
              run: |
                  echo "Processing TODO: $TODO_DESCRIPTION"
                  echo "File: $TODO_FILE:$TODO_LINE"

                  # Create a unique branch name for this TODO
                  BRANCH_NAME="todo/$(echo "$TODO_DESCRIPTION" | \
                    sed 's/[^a-zA-Z0-9]/-/g' | \
                    sed 's/--*/-/g' | \
                    sed 's/^-\|-$//g' | \
                    tr '[:upper:]' '[:lower:]' | \
                    cut -c1-50)"
                  echo "Branch name: $BRANCH_NAME"

                  # Create and switch to new branch (force create if exists)
                  git checkout -B "$BRANCH_NAME"

                  # Run the agent to process the TODO
                  # Stay in repository directory for git operations

                  # Create JSON payload for the agent
                  TODO_JSON=$(cat <<EOF
                  {
                    "file": "$TODO_FILE",
                    "line": $TODO_LINE,
                    "description": "$TODO_DESCRIPTION"
                  }
                  EOF
                  )

                  echo "JSON payload for agent:"
                  echo "$TODO_JSON"

                  # Debug environment and setup
                  echo "Current working directory: $(pwd)"
                  echo "Environment variables:"
                  echo "  LLM_MODEL: $LLM_MODEL"
                  echo "  LLM_BASE_URL: $LLM_BASE_URL"
                  echo "  GITHUB_REPOSITORY: $GITHUB_REPOSITORY"
                  echo "  LLM_API_KEY: ${LLM_API_KEY:+[SET]}"
                  echo "  GITHUB_TOKEN: ${GITHUB_TOKEN:+[SET]}"
                  echo "Available files:"
                  ls -la

                  # Run the agent with comprehensive logging
                  echo "Starting agent execution..."
                  set +e  # Don't exit on error, we want to capture it
                  uv run python agent.py "$TODO_JSON" 2>&1 | tee agent_output.log
                  AGENT_EXIT_CODE=$?
                  set -e

                  echo "Agent exit code: $AGENT_EXIT_CODE"
                  echo "Agent output log:"
                  cat agent_output.log

                  # Show files in working directory
                  echo "Files in working directory:"
                  ls -la

                  # If agent failed, show more details
                  if [ $AGENT_EXIT_CODE -ne 0 ]; then
                    echo "Agent failed with exit code $AGENT_EXIT_CODE"
                    echo "Last 50 lines of agent output:"
                    tail -50 agent_output.log
                    exit $AGENT_EXIT_CODE
                  fi

                  # Check if any changes were made
                  cd "$GITHUB_WORKSPACE"
                  if git diff --quiet; then
                    echo "No changes made by agent, skipping PR creation"
                    exit 0
                  fi

                  # Commit changes
                  git add -A
                  git commit -m "Implement TODO: $TODO_DESCRIPTION

                  Automatically implemented by OpenHands agent.

                  Co-authored-by: openhands <openhands@all-hands.dev>"

                  # Push branch
                  git push origin "$BRANCH_NAME"

                  # Create pull request
                  PR_TITLE="Implement TODO: $TODO_DESCRIPTION"
                  PR_BODY="## 🤖 Automated TODO Implementation

                  This PR automatically implements the following TODO:

                  **File:** \`$TODO_FILE:$TODO_LINE\`
                  **Description:** $TODO_DESCRIPTION

                  ### Implementation
                  The OpenHands agent has analyzed the TODO and implemented the
                  requested functionality.

                  ### Review Notes
                  - Please review the implementation for correctness
                  - Test the changes in your development environment
                  - The original TODO comment will be updated with this PR URL
                    once merged

                  ---
                  *This PR was created automatically by the TODO Management workflow.*"

                  # Create PR using GitHub CLI or API
                  curl -X POST \
                    -H "Authorization: token $GITHUB_TOKEN" \
                    -H "Accept: application/vnd.github.v3+json" \
                    "https://api.github.com/repos/${{ github.repository }}/pulls" \
                    -d "{
                      \"title\": \"$PR_TITLE\",
                      \"body\": \"$PR_BODY\",
                      \"head\": \"$BRANCH_NAME\",
                      \"base\": \"${{ github.ref_name }}\"
                    }"

    summary:
        needs: [scan-todos, process-todos]
        if: always()
        runs-on: ubuntu-latest
        steps:
            - name: Generate Summary
              run: |
                  echo "# 🤖 TODO Management Summary" >> $GITHUB_STEP_SUMMARY
                  echo "" >> $GITHUB_STEP_SUMMARY

                  TODO_COUNT="${{ needs.scan-todos.outputs.todo-count || '0' }}"
                  echo "**TODOs Found:** $TODO_COUNT" >> $GITHUB_STEP_SUMMARY

                  if [ "$TODO_COUNT" -gt 0 ]; then
                    echo "**Processing Status:** ✅ Completed" >> $GITHUB_STEP_SUMMARY
                    echo "" >> $GITHUB_STEP_SUMMARY
                    echo "Check the pull requests created for each TODO" \
                      "implementation." >> $GITHUB_STEP_SUMMARY
                  else
                    echo "**Status:** ℹ️ No TODOs found to process" \
                      >> $GITHUB_STEP_SUMMARY
                  fi

                  echo "" >> $GITHUB_STEP_SUMMARY
                  echo "---" >> $GITHUB_STEP_SUMMARY
                  echo "*Workflow completed at $(date)*" >> $GITHUB_STEP_SUMMARY