Contributing Guide¶
How to contribute to agentwatch development.
Development Setup¶
Prerequisites¶
- Python 3.10+
- tmux
- uv (Python package manager)
- Git
Clone and Install¶
# Clone repository
git clone https://github.com/agentwatch-sh/agentwatch.git
cd agentwatch
# Install in development mode
./install.sh --dev
# Install dependencies
uv sync
Running Tests¶
# All tests
uv run pytest
# Single module
uv run pytest agentwatch/tests/test_detectors_claude_code.py
# Tests matching pattern
uv run pytest -k "test_idle"
# Stop on first failure
uv run pytest -x
# Verbose output
uv run pytest -v
Running the Daemon¶
# Foreground (for debugging)
agentwatch start -f
# Or directly
./agentwatch.py --daemon --config ~/.config/agentwatch/config.yaml
Code Structure¶
agentwatch/
├── cli.py # Command-line interface
├── capture.py # tmux pane capture
├── config.py # Configuration constants
├── utils.py # Shared utilities
├── output/ # Output formatting
│ ├── text.py # Plain text output
│ ├── json.py # JSON output
│ └── png.py # PNG rendering
├── detectors/ # Detection modules
│ ├── base.py # BaseDetector ABC
│ ├── registry.py # Detector orchestration
│ ├── patterns.py # Detection patterns
│ ├── claude_code.py # Claude Code detector
│ └── shell.py # Shell detector
├── service/ # Daemon service
│ ├── daemon.py # Main daemon loop
│ ├── monitor.py # Session monitor
│ ├── state_store.py # State management
│ ├── session_service.py # Coding session operations (SessionService)
│ └── hooks/ # Hook system
├── server/ # Web viewer
│ ├── app.py # aiohttp application
│ ├── routes.py # HTTP routes (/api endpoints)
│ ├── websocket.py # WebSocket handling
│ └── static/ # Frontend assets
├── sessions/ # Coding session management
│ ├── session.py # Session lifecycle (CodingSessionManager)
│ ├── spawner.py # Spawns sub-agent processes
│ └── tmux.py # Async tmux client wrapper
└── tests/ # Test suite
Coding Conventions¶
Python Style¶
- Full type annotations on all functions
- Use dataclasses for structured data
- Async code uses asyncio
- Follow PEP 8 naming conventions
Example¶
from dataclasses import dataclass
from typing import Optional
@dataclass
class DetectionResult:
"""Result of a detection operation."""
name: str
confidence: float
detail: Optional[str] = None
def detect_program(text: str) -> DetectionResult:
"""Detect which program is running.
Args:
text: Terminal content to analyze
Returns:
Detection result with program name and confidence
"""
# Implementation
pass
Detectors¶
Detectors extend BaseDetector and implement:
class MyDetector(BaseDetector):
"""Detector for MyProgram."""
@property
def priority(self) -> int:
"""Higher priority detectors run first."""
return 50
def detect_program(self, text: str) -> Optional[DetectionResult]:
"""Detect if MyProgram is running."""
pass
def detect_state(self, text: str, program: str) -> Optional[DetectionResult]:
"""Detect current state of MyProgram."""
pass
Tests¶
Organize tests by module:
class TestClaudeCodeIdleDetection:
"""Tests for Claude Code idle state detection."""
def test_idle_with_prompt_at_bottom(self):
"""Should detect idle when prompt is at bottom."""
pass
def test_idle_with_autosuggest(self):
"""Should detect idle when autosuggest is visible."""
pass
Frontend¶
- Use
remoteLog()instead ofconsole.log()for debugging - Follow existing patterns in
app.js - Keep JavaScript in separate
.jsfiles
Making Changes¶
Before Starting¶
- Check existing issues for related work
- Open an issue to discuss major changes
- Make sure tests pass on main branch
Development Workflow¶
-
Create a feature branch:
-
Make changes with tests
-
Run tests:
-
Check code style:
-
Commit with descriptive message:
Commit Message Format¶
Types:
feat: New featurefix: Bug fixrefactor: Code refactoringdocs: Documentationtest: Testschore: Maintenance
Pull Request Process¶
- Push your branch
- Open a PR against
main - Fill in the PR template
- Wait for CI to pass
- Address review feedback
- Maintainer merges when ready
Adding Features¶
New Detector¶
- Create
agentwatch/detectors/my_program.py - Extend
BaseDetector - Register in
agentwatch/detectors/__init__.py - Add tests in
agentwatch/tests/test_detectors_my_program.py - Document in detection reference
New Hook Type¶
- Create
agentwatch/service/hooks/my_hook.py - Extend
BaseHook - Register in
agentwatch/service/hooks/__init__.py - Add config schema in
config_loader.py - Document in hooks guide
New Session Operation¶
- Add the operation in
service/session_service.py(SessionService) - Expose it via an
/apiroute inserver/routes.py - Wire up the
agentwatch session ...CLI verb - Add tests
- Document in the sessions reference
New API Endpoint¶
- Add route in
server/routes.py - Follow existing auth patterns
- Add tests
- Regenerate API docs:
Testing¶
Writing Tests¶
import pytest
from agentwatch.detectors import detect_all
class TestMyFeature:
"""Tests for my feature."""
def test_basic_case(self):
"""Should handle basic case."""
result = my_function("input")
assert result == "expected"
def test_edge_case(self):
"""Should handle edge case."""
with pytest.raises(ValueError):
my_function("")
Test Fixtures¶
Use fixtures for common setup:
@pytest.fixture
def sample_capture():
"""Sample terminal capture for testing."""
return """
Claude Code v1.0.30
❯ hello
"""
Capture Files for Tests¶
Save real captures for testing:
# Enable debug captures
agentwatch restart
# Trigger the scenario you want to test
# Copy the capture file
cp ~/.cache/agentwatch/captures/session/capture_*.txt \
agentwatch/tests/fixtures/my_test_case.txt
Documentation¶
Updating Docs¶
- Edit files in
docs/ - Preview locally:
- Check at http://localhost:8000
API Documentation¶
API docs are auto-generated. After changing /api routes or session operations:
Docstring Format¶
def my_function(param: str) -> Result:
"""Short description of the function.
Longer description if needed, explaining behavior,
edge cases, and important notes.
Args:
param: Description of the parameter
Returns:
Description of the return value
Raises:
ValueError: When param is invalid
"""
pass
Releases¶
Releases are automated. Maintainers:
- Update version in
agentwatch/__init__.py - Commit and tag:
The GitHub workflow handles building and publishing.