# AGENTS.md

## Build, Lint, and Test Commands

### Running Tests
- Run all tests: `python -m pytest tests/`
- Run a single test: `python -m pytest tests/test_core.py::test_calculate_tool`
- Run a single test function: `python -m pytest tests/test_core.py::test_calculate_tool::test_basic_calculation`
- Run tests with coverage: `python -m pytest tests/ --cov=core --cov-report=html`

### Linting
- Run linting: `ruff check .`
- Run linting with fix suggestions: `ruff check . --fix`
- Run type checking: `mypy .`

### Build
- No build step required - this is a pure Python library

### Development
- Run the agent CLI: `python core.py`
- Run with custom API key: `API_KEY=your-key python core.py`

## Code Style Guidelines

### General
- Follow PEP 8 for general Python style
- Use type hints for all function parameters and return values
- Keep line length under 88 characters
- Use spaces around operators and after commas
- Use blank lines to separate logical sections

### Imports
- Group imports in this order:
  1. Standard library imports
  2. Third-party imports
  3. Local application imports
- Import specific items rather than using `from module import *`
- Use absolute imports (e.g., `from core import OpenRouterAgent`) rather than relative imports

### Formatting
- Use 4 spaces for indentation (no tabs)
- Use double quotes for string literals (unless containing quotes)
- Use `f""` for string formatting
- Use `snake_case` for function and variable names
- Use `PascalCase` for class names

### Types
- Use `typing` module for all type hints
- Use `Optional[T]` instead of `T | None` for Python < 3.10
- Use `List[T]`, `Dict[K, V]`, `Tuple[T, ...]` instead of `list`, `dict`, `tuple`
- Use `Callable[[ArgType], ReturnType]` for function types

### Naming Conventions
- Functions: `snake_case` (e.g., `calculate_expression`, `get_current_time`)
- Variables: `snake_case` (e.g., `user_input`, `api_key`)
- Classes: `PascalCase` (e.g., `OpenRouterAgent`, `Message`)
- Constants: `UPPER_CASE_WITH_UNDERSCORES` (e.g., `MAX_ITERATIONS`, `DEFAULT_MODEL`)
- Private members: `_private_method`, `_private_variable`
- Protected members: `__protected_method`, `__protected_variable`

### Error Handling
- Use specific exception types rather than bare `except:`
- Catch exceptions with `try/except` blocks
- Log errors using the `logger` module
- Return error messages as strings rather than raising exceptions when possible
- Use `raise` for unexpected errors that cannot be handled gracefully

### Documentation
- Use docstrings for all public functions, classes, and modules
- Use Google-style docstrings with `Args`, `Returns`, and `Raises` sections
- Include examples in docstrings when appropriate
- Use type hints in docstrings for complex types

### Code Structure
- Keep functions short (under 20 lines)
- Use `@dataclass` for simple data structures
- Use `@property` for computed attributes
- Use `@staticmethod` for utility functions that don't need instance access
- Use `@classmethod` for alternative constructors

### Tool Definition
- Use the `@register_tool` decorator to register tools
- Each tool function should have a descriptive docstring
- Use `parameters` dictionary with `type`, `properties`, and `required` keys
- Return string responses for all tool functions
- Handle invalid inputs gracefully with descriptive error messages

### Testing
- Write unit tests for all public functions
- Test edge cases and error conditions
- Use `pytest` with `unittest.mock` for mocking external dependencies
- Test tool execution and error handling
- Test the conversation loop with multiple iterations

### Development Workflow
- Always run `ruff check .` and `mypy .` before committing
- Run `python -m pytest` to ensure all tests pass
- Use `git add . && git commit -m "feat: add new tool"` for commits
- Create pull requests with descriptive titles and summaries

## Agent-Specific Rules
- Never commit API keys or secrets to the repository
- Always use `os.getenv()` to retrieve API keys from environment variables
- Use `logging` module for all logging instead of `print()`
- Use `requests` library for HTTP calls with proper error handling
- Use `json` module for JSON parsing and serialization
- Use `dataclasses` for structured data
- Use `Enum` for fixed sets of values

## Environment Variables
- `OPENROUTER_API_KEY`: Your OpenRouter API key (required for testing)
- `OPENROUTER_MODEL`: Model identifier (default: "qwen/qwen3-coder-next")
- `OPENROUTER_BASE_URL`: OpenRouter API base URL (default: "https://openrouter.ai/api/v1")

## Development Environment
- Python 3.8+ recommended
- Install dependencies: `pip install -r requirements.txt`
- Set up pre-commit hooks: `pre-commit install`

## Contribution Guidelines
- Fork the repository
- Create a feature branch: `git checkout -b feature/new-tool`
- Commit changes with descriptive messages
- Push to the branch: `git push origin feature/new-tool`
- Open a pull request with a detailed description
- Wait for review and address feedback
- Merge when approved

## Release Process
- Update version in `setup.py` or `pyproject.toml`
- Create a git tag: `git tag -a v1.0.0 -m "Release version 1.0.0"`
- Push the tag: `git push origin v1.0.0`
- Create a release on GitHub
- Publish to PyPI: `python -m build && python -m twine upload dist/*`

## Support
- File issues at: https://github.com/anomalyco/opencode/issues
- Join the discussion at: https://github.com/anomalyco/opencode/discussions
- Contact the maintainers via email: maintainers@opencode.ai