From ab30edef42aed509b6fa0ff1eb70838e10dfd906 Mon Sep 17 00:00:00 2001 From: Greybeard Agent Date: Thu, 26 Mar 2026 09:19:41 +0000 Subject: [PATCH] feat: add Claude and Copilot setup documentation - Add .claude/instructions.md with architecture, patterns, and development workflow - Add .github/copilot-training.md with code examples and testing patterns - Add DEVELOPMENT.md with branching strategy, PR requirements, and common tasks - Provides AI-friendly documentation for code generation and review - Includes testing standards, linting requirements, and troubleshooting --- .claude/instructions.md | 224 +++++++++++++++++++++++++++ .github/copilot-training.md | 269 +++++++++++++++++++++++++++++++++ DEVELOPMENT.md | 291 ++++++++++++++++++++++++++++++++++++ 3 files changed, 784 insertions(+) create mode 100644 .claude/instructions.md create mode 100644 .github/copilot-training.md create mode 100644 DEVELOPMENT.md diff --git a/.claude/instructions.md b/.claude/instructions.md new file mode 100644 index 0000000..4da957a --- /dev/null +++ b/.claude/instructions.md @@ -0,0 +1,224 @@ +# Claude Instructions — Greybeard OSS + +## Project Overview + +**Greybeard** is a decision-review framework and CLI tool. It analyzes code changes, documentation, and architectural decisions through multiple lenses (Security, Performance, Team Health, etc.) and provides structured feedback. + +**Core Value:** Turn ad-hoc code review insights into systematic decision intelligence. + +## Architecture + +### Core Modules + +**`greybeard/analyzer.py`** +- `run_review()` — Main entry point for analysis +- Orchestrates backend selection (OpenAI, Anthropic, Copilot, Groq) +- Handles fallbacks and error recovery +- Streaming and non-streaming modes + +**`greybeard/modes.py`** +- Review modes: `review`, `mentor`, `coach`, `brainstorm`, etc. +- Each mode has a distinct system prompt and expectations +- Builds prompts based on packs and context + +**`greybeard/packs.py`** +- Content packs (review lenses, personas, focus areas) +- File-based and GitHub-based pack loading +- Caching for performance +- YAML parsing and validation + +**`greybeard/reporters/`** +- Output formatters: Markdown, JSON, HTML, Dashboard +- Batch analysis aggregation +- Risk deduplication and synthesis + +**`greybeard/storage/` & `greybeard/history.py`** +- Pluggable history storage (file-based default) +- Trend analysis across decisions +- Risk pattern detection + +### CLI + +**`greybeard/cli.py`** +- Commands: `analyze`, `self-check`, `coach`, `batch`, `config`, etc. +- Argument parsing with Click +- Config management (YAML + dict-based) + +## Key Patterns + +### Adding a New Backend + +```python +# greybeard/backends/my_llm.py +from .base import Backend, BackendResponse + +class MyLLMBackend(Backend): + def __init__(self, config): + self.api_key = config.get("api_key") + self.model = config.get("model", "default") + + def call(self, system_prompt, user_message, **kwargs): + """Synchronous call to LLM.""" + response = call_my_llm( + system=system_prompt, + message=user_message, + model=self.model, + api_key=self.api_key + ) + return BackendResponse( + text=response.text, + input_tokens=response.input_tokens, + output_tokens=response.output_tokens + ) + + async def call_async(self, system_prompt, user_message, **kwargs): + """Async wrapper for FastAPI/web use.""" + return await asyncio.to_thread( + self.call, system_prompt, user_message, **kwargs + ) +``` + +### Adding a Review Mode + +```python +# greybeard/modes.py +REVIEW_MODES = { + "my-review": { + "description": "My custom review lens", + "system_prompt": """You are reviewing code through the lens of [FOCUS]. + +Focus on: +- Item 1 +- Item 2 +- Item 3 + +Return structured feedback.""", + "output_format": "markdown", + } +} +``` + +### Adding a Content Pack + +```yaml +# packs/my-pack.yaml +name: my-pack +perspective: Senior Engineer +tone: direct +focus_areas: + - Architecture + - Performance +heuristics: + - Check for race conditions + - Validate error handling +example_questions: + - Is this thread-safe? + - How does this scale? +communication_style: Technical +description: A pack for deep technical review +``` + +## Development Workflow + +1. **Setup:** `uv sync --all-extras` +2. **Create branch:** `git checkout -b feat/description` +3. **Code:** Implement feature +4. **Test:** `uv run pytest tests/ -v` (80%+ coverage required) +5. **Lint:** `uv run ruff check . --fix`, `uv run black .` +6. **Type check:** `uv run mypy greybeard/` +7. **Docs:** Update README if user-facing, add docstrings +8. **Push & PR:** Create PR with detailed description + +## Testing Standards + +- **Unit tests:** Test individual functions (mock dependencies) +- **Integration tests:** Test end-to-end workflows +- **Fixtures:** Use `conftest.py` for shared test data +- **Coverage:** 80%+ required on new/modified files +- **Mocking:** Mock external APIs, use real storage for testing + +### Test Structure +```python +# tests/test_my_feature.py +import pytest +from unittest.mock import Mock, patch +from greybeard.my_feature import my_function + +class TestMyFeature: + """Group related tests in classes.""" + + def test_happy_path(self): + """Test normal operation.""" + result = my_function("input") + assert result == "expected" + + def test_error_handling(self): + """Test error cases.""" + with pytest.raises(ValueError, match="expected error"): + my_function("bad input") + + @patch("greybeard.my_feature.external_api") + def test_with_mock(self, mock_api): + """Test with mocked dependency.""" + mock_api.return_value = "mocked" + result = my_function("input") + assert result == "expected" + mock_api.assert_called_once_with("input") +``` + +## Code Standards + +- **Type hints:** All functions must have type hints (parameters + return) +- **Docstrings:** Google-style for all public functions/classes +- **Naming:** snake_case for variables/functions, PascalCase for classes +- **Imports:** Organized (stdlib, third-party, local), no unused imports +- **Line length:** 100 chars max +- **Error handling:** Catch specific exceptions, provide context + +## Commands + +```bash +# Setup +uv sync --all-extras + +# Testing +uv run pytest tests/ -v +uv run pytest --cov=greybeard --cov-report=term-missing + +# Linting +uv run ruff check . --fix +uv run black . + +# Type checking +uv run mypy greybeard/ + +# Building docs +uv run mkdocs build + +# CLI +uv run greybeard --help +``` + +## How Claude Helps + +✅ **Architecture:** Suggest modular designs, API patterns +✅ **Testing:** Generate comprehensive test cases +✅ **Performance:** Identify bottlenecks, optimize queries +✅ **LLM integration:** Help debug model behavior +✅ **Documentation:** Write user guides, API docs +✅ **Refactoring:** Suggest improvements to existing code + +## Key Decisions + +- **Pluggable backends:** Support multiple LLM providers (OpenAI, Anthropic, Copilot, Groq) +- **Async-ready:** `run_review_async()` for web/FastAPI integration +- **Packs system:** Content packs allow customization without code changes +- **Storage abstraction:** Pluggable storage (file/DB) for history and packs +- **SaaS path:** Core is library-friendly, not CLI-only + +## Useful Links + +- **Docs:** `docs/` directory (built with mkdocs) +- **Examples:** `examples/` directory +- **Tests:** `tests/` directory (mirrors src structure) +- **GitHub:** https://github.com/btotharye/greybeard diff --git a/.github/copilot-training.md b/.github/copilot-training.md new file mode 100644 index 0000000..5427c5b --- /dev/null +++ b/.github/copilot-training.md @@ -0,0 +1,269 @@ +# Copilot Training Data — Greybeard + +## Code Patterns + +### Analyzer Pattern +```python +from greybeard.models import ReviewRequest, ContentPack +from greybeard.analyzer import run_review +from greybeard.config import GreybeardConfig + +# Create review request +pack = ContentPack( + name="staff-core", + perspective="Senior Engineer", + tone="direct" +) +req = ReviewRequest( + mode="review", + pack=pack, + input_text="code to review", + context_notes="any extra context" +) + +# Get config (from file or dict) +config = GreybeardConfig.load() # or .from_dict({...}) + +# Run review +result = run_review(req, config=config) +print(result) + +# Async version for FastAPI +async def review_api(req: ReviewRequest): + result = await run_review_async(req) + return result +``` + +### CLI Command Pattern +```python +# greybeard/cli.py +import click +from greybeard.analyzer import run_review + +@click.command() +@click.argument('input_file', type=click.File('r')) +@click.option('--mode', default='review', help='Review mode') +@click.option('--pack', default='staff-core', help='Content pack') +@click.option('--backend', default='openai', help='LLM backend') +def analyze(input_file, mode, pack, backend): + """Analyze code or documentation.""" + content = input_file.read() + + req = ReviewRequest( + mode=mode, + pack=ContentPack.load(pack), + input_text=content + ) + + config = GreybeardConfig.load() + config.llm.backend = backend + + result = run_review(req, config=config) + click.echo(result) +``` + +### Backend Implementation +```python +# greybeard/backends/custom_backend.py +from typing import Optional +from .base import Backend, BackendResponse + +class CustomBackend(Backend): + """Custom LLM backend implementation.""" + + def __init__(self, config: dict): + self.api_key = config.get("api_key") + self.base_url = config.get("base_url") + self.model = config.get("model", "default-model") + + def call( + self, + system_prompt: str, + user_message: str, + stream: bool = False, + **kwargs + ) -> BackendResponse: + """Call the LLM synchronously.""" + try: + response = self._call_api( + system_prompt=system_prompt, + message=user_message, + stream=stream + ) + + return BackendResponse( + text=response.get("text"), + input_tokens=response.get("input_tokens", 0), + output_tokens=response.get("output_tokens", 0) + ) + except Exception as e: + raise RuntimeError(f"Backend error: {e}") + + def _call_api(self, **kwargs) -> dict: + """Make actual API call.""" + import requests + + headers = { + "Authorization": f"Bearer {self.api_key}", + "Content-Type": "application/json" + } + + payload = { + "model": self.model, + "messages": [ + {"role": "system", "content": kwargs.get("system_prompt")}, + {"role": "user", "content": kwargs.get("message")} + ] + } + + response = requests.post( + f"{self.base_url}/v1/chat/completions", + json=payload, + headers=headers + ) + response.raise_for_status() + + data = response.json() + return { + "text": data["choices"][0]["message"]["content"], + "input_tokens": data.get("usage", {}).get("prompt_tokens", 0), + "output_tokens": data.get("usage", {}).get("completion_tokens", 0) + } +``` + +### Pack Pattern +```python +# Custom content pack +from greybeard.packs import ContentPack + +pack = ContentPack( + name="my-security-pack", + perspective="Security Engineer", + tone="technical", + focus_areas=["Authentication", "Authorization", "Data Protection"], + heuristics=[ + "Check for SQL injection vulnerabilities", + "Verify HTTPS usage", + "Validate input sanitization" + ], + example_questions=[ + "Are there any auth bypass vectors?", + "Is sensitive data encrypted at rest and in transit?" + ], + communication_style="Direct and actionable" +) +``` + +## Testing Patterns + +### Unit Test +```python +import pytest +from unittest.mock import Mock, patch +from greybeard.analyzer import run_review +from greybeard.models import ReviewRequest, ContentPack + +@pytest.fixture +def sample_pack(): + return ContentPack( + name="test", + perspective="Tester", + tone="direct" + ) + +@pytest.fixture +def sample_request(sample_pack): + return ReviewRequest( + mode="review", + pack=sample_pack, + input_text="code sample" + ) + +def test_run_review_with_openai(sample_request): + """Test run_review with OpenAI backend.""" + config = Mock() + config.llm.backend = "openai" + config.llm.resolved_model.return_value = "gpt-4" + config.groq.available = False + + with patch("greybeard.analyzer._run_openai_compat") as mock_run: + mock_run.return_value = ("review text", 100, 200) + + result = run_review(sample_request, config=config) + + assert "review text" in result + mock_run.assert_called_once() + +def test_run_review_groq_fallback_on_simple_task(sample_request): + """Test Groq fallback for simple tasks.""" + config = Mock() + config.llm.backend = "openai" + config.llm.resolved_model.return_value = "gpt-4" + config.groq.available = True + config.groq.use_for_simple_tasks = True + config.groq.model = "llama-3.1-8b" + + sample_request.input_text = "simple" + + with patch("greybeard.analyzer.is_simple_task", return_value=True): + with patch("greybeard.analyzer.run_groq") as mock_groq: + mock_groq.return_value = ("groq response", 50, 100) + + result = run_review(sample_request, config=config) + + assert "groq response" in result + mock_groq.assert_called_once() +``` + +### Integration Test +```python +def test_analyze_cli_with_file(tmp_path): + """Test CLI analyze command with file input.""" + import subprocess + + # Create test file + test_file = tmp_path / "code.py" + test_file.write_text("def hello():\n print('hello')") + + # Run CLI + result = subprocess.run( + ["uv", "run", "greybeard", "analyze", str(test_file)], + capture_output=True, + text=True + ) + + assert result.returncode == 0 + assert len(result.stdout) > 0 # Got some output +``` + +## Common Workflows + +### Adding a New Backend +1. Create `greybeard/backends/my_backend.py` +2. Extend `Backend` base class +3. Implement `call()` and `call_async()` methods +4. Add to config `KNOWN_BACKENDS` +5. Write unit tests (mock API calls) +6. Document in README +7. PR with backend name and usage example + +### Adding a Review Mode +1. Add entry to `REVIEW_MODES` dict in `greybeard/modes.py` +2. Define system prompt (clear, structured expectations) +3. Test with multiple LLM backends +4. Add example in docs +5. PR with usage example + +### Creating a Content Pack +1. Create YAML file in `packs/` +2. Define perspective, tone, focus areas +3. Add heuristics and example questions +4. Test with `greybeard analyze --pack my-pack` +5. PR with documentation + +### Fixing a Bug +1. Write failing test that reproduces bug +2. Fix the code +3. Verify test passes +4. Add edge case tests +5. PR with reproduction steps in description diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..1a15e1e --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,291 @@ +# Development Guide — Greybeard + +## Quick Start + +```bash +# Clone repo +git clone https://github.com/btotharye/greybeard.git +cd greybeard + +# Setup +uv sync --all-extras + +# Run tests +uv run pytest tests/ -v + +# Try CLI +uv run greybeard --help +``` + +## Development Workflow + +### Branching Strategy + +- **Feature branches:** `feat/feature-name` (new features, backends, modes) +- **Bug fix branches:** `fix/bug-description` (bug fixes) +- **Documentation:** `docs/section-name` (docs-only changes) +- **Refactor:** `refactor/what-changed` (non-functional improvements) + +### Making Changes + +1. **Create branch from main:** + ```bash + git checkout main + git pull + git checkout -b feat/my-feature + ``` + +2. **Write code + tests together:** + ```bash + # Edit code in greybeard/ + # Write tests in tests/ + # Keep structure parallel + ``` + +3. **Run tests frequently:** + ```bash + uv run pytest tests/ -v + ``` + +4. **Check coverage:** + ```bash + uv run pytest --cov=greybeard --cov-report=term-missing + # Target: 80%+ on new/modified files + ``` + +5. **Lint and format:** + ```bash + uv run ruff check . --fix + uv run black . + uv run mypy greybeard/ + ``` + +6. **Build docs locally:** + ```bash + uv run mkdocs build --strict + ``` + +7. **Commit with meaningful message:** + ```bash + git commit -m "feat: add my feature + + - What it does + - Why it's needed + - How to use it" + ``` + +8. **Push and create PR:** + ```bash + git push origin feat/my-feature + # Create PR on GitHub with template + ``` + +### PR Requirements + +All PRs must meet these criteria to merge: + +- ✅ **Tests:** All tests pass locally + in CI +- ✅ **Coverage:** 80%+ on new/modified code (required) +- ✅ **Linting:** `ruff check .` passes +- ✅ **Type checking:** `mypy greybeard/` passes +- ✅ **Documentation:** Docstrings, README if user-facing +- ✅ **Docs build:** `mkdocs build --strict` succeeds + +### PR Description Template + +```markdown +## What does this do? +Brief description of feature/fix. + +## Why? +Motivation, problem it solves, or benefit. + +## How? +High-level technical overview. + +## Testing +- What tests were added? +- How can this be tested manually? + +## Breaking changes? +None / Describe if any. + +## Checklist +- [ ] Tests added/updated +- [ ] Coverage 80%+ on new code +- [ ] Linting passes (ruff, black, mypy) +- [ ] Docstrings added +- [ ] README updated (if user-facing) +- [ ] Docs build (`mkdocs build --strict`) +``` + +## Common Tasks + +### Adding a New Backend + +1. Create `greybeard/backends/my_backend.py` +2. Extend `Backend` base class +3. Implement required methods: + ```python + def call(self, system_prompt, user_message, **kwargs) -> BackendResponse: + # Sync call + + async def call_async(self, system_prompt, user_message, **kwargs): + # Async wrapper + ``` +4. Add to `greybeard/config.py` `KNOWN_BACKENDS` +5. Create tests in `tests/test_my_backend.py` (mock API calls) +6. Add to README backends section +7. Example usage in docstring + +### Adding a Review Mode + +1. Add entry to `REVIEW_MODES` in `greybeard/modes.py` +2. Define clear system prompt +3. Test with different backends +4. Document in `docs/modes/` +5. Update README features + +### Creating a Content Pack + +1. Create `packs/my-pack.yaml`: + ```yaml + name: my-pack + perspective: Senior Engineer + tone: direct + focus_areas: [...] + heuristics: [...] + ``` +2. Test: `uv run greybeard analyze --pack my-pack ` +3. Add to `docs/packs/` +4. PR with pack in `packs/` + +### Writing Tests + +Keep tests organized and comprehensive: + +```python +# tests/test_my_feature.py +import pytest +from unittest.mock import Mock, patch + +class TestMyFeature: + """Group related tests.""" + + def test_happy_path(self): + """Normal operation.""" + ... + + def test_error_case(self): + """Error handling.""" + ... + + @patch("greybeard.module.external_call") + def test_with_mock(self, mock_external): + """With mocked dependency.""" + ... + +@pytest.fixture +def sample_pack(): + """Reusable test data.""" + return ContentPack(name="test", perspective="Tester", tone="direct") +``` + +**Coverage requirements:** +- Unit tests: Mock external dependencies +- Integration tests: Use real storage (test DBs, temp files) +- Always test error cases + edge cases +- 80%+ coverage on new/modified code + +### Debugging + +```bash +# Run with print statements +uv run greybeard analyze --verbose + +# Run specific test with output +uv run pytest tests/test_analyzer.py::TestRunReview::test_happy_path -v -s + +# Run with debugger +uv run pytest tests/test_analyzer.py -v --pdb + +# Type checking for specific file +uv run mypy greybeard/analyzer.py --show-error-codes + +# Check what changed (linting) +uv run ruff check greybeard/ --show-source +``` + +## Useful Commands + +```bash +# Setup +uv sync --all-extras + +# Testing +uv run pytest tests/ -v # All tests +uv run pytest tests/test_analyzer.py -v # Specific file +uv run pytest -k test_run_review -v # Specific test pattern +uv run pytest --cov=greybeard --cov-report=term-missing # Coverage + +# Linting +uv run ruff check . --fix # Check + fix +uv run black . --check # Check only +uv run mypy greybeard/ --show-error-codes # Type check + +# Documentation +uv run mkdocs build --strict # Build docs +uv run mkdocs serve # Live preview (http://localhost:8000) + +# CLI +uv run greybeard --help # Show help +uv run greybeard analyze --help # Command help +uv run greybeard analyze --mode review --pack staff-core + +# Development +uv add package-name # Add dependency +uv lock --upgrade # Update lock file +``` + +## Code Standards + +- **Type hints:** All functions require parameter + return types +- **Docstrings:** Google-style for public functions/classes +- **Naming:** snake_case (funcs/vars), PascalCase (classes) +- **Imports:** stdlib → third-party → local, no unused imports +- **Line length:** 100 chars max +- **Comments:** Explain *why*, not *what* (code shows what) + +## Troubleshooting + +### Tests failing locally but CI passes +- Clear cache: `rm -rf .pytest_cache .ruff_cache` +- Reinstall: `uv sync --force-all` + +### Type checking errors +- Install stubs: `uv add --dev types-` +- Check mypy config in `pyproject.toml` + +### Import errors +- Check `greybeard/__init__.py` exports +- Run `uv sync` to ensure venv is updated + +### Coverage not meeting threshold +- Run with `--cov-report=html` for detailed report +- Look at red lines in report +- Add tests for untested branches + +## Getting Help + +- **Questions?** Open an issue on GitHub +- **Bug report?** Include reproduction steps + test case +- **Feature request?** Describe use case + expected behavior +- **Questions about code?** File an issue or ask in discussions + +## Resources + +- **Docs:** `docs/` (built with mkdocs) +- **Examples:** `examples/` +- **Tests:** `tests/` (mirrors `greybeard/` structure) +- **GitHub:** https://github.com/btotharye/greybeard +- **Discord:** Community support (link in README)