This is a 24/7 autonomous GitHub agent that manages PRs and Issues using the OpenHands SDK. It runs continuously, checking every 10 minutes for assigned issues, PR reviews, and mentions.
# Using the run script (recommended)
./run.sh
# Manual execution
source venv/bin/activate
export GITHUB_TOKEN
export GITHUB_USERNAME
export LLM_API_KEY
export LLM_BASE_URL
python3 github_agent.py# Install dependencies
pip install -r requirements.txt
# Activate virtual environment
source venv/bin/activateThis project does not have a formal test suite. To test changes:
# Run a dry-run by executing the agent with test environment variables
export GITHUB_TOKEN="test_token"
export LLM_API_KEY="test_key"
python3 -c "from github_agent import GitHubAgent; agent = GitHubAgent()"No linting or formatting tools are configured. When making changes:
- Run
python3 -m py_compile github_agent.pyto check for syntax errors - Manually review code against the style guidelines below
- Standard library imports first (sorted alphabetically)
- Third-party imports second (sorted alphabetically)
- Local imports last
- Use absolute imports, not relative
import os
import sys
from pathlib import Path
from typing import Optional, List, Dict
from openhands.sdk import LLM, Agent- Shebang line for executable scripts:
#!/usr/bin/env python3 - Module docstring at the top describing purpose
- Logging setup before any other imports that might log
- Class definitions followed by functions
if __name__ == "__main__":guard at the bottom
- Classes: PascalCase (
GitHubAgent) - Functions/Variables: snake_case (
_get_assigned_issues,github_token) - Constants: UPPER_SNAKE_CASE (
HEARTBEAT_INTERVAL) - Private methods: Leading underscore (
_api_request) - Module-level private: Leading underscore prefix
- Use type hints for all function parameters and return values
- Use
Optional[T]for nullable types - Use
List[T],Dict[K, V]fromtypingmodule - Use
Nonefor literal None returns
def _api_request(
endpoint: str,
method: str = "GET",
data: Optional[Dict] = None
) -> Optional[Dict]:- Use try/except blocks for API calls and file operations
- Log errors with appropriate level (ERROR for failures, DEBUG for details)
- Return
Noneor default values on failure rather than raising - Never silently swallow errors - always log
try:
result = self._api_request(endpoint)
except Exception as e:
logger.error(f"Request failed: {e}")
return None- Create module-specific logger:
logger = logging.getLogger("github-agent") - Use structured log levels: DEBUG, INFO, ERROR
- Include context in error messages (repo, issue numbers, etc.)
- Suppress verbose third-party library logs at startup
- Prefix private methods with underscore
- Use descriptive method names (
_handle_issue,_mark_notification_read) - Keep methods focused on single responsibility
- Use data classes/dicts for structured data transfer
- Module-level docstrings describing purpose
- Class docstrings explaining role
- No inline comments for obvious code
- Docstrings use reStructuredText format
Required:
GITHUB_TOKEN- GitHub API tokenLLM_API_KEY- LLM provider API key
Optional:
GITHUB_USERNAME- Bot username (default: "openhands-bot")LLM_MODEL- LLM model (default: "anthropic/claude-sonnet-4-5-20250929")HEARTBEAT_INTERVAL- Seconds between cycles (default: 600)WORK_DIR- Working directorySTATE_DIR- State persistence directory
- Never commit secrets or API keys
- Validate all external input before processing
- Use environment variables for credentials
- Check for
.envfiles before committing
- Use the GitHub REST API via
urllib - Always include Authorization header
- Handle 403 errors specially (rate limiting/permissions)
- Use appropriate rate limiting and error handling
No Cursor or Copilot rules are configured in this repository.
github_agent.py- Main agent implementationrun.sh- Startup script with environment setupprompts/github_agent_system_prompt.j2- System prompt for the agentrequirements.txt- Python dependencies
- The agent runs continuously with a heartbeat loop
- State is persisted to
STATE_DIR/conversations/for each issue/PR - Uses the GitHub Notifications API for real-time updates
- Forks repos when lacking write access
- Comments on issues/PRs to communicate progress